Skip to content

Production Deployment

This guide covers deploying Klaxon to production on AWS, Azure, GCP, or self-hosted infrastructure.

Production Checklist

Before going live, verify:

  • [ ] TLS: HTTPS enforced via load balancer or reverse proxy
  • [ ] SMTP configured: SMTP_HOST set for magic link + email notifications
  • [ ] FCM configured: FCM_SERVER_KEY set for push notifications
  • [ ] Redis configured: REDIS_URL set for rate limiting
  • [ ] Postgres backups: automated via cloud provider or cron
  • [ ] CORS restricted: CORS_ORIGINS set to actual frontend domains (not *)
  • [ ] Dev login disabled: DEV_LOGIN_ENABLED=false (default)
  • [ ] Observability: OTEL_ENABLED=true with collector endpoint, log aggregation configured
  • [ ] Health monitoring: alert on /ready returning non-200
  • [ ] Secrets management: env vars via cloud secrets manager (not plaintext files)
  • [ ] Image pinned: Docker image tag pinned to a specific SHA, not latest

Architecture Overview

Every deployment needs:

ComponentPurposeReplicas
ServerHTTP API, MCP, WebSocket2+ (stateless)
WorkerPush queue, webhooks, email, sweeps1
PostgreSQLData store1 (managed recommended)
RedisRate limiting1

The server and worker run the same Docker image — the worker is started with --worker flag.

Self-Hosted (Docker Compose + Traefik)

For VPS or bare metal. See deploy/docker-compose.prod.yml.

bash
# Set your domain and email
export DOMAIN=klaxon.sh
export ACME_EMAIL=admin@klaxon.sh

# Start
docker compose -f deploy/docker-compose.prod.yml up -d

Traefik handles TLS via Let's Encrypt automatically. Postgres data persists in a named volume. A daily backup cron dumps to /backups.

AWS (ECS Fargate + RDS + ElastiCache)

Terraform module: deploy/terraform/aws/

bash
cd deploy/terraform/aws
cp terraform.tfvars.example terraform.tfvars
# Edit terraform.tfvars with your values
terraform init
terraform plan
terraform apply

Resources provisioned:

  • ECS Fargate cluster (server: 2 tasks, worker: 1 task)
  • RDS PostgreSQL 16 (db.t3.micro, configurable)
  • ElastiCache Redis (cache.t3.micro)
  • Application Load Balancer with ACM TLS certificate
  • ECR repository for Docker images
  • CloudWatch log group
  • VPC with public/private subnets

Pulumi alternative: deploy/pulumi/aws/

Azure (Container Apps + Flexible Server + Cache)

Terraform module: deploy/terraform/azure/

bash
cd deploy/terraform/azure
cp terraform.tfvars.example terraform.tfvars
terraform init && terraform apply

Resources provisioned:

  • Azure Container Apps (server + worker)
  • Azure Database for PostgreSQL Flexible Server
  • Azure Cache for Redis
  • Azure Container Registry
  • Application Gateway with managed TLS

Pulumi alternative: deploy/pulumi/azure/

GCP (Cloud Run + Cloud SQL + Memorystore)

Terraform module: deploy/terraform/gcp/

bash
cd deploy/terraform/gcp
cp terraform.tfvars.example terraform.tfvars
terraform init && terraform apply

Resources provisioned:

  • Cloud Run services (server + worker)
  • Cloud SQL PostgreSQL 16
  • Memorystore Redis
  • Artifact Registry for Docker images
  • Cloud Load Balancing with managed SSL certificate

Pulumi alternative: deploy/pulumi/gcp/

Kubernetes (Helm)

See the Kubernetes / Helm guide. The Helm chart is published to oci://ghcr.io/ottercoders/charts.

bash
helm install klaxon oci://ghcr.io/ottercoders/charts/klaxon \
  --set secrets.databaseUrl="postgres://..." \
  --set ingress.enabled=true \
  --set ingress.hosts[0].host=klaxon.sh

Environment Variables Reference

See Configuration for the full list. Key production variables:

bash
DATABASE_URL=postgres://klaxon:SECRET@db:5432/klaxon
REDIS_URL=redis://cache:6379
CORS_ORIGINS=https://klaxon.sh
APP_URL=https://klaxon.sh
SMTP_HOST=smtp.sendgrid.net
SMTP_USER=apikey
SMTP_PASS=SG.xxx
SMTP_FROM=noreply@klaxon.sh
FCM_SERVER_KEY=AAAA...
OTEL_ENABLED=true
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317