Restore from a backup

For the day the disk dies, the box is stolen, or you move to new hardware. Recover documents and settings on a replacement Linux machine using your backup and recovery keys.

On this page

This procedure uses a backup and your recovery information. You do not need access to the old machine. Restore the same Harbor release first, then upgrade after verifying recovery.

What you need#

From the envelope:

  1. The master key. It is required to decrypt the documents.
  2. The backup password.
  3. Where the repository is, and its credentials.
  4. The recovery codes, if your authenticator app is gone too.

The volume passphrase from the old box is not needed. A new box gets a new volume and a new passphrase, which then goes on a new envelope.

1. A box with an empty vault#

Prepare the new machine with the install guide for it, up to running the installer, and set up the data volume; install Tailscale if you use it. Then stop before the installer: a restore puts the old secrets back instead of generating new ones, so this part is done by hand, following the repository's deploy.md for the images and the configuration file. When it comes to secrets, put the old ones back exactly:

mkdir -p /data/secrets && chmod 700 /data/secrets
printf '%s\n' '<master key from the envelope>' > /data/secrets/kek
printf '%s\n' '<backup password from the envelope>' > /data/secrets/restic-password
chmod 600 /data/secrets/kek /data/secrets/restic-password

Set the repository and its credentials in /data/harbor.env as they were. Check each value carefully. Repository access verifies the backup password; opening restored documents also verifies the document master key.

Do not start the stack yet. Two shortcuts for what follows:

cd /opt/harbor
export $(grep -v '^#' /data/harbor.env | xargs)
alias dc='docker compose --env-file /data/harbor.env -f compose.yml -f compose.prod.yml'

2. Bring the files back#

dc up -d postgres                       # the backup container needs it to start
dc run --rm backup restic snapshots     # proves the password and the repository; lists what exists
dc run --rm backup restic restore latest --target /

The last line puts everything back where it was: the documents under /data/blobs, the database dump at /data/dumps/harbor.dump. Both paths are mounts inside the container, so nothing else is written. To restore a particular night instead of the latest, use its id from the list.

3. Load the database#

dc run --rm backup pg_restore --no-owner --exit-on-error \
  --dbname=postgres://harbor:harbor@postgres:5432/harbor /data/dumps/harbor.dump

This is the same command the monthly test runs against a scratch database. The dump includes migration history. Use the matching Harbor release to avoid introducing a schema upgrade during recovery.

4. Start and sign in#

dc up -d
dc logs -f api        # wait for "API listening on :4000"

Sign in at the new address with your password and authenticator. The authenticator secrets were sealed under the master key, which is why the envelope holds it. Sessions and invitations are in the dump too.

5. Verify recovery#

0 / 5 proven