Skip to content

Restore CMS from a backup

benoit74 edited this page May 28, 2026 · 1 revision

Download a backup

Backups are in borgbase. To download them you need the read-only credentials:

# those are all static values you need to enter
# those are all for the _slave_ (aka readonly) bitwarden account
export BW_CLIENTID=user.xxxxxxxxx
export BW_CLIENTSECRET=xxxxxxxxxxxx
export BW_PASSWORD=xxxxxxxxxxxx

Select a backup

docker run --rm -e BW_CLIENTID=$BW_CLIENTID -e BW_CLIENTSECRET=$BW_CLIENTSECRET -e BW_PASSWORD=$BW_PASSWORD ghcr.io/kiwix/borg-backup restore --name openzim-cms-postgresdb --list

openzim-cms-postgresdb is the name of the Borgbase repository in which we archive the CMS DB backups.

Output would look like

List avaible archives ...
Warning: Attempting to access a previously unknown unencrypted repository!
Do you want to continue? [yN] yes (from BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK)
openzim-cms-postgresdb__backup__2024-12-31T10:04:44 Tue, 2024-12-31 10:04:45 [629061e783112963cea5459c484bdd881126b9434c83c62346667675bd72a922]
openzim-cms-postgresdb__backup__2025-05-31T10:04:45 Sat, 2025-05-31 10:04:46 [312ce3a02919ee2e6fd221715e2df0c8d636867123fdf7c3e79d4865961b381a]
openzim-cms-postgresdb__backup__2025-06-30T10:04:44 Mon, 2025-06-30 10:04:45 [b5c11599b4c1a2701d226d6f978ba3533eee709505be99f2c56c867dc8853800]
openzim-cms-postgresdb__backup__2025-07-31T10:04:44 Thu, 2025-07-31 10:04:45 [49389eaed4aa2e1346b6f9eba48d5eb5a3c951884328b98c33453bc2fc81c292]
openzim-cms-postgresdb__backup__2025-08-31T10:04:44 Sun, 2025-08-31 10:04:45 [1d418df59be7691ad11bb8b9cb33f94488f518f1453736eea8340c4b834a4a50]
openzim-cms-postgresdb__backup__2025-09-30T10:04:44 Tue, 2025-09-30 10:04:45 [f70c4d195a2f187befb5f5f3d344aa3a022f7124243ea42ac473481220ae89ad]
openzim-cms-postgresdb__backup__2025-10-31T10:04:44 Fri, 2025-10-31 10:04:45 [11f18cf6fcaeeb44d2d80699c8259a7348fadfb3ab97b225ade03a6e309df04d]
openzim-cms-postgresdb__backup__2025-11-30T10:04:44 Sun, 2025-11-30 10:04:45 [f9a49b3090a9e87a3eb3fe09734d70f3b72d8b4a093bc4ef63afc4a5e62a0b59]
openzim-cms-postgresdb__backup__2025-12-31T10:04:45 Wed, 2025-12-31 10:04:46 [25ea5aaaff2583994b4b5c6456b749c9c9522fd17f3623371b7f6cb339ae0bac]
openzim-cms-postgresdb__backup__2026-01-31T10:04:44 Sat, 2026-01-31 10:04:45 [2c89db9872090c06a05a177091d4943b7d08be65c2b212c674829d3b4bc4b354]
openzim-cms-postgresdb__backup__2026-02-28T10:04:52 Sat, 2026-02-28 10:04:53 [31c3b669e178de37aad710e508db05f7ad18a338599ee366ad14beab586f8873]
openzim-cms-postgresdb__backup__2026-03-31T10:04:52 Tue, 2026-03-31 10:04:54 [a24efb1ba97c6521ff45dead727621546f1e6aa1ad161482782003fc8fc8337f]
openzim-cms-postgresdb__backup__2026-04-19T10:04:52 Sun, 2026-04-19 10:04:54 [8a78ecbe649662afdcaddd6fc4ac2c37705f5346c5f2e8839ae180ffc40218bb]
openzim-cms-postgresdb__backup__2026-04-26T10:04:52 Sun, 2026-04-26 10:04:54 [40548e8b8ce644d8cab23a1a41dbcaf3acc042f265e17a15f04c30339f2ec967]
openzim-cms-postgresdb__backup__2026-04-30T10:04:53 Thu, 2026-04-30 10:04:55 [cc31126fd8af4ef564720abe46fe2688194a7a29371d9097af2f814d001af6fe]
openzim-cms-postgresdb__backup__2026-05-03T10:04:53 Sun, 2026-05-03 10:04:54 [38ec6f551a63c8bf2e85096e0033f6379ecc9a366d940466088ceb583c3a4ab4]
openzim-cms-postgresdb__backup__2026-05-10T10:04:53 Sun, 2026-05-10 10:04:55 [f825bec55ac9f733e877782e8d51589be3a2dc6e7bf4f7bdf1b774f3f440a247]
openzim-cms-postgresdb__backup__2026-05-17T10:04:53 Sun, 2026-05-17 10:04:55 [fd4069154db655576adc745aaa7ab8df3dbd1d4c5dd70f7c3250e529441db1a2]
openzim-cms-postgresdb__backup__2026-05-21T10:04:53 Thu, 2026-05-21 10:04:55 [298c7d42d95badaf80930ebfa3433b0cdf1f17505368174438737d0261711a5d]
openzim-cms-postgresdb__backup__2026-05-22T10:05:05 Fri, 2026-05-22 10:05:07 [a1bac008764588f8dec530c0582e5c4dd0b51c85bb5a3f2d93abb5c054e69671]
openzim-cms-postgresdb__backup__2026-05-23T10:04:52 Sat, 2026-05-23 10:04:54 [fbd51e4cd26793747c33cb055dcf585b25232011f409457638aeef54bcd032a4]
openzim-cms-postgresdb__backup__2026-05-24T10:04:53 Sun, 2026-05-24 10:04:55 [fb0c45b49342429675f616a7d04816c97dac013eb1a55bf6e24906a59f4911b6]
openzim-cms-postgresdb__backup__2026-05-25T10:04:52 Mon, 2026-05-25 10:04:54 [d5fdf361fadfdc8d8647e3286b55aa7eec39ed95686c77630b9e04f4b523b5c2]
openzim-cms-postgresdb__backup__2026-05-26T10:04:54 Tue, 2026-05-26 10:04:55 [fd32fc58043ccd22510bcf1776570f37a0b337a6e742fa887033af53efb69782]
openzim-cms-postgresdb__backup__2026-05-27T10:04:54 Wed, 2026-05-27 10:04:55 [36259686b57cfdb96c60a29b926c6dbf645ed0015a8280043a3ff20ad0caa15e]
openzim-cms-postgresdb__backup__2026-05-28T10:04:53 Thu, 2026-05-28 10:04:55 [a362f8558a227ddfc2e3cc28aab84e14a7c19255736b414743b48cbde0b69a1a]

