diff --git a/.drone/drone.yml b/.drone/drone.yml
deleted file mode 100644
index aa10b18..0000000
--- a/.drone/drone.yml
+++ /dev/null
@@ -1,142 +0,0 @@
-kind: pipeline
-type: exec
-name: linux-amd64
-
-platform:
-  arch: amd64
-  os: linux
-
-steps:
-- name: test
-  commands:
-  - mkdir -p $HOMEPATH/.docker; echo $IMAGE_PULL_SECRETS > $HOMEPATH/.docker/config.json
-  - make docker-build test
-  environment:
-    VERSION: ${DRONE_TAG:-latest}-linux-amd64
-    DEV_REGISTRY:
-      from_secret: dev_registry
-    DRYCC_REGISTRY:
-      from_secret: drycc_registry
-    IMAGE_PULL_SECRETS:
-      from_secret: container_pull_secrets
-  when:
-    event:
-    - push
-    - tag
-    - pull_request
-
-- name: publish
-  commands:
-  - echo $CONTAINER_PASSWORD | docker login $DRYCC_REGISTRY --username $CONTAINER_USERNAME --password-stdin > /dev/null 2>&1
-  - make docker-build docker-immutable-push
-  environment:
-    VERSION: ${DRONE_TAG:-latest}-linux-amd64
-    DEV_REGISTRY:
-      from_secret: dev_registry
-    DRYCC_REGISTRY:
-      from_secret: drycc_registry
-    CONTAINER_USERNAME:
-      from_secret: container_username
-    CONTAINER_PASSWORD:
-      from_secret: container_password
-  when:
-    event:
-    - push
-    - tag
-
----
-kind: pipeline
-type: exec
-name: linux-arm64
-
-platform:
-  arch: arm64
-  os: linux
-
-steps:
-- name: publish
-  commands:
-  - echo $CONTAINER_PASSWORD | docker login $DRYCC_REGISTRY --username $CONTAINER_USERNAME --password-stdin > /dev/null 2>&1
-  - make docker-build docker-immutable-push
-  environment:
-    VERSION: ${DRONE_TAG:-latest}-linux-arm64
-    DEV_REGISTRY:
-      from_secret: dev_registry
-    DRYCC_REGISTRY:
-      from_secret: drycc_registry
-    CONTAINER_USERNAME:
-      from_secret: container_username
-    CONTAINER_PASSWORD:
-      from_secret: container_password
-  when:
-    event:
-    - push
-    - tag
-
----
-kind: pipeline
-type: docker
-name: manifest
-image_pull_secrets:
-- container_pull_secrets
-
-steps:
-
-- name: generate manifest
-  image: registry.drycc.cc/drycc/python-dev
-  pull: always
-  commands:
-  - sed -i "s/registry.drycc.cc/$${DRYCC_REGISTRY}/g" .drone/manifest.tmpl
-  environment:
-    DEV_REGISTRY:
-      from_secret: dev_registry
-    DRYCC_REGISTRY:
-      from_secret: drycc_registry
-
-- name: publish
-  image: plugins/manifest
-  settings:
-    spec: .drone/manifest.tmpl
-    username:
-      from_secret: container_username
-    password:
-      from_secret: container_password
-  environment:
-    DEV_REGISTRY:
-      from_secret: dev_registry
-    DRYCC_REGISTRY:
-      from_secret: drycc_registry
-
-trigger:
-  event:
-  - push
-  - tag
-
-depends_on:
-- linux-amd64
-- linux-arm64
-
----
-kind: pipeline
-type: exec
-name: chart
-
-steps:
-- name: generate chart
-  commands:
-  - IMAGE_TAG=$([ ! -z $DRONE_TAG ] && echo \"${DRONE_TAG:1}\" || echo \"canary\")
-  - sed -i "s/imageTag:\ \"canary\"/imageTag:\ $IMAGE_TAG/g" charts/database/values.yaml
-  - helm package -u charts/database --version $([ -z $DRONE_TAG ] && echo 1.0.0 || echo ${DRONE_TAG#v})
-  - echo $CONTAINER_PASSWORD | helm registry login $DRYCC_REGISTRY -u $CONTAINER_USERNAME --password-stdin
-  - helm push database-$([ -z $DRONE_TAG ] && echo 1.0.0 || echo ${DRONE_TAG#v}).tgz oci://$DRYCC_REGISTRY/$([ -z $DRONE_TAG ] && echo charts-testing || echo charts)
-  environment:
-    DRYCC_REGISTRY:
-      from_secret: drycc_registry
-    CONTAINER_USERNAME:
-      from_secret: container_username
-    CONTAINER_PASSWORD:
-      from_secret: container_password
-  when:
-    event:
-    - push
-    - tag
diff --git a/.drone/manifest.tmpl b/.drone/manifest.tmpl
deleted file mode 100644
index 0182d12..0000000
--- a/.drone/manifest.tmpl
+++ /dev/null
@@ -1,18 +0,0 @@
-image: registry.drycc.cc/drycc/postgres:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}canary{{/if}}
-{{#if build.tags}}
-tags:
-{{#each build.tags}}
-  - {{this}}
-{{/each}}
-{{/if}}
-manifests:
-  -
-    image: registry.drycc.cc/drycc/postgres:{{#if build.tag}}{{build.tag}}-{{else}}latest-{{/if}}linux-amd64
-    platform:
-      architecture: amd64
-      os: linux
-  -
-    image: registry.drycc.cc/drycc/postgres:{{#if build.tag}}{{build.tag}}-{{else}}latest-{{/if}}linux-arm64
-    platform:
-      architecture: arm64
-      os: linux
diff --git a/.gitignore b/.gitignore
index 1ee9ef0..4573d78 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
 contrib/ci/tmp
-.vscode/
\ No newline at end of file
+.vscode/
+charts/database/Chart.lock
+charts/database/charts/
diff --git a/.woodpecker/build-linux.yml b/.woodpecker/build-linux.yml
new file mode 100644
index 0000000..ef4ecfd
--- /dev/null
+++ b/.woodpecker/build-linux.yml
@@ -0,0 +1,35 @@
+matrix:
+  platform:
+    - linux/amd64
+    - linux/arm64
+
+labels:
+  type: exec
+  platform: ${platform}
+
+steps:
+- name: publish-linux
+  image: bash
+  commands:
+  - export VERSION=$([ -z $CI_COMMIT_TAG ] && echo latest || echo $CI_COMMIT_TAG)-$(sed 's#/#-#g' <<< $CI_SYSTEM_PLATFORM)
+  - echo $CONTAINER_PASSWORD | podman login $DRYCC_REGISTRY --username $CONTAINER_USERNAME --password-stdin > /dev/null 2>&1
+  - make podman-build podman-immutable-push
+  environment:
+    CODENAME:
+      from_secret: codename
+    DEV_REGISTRY:
+      from_secret: dev_registry
+    DRYCC_REGISTRY:
+      from_secret: drycc_registry
+    CONTAINER_USERNAME:
+      from_secret: container_username
+    CONTAINER_PASSWORD:
+      from_secret: container_password
+  when:
+    event:
+    - push
+    - tag
+    - cron
+
+depends_on:
+- test-linux
\ No newline at end of file
diff --git a/.woodpecker/chart.yaml b/.woodpecker/chart.yaml
new file mode 100644
index 0000000..cfcd3ec
--- /dev/null
+++ b/.woodpecker/chart.yaml
@@ -0,0 +1,33 @@
+labels:
+  type: exec
+  platform: linux/amd64
+
+steps:
+- name: generate-chart
+  image: bash
+  commands:
+  - export VERSION=$(sed 's#v##' <<< $CI_COMMIT_TAG)
+  - export IMAGE_TAG=$([ ! -z $CI_COMMIT_TAG ] && echo \"$VERSION\" || echo \"canary\")
+  - export APP_VERSION=$([ -z $CI_COMMIT_TAG ] && echo $CI_COMMIT_SHA || echo $VERSION)
+  - export CHART_VERSION=$([ -z $CI_COMMIT_TAG ] && echo 1.0.0 || echo $VERSION)
+  - sed -i "s/imageTag:\ \"canary\"/imageTag:\ $IMAGE_TAG/g" charts/$${CI_REPO_NAME}/values.yaml
+  - helm package -u charts/$${CI_REPO_NAME} --version $CHART_VERSION --app-version $APP_VERSION
+  - echo $CONTAINER_PASSWORD | helm registry login $DRYCC_REGISTRY -u $CONTAINER_USERNAME --password-stdin
+  - helm push $${CI_REPO_NAME}-$CHART_VERSION.tgz oci://$DRYCC_REGISTRY/$([ -z $CI_COMMIT_TAG ] && echo charts-testing || echo charts)
+  environment:
+    DEV_REGISTRY:
+      from_secret: dev_registry
+    DRYCC_REGISTRY:
+      from_secret: drycc_registry
+    CONTAINER_USERNAME:
+      from_secret: container_username
+    CONTAINER_PASSWORD:
+      from_secret: container_password
+  when:
+    event:
+    - push
+    - tag
+    - cron
+
+depends_on:
+- manifest
diff --git a/.woodpecker/manifest.tmpl b/.woodpecker/manifest.tmpl
new file mode 100644
index 0000000..8739535
--- /dev/null
+++ b/.woodpecker/manifest.tmpl
@@ -0,0 +1,18 @@
+image: registry.drycc.cc/drycc/{{project}}:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}canary{{/if}}
+{{#if build.tags}}
+tags:
+{{#each build.tags}}
+  - {{this}}
+{{/each}}
+{{/if}}
+manifests:
+  -
+    image: registry.drycc.cc/drycc/{{project}}:{{#if build.tag}}{{build.tag}}-{{else}}latest-{{/if}}linux-amd64
+    platform:
+      architecture: amd64
+      os: linux
+  -
+    image: registry.drycc.cc/drycc/{{project}}:{{#if build.tag}}{{build.tag}}-{{else}}latest-{{/if}}linux-arm64
+    platform:
+      architecture: arm64
+      os: linux
diff --git a/.woodpecker/manifest.yml b/.woodpecker/manifest.yml
new file mode 100644
index 0000000..19fc70c
--- /dev/null
+++ b/.woodpecker/manifest.yml
@@ -0,0 +1,43 @@
+labels:
+  type: exec
+  platform: linux/amd64
+
+steps:
+- name: generate-manifest
+  image: bash
+  commands:
+  - sed -i "s/{{project}}/$${CI_REPO_NAME}/g" .woodpecker/manifest.tmpl
+  - sed -i "s/registry.drycc.cc/$${DRYCC_REGISTRY}/g" .woodpecker/manifest.tmpl
+  environment:
+    DRYCC_REGISTRY:
+      from_secret: drycc_registry
+  when:
+    event:
+    - tag
+    - push
+    - cron
+
+- name: publish-manifest
+  image: bash
+  commands:
+  - podman run --rm
+    -e PLUGIN_SPEC=.woodpecker/manifest.tmpl
+    -e PLUGIN_USERNAME=$CONTAINER_USERNAME
+    -e PLUGIN_PASSWORD=$CONTAINER_PASSWORD
+    -e DRONE_TAG=$CI_COMMIT_TAG
+    -v $(pwd):$(pwd)
+    -w $(pwd)
+    docker.io/plugins/manifest
+  environment:
+    CONTAINER_USERNAME:
+      from_secret: container_username
+    CONTAINER_PASSWORD:
+      from_secret: container_password
+  when:
+    event:
+    - tag
+    - push
+    - cron
+
+depends_on:
+- build-linux
diff --git a/.woodpecker/test-linux.yml b/.woodpecker/test-linux.yml
new file mode 100644
index 0000000..194832f
--- /dev/null
+++ b/.woodpecker/test-linux.yml
@@ -0,0 +1,24 @@
+matrix:
+  platform:
+  - linux/amd64
+  - linux/arm64
+
+labels:
+  type: exec
+  platform: ${platform}
+
+steps:
+- name: test-linux
+  image: bash
+  commands:
+  - make test
+  environment:
+    CODENAME:
+      from_secret: codename
+    DEV_REGISTRY:
+      from_secret: dev_registry
+  when:
+    event:
+    - push
+    - tag
+    - cron
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 2e2c6ae..c0c3290 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,5 +1,4 @@
-# How to Contribute
+# Contributing to Drycc
 
 This project is part of Drycc. You can find the latest contribution
-guidelines [at the Drycc project](https://github.com/drycc/drycc/blob/main/CONTRIBUTING.md).
-
+guidelines [in our documentation](https://www.drycc.cc/docs/workflow/contributing/overview/).
diff --git a/Dockerfile b/Dockerfile
index 60fd030..f0764de 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,38 +1,47 @@
-FROM registry.drycc.cc/drycc/base:bullseye
+ARG CODENAME
+FROM registry.drycc.cc/drycc/base:${CODENAME}
 
 COPY rootfs/usr /usr/
 COPY rootfs/entrypoint.sh /entrypoint.sh
-ENV PYTHON_VERSION="3.10.6" \
-  PG_MAJOR=14 \
-  POSTGRESQL_VERSION="14.5"
 
-ENV PGDATA /data/${PG_MAJOR}
 
-RUN install-packages gcc \
+ARG PYTHON_VERSION="3.13" \
+  POSTGRES_EXPORTER_VERSION="0.18.1"
+
+ENV HOME=/data \
+  PG_MAJOR=18 \
+  PG_MINOR=1 \
+  S3_RCLONE_VERSION="1.71.1" 
+
+ENV PGDATA=$HOME/$PG_MAJOR
+
+RUN install-packages vim gcc pigz jq\
   && install-stack python $PYTHON_VERSION \
-  && install-stack postgresql $POSTGRESQL_VERSION \
+  && install-stack postgresql $PG_MAJOR.$PG_MINOR \
+  && install-stack rclone $S3_RCLONE_VERSION \
+  && install-stack postgres_exporter $POSTGRES_EXPORTER_VERSION \
   && . init-stack \
   && set -eux; pip3 install --disable-pip-version-check --no-cache-dir psycopg[binary] patroni[kubernetes] 2>/dev/null; set +eux \
   && apt-get purge -y --auto-remove gcc \
   && apt-get autoremove -y \
   && apt-get clean -y \
   && rm -rf \
-    /usr/share/doc \
-    /usr/share/man \
-    /usr/share/info \
-    /usr/share/locale \
-    /var/lib/apt/lists/* \
-    /var/log/* \
-    /var/cache/debconf/* \
-    /etc/systemd \
-    /lib/lsb \
-    /lib/udev \
-    /usr/lib/`echo $(uname -m)`-linux-gnu/gconv/IBM* \
-    /usr/lib/`echo $(uname -m)`-linux-gnu/gconv/EBC* \
+  /usr/share/doc \
+  /usr/share/man \
+  /usr/share/info \
+  /usr/share/locale \
+  /var/lib/apt/lists/* \
+  /var/log/* \
+  /var/cache/debconf/* \
+  /etc/systemd \
+  /lib/lsb \
+  /lib/udev \
+  /usr/lib/`echo $(uname -m)`-linux-gnu/gconv/IBM* \
+  /usr/lib/`echo $(uname -m)`-linux-gnu/gconv/EBC* \
   && mkdir -p /usr/share/man/man{1..8} \
   && mkdir -p $PGDATA \
   && groupadd postgres && useradd -g postgres postgres \
-  && chown -R postgres:postgres /data
+  && chown -R postgres:postgres $HOME
 
 USER postgres
 ENTRYPOINT ["init-stack", "/entrypoint.sh"]
diff --git a/MAINTAINERS.md b/MAINTAINERS.md
index 634e415..fc5f4fa 100644
--- a/MAINTAINERS.md
+++ b/MAINTAINERS.md
@@ -1,4 +1,4 @@
 # Drycc Maintainers
 
 This project is part of Drycc. The official maintainers documentation is
-located [in the main project](https://github.com/drycc/drycc/blob/main/MAINTAINERS.md).
+located [in our documentation](http://www.drycc.cc/contributing/maintainers/).
diff --git a/Makefile b/Makefile
index 5eaa3de..185c51b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 # Short name: Short name, following [a-zA-Z_], used all over the place.
 # Some uses for short name:
-# - Docker image name
+# - Container image name
 # - Kubernetes service, rc, pod, secret, volume names
-SHORT_NAME := postgres
+SHORT_NAME := database
 DRYCC_REGISTRY ?= ${DEV_REGISTRY}
 IMAGE_PREFIX ?= drycc
 PLATFORM ?= linux/amd64,linux/arm64
@@ -15,23 +15,20 @@ SHELL_SCRIPTS = $(wildcard rootfs/usr/share/scripts/patroni/*)
 # and other build options
 DEV_ENV_IMAGE := ${DEV_REGISTRY}/drycc/go-dev
 DEV_ENV_WORK_DIR := /opt/drycc/go/src/${REPO_PATH}
-DEV_ENV_CMD := docker run --rm -v ${CURDIR}:${DEV_ENV_WORK_DIR} -w ${DEV_ENV_WORK_DIR} ${DEV_ENV_IMAGE}
-DEV_ENV_CMD_INT := docker run -it --rm -v ${CURDIR}:${DEV_ENV_WORK_DIR} -w ${DEV_ENV_WORK_DIR} ${DEV_ENV_IMAGE}
+DEV_ENV_CMD := podman run --rm -v ${CURDIR}:${DEV_ENV_WORK_DIR} -w ${DEV_ENV_WORK_DIR} ${DEV_ENV_IMAGE}
+DEV_ENV_CMD_INT := podman run -it --rm -v ${CURDIR}:${DEV_ENV_WORK_DIR} -w ${DEV_ENV_WORK_DIR} ${DEV_ENV_IMAGE}
 
-all: docker-build docker-push
+all: podman-build podman-push
 
 # For cases where we're building from local
 # We also alter the RC file to set the image name.
-docker-build:
-	docker build ${DOCKER_BUILD_FLAGS} -t ${IMAGE} .
-	docker tag ${IMAGE} ${MUTABLE_IMAGE}
-
-docker-buildx:
-	docker buildx build --platform ${PLATFORM} -t ${IMAGE} . --push
+podman-build:
+	podman build --build-arg CODENAME=${CODENAME} -t ${IMAGE} .
+	podman tag ${IMAGE} ${MUTABLE_IMAGE}
 
 test: test-style
 
 test-style:
 	${DEV_ENV_CMD} shellcheck $(SHELL_SCRIPTS)
 
-.PHONY: all docker-build docker-push test
+.PHONY: all podman-build podman-push test
diff --git a/README.md b/README.md
index fa2c5a5..80225f9 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 
 # Drycc Postgres
-[![Build Status](https://drone.drycc.cc/api/badges/drycc/postgres/status.svg)](https://drone.drycc.cc/drycc/postgres)
+[![Build Status](https://woodpecker.drycc.cc/api/badges/drycc/database/status.svg)](https://woodpecker.drycc.cc/drycc/database)
 
 Drycc (pronounced DAY-iss) Workflow is an open source Platform as a Service (PaaS) that adds a developer-friendly layer to any [Kubernetes](http://kubernetes.io) cluster, making it easy to deploy and manage applications on your own servers.
 
@@ -8,10 +8,6 @@ For more information about the Drycc Workflow, please visit the main project pag
 
 We welcome your input! If you have feedback, please submit an [issue][issues]. If you'd like to participate in development, please read the "Development" section below and submit a [pull request][prs].
 
-# About
-
-This component is a PostgreSQL database for use in Kubernetes. It builds on the official [postgres](https://registry.hub.docker.com/_/postgres/) Docker image. While it's intended for use inside of the Drycc Workflow open source [PaaS](https://en.wikipedia.org/wiki/Platform_as_a_service), it's flexible enough to be used as a standalone pod on any Kubernetes cluster or even as a standalone Docker container.
-
 # Development
 
 The Drycc project welcomes contributions from all developers. The high level process for development matches many other open source projects. See below for an outline.
@@ -27,7 +23,7 @@ The Drycc project welcomes contributions from all developers. The high level pro
 In order to develop and test this component in a Drycc cluster, you'll need the following:
 
 * [GNU Make](https://www.gnu.org/software/make/)
-* [Docker](https://www.docker.com/) installed, configured and running
+* [Podman](https://podman.io/) installed, configured and running
 * A working Kubernetes cluster and `kubectl` installed and configured to talk to the cluster
  * If you don't have this setup, please see [the Kubernetes documentation][k8s-docs]
 
@@ -39,27 +35,27 @@ If your feature or bugfix doesn't easily lend itself to unit/integration testing
 
 ### Dogfooding
 
-Finally, we encourage you to [dogfood](https://en.wikipedia.org/wiki/Eating_your_own_dog_food) this component while you're writing code on it. To do so, you'll need to build and push Docker images with your changes.
+Finally, we encourage you to [dogfood](https://en.wikipedia.org/wiki/Eating_your_own_dog_food) this component while you're writing code on it. To do so, you'll need to build and push Container images with your changes.
 
 This project has a [Makefile](https://github.com/drycc/postgres/blob/main/Makefile) that makes these tasks significantly easier. It requires the following environment variables to be set:
 
-* `DRYCC_REGISTRY` - A Docker registry that you have push access to and your Kubernetes cluster can pull from
+* `DRYCC_REGISTRY` - A Container registry that you have push access to and your Kubernetes cluster can pull from
   * If this is [Docker Hub](https://hub.docker.com/), leave this variable empty
   * Otherwise, ensure it has a trailing `/`
-* `IMAGE_PREFIX` - The organization in the Docker repository. This defaults to `drycc`, but if you don't have access to that organization, set this to one you have push access to.
+* `IMAGE_PREFIX` - The organization in the Container repository. This defaults to `drycc`, but if you don't have access to that organization, set this to one you have push access to.
 * `SHORT_NAME` (optional) - The name of the image. This defaults to `postgres`
-* `VERSION` (optional) - The tag of the Docker image. This defaults to the current Git SHA (the output of `git rev-parse --short HEAD`)
+* `VERSION` (optional) - The tag of the Container image. This defaults to the current Git SHA (the output of `git rev-parse --short HEAD`)
 
-Assuming you have these variables set correctly, run `make docker-build` to build the new image, and `make docker-push` to push it. Here is an example command that would push to `example.com/arschles/postgres:devel`:
+Assuming you have these variables set correctly, run `make podman-build` to build the new image, and `make podman-push` to push it. Here is an example command that would push to `example.com/arschles/postgres:devel`:
 
 ```console
 export DRYCC_REGISTRY=example.com/
 export IMAGE_PREFIX=arschles
 export VERSION=devel
-make docker-build docker-push
+make podman-build podman-push
 ```
 
-Note that you'll have to push your image to a Docker repository (`make docker-push`) in order for your Kubernetes cluster to pull the image. This is important for testing in your cluster.
+Note that you'll have to push your image to a Container repository (`make podman-push`) in order for your Kubernetes cluster to pull the image. This is important for testing in your cluster.
 
 
 [issues]: https://github.com/drycc/postgres/issues
diff --git a/charts/database/Chart.yaml b/charts/database/Chart.yaml
index 0ec5901..d12aee8 100644
--- a/charts/database/Chart.yaml
+++ b/charts/database/Chart.yaml
@@ -1,10 +1,11 @@
 name: database
 apiVersion: v2
+appVersion: 1.0.0
 dependencies:
   - name: common
     repository: oci://registry.drycc.cc/charts
-    version: ~1.1.1
-home: https://github.com/drycc/postgres
+    version: ~1.1.2
+home: https://github.com/drycc/database
 version: v1.1.0
 description: A PostgreSQL database used by Drycc Workflow.
 keywords:
diff --git a/charts/database/templates/_helper.tpl b/charts/database/templates/_helper.tpl
index 0cf961a..3d1638f 100644
--- a/charts/database/templates/_helper.tpl
+++ b/charts/database/templates/_helper.tpl
@@ -1,7 +1,51 @@
 {{- define "database.envs" }}
 env:
-- name: DATABASE_STORAGE
-  value: "{{.Values.global.storage}}"
+- name: RETAIN_BACKUPS_AGE
+  value: "{{.Values.cronjob.retainBackupsAge}}"
+{{- if (.Values.storageEndpoint) }}
+- name: "DRYCC_STORAGE_BUCKET"
+  valueFrom:
+    secretKeyRef:
+      name: database-creds
+      key: storage-bucket
+- name: "DRYCC_STORAGE_ENDPOINT"
+  valueFrom:
+    secretKeyRef:
+      name: database-creds
+      key: storage-endpoint
+- name: "DRYCC_STORAGE_ACCESSKEY"
+  valueFrom:
+    secretKeyRef:
+      name: database-creds
+      key: storage-accesskey
+- name: "DRYCC_STORAGE_SECRETKEY"
+  valueFrom:
+    secretKeyRef:
+      name: database-creds
+      key: storage-secretkey
+- name: "DRYCC_STORAGE_PATH_STYLE"
+  valueFrom:
+    secretKeyRef:
+      name: database-creds
+      key: storage-path-style
+{{- else if .Values.storage.enabled  }}
+- name: "DRYCC_STORAGE_BUCKET"
+  value: "database"
+- name: "DRYCC_STORAGE_ENDPOINT"
+  value: http://drycc-storage:9000
+- name: "DRYCC_STORAGE_ACCESSKEY"
+  valueFrom:
+    secretKeyRef:
+      name: storage-creds
+      key: accesskey
+- name: "DRYCC_STORAGE_SECRETKEY"
+  valueFrom:
+    secretKeyRef:
+      name: storage-creds
+      key: secretkey
+- name: "DRYCC_STORAGE_PATH_STYLE"
+  value: "true"
+{{- end }}
 {{- if eq .Values.debug "true" }}
 - name: PATRONI_LOG_LEVEL
   value: DEBUG
@@ -36,6 +80,10 @@ env:
   value: '0.0.0.0:5432'
 - name: PATRONI_RESTAPI_LISTEN
   value: '0.0.0.0:8008'
+- name: "DRYCC_DATABASE_INIT_NAMES"
+  value: "{{.Values.initDatabases}}"
+- name: "DRYCC_DATABASE_EXTENSIONS"
+  value: "{{.Values.databaseExtensions}}"
 - name: DRYCC_DATABASE_SUPERUSER
   valueFrom:
     secretKeyRef:
@@ -66,31 +114,4 @@ env:
     secretKeyRef:
       name: database-creds
       key: password
-{{- if eq .Values.global.storageLocation "on-cluster" }}
-- name: "DRYCC_STORAGE_HEALTH"
-  valueFrom:
-    secretKeyRef:
-      name: storage-creds
-      key: health
-{{- end }}
-{{- end }}
-
-{{/* Generate database deployment limits */}}
-{{- define "database.limits" -}}
-{{- if or (.Values.limitsCpu) (.Values.limitsMemory)}}
-resources:
-  limits:
-    {{- if (.Values.limitsCpu) }}
-    cpu: {{.Values.limitsCpu}}
-    {{- end }}
-    {{- if (.Values.limitsMemory) }}
-    memory: {{.Values.limitsMemory}}
-    {{- end }}
-    {{- if (.Values.limitsHugepages2Mi) }}
-    hugepages-2Mi: {{.Values.limitsHugepages2Mi}}
-    {{- end }}
-    {{- if (.Values.limitsHugepages1Gi) }}
-    hugepages-1Gi: {{.Values.limitsHugepages1Gi}}
-    {{- end }}
-{{- end }}
 {{- end }}
diff --git a/charts/database/templates/database-clusterrole.yaml b/charts/database/templates/database-clusterrole.yaml
index 11b2f70..066c2e1 100644
--- a/charts/database/templates/database-clusterrole.yaml
+++ b/charts/database/templates/database-clusterrole.yaml
@@ -1,8 +1,7 @@
-{{- if eq .Values.global.databaseLocation "on-cluster" }}
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRole
 metadata:
-  name: drycc-database
+  name: {{ printf "%s:drycc-database" .Release.Namespace | quote }}
 rules:
 - apiGroups:
   - ""
@@ -12,4 +11,3 @@ rules:
   - kubernetes
   verbs:
   - get
-{{- end }}
diff --git a/charts/database/templates/database-clusterrolebinding.yaml b/charts/database/templates/database-clusterrolebinding.yaml
index 11877bc..24e3fa6 100644
--- a/charts/database/templates/database-clusterrolebinding.yaml
+++ b/charts/database/templates/database-clusterrolebinding.yaml
@@ -1,14 +1,12 @@
-{{- if eq .Values.global.databaseLocation "on-cluster" }}
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
 metadata:
-  name: drycc-database
+  name: {{ printf "%s:drycc-database" .Release.Namespace | quote }}
 roleRef:
   apiGroup: rbac.authorization.k8s.io
   kind: ClusterRole
-  name: drycc-database
+  name: {{ printf "%s:drycc-database" .Release.Namespace | quote }}
 subjects:
 - kind: ServiceAccount
   name: drycc-database
   namespace: {{ .Release.Namespace }}
-{{- end }}
diff --git a/charts/database/templates/database-cronjob-backup.yaml b/charts/database/templates/database-cronjob-backup.yaml
new file mode 100644
index 0000000..ee4e042
--- /dev/null
+++ b/charts/database/templates/database-cronjob-backup.yaml
@@ -0,0 +1,29 @@
+{{- if .Values.cronjob.enabled }}
+apiVersion: {{ include "common.capabilities.cronjob.apiVersion" . }}
+kind: CronJob
+metadata:
+  name: drycc-database-cronjob-backup
+  labels:
+    heritage: drycc
+  annotations:
+    component.drycc.cc/version: {{ .Values.imageTag }}
+
+spec:
+  schedule: "{{ .Values.cronjob.scheduleCronJob }}"
+  failedJobsHistoryLimit: 1
+  successfulJobsHistoryLimit: 1
+  jobTemplate:
+    spec:
+      template:
+        spec:
+          restartPolicy: OnFailure              
+          containers:         
+          - name: drycc-database-cronjob-backup
+            image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/database:{{.Values.imageTag}}
+            imagePullPolicy: {{.Values.imagePullPolicy}}
+            command:
+            - init-stack
+            args:  
+            - /usr/share/scripts/backup.sh
+            {{- include "database.envs" . | indent 12 }}
+{{- end -}}
\ No newline at end of file
diff --git a/charts/database/templates/database-role-binding.yaml b/charts/database/templates/database-role-binding.yaml
index bbca50b..e927dab 100644
--- a/charts/database/templates/database-role-binding.yaml
+++ b/charts/database/templates/database-role-binding.yaml
@@ -1,4 +1,3 @@
-{{- if eq .Values.global.databaseLocation "on-cluster" }}
 apiVersion: rbac.authorization.k8s.io/v1
 kind: RoleBinding
 metadata:
@@ -10,4 +9,3 @@ roleRef:
 subjects:
 - kind: ServiceAccount
   name: drycc-database
-{{- end }}
diff --git a/charts/database/templates/database-role.yaml b/charts/database/templates/database-role.yaml
index 5ed547c..8957f9b 100644
--- a/charts/database/templates/database-role.yaml
+++ b/charts/database/templates/database-role.yaml
@@ -1,4 +1,3 @@
-{{- if eq .Values.global.databaseLocation "on-cluster" }}
 apiVersion: rbac.authorization.k8s.io/v1
 kind: Role
 metadata:
@@ -53,4 +52,3 @@ rules:
   - services
   verbs:
   - create
-{{- end }}
diff --git a/charts/database/templates/database-secret-creds.yaml b/charts/database/templates/database-secret-creds.yaml
index 83424f2..6b7f01d 100644
--- a/charts/database/templates/database-secret-creds.yaml
+++ b/charts/database/templates/database-secret-creds.yaml
@@ -1,4 +1,3 @@
-{{ if eq .Values.global.databaseLocation "on-cluster"}}
 apiVersion: v1
 kind: Secret
 metadata:
@@ -6,13 +5,17 @@ metadata:
   labels:
     app: drycc-database
     heritage: drycc
-  annotations:
-    "helm.sh/hook": pre-install
 data:
-  superuser: {{ if .Values.superuser | default "" | ne "" }}{{ .Values.superuser | lower | b64enc }}{{ else }}{{ randAlpha 32 | lower | b64enc }}{{ end }}
-  superuser-password: {{ if .Values.superuserPassword | default "" | ne "" }}{{ .Values.superuserPassword | b64enc }}{{ else }}{{ randAlphaNum 32 | b64enc }}{{ end }}
-  replicator: {{ if .Values.replicator | default "" | ne "" }}{{ .Values.replicator | lower | b64enc }}{{ else }}{{ randAlpha 32 | lower | b64enc }}{{ end }}
-  replicator-password: {{ if .Values.replicatorPassword | default "" | ne "" }}{{ .Values.replicatorPassword | b64enc }}{{ else }}{{ randAlphaNum 32 | b64enc }}{{ end }}
-  user: {{ if .Values.user | default "" | ne "" }}{{ .Values.user | lower | b64enc }}{{ else }}{{ randAlpha 32 | lower | b64enc }}{{ end }}
-  password: {{ if .Values.password | default "" | ne "" }}{{ .Values.password | b64enc }}{{ else }}{{ randAlphaNum 32 | b64enc }}{{ end }}
-{{- end }}
+  superuser: {{ include "common.secrets.lookup" (dict "secret" "database-creds" "key" "superuser" "defaultValue" (.Values.superuser | default (randAlpha 32) | lower) "context" $) }}
+  superuser-password: {{ include "common.secrets.lookup" (dict "secret" "database-creds" "key" "superuser-password" "defaultValue" (.Values.superuserPassword | default (randAlphaNum 32)) "context" $) }}
+  replicator: {{ include "common.secrets.lookup" (dict "secret" "database-creds" "key" "replicator" "defaultValue" (.Values.replicator | default (randAlpha 32) | lower) "context" $) }}
+  replicator-password: {{ include "common.secrets.lookup" (dict "secret" "database-creds" "key" "replicator-password" "defaultValue" (.Values.replicatorPassword | default (randAlphaNum 32) | lower) "context" $) }}
+  user: {{ include "common.secrets.lookup" (dict "secret" "database-creds" "key" "user" "defaultValue" (.Values.user | default (randAlpha 32) | lower) "context" $) }}
+  password: {{ include "common.secrets.lookup" (dict "secret" "database-creds" "key" "password" "defaultValue" (.Values.password | default (randAlphaNum 32)) "context" $) }}
+  {{- if (.Values.storageEndpoint) }}
+  storage-bucket: {{ .Values.storageBucket | b64enc }}
+  storage-endpoint: {{ .Values.storageEndpoint | b64enc }}
+  storage-accesskey: {{ .Values.storageAccesskey | b64enc }}
+  storage-secretkey: {{ .Values.storageSecretkey | b64enc }}
+  storage-path-style: {{ .Values.storagePathStyle | b64enc }}
+  {{- end }}
diff --git a/charts/database/templates/database-service-account.yaml b/charts/database/templates/database-service-account.yaml
index 553f18e..d429cfa 100644
--- a/charts/database/templates/database-service-account.yaml
+++ b/charts/database/templates/database-service-account.yaml
@@ -1,8 +1,6 @@
-{{- if eq .Values.global.databaseLocation "on-cluster" }}
 apiVersion: v1
 kind: ServiceAccount
 metadata:
   name: drycc-database
   labels:
     heritage: drycc
-{{- end }}
diff --git a/charts/database/templates/database-service-replica.yaml b/charts/database/templates/database-service-replica.yaml
index 0bc8c00..e168d0d 100644
--- a/charts/database/templates/database-service-replica.yaml
+++ b/charts/database/templates/database-service-replica.yaml
@@ -1,4 +1,3 @@
-{{- if eq .Values.global.databaseLocation "on-cluster" }}
 apiVersion: v1
 kind: Service
 metadata:
@@ -20,4 +19,3 @@ spec:
   selector:
     app: drycc-database
     role: replica
-{{- end }}
diff --git a/charts/database/templates/database-service.yaml b/charts/database/templates/database-service.yaml
index 5aa9fe9..0638885 100644
--- a/charts/database/templates/database-service.yaml
+++ b/charts/database/templates/database-service.yaml
@@ -1,4 +1,3 @@
-{{- if eq .Values.global.databaseLocation "on-cluster" }}
 apiVersion: v1
 kind: Service
 metadata:
@@ -14,4 +13,3 @@ spec:
   ports:
     - port: 5432
       targetPort: 5432
-{{- end }}
diff --git a/charts/database/templates/database-statefulset.yaml b/charts/database/templates/database-statefulset.yaml
index 61280d0..300bc7b 100644
--- a/charts/database/templates/database-statefulset.yaml
+++ b/charts/database/templates/database-statefulset.yaml
@@ -1,4 +1,3 @@
-{{- if eq .Values.global.databaseLocation "on-cluster" }}
 apiVersion: apps/v1
 kind: StatefulSet
 metadata:
@@ -16,38 +15,38 @@ spec:
       cluster-name: drycc-database
   template:
     metadata:
-      labels:
+      annotations:
+        prometheus.io/path: /metrics
+        prometheus.io/port: "9187"
+        prometheus.io/scrape: "true"
+      labels: {{- include "common.labels.standard" . | nindent 8 }}
         app: drycc-database
         cluster-name: drycc-database
     spec:
       affinity:
-        podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAffinityPreset.type "key" .Values.podAffinityPreset.key "values" .Values.podAffinityPreset.values ) | nindent 10 }}
-        podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAntiAffinityPreset.type "key" .Values.podAntiAffinityPreset.key "values" .Values.podAntiAffinityPreset.values ) | nindent 10 }}
+        podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAffinityPreset.type "component" "" "extraMatchLabels" .Values.podAffinityPreset.extraMatchLabels "topologyKey" "" "context" $) | nindent 10 }}
+        podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAntiAffinityPreset.type "component" "" "extraMatchLabels" .Values.podAntiAffinityPreset.extraMatchLabels "topologyKey" "" "context" $) | nindent 10 }}
         nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.nodeAffinityPreset.type "key" .Values.nodeAffinityPreset.key "values" .Values.nodeAffinityPreset.values ) | nindent 10 }}
       serviceAccountName: drycc-database
-      {{- if eq .Values.global.storageLocation "on-cluster" }}
-      initContainers:
-      - name: drycc-database-init
-        image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/python-dev:latest
-        imagePullPolicy: {{.Values.imagePullPolicy}}
-        args:
-          - netcat
-          - -v
-          - -g
-          - $(DRYCC_STORAGE_HEALTH)
-        {{- include "database.envs" . | indent 8 }}
-      {{- end }}
       containers:
       - name: drycc-database
-        image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/postgres:{{.Values.imageTag}}
+        image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/database:{{.Values.imageTag}}
         imagePullPolicy: {{.Values.imagePullPolicy}}
+        {{- if .Values.diagnosticMode.enabled }}
+        command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 10 }}
+        args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 10 }}
+        {{- end }}
         ports:
         - containerPort: 8008
           protocol: TCP
         - containerPort: 5432
           protocol: TCP
-        {{- include "database.limits" . | indent 8 }}
         {{- include "database.envs" . | indent 8 }}
+        {{- with index .Values "resources" }}
+        resources:
+          {{- toYaml . | nindent 10 }}
+        {{- end }}
+        {{- if not .Values.diagnosticMode.enabled }}
         lifecycle:
           preStop:
             exec:
@@ -79,9 +78,64 @@ spec:
           initialDelaySeconds: 10
           timeoutSeconds: 5
           failureThreshold: 3
+        {{- end }}
         volumeMounts:
         - name: database-data
           mountPath: /data
+      - name: drycc-database-metrics
+        image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/database:{{.Values.imageTag}}
+        imagePullPolicy: {{.Values.imagePullPolicy}}
+        {{- if .Values.diagnosticMode.enabled }}
+        command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 10 }}
+        args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 10 }}
+        {{- else }}
+        command:
+        - init-stack
+        args:
+        - postgres_exporter
+        {{- end }}
+        ports:
+        - containerPort: 9187
+          protocol: TCP
+        env:
+        - name: DATA_SOURCE_URI
+          value: "127.0.0.1:5432/postgres?sslmode=disable"
+        - name: DATA_SOURCE_USER
+          valueFrom:
+            secretKeyRef:
+              name: database-creds
+              key: user
+        - name: DATA_SOURCE_PASS
+          valueFrom:
+            secretKeyRef:
+              name: database-creds
+              key: password
+        startupProbe:
+          initialDelaySeconds: 10
+          tcpSocket:
+              port: 9187
+          periodSeconds: 10
+          timeoutSeconds: 1
+          failureThreshold: 15
+          successThreshold: 1
+        livenessProbe:
+          initialDelaySeconds: 5
+          httpGet:
+            path: /
+            port: 9187
+          periodSeconds: 10
+          timeoutSeconds: 5
+          failureThreshold: 6
+          successThreshold: 1
+        readinessProbe:
+          initialDelaySeconds: 5
+          httpGet:
+            path: /
+            port: 9187
+          periodSeconds: 10
+          timeoutSeconds: 5
+          failureThreshold: 6
+          successThreshold: 1
   {{- if .Values.persistence.enabled }}
   volumeClaimTemplates:
   - metadata:
