Guides

Backups & restore

Astrodock keeps all its data on your box. One script captures the databases and the object store into a single timestamped tarball. Schedule it with cron, and copy the result off the box for real safety.

What data exists

Everything Astrodock stores lives in Docker volumes, so it survives container restarts and upgrades. The pieces worth backing up:

VolumeWhat's in it
pgdataThe Postgres data: the control-plane database plus every internal per-app database.
objectdataThe bundled object store (files apps uploaded in internal-storage mode).
staticBuilt static assets served for Node buildpack apps.
apps / reposDeployed app working directories and cloned source — rebuilt on deploy.
pm2homeProcess-manager state for running apps.
caddy_data / caddy_configIssued TLS certificates and the proxy's runtime config.

The backup script focuses on the two that hold your irreplaceable data — the databases (pgdata) and the object store (objectdata). The rest is regenerated from your repo and .env on deploy; certificates re-issue themselves.

Don't forget .env

Your .env holds the secrets needed to read encrypted data back. It's gitignored, so keep your own safe copy somewhere private — without it a restore is much harder.

Run a backup

From the repo root, with the stack running:

./scripts/backup.sh

By default the tarball lands in ./backups/. Pass a directory to put it elsewhere:

./scripts/backup.sh /mnt/backups

Under the hood the script:

You'll see progress lines like [backup] dumping all databases… and a final [backup] wrote … with the tarball path.

Schedule it with cron

Backups are only useful if they run on their own. Add a cron entry on the host. For a nightly backup at 3:15 AM:

# crontab -e
15 3 * * *  cd /path/to/astrodock && ./scripts/backup.sh /mnt/backups >> /var/log/astrodock-backup.log 2>&1

Use a full path

Cron runs with a bare environment, so cd into the repo first (as above) and use an absolute output directory. Logging to a file lets you confirm it actually ran.

Prune old tarballs periodically so they don't fill the disk — keep, say, the last 7–30 days depending on how much room you have.

Copy backups off the box

The script can push each tarball to an external S3 bucket. Set BACKUP_S3_BUCKET in the environment (with AWS credentials available via the environment or your awscli config), and it uploads after writing the local copy:

BACKUP_S3_BUCKET=my-astrodock-backups ./scripts/backup.sh /mnt/backups

When the variable is unset, the upload step is skipped entirely and you just get the local tarball. Any S3-compatible store with working credentials works here.

The single-box caveat

Local backups protect you from data corruption and fat-fingering — but if the whole box dies, the backups die with it. Always keep at least one copy off the box (the BACKUP_S3_BUCKET upload, or your own rsync/copy to another machine). This off-box copy is the one place an external dependency genuinely earns its keep.

Restore

Restore is a deliberate, manual process — there's no one-click button, and that's on purpose, so you don't overwrite live data by accident. The outline:

  1. Get the tarball onto the host

    Copy your chosen astrodock-backup-<timestamp>.tar.gz to the server and unpack it. Inside you'll find all-databases.sql and objectdata.tar.

    tar -xzf astrodock-backup-20260530T031500Z.tar.gz
  2. Bring the stack up enough to restore into

    Start at least the postgres and objectstore services so there's a target to restore into. On a fresh box, run docker compose up -d with a matching .env first.

  3. Restore the databases

    Feed the SQL dump back into Postgres through the container. pg_dumpall output recreates every database and role:

    docker compose exec -T postgres psql -U astrodock < all-databases.sql
  4. Restore the object store

    Untar objectdata.tar back into the object store's data directory (inside its container / volume), then restart that service so it re-reads its data.

  5. Restart and verify

    Run docker compose up -d, then check the apps and the Health page in the dashboard. Confirm a known app loads and its data is present.

Practice before you need it

Restore touches your live databases. Do a dry run on a spare box at least once so the steps are familiar — the worst time to learn the procedure is during a real outage.

Related