Start / Upgrade

Upgrade a self-hosted instance

Move from the image you run (X) to a later tag or commit (Y), keeping the database and the keys.

X is the image running now; Y is a later v* tag, or a git commit if you build from source.

curl -s http://127.0.0.1:3800/health
docker compose images
secondlayer --version

Published images are ghcr.io/ryanwaits/secondlayer-runtime:<tag> (releases); latest moves, so pin a v* tag. One jump to Y; read every changelog entry dated after X before you pull (that page owns what broke). The CLI is a separate npm version (secondlayer --version); bump it so commands match the instance you land on.

The index can be rebuilt from the archive. The keys cannot.

KeepWhy
postgres_data volumechain, subgraph tables, webhook rows
subgraphs_data volumecompiled handlers
SECONDLAYER_SECRETS_KEYdecrypts webhook signing secrets in Postgres
INSTANCE_TOKENcallers; required at boot
STREAMS_SIGNING_PRIVATE_KEY, SECONDLAYER_WEBHOOK_SIGNING_PRIVATE_KEYplatform signature on deliveries
POSTGRES_PASSWORDthe volume already uses it

Per-webhook HMAC secrets (whsec_…) live encrypted in the database, so you do not export them separately. Losing SECONDLAYER_SECRETS_KEY makes every existing whsec_ unreadable; rotate each webhook rather than minting a new master key. See Authentication.

secondlayer backup writes the index plus those keys, encrypted under a passphrase.

A full dump of a mainnet index takes hours. A filesystem snapshot of the volume is the faster backup if the host can take one. Copy .env somewhere the database backups are not; the upgrade itself is minutes.

Do not wipe the volume

docker compose down -v deletes postgres_data, and secondlayer setup --force mints a new secrets key that leaves existing webhook secrets unreadable. Stop with docker compose down (no -v). setup is not an upgrade: bootstrap refuses a database that already has blocks.

Pin Y, then restart. pull when compose already lists a secondlayer image; git checkout and --build when this directory is a checkout.

# published image: set image to .../secondlayer-runtime:<Y>
docker compose pull
docker compose up -d --remove-orphans
git fetch
git checkout <Y>
docker compose down --remove-orphans
docker compose up -d --build --remove-orphans

--remove-orphans stops services Y's compose file no longer lists. Migrations run at boot under an advisory lock, forward-only.

Confirm /health is ok, then verify against the archive.

curl http://127.0.0.1:3800/health
secondlayer verify all --against <manifest>

To roll back, pin X again. A migrated schema stays migrated, so roll back the image, not the database.