@@ -103,4 +157,3 @@ spec:
       - name: database-data
         emptyDir: {}
   {{- end }}
-{{- end }}
diff --git a/charts/database/values.yaml b/charts/database/values.yaml
index 08cd8cd..e856429 100644
--- a/charts/database/values.yaml
+++ b/charts/database/values.yaml
@@ -2,13 +2,32 @@ imageOrg: "drycc"
 imagePullPolicy: "Always"
 imageTag: "canary"
 imageRegistry: "registry.drycc.cc"
-# limitsCpu: "100m"
-# limitsMemory: "50Mi"
-# limitsHugepages2Mi: 100Mi
-# limitsHugepages1Gi: 2Gi
 
 replicas: 3
 
+## Enable diagnostic mode
+##
+diagnosticMode:
+  ## @param diagnosticMode.enabled Enable diagnostic mode (all probes will be disabled and the command will be overridden)
+  ##
+  enabled: false
+  ## @param diagnosticMode.command Command to override all containers
+  ##
+  command:
+    - sleep
+  ## @param diagnosticMode.args Args to override all containers
+  ##
+  args:
+    - infinity
+
+resources: {}
+  # limits:
+  #   cpu: 200m
+  #   memory: 50Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 30Mi
+
 nodeAffinityPreset:
   key: "drycc.cc/node"
   type: "soft"
