Skip to content

Docker Compose Deployment

This guide covers deploying Open Chat Studio on a single server or small cluster using docker-compose.prod.yml.

For larger deployments

For container-orchestrated deployments (ECS, Kubernetes), see the AWS Fargate guide instead. For managed PaaS hosting, see the Heroku guide.

Prerequisites

  • Docker Engine 24+ and Docker Compose v2
  • A domain name with DNS pointing to your server
  • A reverse proxy (nginx, Caddy, Traefik) handling TLS termination

Step 1: Build the Image

Clone the repository and build the production image.

git clone https://github.com/dimagi/open-chat-studio.git
cd open-chat-studio

docker build -t open-chat-studio:latest .

Step 2: Create the Environment File

Copy the example and fill in your values:

cp .env.example .env.prod

At minimum, set:

# .env.prod

SECRET_KEY=<generate a strong secret key>
DJANGO_SETTINGS_MODULE=config.settings_production
DJANGO_ALLOWED_HOSTS=yourdomain.com

# If using the bundled PostgreSQL container:
DATABASE_URL=postgres://postgres:yourpassword@db:5432/open_chat_studio

# If using the bundled Redis container:
REDIS_URL=redis://redis:6379

# Email (required for user registration)
DJANGO_EMAIL_BACKEND=anymail.backends.mailgun.EmailBackend
MAILGUN_API_KEY=your-mailgun-api-key
MAILGUN_SENDER_DOMAIN=mail.yourdomain.com

# Encryption (recommended: set explicitly rather than relying on SECRET_KEY)
CRYPTOGRAPHY_KEY=<generate a strong key>
CRYPTOGRAPHY_SALT=<generate a random salt>

See Configuration Reference for all available options.

Step 3: Start the Services

If using the bundled PostgreSQL container, also set POSTGRES_PASSWORD (it must match the password in DATABASE_URL):

POSTGRES_PASSWORD=yourpassword docker compose -f docker-compose.prod.yml up -d

Or export it first:

export POSTGRES_PASSWORD=yourpassword
docker compose -f docker-compose.prod.yml up -d

On first start, the migrate service runs all database migrations and then exits before the web and worker services start.

Step 4: Create a Superuser

docker compose -f docker-compose.prod.yml run --rm web python manage.py createsuperuser

Then log in at https://yourdomain.com/admin/ and create a Team.

Step 5: Configure a Reverse Proxy

The web service listens on port 8000 (or $PORT). Put a TLS-terminating reverse proxy in front of it.

Example: Caddy

yourdomain.com {
    reverse_proxy localhost:8000
}

Example: nginx

server {
    listen 443 ssl;
    server_name yourdomain.com;

    # ... TLS config ...

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Also add CSRF_TRUSTED_ORIGINS=https://yourdomain.com to .env.prod.

Useful Commands

# View logs
docker compose -f docker-compose.prod.yml logs -f web
docker compose -f docker-compose.prod.yml logs -f celery_worker

# Run a management command
docker compose -f docker-compose.prod.yml run --rm web python manage.py <command>

# Apply migrations after an upgrade
docker compose -f docker-compose.prod.yml run --rm migrate

# Rebuild after a code update
docker build -t open-chat-studio:latest .
docker compose -f docker-compose.prod.yml up -d

Scaling

To run multiple web workers, either increase WEB_WORKERS (threads within one container):

WEB_WORKERS=4 docker compose -f docker-compose.prod.yml up -d

Or scale the web service to multiple containers (requires an external load balancer and shared storage/S3):

docker compose -f docker-compose.prod.yml up -d --scale web=3

Warning

Run exactly one celery_beat container. Running multiple instances will cause duplicate scheduled tasks.

Using Managed Database and Redis

For production resilience, replace the bundled db and redis containers with managed services. Update your .env.prod:

DATABASE_URL=postgres://user:pass@your-rds-endpoint:5432/open_chat_studio
REDIS_URL=rediss://your-elasticache-endpoint:6379  # note: rediss:// for TLS
REDIS_USE_TLS=True

Then remove the db and redis services from your compose file (or use an override file).

pgvector requirement

Your managed PostgreSQL instance must have the pgvector extension enabled (version ≥ 0.7.0). On Amazon RDS this is available from PostgreSQL 15.2+. On Google Cloud SQL it is available from PostgreSQL 14+.