Skip to content

Convox Deployment

Rack Gateway deploys as a single Convox service that serves the API and the web UI. An optional admin service is included in convox.yml for running migrations or admin tasks.

  • Convox CLI authenticated against your rack (for the first deploy; later deploys can go through the gateway)
  • Google OAuth client configured (see OAuth Setup)
  • A PostgreSQL database with the audit roles, an admin user and an app user (see Database Setup)
  • A private network to reach it: the gateway service is internal: true (see Private Network)
  1. Set required environment variables

    Terminal window
    convox env set -a rack-gateway \
    DOMAIN=gateway.example.com \
    APP_SECRET_KEY=$(openssl rand -base64 32) \
    AUDIT_HMAC_SECRET=$(openssl rand -base64 32) \
    COLUMN_ENCRYPTION_KEY=$(openssl rand -base64 32) \
    GOOGLE_CLIENT_ID=your-client-id \
    GOOGLE_CLIENT_SECRET=your-client-secret \
    GOOGLE_ALLOWED_DOMAIN=example.com \
    ADMIN_USERS=admin@example.com \
    RACK_TOKEN=your-convox-rack-token \
    DATABASE_URL=postgres://rack_gateway_app:...@db-host:5432/rack_gateway \
    ADMIN_DATABASE_URL=postgres://rack_gateway_admin:...@db-host:5432/rack_gateway
  2. (Optional) Configure audit anchors

    Terminal window
    convox env set -a rack-gateway \
    AUDIT_ANCHOR_BUCKET=your-worm-bucket \
    AUDIT_ANCHOR_CHAIN_ID=production

    The gateway’s IAM role (the IAM_ROLE_ARN annotation in convox.yml) needs to write to the bucket. See S3 WORM Storage.

  3. Build, migrate, promote

    The gateway never migrates on startup, so convox deploy alone would start a release against an old schema. Build the release, migrate with it, then promote it:

    Terminal window
    convox build -a rack-gateway --description "rack-gateway vX.Y.Z" # prints the release ID
    convox run admin ./rack-gateway-api migrate -a rack-gateway --release <release-id>
    convox releases promote <release-id> -a rack-gateway
  4. Verify

    Terminal window
    curl -s https://gateway.example.com/api/v1/health

    Then sign in as one of the ADMIN_USERS and enroll MFA.

VariableDescription
DOMAINGateway domain (used for OAuth redirects)
APP_SECRET_KEYSession/CSRF secret (at least 32 bytes)
AUDIT_HMAC_SECRETAudit hash chain secret (at least 32 bytes)
DATABASE_URLThe app user’s connection string
ADMIN_DATABASE_URLThe admin user’s connection string, for the admin service
COLUMN_ENCRYPTION_KEYEncrypts stored TOTP seeds and the Slack token (openssl rand -base64 32)
GOOGLE_CLIENT_IDOAuth client ID
GOOGLE_CLIENT_SECRETOAuth client secret
GOOGLE_ALLOWED_DOMAINAllowed email domain
ADMIN_USERSComma-separated bootstrap admin emails
RACK_TOKENConvox rack API token
VariableDescription
RACK_ALIASShort rack identifier
RACK_DISPLAY_NAMEHuman-readable rack name
VariableDescription
RACK_HOSTConvox rack API URL (override)
POSTMARK_API_TOKENEmail notifications
SLACK_CLIENT_IDSlack integration
SLACK_CLIENT_SECRETSlack integration

Use an external PostgreSQL (for example RDS) set up as in Database Setup: the gateway service connects as the app user (DATABASE_URL), and the admin service as the admin user (RGW_DATABASE_URL=${ADMIN_DATABASE_URL} in convox.yml).

Use the admin service in convox.yml for database tasks, against the release you’re about to promote:

Terminal window
convox run admin ./rack-gateway-api migrate -a rack-gateway --release <release-id>

migrate needs COLUMN_ENCRYPTION_KEY like the server does (convox.yml shares it with every service).

Once the gateway runs, deploy it through itself with the rack-gateway CLI. From the repository root:

Terminal window
./scripts/bump-version.sh patch # pins convox.yml to the new image tag
./scripts/deploy.sh <rack> # build, migrate against the new release, promote

scripts/deploy_all.sh runs deploy.sh for each rack in its RACKS list in turn (edit the list for your racks).

The repository ships a production-ready convox.yml that defines:

  • gateway service (API + web UI)
  • admin service (on-demand maintenance)
  • CloudWatch retention via LOG_RETENTION_DAYS in appSettings
  • The image pinned to an immutable release tag (docker.io/docspringcom/rack-gateway:vX.Y.Z), never :latest

Keep the manifest in sync with your deployment.