Skip to content

Production Checklist

Use this checklist before deploying Rack Gateway to production. Each item addresses a security or operational requirement.

  • APP_SECRET_KEY and AUDIT_HMAC_SECRET generated securely

    Terminal window
    openssl rand -base64 32

    At least 32 bytes each. Never reuse across environments, and never change AUDIT_HMAC_SECRET once events are written (it keys the audit hash chain). Store both securely.

  • Running a release build

    Terminal window
    ./rack-gateway-api build-info # must report: test bypasses: compiled out
  • COLUMN_ENCRYPTION_KEY generated and backed up

    Terminal window
    openssl rand -base64 32

    Encrypts stored TOTP seeds and the Slack token. Never reuse across environments, never use the development key, and back it up: without it users must re-enroll TOTP and Slack must be reconnected. See Column Encryption.

  • HTTPS enabled with valid certificates

    • Let’s Encrypt or organization CA
    • TLS 1.2+ only
    • HSTS enabled
  • Domain configured correctly

    • DOMAIN set to production hostname
    • DNS records configured
    • SSL certificate covers domain
  • Google OAuth configured

    • Production OAuth client created
    • Redirect URIs point to production domain
    • GOOGLE_ALLOWED_DOMAIN restricts to your organization
  • Admin users specified

    • ADMIN_USERS contains verified admin emails
    • At least 2 admins for redundancy
  • Session timeout configured

    • RGW_SETTING_SESSION_TIMEOUT_MINUTES, or Settings → Session Timeout
    • Default: 5 minutes of inactivity for web sessions (CLI sessions last 90 days from their last use)
  • PostgreSQL properly configured

    • Production-grade instance (not Docker)
    • Encryption at rest enabled
    • TLS connections that verify the server (PGSSLMODE=verify-full with PGSSLROOTCERT)
    • Audit roles created, the gateway connecting as the app user and migrations as the admin user (see Database Setup)
    • Migrations applied with rack-gateway-api migrate before the release starts
  • Database backups configured

    • Automated daily backups
    • Point-in-time recovery enabled
    • Backup retention meets compliance requirements
  • Connection pool sized correctly

    • DB_MAX_OPEN_CONNS appropriate for load
    • Monitor connection usage
  • Resource limits configured

    • Memory limits prevent OOM kills
    • CPU limits ensure fair sharing
    • Instance count chosen (the default convox.yml runs one)
  • Health checks enabled

    • /api/v1/health for liveness and readiness (it fails for a minute after any audit write failure)
    • Appropriate intervals and thresholds
  • Reverse proxy configured

    • TRUSTED_PROXY_CIDRS lists the proxies in front of the gateway
    • WebSocket upgrades pass through, request bodies aren’t size-limited
  • Private network deployment (Recommended)

  • Firewall rules configured

    • Only required ports open
    • Database accessible only from gateway
    • No unnecessary public endpoints
  • MFA configured

    • MFA enrollment required for all users
    • Step-up MFA for sensitive actions
    • Backup codes generated and stored securely
  • RBAC policies reviewed

    • Least privilege principle applied
    • No unnecessary admin accounts
    • Roles assigned appropriately
  • API tokens managed

    • Tokens have appropriate roles
    • Token rotation schedule established
    • Unused tokens deleted
  • Audit logging reviewed

    • Always on: every request is recorded before it acts, with user attribution
    • Env values redacted; audit_visible_env_vars lists only harmless keys
    • Container log retention set (LOG_RETENTION_DAYS in convox.yml)
  • Audit anchoring configured (Recommended)

    • S3 WORM bucket created
    • AUDIT_ANCHOR_BUCKET and AUDIT_ANCHOR_CHAIN_ID set
    • AUDIT_VERIFY_HEARTBEAT_URL set to a heartbeat monitor, so you hear when hourly verification stops
    • See S3 WORM Storage
  • HMAC secret configured

    • AUDIT_HMAC_SECRET set to secure random value
    • Never changes after initial deployment
    • Documented for recovery
  • Error tracking enabled

    • SENTRY_DSN configured for backend
    • SENTRY_JS_DSN configured for frontend
    • Alerts configured for errors
  • Metrics collection enabled

    • Health endpoint monitoring, or UPTIME_HEARTBEAT_URL pinged while the gateway is healthy
    • Database metrics tracked
    • Alert thresholds configured
  • Log aggregation configured

    • Logs shipped to centralized system
    • Log retention meets requirements
    • Searchable for incident response
  • Runbooks documented

    • Deployment procedures
    • Rollback procedures
    • Incident response playbooks
  • On-call rotation established

    • Escalation procedures defined
    • Contact information current
    • Access credentials available
  • Disaster recovery tested

    • Database restoration tested
    • Failover procedures documented
    • Recovery time objectives defined
  • Rack connection verified

    • RACK_TOKEN valid and not expired
    • RACK_HOST points to correct rack
    • rack-gateway rack info works through the gateway
  • Proxy functionality tested

    • rack-gateway apps returns expected results
    • Build and deploy operations work
    • Environment variable access works
  • Email notifications configured (Optional)

    • POSTMARK_API_TOKEN set
    • POSTMARK_FROM verified in Postmark
    • Test email sent successfully
  • Slack notifications configured (Optional)

    • Slack app installed
    • Channels configured for events
    • Test notification sent
  • Deploy approvals configured (If using)

    • CIRCLECI_TOKEN set, for CircleCI auto-approval
    • Approval job names match
    • GitHub integration tested
    • service_image_patterns set for each app, pinning the image repository (approval-bound builds are refused without it)
    • approved_deploy_commands lists the exact commands CI runs (an empty list allows none)
    • vcs_repo set to owner/repo for CircleCI auto-approval
  • CI/CD tokens created

    • API tokens with cicd role
    • Tokens stored securely in CI system
    • Test deployment successful
  1. Verify health endpoints

    Terminal window
    curl https://gateway.example.com/api/v1/health
  2. Test user login

    • Open web UI
    • Continue with Google
    • Verify correct roles assigned
  3. Test MFA enrollment

    • Enroll at least one MFA method
    • Verify step-up MFA works
  4. Test Convox operations

    Terminal window
    rack-gateway apps
    rack-gateway ps -a myapp
  5. Verify audit logging

    • Check recent audit events in web UI
    • Verify events have correct user attribution
  6. Test notifications

    • Trigger a security event
    • Verify email/Slack notification received
  7. Test deploy workflow (If using)

    • Create test approval request
    • Approve and verify CI auto-approval
  • Audit logging enabled with retention
  • MFA enforced for all users
  • Access control via RBAC
  • Change management (deploy approvals)
  • Monitoring and alerting configured
  • Incident response procedures documented
  • Encryption at rest (database, S3)
  • Encryption in transit (TLS)
  • PII handling documented
  • Data retention policies configured
  • Access logging enabled
  • Secrets stored securely (not in git)
  • Least privilege principle applied
  • Regular security reviews scheduled
  • Dependency updates monitored
  • Penetration testing planned