@@ -16,19 +35,34 @@ nodeAffinityPreset:
   - "true"
 
 podAffinityPreset:
-  key: "security"
   type: ""
-  values:
-  - "drycc-security"
+  extraMatchLabels:
+    security: "drycc-security"
 
 podAntiAffinityPreset:
-  key: "app"
   type: "soft"
-  values:
-  - "drycc-database"
+  extraMatchLabels:
+    app: "drycc-database"
 
 debug: "false"
+# Patroni pg_ctl timeout
 timeout: "1200"
+
+# The following parameters will no longer use the built-in storage component.
+storageBucket: "database"
+storageEndpoint: ""
+storageAccesskey: ""
+storageSecretkey: ""
+storagePathStyle: "true"
+
+storage:
+  enabled: true
+
+cronjob:
+  enabled: true
+  scheduleCronJob: "0 3 * * *"
+  retainBackupsAge: 30d
+
 # Service
 service:
   # Provide any additional service annotations
@@ -49,26 +83,12 @@ persistence:
   storageClass: ""
 # The username and password to be used by the on-cluster database.
 # If left empty they will be generated
-# The user name should be set to lowercase letters 
+# The user name should be set to lowercase letters
 superuser: "postgres"
 superuserPassword: ""
 replicator: "standby"
 replicatorPassword: ""
 user: ""
 password: ""
