Skip to main content
Deploy Twenty on your own infrastructure using Docker Compose for a production-ready setup.

Overview

Docker Compose provides the easiest way to self-host Twenty with all required services configured and ready to go. Includes:
  • Twenty server (API + frontend)
  • Worker for background jobs
  • PostgreSQL database
  • Redis for caching

Prerequisites

  • Docker Engine 20.10+
  • Docker Compose v2.0+
  • 2GB+ RAM available
  • Domain name (for production use)

Quick Start

1. Download Configuration Files

Create a directory for your Twenty installation:
mkdir twenty-self-hosted
cd twenty-self-hosted
Download the Docker Compose configuration:
curl -O https://raw.githubusercontent.com/twentyhq/twenty/main/packages/twenty-docker/docker-compose.yml
curl -O https://raw.githubusercontent.com/twentyhq/twenty/main/packages/twenty-docker/.env.example

2. Configure Environment Variables

Copy the example environment file:
cp .env.example .env
Edit .env with your configuration:
.env
# Twenty version (latest or specific version)
TAG=latest

# Server URL (use your domain or IP)
SERVER_URL=http://localhost:3000

# Generate a secure secret
APP_SECRET=your-secure-random-string-here

# Storage configuration
STORAGE_TYPE=local

# Database credentials (change in production!)
# PG_DATABASE_USER=postgres
# PG_DATABASE_PASSWORD=strong-password-here
Important: Generate a secure APP_SECRET using:
openssl rand -base64 32
Never use the default value in production!

3. Start Services

Start all containers:
docker compose up -d
This will:
  • Pull the Twenty Docker image
  • Start PostgreSQL and Redis
  • Initialize the database
  • Start the web server and worker

4. Verify Installation

Check that all services are running:
docker compose ps
You should see:
  • server - Running on port 3000
  • worker - Processing background jobs
  • db - PostgreSQL database
  • redis - Redis cache
Access Twenty at http://localhost:3000 (or your configured SERVER_URL).

Docker Compose Configuration

The docker-compose.yml includes four main services:

Server Service

server:
  image: twentycrm/twenty:latest
  ports:
    - "3000:3000"
  environment:
    PG_DATABASE_URL: postgres://postgres:postgres@db:5432/default
    REDIS_URL: redis://redis:6379
    SERVER_URL: ${SERVER_URL}
    APP_SECRET: ${APP_SECRET}
  depends_on:
    db:
      condition: service_healthy
    redis:
      condition: service_healthy
  restart: always

Worker Service

Handles background jobs:
worker:
  image: twentycrm/twenty:latest
  command: ["yarn", "worker:prod"]
  environment:
    DISABLE_DB_MIGRATIONS: "true"
    DISABLE_CRON_JOBS_REGISTRATION: "true"
  depends_on:
    server:
      condition: service_healthy

Database Service

db:
  image: postgres:16
  volumes:
    - db-data:/var/lib/postgresql/data
  environment:
    POSTGRES_DB: default
    POSTGRES_PASSWORD: postgres
  healthcheck:
    test: pg_isready -U postgres

Redis Service

redis:
  image: redis
  command: ["--maxmemory-policy", "noeviction"]
  healthcheck:
    test: ["CMD", "redis-cli", "ping"]

Volume Management

Persistent data is stored in Docker volumes:
volumes:
  db-data:              # PostgreSQL database
  server-local-data:    # Uploaded files (when using local storage)

Backup Volumes

Backup your data regularly:
# Backup database
docker compose exec db pg_dump -U postgres default > backup.sql

# Backup files
docker compose exec server tar czf /tmp/files.tar.gz /app/packages/twenty-server/.local-storage
docker compose cp server:/tmp/files.tar.gz ./files-backup.tar.gz

Restore from Backup

# Restore database
cat backup.sql | docker compose exec -T db psql -U postgres default

# Restore files
docker compose cp ./files-backup.tar.gz server:/tmp/files.tar.gz
docker compose exec server tar xzf /tmp/files.tar.gz -C /

Environment Variables

Required Variables

SERVER_URL
string
required
Public URL where Twenty will be accessible (e.g., https://crm.yourcompany.com)
APP_SECRET
string
required
Secret key for encryption and JWT signing. Generate with openssl rand -base64 32

Storage Configuration

STORAGE_TYPE
string
default:"local"
Storage backend: local or s3
STORAGE_S3_REGION
string
AWS region (when using S3 storage)
STORAGE_S3_NAME
string
S3 bucket name
STORAGE_S3_ENDPOINT
string
Custom S3 endpoint (for S3-compatible services)

Authentication Providers

AUTH_GOOGLE_CLIENT_ID
string
Google OAuth client ID
AUTH_GOOGLE_CLIENT_SECRET
string
Google OAuth client secret
AUTH_MICROSOFT_CLIENT_ID
string
Microsoft OAuth client ID
AUTH_MICROSOFT_CLIENT_SECRET
string
Microsoft OAuth client secret

Email Configuration

EMAIL_DRIVER
string
default:"smtp"
Email driver: smtp or logger (for testing)
EMAIL_SMTP_HOST
string
SMTP server hostname
EMAIL_SMTP_PORT
number
SMTP server port (typically 587 or 465)
EMAIL_FROM_ADDRESS
string
Sender email address

Common Operations

View Logs

# All services
docker compose logs -f

# Specific service
docker compose logs -f server
docker compose logs -f worker

Restart Services

# All services
docker compose restart

# Specific service
docker compose restart server

Update to Latest Version

# Pull latest image
docker compose pull

# Restart with new image
docker compose up -d

Run Database Migrations

Migrations run automatically on server start. To run manually:
docker compose exec server yarn database:migrate:prod

Access Database

docker compose exec db psql -U postgres default

Scale Workers

Increase worker instances for better performance:
docker compose up -d --scale worker=3

Production Recommendations

Use HTTPS

Always use TLS/SSL in production with a reverse proxy like Nginx or Traefik

Strong Secrets

Generate cryptographically secure secrets and credentials

Regular Backups

Automate database and file backups

Monitor Resources

Set up monitoring for CPU, memory, and disk usage

Reverse Proxy Example (Nginx)

server {
    listen 443 ssl;
    server_name crm.yourcompany.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.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;
    }
}

Troubleshooting

Check logs for errors:
docker compose logs server
Common issues:
  • Missing or invalid APP_SECRET
  • Database connection failed
  • Port 3000 already in use
Ensure the database is healthy:
docker compose ps db
docker compose logs db
The server waits for db:5432 to be ready before starting.
Check volume permissions:
docker compose exec server ls -la /app/packages/twenty-server/.local-storage
For S3 storage, verify credentials and bucket permissions.
Verify worker is running:
docker compose ps worker
docker compose logs worker
Check Redis connection:
docker compose exec redis redis-cli ping

Next Steps

Configuration

Configure your Twenty instance

Kubernetes

Deploy on Kubernetes

Troubleshooting

Common issues and solutions

API Keys

Set up API authentication

Build docs developers (and LLMs) love