Terminal window
# Required
APP_SECRET_KEY=$(openssl rand -base64 32)
AUDIT_HMAC_SECRET=$(openssl rand -base64 32) # Never change it after the first event
COLUMN_ENCRYPTION_KEY=$(openssl rand -base64 32) # Generate once and back it up
DATABASE_URL=postgres://rack_gateway_app:...@db:5432/rack_gateway?sslmode=require
DOMAIN=gateway.example.com
GOOGLE_CLIENT_ID=xxx
GOOGLE_CLIENT_SECRET=xxx
GOOGLE_ALLOWED_DOMAIN=example.com
RACK_TOKEN=xxx
ADMIN_USERS=admin1@example.com,admin2@example.com
# Recommended
LOG_RETENTION_DAYS=400
RACK_ALIAS=production
RACK_DISPLAY_NAME="Production"
TRUSTED_PROXY_CIDRS=10.0.0.0/16 # The proxies in front of the gateway
# If using audit anchoring
AUDIT_ANCHOR_BUCKET=audit-anchors-prod
AUDIT_ANCHOR_CHAIN_ID=production
# If using email
POSTMARK_API_TOKEN=xxx
POSTMARK_FROM=gateway@example.com
# If using Slack
SLACK_CLIENT_ID=xxx
SLACK_CLIENT_SECRET=xxx
# If using Sentry
SENTRY_DSN=https://xxx@sentry.io/xxx
SENTRY_JS_DSN=https://xxx@sentry.io/xxx
SENTRY_ENVIRONMENT=production
Terminal window
# Similar to production but with staging-specific values
APP_SECRET_KEY=$(openssl rand -base64 32) # Different from prod!
AUDIT_HMAC_SECRET=$(openssl rand -base64 32) # Different from prod!
COLUMN_ENCRYPTION_KEY=$(openssl rand -base64 32) # Different from prod!
DOMAIN=gateway-staging.example.com
RACK_ALIAS=staging
RACK_DISPLAY_NAME="Staging"
LOG_RETENTION_DAYS=90 # Shorter for staging

Before going live, ensure these stakeholders have reviewed:

  • Security team: Security hardening complete
  • Operations team: Monitoring and runbooks ready
  • Compliance team: Audit requirements met
  • Development team: Integration testing complete
  • Management: Go-live approval obtained