Skip to content

Back up and restore ReleaseDesk ​

ReleaseDesk stores release metadata in SQLite and uploaded files in disk or S3 storage. A usable backup needs both, plus the secrets used to read protected data after a restore. Set up backups before publishing builds you cannot easily re-upload.

What to keep ​

ComponentLocationWhat happens if it is missing
SQLite databaseRD_DATA_DIR/releasedesk.dbApps, releases, channels, testers, tokens, signing key records, statistics, and audit entries are lost.
Artifact storageRD_DATA_DIR/storage/ when RD_STORAGE=disk; the bucket named by RD_S3_BUCKET when RD_STORAGE=s3Database records remain, but their files cannot be downloaded.
Container registry dataBlobs and manifests under registry/ in artifact storage; repository, tag and manifest metadata in the databaseBack up both together. Tags and manifests in the database point at blobs in storage, so a database restored without its blobs (or the reverse) leaves images that cannot be pulled.
RD_MASTER_KEYYour secret store or deployment environmentStored signing keys and other encrypted secrets cannot be decrypted. Existing sessions may also stop working.
RD_STATS_SECRETYour secret store or deployment environmentDevice IDs hash differently after recovery, breaking continuity in device and adoption statistics.

Back up the deployment settings needed to reconnect to GitHub, mail, and storage as well. Keep RD_MASTER_KEY in a protected place separate from the database backup. Do not replace it with a new value during recovery. In development, ReleaseDesk can generate an in-memory key when the setting is absent; that fallback does not survive a restart and is unsuitable for a recoverable deployment.

The database and artifacts should be recoverable to roughly the same point in time. Restoring a newer database against an older artifact copy can leave downloads pointing to missing files. The same applies to container images: restore the registry/ storage prefix and the database from the same point in time. Garbage collection removes unreferenced blobs after a grace period (7 days by default), so a storage copy older than that can be missing blobs a newer database still references. Extra artifact files without database rows are less disruptive, but they still use storage and should be reviewed later.

Back up the database ​

ReleaseDesk opens SQLite in WAL mode. A live copy of releasedesk.db alone can miss committed transactions still in the WAL file. Use SQLite's online backup command for scheduled snapshots, or run a WAL-aware replication tool such as Litestream. SQLite documents the .backup command for creating a consistent copy while a database is in use.

For a simple scheduled copy, replace the paths with those on your host:

sh
backup_file="/backup/releasedesk-$(date -u +%Y%m%dT%H%M%SZ).db"
sqlite3 /var/lib/releasedesk/releasedesk.db \
  ".backup '$backup_file'"
sqlite3 "$backup_file" "PRAGMA integrity_check;"

The integrity check should print ok. Send the resulting file to a second host or backup service; a copy on the same disk does not protect against disk loss. Set a retention period that covers the time it would take you to notice a bad upload, accidental deletion, or corrupted host. Use the same backup schedule to capture your deployment settings and secrets, while keeping the secrets under separate access controls.

Continuous replication with Litestream ​

The Litestream configuration reference describes a current configuration with one replica per database. For example, if RD_DATA_DIR=/var/lib/releasedesk:

yaml
snapshot:
  interval: 24h
  retention: 168h

dbs:
  - path: /var/lib/releasedesk/releasedesk.db
    replica:
      url: s3://releasedesk-db-backup/releasedesk.db

Provide the backup bucket credentials through Litestream's environment, not in the checked-in YAML. Place the replica in a separate bucket from app artifacts; a second account or failure domain provides stronger protection. Litestream must see the same database and WAL files as ReleaseDesk, so a container sidecar needs the database volume mounted at the same path. Run replication continuously and monitor it: an old successful snapshot does not prove recent transactions have reached the replica. The Litestream replicate reference covers service operation and the restore reference covers point-in-time recovery.

The older replicas: list and per-replica retention setting in some deployment notes are from Litestream's earlier configuration format. Check the version you install and use its matching reference before starting replication.

Back up artifacts ​

Disk storage ​

With RD_STORAGE=disk, uploaded files live under RD_DATA_DIR/storage/, including artifacts/ and app logos. Back up the whole storage/ tree to another machine or bucket. A filesystem snapshot, restic repository, or another file backup tool can do this. Keep the SQLite database on its own SQLite-aware backup schedule; a file-level copy of the live data directory is not a substitute for the database backup above.

