Sinatra Docs
Self-hosting

6. Populate `.env.production`

The complete env-var reference for a self-hosted Sinatra instance.

Sinatra cascades env files at the repo root via dotenv-flow (later overrides earlier):

  1. .env — committed cross-env defaults.
  2. .env.local — gitignored cross-env local overrides.
  3. .env.production — committed prod defaults (you create this).
  4. .env.production.local — gitignored prod-only secrets.

For a real deploy, secrets (*_SECRET, *_API_KEY, *_PRIVATE_KEY, SINATRA_KMS_KEY) belong in your secret manager (GCP Secret Manager, AWS Secrets Manager, Doppler, etc.) and are injected at deploy time — not committed. The pattern below shows the env-var shape; the storage mechanism is up to you.

Full template

# ────────────────────────────────────────────────────────────────────────
# Database & Temporal
# ────────────────────────────────────────────────────────────────────────
DATABASE_URL=postgresql://sinatra:CHANGE_ME@db.example.com:5432/sinatra

TEMPORAL_ADDRESS=temporal.example.com:7233
TEMPORAL_NAMESPACE=default
# TEMPORAL_API_KEY=...                  # only when using Temporal Cloud

# ────────────────────────────────────────────────────────────────────────
# API server
# ────────────────────────────────────────────────────────────────────────
HOST=0.0.0.0
PORT=8080
APP_BASE_URL=https://sinatra.example.com   # your public URL (step 8)
LINEAR_REDIRECT_URI=https://sinatra.example.com/install/linear/callback

# ────────────────────────────────────────────────────────────────────────
# KMS — for envelope-encrypting tenant credentials
# ────────────────────────────────────────────────────────────────────────
# Production: GCP KMS resource name
SINATRA_KMS_KEY=projects/<proj>/locations/<loc>/keyRings/<ring>/cryptoKeys/<key>
# OR (single-tenant evaluation only) a 32-byte base64 dev key:
# SINATRA_LOCAL_DEV_KMS_KEY=<base64 32 bytes>

INSTALL_STATE_SECRET=<random hex>             # signs OAuth state tokens

# ────────────────────────────────────────────────────────────────────────
# Linear App  (from step 3)
# ────────────────────────────────────────────────────────────────────────
LINEAR_CLIENT_ID=lin_app_xxxxxxxxxxxx
LINEAR_CLIENT_SECRET=lin_app_secret_xxxxxxxxxxxx
LINEAR_WEBHOOK_SECRET=lin_wh_xxxxxxxxxxxx

# ────────────────────────────────────────────────────────────────────────
# GitHub App  (from step 2)
# ────────────────────────────────────────────────────────────────────────
GITHUB_APP_ID=123456
GITHUB_APP_SLUG=sinatra-acme
GITHUB_APP_WEBHOOK_SECRET=<hex>
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
MIIE...
-----END RSA PRIVATE KEY-----"

# ────────────────────────────────────────────────────────────────────────
# Sandbox  (from step 4)
# ────────────────────────────────────────────────────────────────────────
SANDBOX_PROVIDER=daytona                      # or 'docker'
DAYTONA_API_KEY=daytona_xxxxxxxxxxxxxxxxxxxx  # required if provider=daytona

Generating the random secrets

# INSTALL_STATE_SECRET (hex)
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

# SINATRA_LOCAL_DEV_KMS_KEY (base64, evaluation only)
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"

Verifying

After populating the env file, the API and worker should start without 4xx-ing on startup. The first request to /install/linear will validate Linear credentials; the first webhook delivery will validate GitHub.

Continue to Run with Docker Compose →