Skip to content
Back to site

Upgrade and backup

Run everything here from the install directory (~/railhook by default) with the railhook helper the installer wrote.

Terminal window
cd ~/railhook
./railhook upgrade v2.16.6 # pin a release; with no version it keeps the tags already in .env

upgrade runs these steps in order:

  1. Fetches the helper and the Caddyfile for the target release.
  2. Pins API_IMAGE_TAG, WORKER_IMAGE_TAG and UI_IMAGE_TAG in .env.
  3. Takes a database backup, and stops if that fails.
  4. Replaces docker-compose.yml with the release’s copy and keeps yours as docker-compose.yml.previous.
  5. Pulls the images and restarts the database, cache and dashboard.
  6. Replaces the API containers one at a time. The new API runs the release’s migrations.
  7. Restarts the worker once the new API is serving.

A new worker does not start on an unmigrated schema. If it starts before the API has migrated (for example ./railhook start after a tag change), it waits up to 15 minutes and logs Waiting for the API to migrate the schema.

With one API container, clients see about twenty seconds of 502 during the swap. API_REPLICAS=2 in .env removes the gap.

Rolling back returns the images, not the database schema. Migrations only run forward.

Terminal window
sed -i 's|^API_IMAGE_TAG=.*|API_IMAGE_TAG=2.16.5|' .env # and WORKER_IMAGE_TAG, UI_IMAGE_TAG
./railhook start

A code problem needs only the old images. A migration problem needs the backup the upgrade took.

Terminal window
./railhook doctor

Re-runs the installer’s machine and configuration checks against the files on disk, so a bad hand edit to .env shows up before an outage.

Terminal window
./railhook backup

Writes backup-<timestamp>.dump (PostgreSQL custom format) into the install directory. Installer-made installations also take scheduled dumps through the db-backup service:

Variable Default Meaning
DB_BACKUP_INTERVAL_SECONDS 86400 How often a dump is taken
BACKUP_RETENTION_DAYS 30 How long dumps are kept
BACKUP_DIR ./backups Where they are written
  1. Stop the API and the worker

    Terminal window
    cd ~/railhook
    set -a; . ./.env; set +a
    docker compose stop api worker
  2. Restore the dump

    Terminal window
    docker cp backup-20260913T020000Z.dump webhook-postgres:/tmp/restore.dump
    docker exec webhook-postgres pg_restore \
    -U "${POSTGRES_USER:-webhook_user}" -d "${POSTGRES_DB:-webhook_platform}" \
    --clean --if-exists --no-owner --no-privileges /tmp/restore.dump
    docker exec webhook-postgres rm -f /tmp/restore.dump
  3. Flush Redis

    Redis holds only derived data that rebuilds itself. A stale cache is worse than an empty one.

    Terminal window
    docker exec webhook-redis redis-cli -a "$REDIS_PASSWORD" FLUSHALL
  4. Start the stack

    Terminal window
    ./railhook start

After a restore, pending deliveries are claimed on the worker’s next poll. Deliveries that were in progress when the dump was taken are claimed again once their claim times out (WEBHOOK_CLAIM_TIMEOUT_SECONDS, 300 by default), so an endpoint may receive such an attempt twice. Events accepted after the dump are lost.