For example, a restic job could back up only the artifact tree:

sh
restic -r s3:https://s3.backup.example.com/releasedesk-restic \
  backup /var/lib/releasedesk/storage

This command assumes restic and its repository credentials are already configured. Verify that the job includes the files under storage/artifacts/, and test restoring one to a temporary location.

S3-compatible storage ​

With RD_STORAGE=s3, back up the bucket named by RD_S3_BUCKET. Bucket versioning can provide a recovery window for an accidental overwrite or delete. For a separate copy, replicate to a second bucket or use a scheduled copy job. Keep the replica's credentials independent of the app's storage credentials where possible.

sh
rclone copy primary:releasedesk backup:releasedesk-artifacts \
  --immutable --transfers 8

copy does not propagate source deletions into the backup. That matters because ReleaseDesk intentionally deletes old artifacts under its retention policy. Review the backup bucket's own lifecycle rules so retained copies remain available long enough to cover your recovery window. Test credentials and object access as well as listing: the server needs to read the restored object's exact storage key.

Test a recovery ​

A backup is useful only if you can restore it. At least periodically, restore a database to a scratch path, run SQLite's integrity check, and inspect representative rows. With Litestream, for example:

sh
litestream restore -config /etc/litestream.yml \
  -o /tmp/releasedesk-restore.db \
  /var/lib/releasedesk/releasedesk.db
sqlite3 /tmp/releasedesk-restore.db "PRAGMA integrity_check;"

Litestream will not overwrite an existing output database by default. Choose a fresh scratch path for each test. To check an older recovery point, add -timestamp with a UTC timestamp supported by the replica's retention window. Restore sample artifact files alongside the database and compare them with the artifact hashes shown in ReleaseDesk. A database integrity result of ok says nothing about whether the artifact store is complete.

For a full recovery, follow this order:

  1. Stop ReleaseDesk and the database replication process. Preserve the current database, WAL, and shared-memory files until the restored instance has been checked; do not merge their old WAL with a restored database.
  2. Restore the artifact tree or bucket to the chosen recovery point. Keep the original storage keys and configure RD_STORAGE and the relevant storage settings for that copy.
  3. Restore the matching SQLite snapshot to an empty target path. Verify it with PRAGMA integrity_check; before making it the active releasedesk.db.
  4. Restore the original RD_MASTER_KEY and RD_STATS_SECRET, plus the GitHub, mail, base URL, and storage settings needed by this instance.
  5. Start ReleaseDesk. It applies pending database migrations on startup. Check /healthz, open the dashboard, download at least one artifact from each important app, and request a signed update feed with a client that verifies its signature.

Do a rehearsal on a separate host or data directory before relying on this procedure for an outage. A rehearsal also reveals missing bucket permissions, secrets, or files without risking the running instance.

Retention and recovery points ​

RD_RETAIN_RELEASES_PER_CHANNEL controls ReleaseDesk's cleanup of old promoted releases and their artifacts. Releases currently promoted to a channel and releases never promoted are retained by that job. Backups made before cleanup may still contain older builds. If you restore a database from before cleanup against a storage copy from after cleanup, those older rows can point to deleted files. Choose database and artifact recovery points from the same window, and check downloads before reopening the instance to users.

Running on Postgres ​

Set RD_DATABASE_URL=postgres://user:pass@host:5432/dbname to store metadata in Postgres instead of SQLite. Migrations are applied at startup. In that mode the database row in the table above is your Postgres database: back it up with pg_dump (or your provider's snapshots/PITR) instead of copying releasedesk.db, and ignore the SQLite and Litestream sections. RD_DATA_DIR is still used for disk storage and resumable-upload scratch space.

For Docker, deploy/prod/docker-compose.postgres.yml adds a bundled Postgres service: docker compose -f docker-compose.yml -f docker-compose.postgres.yml up -d (set POSTGRES_PASSWORD in .env). Back it up with docker compose exec postgres pg_dump -U releasedesk releasedesk > backup.sql.

Existing SQLite data is not migrated automatically, and RD_DEMO_MODE is only supported with SQLite.