Skip to main content

Production Architecture

BunShip runs as a set of cooperating services. In production, the minimum deployment consists of an API server, a background worker, a Redis instance, and a Turso database.
                    Internet
                       |
                  [Load Balancer]
                   /         \
            [API Server]  [API Server]
                |    \       /    |
                |     [Redis]     |
                |        |        |
                |    [Worker]     |
                |                 |
            [Turso DB]       [S3 Storage]
ComponentRoleTechnology
API ServerHandles HTTP requests, authentication, routingBun + Elysia
WorkerProcesses background jobs (emails, webhooks, billing sync)BullMQ
DatabasePersistent storage for users, orgs, subscriptionsTurso (libSQL/SQLite)
RedisJob queues, caching, rate limitingRedis 7+
S3 StorageFile uploads, avatars, attachmentsAny S3-compatible provider

Production Checklist

Complete every item before your first production deployment.
1

Generate secrets

Create strong, unique values for every secret. Never reuse development values.
# JWT secrets (32+ characters each)
openssl rand -base64 32  # JWT_SECRET
openssl rand -base64 32  # JWT_REFRESH_SECRET

# Redis password
openssl rand -base64 24  # REDIS_PASSWORD

# Cron secret
openssl rand -hex 16     # CRON_SECRET
2

Provision Turso database

Create a production database on Turso Cloud. Choose a primary region close to your API servers.
turso db create bunship-prod --group default
turso db show bunship-prod --url       # DATABASE_URL
turso db tokens create bunship-prod    # DATABASE_AUTH_TOKEN
3

Provision Redis

Use a managed Redis provider (Upstash, Railway addon, ElastiCache) or run Redis in Docker with a password and persistence enabled.
4

Configure S3 storage

Create a bucket in AWS S3, Cloudflare R2, or another S3-compatible service. Set a CORS policy that allows uploads from your frontend domain.
5

Set up Stripe production keys

Switch from sk_test_ to sk_live_ keys. Create a production webhook endpoint pointing to https://api.yourdomain.com/webhooks/stripe and subscribe to the required events.
6

Configure email sending

Verify your production domain in Resend. Update EMAIL_FROM to use the verified domain.
7

Set all environment variables

See the full list in the Environment Configuration section below.
8

Run database migrations

NODE_ENV=production bun run db:migrate
9

Verify health endpoint

After deploying, confirm the health check returns a 200 response.
curl -f https://api.yourdomain.com/health

Environment Configuration

Set every variable listed below in your production environment. Use a secrets manager (not .env files) whenever possible.

Required Variables

# Application
NODE_ENV=production
API_URL=https://api.yourdomain.com
FRONTEND_URL=https://yourdomain.com

# Database (Turso Cloud)
TURSO_DATABASE_URL=libsql://your-db.turso.io
TURSO_AUTH_TOKEN=your-turso-auth-token

# Redis
REDIS_HOST=your-redis-host
REDIS_PORT=6379
REDIS_URL=redis://:your-password@your-redis-host:6379

# JWT (use unique, randomly generated values)
JWT_SECRET=your-production-jwt-secret-min-32-chars
JWT_REFRESH_SECRET=your-production-refresh-secret-min-32-chars

# Stripe (live keys)
STRIPE_SECRET_KEY=sk_live_xxx
STRIPE_WEBHOOK_SECRET=whsec_xxx
STRIPE_PRO_MONTHLY_PRICE_ID=price_xxx
STRIPE_PRO_YEARLY_PRICE_ID=price_xxx
STRIPE_ENTERPRISE_MONTHLY_PRICE_ID=price_xxx
STRIPE_ENTERPRISE_YEARLY_PRICE_ID=price_xxx

# Email
RESEND_API_KEY=re_xxx
EMAIL_FROM="YourApp <[email protected]>"

Optional Variables

# S3 storage
S3_ENDPOINT=https://s3.amazonaws.com
S3_BUCKET=your-bucket
S3_ACCESS_KEY_ID=xxx
S3_SECRET_ACCESS_KEY=xxx
S3_REGION=us-east-1

# OAuth providers
GOOGLE_CLIENT_ID=xxx
GOOGLE_CLIENT_SECRET=xxx
GITHUB_CLIENT_ID=xxx
GITHUB_CLIENT_SECRET=xxx

# Two-factor auth
TOTP_ISSUER=YourApp

# Monitoring
SENTRY_DSN=https://[email protected]/xxx

# Demo / Cron
DEMO_MODE=false
CRON_SECRET=your-cron-secret
Never commit .env files containing production secrets to version control. Use your platform’s secrets management (Railway variables, AWS Secrets Manager, Fly.io secrets, etc.) instead.

Security Headers and CORS

BunShip applies security headers automatically in production (NODE_ENV=production). The defaults are:
HeaderValue
Strict-Transport-Securitymax-age=31536000; includeSubDomains
X-Content-Type-Optionsnosniff
X-Frame-OptionsDENY
X-XSS-Protection0 (relies on CSP instead)
CORS is configured through the FRONTEND_URL environment variable. In production, only requests from that origin are accepted. If you need additional origins, update the CORS configuration in apps/api/src/index.ts.

Health Checks and Monitoring

Health Endpoint

BunShip exposes GET /health which returns:
{
  "status": "ok",
  "timestamp": "2026-01-28T10:00:00.000Z",
  "uptime": 12345,
  "version": "1.0.0"
}
Configure your load balancer or orchestrator to poll this endpoint every 30 seconds. A non-200 response means the instance should be replaced.

What to Monitor

MetricAlert ThresholdWhy
API response time (p95)> 500msPerformance degradation
Error rate (5xx)> 1%Application failures
Redis memory usage> 80% capacityQueue backpressure risk
Worker queue depth> 1000 pending jobsWorker needs scaling
Database connection errorsAnyTurso connectivity issue
SSL certificate expiry< 14 daysPrevents downtime
  • Error tracking: Sentry (set SENTRY_DSN)
  • Uptime monitoring: BetterUptime, Checkly, or UptimeRobot against /health
  • Logs: Structured JSON logs are written to stdout. Ship them to Datadog, Grafana Cloud, or your preferred log aggregator.
  • Metrics: Export Prometheus metrics from /metrics (if enabled) or use your platform’s built-in dashboards.

Deployment Options