● Server & Claude Code
Docker Compose backups that actually restore: pg_dump, SQLite, and a tested restore
Most self-hosting backup advice is "tar up the volume". That works until the day you restore a database that was mid-write when you copied it. Here's a method for Docker Compose apps that was tested the only way that counts: back up, delete the app, restore, and check the data is back.
Two kinds of apps, two methods
| App stores data in | Examples | Safe backup |
|---|---|---|
| Postgres (or MySQL) | Umami, many analytics and CRM apps | pg_dump while it runs: a consistent snapshot, no downtime |
| SQLite / plain files | Uptime Kuma, Vaultwarden, n8n, ntfy | Stop the app for a few seconds, archive, start again |
A live copy of a SQLite file can catch it halfway through a write. Stopping for a few seconds at 3:30 a.m. is a small price.
The Postgres part
cd /srv/umami
docker compose exec -T db pg_dump -U umami -d umami --clean --if-exists > .backup-umami.sql
tar -czf /var/backups/apps/umami_$(date -u +%Y%m%dT%H%M%SZ).tar.gz --exclude=./db -C /srv/umami .
rm .backup-umami.sql
The archive holds the compose file, the .env and the SQL dump, but not the raw database directory, which you can't safely restore from a live copy anyway.
The SQLite / files part
cd /srv/uptime-kuma
docker compose stop -t 20
tar -czf /var/backups/apps/uptime-kuma_$(date -u +%Y%m%dT%H%M%SZ).tar.gz -C /srv/uptime-kuma .
docker compose start
The test: back up, destroy, restore
On this server: start Umami, create a website record in it, run the backup, then docker compose down -v and move the app directory away. Restore from the archive:
mkdir /srv/umami && tar -xzf /var/backups/apps/umami_<timestamp>.tar.gz -C /srv/umami
cd /srv/umami
docker compose up -d db && sleep 8
docker compose exec -T db psql -q -U umami -d umami < .backup-umami.sql # 0 errors
docker compose up -d
Result: Umami came back up, the login worked, and the website record created before the backup was there. psql reported zero errors. The Uptime Kuma container was stopped only for the length of the copy and running again straight after.
Make it a habit, not a hope
- Run it nightly from a systemd timer (with
Persistent=true, so a missed run happens after a reboot) and keep about 14 days. - Copy archives off the server. A backup on the same disk doesn't survive the disk.
chmod 600the archives: they contain your.envsecrets.- Restore once, now, on purpose. A backup you've never restored is a hope, not a backup.
Need a VPS to try this on? Everything here was tested on a DigitalOcean Ubuntu 24.04 droplet: get one on DigitalOcean. Referral link: if you sign up through it and spend $25, the site owner gets $25 in DigitalOcean credit. Your price is the same.