Upgrade & Backup

Move a self-hosted Solana Developer Platform to a new release and protect its data.

Upgrade to a new release, roll back, and back up the data that matters.

Upgrade

A release ships new images and an updated compose.yml.

  1. Refresh the install files. Re-run the install script. It replaces compose.yml with the new release's, verified against its checksums. It never touches .env, keeps an existing .env.example, and prints a link to the new release's template so you can check for new variables.

    Terminal
    curl -fsSL https://github.com/solana-foundation/solana-developer-platform/releases/latest/download/install.sh | bash

    To install a specific release instead of the latest, set INSTALL_VERSION to its tag:

    Terminal
    curl -fsSL https://github.com/solana-foundation/solana-developer-platform/releases/latest/download/install.sh | INSTALL_VERSION=vX.Y.Z bash
  2. Pin the version. Set SDP_VERSION in .env to the same release tag, not latest, so every service runs one known build.

  3. Pull and restart.

    Terminal
    cd ~/sdp
    docker compose pull
    docker compose up -d

    sdp-migrate applies any new database migrations before the API starts.

  4. Verify that the services are healthy, as in the Quickstart.

Roll back

To run the previous release again, re-run the install script with its tag in INSTALL_VERSION, set SDP_VERSION to that tag, and run docker compose up -d.

Migrations don't reverse. If the newer release applied any, restore a backup taken before the upgrade instead of only switching versions.

Backup

Two things hold your state:

  • The Postgres database: all platform data. The bundled database lives in the sdp-postgres-data volume (sdp_sdp-postgres-data in docker volume ls). Back up an external DATABASE_URL with your database provider's tools.
  • Your .env: configuration and secrets you can't regenerate. Without the same API_KEY_PEPPER, no existing API key matches. Without the same CUSTODY_ENCRYPTION_KEY, SDP can't decrypt the custody secrets it stored, such as local wallet keys. Keep the file in a secret manager.

Redis is a cache and doesn't need a backup.

Back up the database

Take a logical dump with pg_dump inside the running container. Running it through sh -c lets it read POSTGRES_USER and POSTGRES_DB there, so custom values work:

Terminal
cd ~/sdp
docker compose exec -T postgres \
  sh -c 'pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB"' > sdp-backup.sql

Keep dumps off the host, on a schedule that fits your recovery needs.

Restore the database

A plain pg_dump holds the full schema and the migration history, so restore it into an empty database and let the stack start on top. Restoring over an already migrated database collides with the schema sdp-migrate created.

Terminal
cd ~/sdp
docker compose down                       # stop every service
docker volume rm sdp_sdp-postgres-data    # discard the current database (destructive)
docker compose up -d postgres             # start a fresh, empty Postgres
until docker compose exec -T postgres \
  sh -c 'pg_isready -U "$POSTGRES_USER"' >/dev/null 2>&1; do sleep 1; done
docker compose exec -T postgres \
  sh -c 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB"' < sdp-backup.sql
docker compose up -d                      # start the rest

On that final up, sdp-migrate skips every migration the dump already records, so an older dump gets only the newer migrations.

Restore the matching .env too, so secrets such as CUSTODY_ENCRYPTION_KEY match the data they protect. Restore an external DATABASE_URL through your database provider instead of the bundled postgres service.