Skip to content

Testing a backup

A backup nobody has restored is a hypothesis. 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 one from it recreates the stack you are running rather than standing 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 that are nobody else’s.

    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.

    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 outlives the drill, the image included: it is a copy of your instance close to 800 MB, and it is the one piece that stays behind unnoticed because nothing lists it next to 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 browser you were told to open answers nothing at all, and the refusal is 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, and that is the point of the drill rather than a shortcut: 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 catch a restore that came back short.

The repository does the same thing under assertion rather than by eye: apps/api/src/data-io/roundtrip.live.test.ts fills an account, exports it, has its volume deleted, restores into an empty database and compares the two column by column. Its header carries the exact commands. It needs a database it may destroy, so it runs only when LIVE_DB_URL names one; without that variable it skips.

Privacy