-
-global:
-  # Set the location of Workflow's Object Storage
-  #
-  # Valid values are:
-  # - on-cluster: Run drycc storage within the Kubernetes cluster
-  # - off-cluster: Run Storage outside the Kubernetes cluster (Compatible with s3 API)
-  storageLocation: "on-cluster"
-  # Set the location of Workflow's PostgreSQL database
-  #
-  # Valid values are:
-  # - on-cluster: Run PostgreSQL within the Kubernetes cluster (credentials are generated
-  #   automatically; backups are sent to object storage
-  #   configured above)
-  # - off-cluster: Run PostgreSQL outside the Kubernetes cluster
-  databaseLocation: "on-cluster"
+initDatabases: "controller,passport,grafana,quickwit"
+databaseExtensions: ""
diff --git a/rootfs/entrypoint.sh b/rootfs/entrypoint.sh
index 40e2ddf..8865438 100755
--- a/rootfs/entrypoint.sh
+++ b/rootfs/entrypoint.sh
@@ -1,5 +1,4 @@
 #!/bin/bash
-
 if [[ $UID -ge 10000 ]]; then
     GID=$(id -g)
     sed -e "s/^postgres:x:[^:]*:[^:]*:/postgres:x:$UID:$GID:/" /etc/passwd > /tmp/passwd
