Niche Guides·7 min read·

Backup and restore for self-hosted VeloCMS

How to set up automated PocketBase backups, store them off-site, and restore from a backup when something goes wrong.

Self-hosted VeloCMS stores all data in a PocketBase SQLite database and media files in a storage directory (or Cloudflare R2 if configured). A backup strategy should cover both. This guide assumes you're running VeloCMS via Docker Compose on a VPS.

What to back up

  • PocketBase data directory — typically ./pb_data/ — contains the SQLite database and local media uploads.
  • Environment file (.env) — contains your API keys and secrets. Store this separately in a secrets manager, not in the same backup.
  • Custom themes directory — if you've created custom theme JSON files outside the default templates.

Automated daily backup with a cron job

PocketBase has a built-in backup API. You can call it with a cron job to create a timestamped backup automatically each night. Add this to your server's crontab (crontab -e):

# Daily backup at 03:00 UTC
0 3 * * * curl -X POST \
  "http://localhost:8090/api/backups" \
  -H "Authorization: Bearer $PB_SUPERUSER_TOKEN" \
  >> /var/log/velocms-backup.log 2>&1

Replace localhost:8090 with your PocketBase URL if it's on a different port. The backup is created in pb_data/backups/ as a .zip file containing the full database and media. Set PB_SUPERUSER_TOKEN to a long-lived superuser token from your PocketBase admin panel.

Shipping backups off-site

On-server backups don't help if the server fails. After each backup, copy the .zip to an off-site location. Cloudflare R2, AWS S3, or Backblaze B2 all work. Use rclone — a cross-platform CLI that supports all three providers — to sync the backups directory after each cron run. A 7-day retention with daily backups means you can restore to any point in the last week.

Restoring from a backup

To restore: (1) stop the VeloCMS containers (docker compose down), (2) download the backup .zip from your off-site storage, (3) unzip it into your pb_data/ directory — overwriting the existing files, (4) restart containers (docker compose up -d). PocketBase reads the restored database on startup. Verify restoration by logging into /admin and checking that your content is present.

Restoring a backup overwrites your current database permanently. There is no undo. If you're unsure, rename the existing pb_data/ to pb_data_old/ before restoring — this gives you a fallback if the restore fails.

Testing your backup process

A backup you've never tested is not a backup — it's hope. Every 90 days, restore a backup to a local environment and verify that the site loads, posts are present, and media serves correctly. If the restoration fails, the problem is in your backup procedure, not in a crisis.