Choose one based on its date. Check the default backup periodicity in borg-backup tool and potential customization in k8s backup cronjob.

Note: the archive name is the first column (stops at first space). ex: openzim-cms-postgresdb__backup__2026-05-28T10:04:53.

Extract a Backup file

With your selected archive name, download+extract it to your filesystem:

docker run -v /data/restore:/restore:rw -e BW_CLIENTID=$BW_CLIENTID -e BW_CLIENTSECRET=$BW_CLIENTSECRET -e BW_PASSWORD=$BW_PASSWORD ghcr.io/kiwix/borg-backup restore --name openzim-cms-postgresdb --extract "openzim-cms-postgresdb__backup__2026-05-28T10:04:53"

CMS backup is a single Custom Database Dump file that would be extracted to /data/restore in this example. The file has no extension ; move it to a more practical location

mv /data/restore/root/.borgmatic/postgresql_databases/db-service/cms /data/restore/cms

Test the dump file

# start a new postrges server.
# note that this will create the `cms` database and its credentials
docker run -v /data/restore:/data -it --name pg-tester --rm -e POSTGRES_DB=cms -e POSTGRES_USER=cms -e POSTGRES_PASSWORD=cmspass -p 5432:5432 postgres:15.2-bullseye
# import the dump in the same container
docker exec -it pg-tester pg_restore -U cms -d cms /data/cms

Check the DB structure and data using any postgres client (DBeaver)

Production Restore Procedure

If the cms is running

  • shutdown the API deployment by scaling it to 0.
  • shutdown the shuttle deployment by scaling it to 0.
  • shutdown the mill deployment by scaling it to 0.
  • shutdown the postgres sts by scaling it to 0.
  • Cleanup the volume
  • Move the dump file to the volume folder
  • Start the postgres sts by scaling it to 1
  • Open a shell on the postgres container
  • Restore the dump pg_restore -U cms -d cms /var/lib/postgresql/data/cms
  • Start a PortForward and ensure the data is there
  • Check the DB structure and data using any postgres client
  • shutdown the API deployment by scaling it to 1.
  • shutdown the shuttle deployment by scaling it to 1.
  • shutdown the mill deployment by scaling it to 1.

Downloading dump into volume

In order to get the dump file into the volume, one needs to launch borg-backup into the cluster. This would be done with a temporary Job

---
apiVersion: batch/v1
kind: Job
metadata:
  name: borg-accessor
  namespace: cms
spec:
  backoffLimit: 1
  template:
    metadata:
      labels:
        app: borg-app
    spec:
      containers:
      - name: borg-backup
        image: ghcr.io/kiwix/borg-backup
        command: ["restore", "--name", "openzim-cms-postgresdb", "--extract", "openzim-cms-postgresdb__backup__2026-05-28T10:04:53"]
        imagePullPolicy: Always
        env:
        - name: BW_CLIENTID
          value: "xxxx"
        - name: BW_CLIENTSECRET
          value: "xxxx"
        - name: BW_PASSWORD
          value: "xxx"
        volumeMounts:
        - name: data-volume
          mountPath: "/restore"
          readOnly: false
      volumes:
      - name: data-volume
        persistentVolumeClaim:
          claimName: cms-db-pvc
      restartPolicy: Never
      nodeSelector:
        k8s.kiwix.org/role: "services"

Clone this wiki locally