@@ -10,22 +9,48 @@ fi
 cat > /data/patroni.yaml <<__EOF__
 bootstrap:
   dcs:
+    ttl: 30
+    loop_wait: 10
+    retry_timeout: 10
+    maximum_lag_on_failover: 1048576
+    failsafe_mode: true
     postgresql:
       use_pg_rewind: true
+      use_slots: true
   initdb:
-  - auth-host: md5
+  - auth-host: scram-sha-256
   - auth-local: trust
   - encoding: UTF8
   - locale: ${LANG}
   - data-checksums
   pg_hba:
-  - host all all 0.0.0.0/0 md5
-  - host replication ${DRYCC_DATABASE_REPLICATOR} ${PATRONI_KUBERNETES_POD_IP}/16 md5
+  - host all all 0.0.0.0/0 scram-sha-256
+  - host replication ${DRYCC_DATABASE_REPLICATOR} ${PATRONI_KUBERNETES_POD_IP}/16 scram-sha-256
   post_bootstrap: /usr/share/scripts/patroni/post_init.sh
 restapi:
   connect_address: '${PATRONI_KUBERNETES_POD_IP}:8008'
 postgresql:
   data_dir: '${PGDATA}'
+  parameters:
+    shared_preload_libraries: 'auto_explain,pg_stat_statements'
+    hot_standby: "on"
+    max_connections: 1005
+    max_worker_processes: 8
+    max_wal_senders: 10
+    max_replication_slots: 10
+    hot_standby_feedback: on
+    max_prepared_transactions: 0
+    max_locks_per_transaction: 64
+    wal_log_hints: "on"
+    wal_level: logical
+    track_commit_timestamp: "off"
+    archive_mode: "on"
+    archive_timeout: 300s
+    archive_command: "/bin/true"
+    log_min_duration_statement: 1000
+    log_lock_waits: on
+    log_statement: 'ddl' 
+    jit: off
   connect_address: '${PATRONI_KUBERNETES_POD_IP}:5432'
   authentication:
     superuser:
