Data backup and restoration with Docker Compose

Backup and restore data in the CRISalid Docker Compose stack.

Typically, backups are produced on a production server and then transferred (via SFTP) to a development environment for restoration.


Overview

There are two database types to consider (Redis is not covered here as it is generally used for caching and can be safely cleared):

Neo4j backup strategies

  • Quick backup → copy the neo4j/data directory
  • Proper backup → use neo4j-admin database dump

PostgreSQL deployment modes

Only SoVisu+ and Harvester databases are covered here, as Keycloak and Airflow restoration from one environment to another are not recommended.

  • Inside Docker Compose (containers: svp-db, harvester-db)
  • Outside Docker (managed database server, e.g. production)

Neo4j

All commands are run from:

crisalid-deployment/docker

⚡ Quick backup (filesystem copy)

Fast and simple. Suitable for development or emergency copies.

⚠️ This backup method will include both neo4j and system databases, so it will overwrite users/passwords on restore.

Backup

cd docker/neo4j

sudo tar --numeric-owner -czvf neo4j-data-$(date +%F).tar.gz data

Restore

⚠️ Neo4j must be stopped before restoring. It is highly recommended to stop all the services hat are directly speaking to Neo4j (e.g. crisalid-ikg, crisalid-apollo, ofelia, etc.) to avoid any connection issues during the restore process.

cd docker

docker compose --file docker-compose.yml \
  --file docker-compose.dev.yml \
  --profile neo4j \
  --profile ikg \
  --profile apollo \
  --profile ofelia \
  stop neo4j crisalid-ikg apollo crisalid-ofelia

Then:

tar -xzvf neo4j-data-YYYY-MM-DD.tar.gz -C docker/neo4j

Fix ownership:

cd docker/neo4j
sudo chown -R 7474:7474 data

Restart:

docker compose --profile neo4j up -d neo4j

In case you have a direct access to the source server, direct synchronization is possible:

cd docker/neo4j
sudo rsync -avz --delete \
  user@source-server:/path/to/neo4j/data/ \
  data/

PostgreSQL

Two cases depending on where PostgreSQL runs.


Case 1 — PostgreSQL inside Docker Compose

Containers:

  • svp-db
  • harvester-db

Backup

Run sovisuplus (at least the database container) in detached mode:

docker compose -f docker-compose.yaml \
                -f docker-compose.dev.yaml \
                -f docker-compose.local-postgres.yaml \
                --profile sovisuplus-db  up -d

Then, dump the database into custom format (compressed, non-plain SQL):

docker compose exec -T svp-db \
  pg_dump -U "$SVP_DB_USER" -d "$SVP_DB_NAME" \
  --format=custom --no-owner --no-privileges \
  > sovisuplus.dump

Run the same commands for Harvester:

docker compose -f docker-compose.yaml \
                -f docker-compose.dev.yaml \
                -f docker-compose.local-postgres.yaml \
                --profile harvester-db  up -d
docker compose exec -T harvester-db \
  pg_dump -U "$HARVESTER_DB_USER" -d "$HARVESTER_DB_NAME" \
  --format=custom --no-owner --no-privileges \
  > harvester.dump

Restore

For the restoration commands to works, the databases container should have be started at least once and the databases initialized by prisma or alembic migrations.

cat sovisuplus.dump | \
  docker compose exec -T svp-db \
  pg_restore -U "$SVP_DB_USER" \
    -d "$SVP_DB_NAME" \
    --clean --if-exists \
    --no-owner --no-privileges
cat harvester.dump | \
  docker compose exec -T harvester-db \
  pg_restore -U "$HARVESTER_DB_USER" -d "$HARVESTER_DB_NAME" \
    --clean --if-exists \
    --no-owner --no-privileges

Case 2 — PostgreSQL outside Docker (production / managed DB)

Backup (on server)

Use the dump_prod_dbs.sh script:

./scripts/dump_prod_dbs.sh

Transfer

Copy dump files from production to development machine using SFTP.


Restore (developer environment)

Use the restore script:

./scripts/restore_prod_dbs.sh /path/to/sovisuplus.dump /path/to/harvester.dump

examples:

./scripts/restore_prod_dbs.sh  /opt/crisalid/backups/sovisuplus_svp_prd_20260402_173929.dump /opt/crisalid/backups/harvester_p1ps_harv_db_20260402_174259.dump

This script:

  • validates dump filenames
  • asks for confirmation
  • stops services (sovisuplus, harvester-worker, etc.)
  • restores databases
  • restarts services