> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bunship.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Deployment Overview

> Deploy BunShip to production

## 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]
```

| Component  | Role                                                       | Technology                 |
| ---------- | ---------------------------------------------------------- | -------------------------- |
| API Server | Handles HTTP requests, authentication, routing             | Bun + Elysia               |
| Worker     | Processes background jobs (emails, webhooks, billing sync) | BullMQ                     |
| Database   | Persistent storage for users, orgs, subscriptions          | Turso (libSQL/SQLite)      |
| Redis      | Job queues, caching, rate limiting                         | Redis 7+                   |
| S3 Storage | File uploads, avatars, attachments                         | Any S3-compatible provider |

## Production Checklist

Complete every item before your first production deployment.

<Steps>
  <Step title="Generate secrets">
    Create strong, unique values for every secret. Never reuse development values.

    ```bash theme={null}
    # 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
    ```
  </Step>

  <Step title="Provision Turso database">
    Create a production database on Turso Cloud. Choose a primary region close to your API servers.

    ```bash theme={null}
    turso db create bunship-prod --group default
    turso db show bunship-prod --url       # DATABASE_URL
    turso db tokens create bunship-prod    # DATABASE_AUTH_TOKEN
    ```
  </Step>

  <Step title="Provision Redis">
    Use a managed Redis provider (Upstash, Railway addon, ElastiCache) or run Redis in Docker with a password and persistence enabled.
  </Step>

  <Step title="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.
  </Step>

  <Step title="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.
  </Step>

  <Step title="Configure email sending">
    Verify your production domain in Resend. Update `EMAIL_FROM` to use the verified domain.
  </Step>

  <Step title="Set all environment variables">
    See the full list in the [Environment Configuration](#environment-configuration) section below.
  </Step>

  <Step title="Run database migrations">
    ```bash theme={null}
    NODE_ENV=production bun run db:migrate
    ```
  </Step>

  <Step title="Verify health endpoint">
    After deploying, confirm the health check returns a 200 response.

    ```bash theme={null}
    curl -f https://api.yourdomain.com/health
    ```
  </Step>
</Steps>

## Environment Configuration

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

### Required Variables

```bash theme={null}
# 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 <noreply@yourdomain.com>"
```

### Optional Variables

```bash theme={null}
# 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://xxx@xxx.ingest.sentry.io/xxx

# Demo / Cron
DEMO_MODE=false
CRON_SECRET=your-cron-secret
```

<Warning>
  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.
</Warning>

## Security Headers and CORS

BunShip applies security headers automatically in production (`NODE_ENV=production`). The defaults are:

| Header                      | Value                                 |
| --------------------------- | ------------------------------------- |
| `Strict-Transport-Security` | `max-age=31536000; includeSubDomains` |
| `X-Content-Type-Options`    | `nosniff`                             |
| `X-Frame-Options`           | `DENY`                                |
| `X-XSS-Protection`          | `0` (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:

```json theme={null}
{
  "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

| Metric                     | Alert Threshold     | Why                      |
| -------------------------- | ------------------- | ------------------------ |
| API response time (p95)    | > 500ms             | Performance degradation  |
| Error rate (5xx)           | > 1%                | Application failures     |
| Redis memory usage         | > 80% capacity      | Queue backpressure risk  |
| Worker queue depth         | > 1000 pending jobs | Worker needs scaling     |
| Database connection errors | Any                 | Turso connectivity issue |
| SSL certificate expiry     | \< 14 days          | Prevents downtime        |

### Recommended Monitoring Stack

* **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

<CardGroup cols={2}>
  <Card title="Docker" icon="docker" href="/deployment/docker">
    Run BunShip with Docker Compose on any server or VPS
  </Card>

  <Card title="Railway" icon="train" href="/deployment/railway">
    One-click deploy with automatic builds and managed infrastructure
  </Card>

  <Card title="Fly.io" icon="globe" href="/deployment/fly-io">
    Deploy globally with edge regions and automatic scaling
  </Card>

  <Card title="AWS" icon="aws" href="/deployment/aws">
    Full control with ECS Fargate, ALB, and the AWS ecosystem
  </Card>
</CardGroup>