diff --git a/rootfs/usr/share/scripts/backup.sh b/rootfs/usr/share/scripts/backup.sh
new file mode 100755
index 0000000..441c33e
--- /dev/null
+++ b/rootfs/usr/share/scripts/backup.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+set -e
+
+# Setup Rclone 
+/usr/share/scripts/create_bucket
+
+# Backup PostgreSQL databases to S3-compatible object storage
+export PGPASSWORD=$DRYCC_DATABASE_SUPERUSER_PASSWORD
+PGPORT=$DRYCC_DATABASE_REPLICA_SERVICE_PORT_POSTGRES
+PGUSER=postgres
+POSTGRES_HOST=$DRYCC_DATABASE_REPLICA_SERVICE_HOST
+RETAIN_BACKUPS_AGE=$RETAIN_BACKUPS_AGE
+
+# PostgreSQL global objects backup 
+BACKUP_PATH="${DRYCC_STORAGE_BUCKET}/$(date +%Y%m%d%H%M)"
+echo "DB: ${POSTGRES_USER}@${POSTGRES_HOST}"
+echo "S3 Storage: storage:${BACKUP_PATH}"
+# Backup global objects
+if pg_dumpall -g -U "${POSTGRES_USER}" -h "${POSTGRES_HOST}" \
+  | pigz -c -p 4 -6 \
+  | rclone rcat \
+      "storage:${BACKUP_PATH}/roles_globals.sql.gz" \
+      --bwlimit 10M \
+      --transfers 4 \
+      --s3-chunk-size 64M \
+      --stats 5s \
+      --progress \
+      --retries 3; then  
+  echo "✅ PostgreSQL global objects backup complated!" 
+fi 
+  # fetch the list of databases
+  DATABASES=$(psql -U "$POSTGRES_USER" -h "$POSTGRES_HOST" -t -c "SELECT datname FROM pg_database WHERE datistemplate = false;")
+
+  # backup each database individually
+  for DB in $DATABASES; do
+    echo "Backing up $DB to $MINIO_PATH/$DB.sql.gz"
+    if pg_dump -U "${POSTGRES_USER}" -h "${POSTGRES_HOST}" "$DB" \
+        | pigz -c -p 4 -6 \
+        | rclone rcat \
+            "storage:${BACKUP_PATH}/$DB.sql.gz" \
+            --bwlimit 10M \
+            --transfers 4 \
+            --s3-chunk-size 64M \
+            --stats 5s \
+            --progress \
+            --retries 3; then
+        echo "✅ PostgreSQL $DB global objects backup completed!"
+    fi
+  done
+
+  echo "Backup process completed!"
+
+  echo "delete storage before ${RETAIN_BACKUPS_AGE} ..."
+  rclone delete "storage:${DRYCC_STORAGE_BUCKET}" \
+    --min-age ${RETAIN_BACKUPS_AGE} \
+    --include "*.sql.gz" \
+    --dry-run \
+    -v  || true
+
+  rclone delete "storage:${DRYCC_STORAGE_BUCKET}" \
+    --min-age ${RETAIN_BACKUPS_AGE} \
+    --include "*.sql.gz" \
+    || true
+  echo "delete completed."
+
+echo "=== backup completed: $(date) ==="
diff --git a/rootfs/usr/share/scripts/create_bucket b/rootfs/usr/share/scripts/create_bucket
new file mode 100755
index 0000000..addadaa
--- /dev/null
+++ b/rootfs/usr/share/scripts/create_bucket
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+set -e
+
+mkdir -p ~/.config/rclone
+touch ~/.config/rclone/rclone.conf
+rclone config create storage s3 \
+  provider=Other \
+  access_key_id="${DRYCC_STORAGE_ACCESSKEY}" \
+  secret_access_key="${DRYCC_STORAGE_SECRETKEY}" \
+  endpoint="${DRYCC_STORAGE_ENDPOINT}" \
+  force_path_style="${DRYCC_STORAGE_PATH_STYLE:-true}" --no-output
+
+if ! rclone lsd storage: > /dev/null 2>&1; then
+  sleep 9s
+  echo "waiting for object storage to become ready..."
+fi
+
+rclone mkdir "storage:${DRYCC_STORAGE_BUCKET}"
diff --git a/rootfs/usr/share/scripts/patroni/post_init.sh b/rootfs/usr/share/scripts/patroni/post_init.sh
index 90478b1..a8f75f5 100755
--- a/rootfs/usr/share/scripts/patroni/post_init.sh
+++ b/rootfs/usr/share/scripts/patroni/post_init.sh
@@ -4,11 +4,20 @@ set -Eeu
 if [[ ( -n "$DRYCC_DATABASE_USER") &&  ( -n "$DRYCC_DATABASE_PASSWORD")]]; then
   echo "Creating user ${DRYCC_DATABASE_USER}"
   psql "$1" -w -c "create user ${DRYCC_DATABASE_USER} WITH LOGIN ENCRYPTED PASSWORD '${DRYCC_DATABASE_PASSWORD}'"
