Backup & restore¶
Vesana writes three classes of data you must back up:
| Class | Where | Recoverable without backup? |
|---|---|---|
| Database (Postgres) | Compose volume pgdata |
No |
| Configuration | DB + .env (secrets) |
Partly — .env can be regenerated, but FIELD_ENCRYPTION_KEY is irreplaceable |
| Wiki attachments / uploads | Volume uploads |
No |
FIELD_ENCRYPTION_KEY is the only thing that can't be replaced
Encrypted DB fields (e.g. SNMP communities) can never be decrypted again without the key. The key must live outside the backup volume.
Automatic backup (sidecar)¶
Vesana ships an optional backup sidecar in the compose stack.
Enable¶
Configure¶
In .env:
| Variable | Default | Meaning |
|---|---|---|
BACKUP_SCHEDULE |
0 2 * * * |
Cron expression (daily 02:00 UTC) |
BACKUP_RETENTION_DAYS |
7 |
Files older than X days are deleted |
BACKUP_API_TOKEN |
empty | Optional: admin token for additional config export |
Restart the sidecar after changes:
What's backed up¶
- Database dump —
pg_dumpas compressed SQL:backup-YYYYMMDD-HHMMSS.sql.gz - Config export (if
BACKUP_API_TOKENis set) — JSON snapshot of tenants, hosts, profiles, alert rules etc. via/api/v1/admin/export - Compose file snapshot — the
docker-compose.prod.ymlactive at backup time
All backups land in volume backups, mounted at /opt/vesana/backups.
Inspect¶
ls -la /opt/vesana/backups/
docker compose -f /opt/vesana/docker-compose.prod.yml run --rm backup ls -la /backups/
Manual backup¶
Without the sidecar:
cd /opt/vesana
docker compose -f docker-compose.prod.yml exec postgres \
pg_dump -U vesana vesana | gzip > backup-$(date +%Y%m%d-%H%M%S).sql.gz
Config export via API:
curl -H "Authorization: Bearer <ADMIN_JWT>" \
https://your-domain.tld/api/v1/admin/export \
> config-export-$(date +%Y%m%d).json
Storing safely¶
| Content | Where | Who needs access |
|---|---|---|
pgdata backups |
External NAS, S3, Veeam, USB disk in safe | Backup operator |
FIELD_ENCRYPTION_KEY |
Password manager | Lukas / operations owner |
SECRET_KEY (JWT) |
Password manager | Only for disaster recovery |
.env whole |
Encrypted container, separate from DB backup | Backup operator |
Don't put keys in the same backup as the database
Whoever has both the database and the FIELD_ENCRYPTION_KEY can read SNMP communities and other encrypted fields in clear. Separate them.
Restore¶
Database¶
cd /opt/vesana
# 1. Stop writing services
docker compose -f docker-compose.prod.yml stop api receiver worker
# 2. Restore backup
gunzip -c backup-YYYYMMDD-HHMMSS.sql.gz | \
docker compose -f docker-compose.prod.yml exec -T postgres \
psql -U vesana vesana
# 3. Start services
docker compose -f docker-compose.prod.yml up -d
For a fresh-instance restore, clear pgdata first:
docker compose -f docker-compose.prod.yml down
docker volume rm vesana_pgdata
docker compose -f docker-compose.prod.yml up -d postgres
# wait until postgres is healthy
gunzip -c backup-YYYYMMDD-HHMMSS.sql.gz | \
docker compose -f docker-compose.prod.yml exec -T postgres \
psql -U vesana vesana
docker compose -f docker-compose.prod.yml up -d
Config import¶
curl -X POST \
-H "Authorization: Bearer <ADMIN_JWT>" \
-H "Content-Type: application/json" \
-d @config-export.json \
https://your-domain.tld/api/v1/admin/import
A full config import overwrites existing tenants and hosts. Only import into an empty instance.
Disaster drill¶
A restore that's never been tested is hope, not backup. Do this once per quarter.
# 1. Test server / local VM with the latest backup
# 2. Make latest backup tarball + .env (with FIELD_ENCRYPTION_KEY) available
# 3. Run setup script, copy SECRET_KEY and FIELD_ENCRYPTION_KEY from original .env
# 4. Clear pgdata, restore via gunzip as above
# 5. Test login with original admin
# 6. Open at least one host, view a service with encrypted snmp_community → must work
If step 6 fails (snmp_community is masked even though a value should be there), the FIELD_ENCRYPTION_KEY from backup isn't the right one.
Recommended strategy¶
- Backup sidecar active for daily DB dumps
FIELD_ENCRYPTION_KEYoutside in password manager + printout in safe- Weekly off-site copy of backup files (S3, NFS, USB rotation)
- Quarterly drill on a separate machine
Next¶
- Updates — the updater takes a pre-update backup automatically
- Security → Encryption