Skip to content

Testing a backup

You do not know a backup works until someone has restored it. Testing it does not touch your instance, but it cannot be a second docker compose up either: the compose file pins its project name, so a second run recreates the stack you are running instead of starting a copy beside it. Build the image under a name of your own and run the pair by hand.

  1. A network and a database of their own.

    Terminal window
    docker network create badlen-restore-test
    docker run -d --name badlen-restore-db --network badlen-restore-test \
    -e POSTGRES_USER=rt -e POSTGRES_PASSWORD=rt -e POSTGRES_DB=rt \
    -v badlen-restore-test-pgdata:/var/lib/postgresql postgres:18-alpine
  2. The application, on a port nothing else uses. It applies the migrations itself before it serves, so there is no separate schema step. Run by hand, it expects the address in WEB_ORIGIN, the name the compose file gives PUBLIC_URL.

    Terminal window
    docker build -t badlen-restore-test -f Dockerfile.api --target runtime .
    docker run -d --name badlen-restore-app --network badlen-restore-test -p 8099:3001 \
    -e DATABASE_URL='postgresql://rt:rt@badlen-restore-db:5432/rt?schema=public' \
    -e JWT_ACCESS_SECRET="$(openssl rand -hex 32)" \
    -e SECRET_ENCRYPTION_KEY="$(openssl rand -base64 32)" \
    -e WEB_ORIGIN=http://localhost:8099 \
    badlen-restore-test
  3. Open http://localhost:8099, sign up with anything, import your file.

  4. Take it all down. Nothing here should outlive the drill, the image included: it is a copy of your instance close to 800 MB, and it is the piece most easily forgotten, because it is not listed with the containers.

    Terminal window
    docker rm -f badlen-restore-app badlen-restore-db
    docker volume rm badlen-restore-test-pgdata
    docker network rm badlen-restore-test
    docker rmi badlen-restore-test

Both secrets on that docker run are generated rather than typed, and the access one especially: the boot check refuses a JWT_ACCESS_SECRET shorter than 16 characters, and a container it refuses exits at once, after applying the migrations. Nothing then listens on 8099, so the page you open gets no answer, and the refusal shows only in docker logs badlen-restore-app, where it names the variable.

The encryption key on the line under it is a new one every time, because that is what the drill tests: a sealed file opens here, on an instance that has never seen the key of the one that wrote it.

Compare against the real instance: the net worth, the number of operations on your busiest account, and one line’s cost basis. Those three are enough to catch an incomplete restore.