-
-  echo "Creating passport and controller databases"
-  psql "$1" -w -c "CREATE DATABASE passport OWNER ${DRYCC_DATABASE_USER}"
-  psql "$1" -w -c "CREATE DATABASE controller OWNER ${DRYCC_DATABASE_USER}"
-
+  psql "$1" -w -c "GRANT pg_monitor TO ${DRYCC_DATABASE_USER}"
+  for dbname in ${DRYCC_DATABASE_INIT_NAMES//,/ }
+  do
+    echo "Creating database ${dbname}"
+    psql "$1" -w -c "CREATE DATABASE ${dbname} OWNER ${DRYCC_DATABASE_USER}"
+    for extension in ${DRYCC_DATABASE_EXTENSIONS//,/ }
+    do
+      echo "Creating extension ${extension}"
+      psql "$1" -w << EOF
+\c ${dbname};
+create extension ${extension};
+EOF
+    done
+  done
 else
   echo "Skipping user creation"
   echo "Skipping database creation"
diff --git a/versioning.mk b/versioning.mk
index fd4a488..10e3d7b 100644
--- a/versioning.mk
+++ b/versioning.mk
@@ -10,13 +10,13 @@ info:
 	@echo "Immutable tag:   ${IMAGE}"
 	@echo "Mutable tag:     ${MUTABLE_IMAGE}"
 
-.PHONY: docker-push
-docker-push: docker-immutable-push docker-mutable-push
+.PHONY: podman-push
+podman-push: podman-immutable-push podman-mutable-push
 
-.PHONY: docker-immutable-push
-docker-immutable-push:
-	docker push ${IMAGE}
+.PHONY: podman-immutable-push
+podman-immutable-push:
+	podman push ${IMAGE}
 
-.PHONY: docker-mutable-push
-docker-mutable-push:
-	docker push ${MUTABLE_IMAGE}
+.PHONY: podman-mutable-push
+podman-mutable-push:
+	podman push ${MUTABLE_IMAGE}
