Skip to content

Production Deployment

This page covers the additional steps required to harden a Strawly deployment for production use.

Checklist

Before going live, work through each item:

  • [ ] Change the default admin password (instructions)
  • [ ] Generate strong secrets with ./scripts/generate-secrets.sh
  • [ ] Set CORS_ORIGIN to your production frontend URL
  • [ ] Enable HTTPS via a reverse proxy
  • [ ] Use a managed PostgreSQL database (not a Docker volume)
  • [ ] Set up automated database backups
  • [ ] Set up Redis for token revocation (required for multi-instance deployments)
  • [ ] Configure log aggregation
  • [ ] Set up monitoring and alerting
  • [ ] Configure firewall rules
  • [ ] Set Docker resource limits
  • [ ] Set up automated image updates

HTTPS with a reverse proxy

Strawly does not handle TLS termination itself. Put a reverse proxy in front of it.

Example nginx configuration (adapt as needed):

server {
    listen 443 ssl;
    server_name strawly.example.com;

    ssl_certificate     /etc/letsencrypt/live/strawly.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/strawly.example.com/privkey.pem;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

server {
    listen 443 ssl;
    server_name api.strawly.example.com;

    # ... same SSL config ...

    location / {
        proxy_pass http://localhost:3001;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Use Certbot or Caddy to manage certificates automatically.

After adding a reverse proxy, update CORS_ORIGIN in .env to your production frontend URL and regenerate:

npm run generate-compose
docker compose -f docker-compose.generated.yml up -d

Managed PostgreSQL

For production, use a managed database service (AWS RDS, Azure Database for PostgreSQL, etc.) rather than the Docker volume, which is not backed up by default.

  1. Provision a managed PostgreSQL 14+ database.

  2. Update .env:

    bash DATABASE_URL=postgresql://strawly:password@your-db-host:5432/strawly

  3. Remove the postgres service from the generated compose, or set POSTGRES_ENABLED=false if supported in your deployment version.

  4. Run migrations against the managed database on first deploy:

    bash docker compose -f docker-compose.generated.yml run --rm migrations

Database backups

If using the Docker volume (not recommended for production), schedule regular dumps:

# Example: daily pg_dump to a local file
docker exec strawly-postgres pg_dump -U strawly strawly > backup-$(date +%Y%m%d).sql

For managed databases, use the provider's built-in backup and point-in-time recovery features.

Redis for token revocation

The backend uses an in-memory store for JWT token revocation by default. This works for single-instance deployments, but does not survive restarts or share state across multiple backend instances.

For production or multi-instance deployments, configure Redis:

  1. Add a Redis service to your deployment or use a managed Redis instance.

  2. Set REDIS_URL in .env:

    bash REDIS_URL=redis://localhost:6379

  3. Regenerate and redeploy.

Docker resource limits

Add resource limits to prevent any one service from consuming all available memory or CPU:

# In docker-compose.generated.yml (or a local override)
services:
  backend:
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 4G
        reservations:
          cpus: '1.0'
          memory: 2G

Horizontal scaling

To run multiple backend instances behind a load balancer:

  1. Configure Redis for token revocation (required — see above).
  2. Put a load balancer in front (nginx, HAProxy, or a cloud load balancer).
  3. Scale the backend:

    bash docker compose -f docker-compose.generated.yml up -d --scale backend=3