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/datadirectory - 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
neo4jandsystemdatabases, so it will overwrite users/passwords on restore.
Backup
cd docker/neo4j
sudo tar --numeric-owner -czvf neo4j-data-$(date +%F).tar.gz dataRestore
⚠️ 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-ofeliaThen:
tar -xzvf neo4j-data-YYYY-MM-DD.tar.gz -C docker/neo4jFix ownership:
cd docker/neo4j
sudo chown -R 7474:7474 dataRestart:
docker compose --profile neo4j up -d neo4jIn 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/🧱 Proper backup (recommended)
Safe backup using
neo4j-admin.
Before running the backup script, check your NEO4J_ADMIN_IMAGE variable in .env to ensure you are using the correct Neo4j version for the backup. The variable must contain the full image reference, including edition and base OS (e.g. neo4j/neo4j-admin:2026.06.0-community-debian).
Backup (on source environment)
./scripts/neo4j_offline_backup.sh devThis:
- stops Neo4j
- dumps databases into
neo4j/backups/<timestamp>/ - restarts services
Restore (on target environment)
case 1: restore backup on a local development environment. case 2: restore backup into a staging environment (e.g.
staging)
Transfer backup directory from production to target machine (using SFTP or equivalent)
Place it in:
docker/neo4j/backups/<timestamp>/Fix permission issues to allow the restore script to read the dump files:
cd docker/neo4j/backups/<timestamp>/
sudo chown -R 7474:7474 .- Run:
./scripts/neo4j_offline_restore.sh dev <timestamp>⚠️ Only the
neo4jdatabase is restored (notsystem), so users/passwords are preserved.
PostgreSQL
Two cases depending on where PostgreSQL runs.
Case 1 — PostgreSQL inside Docker Compose
Containers:
svp-dbharvester-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 -dThen, 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.dumpRun 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 -ddocker compose exec -T harvester-db \
pg_dump -U "$HARVESTER_DB_USER" -d "$HARVESTER_DB_NAME" \
--format=custom --no-owner --no-privileges \
> harvester.dumpRestore
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-privilegescat harvester.dump | \
docker compose exec -T harvester-db \
pg_restore -U "$HARVESTER_DB_USER" -d "$HARVESTER_DB_NAME" \
--clean --if-exists \
--no-owner --no-privilegesCase 2 — PostgreSQL outside Docker (production / managed DB)
Backup (on server)
Use the dump_prod_dbs.sh script:
./scripts/dump_prod_dbs.shTransfer
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.dumpexamples:
./scripts/restore_prod_dbs.sh /opt/crisalid/backups/sovisuplus_svp_prd_20260402_173929.dump /opt/crisalid/backups/harvester_p1ps_harv_db_20260402_174259.dumpThis script:
- validates dump filenames
- asks for confirmation
- stops services (
sovisuplus,harvester-worker, etc.) - restores databases
- restarts services