---
title: Docker Deployment Guide
description: Complete guide to deploy Chatwoot using Docker containers for production environments.
sidebarTitle: Docker
---

Docker provides a consistent, portable way to deploy Chatwoot across different environments. This guide covers production deployment using Docker Compose with best practices for security, performance, and maintenance.

## Prerequisites

Before starting, ensure you have:

- Docker 20.10+ installed
- Docker Compose 2.0+ installed
- At least 4GB RAM and 2 CPU cores
- Domain name with DNS configured (recommended)
- Basic understanding of Docker concepts

### Version Check

Verify your Docker installation:

```bash
$ docker --version
Docker version 25.0.4, build 1a576c5

$ docker compose version
Docker Compose version v2.24.7
```

<Note>
Container names use dashes instead of underscores by default with newer Docker Compose versions. If using an older version, replace `-` with `_` and use `docker-compose` instead of `docker compose`.
</Note>

## Quick Start

### 1. Install Docker

**Ubuntu/Debian:**
```bash
# Update package index
apt-get update && apt-get upgrade -y

# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# Install Docker Compose plugin
apt install docker-compose-plugin

# Add user to docker group (optional)
sudo usermod -aG docker $USER
```

**CentOS/RHEL:**
```bash
# Install Docker
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin

# Start Docker service
sudo systemctl start docker
sudo systemctl enable docker
```

### 2. Download Configuration Files

```bash
# Create project directory
mkdir chatwoot && cd chatwoot

# Download environment template
wget -O .env https://raw.githubusercontent.com/chatwoot/chatwoot/develop/.env.example

# Download Docker Compose configuration
wget -O docker-compose.yaml https://raw.githubusercontent.com/chatwoot/chatwoot/develop/docker-compose.production.yaml
```

### 3. Configure Environment

Edit the `.env` file with your settings:

```bash
nano .env
```

**Essential configurations:**

```env
# Database Configuration
POSTGRES_PASSWORD=your_secure_postgres_password
REDIS_PASSWORD=your_secure_redis_password

# Application Configuration
SECRET_KEY_BASE=your_secret_key_base_64_chars_long
FRONTEND_URL=https://your-domain.com

# Email Configuration (required for notifications)
MAILER_SENDER_EMAIL=noreply@your-domain.com
SMTP_ADDRESS=smtp.your-provider.com
SMTP_PORT=587
SMTP_USERNAME=your-smtp-username
SMTP_PASSWORD=your-smtp-password
SMTP_AUTHENTICATION=plain
SMTP_ENABLE_STARTTLS_AUTO=true

# File Storage (optional - defaults to local)
ACTIVE_STORAGE_SERVICE=local
# For S3: ACTIVE_STORAGE_SERVICE=amazon
# AWS_ACCESS_KEY_ID=your_access_key
# AWS_SECRET_ACCESS_KEY=your_secret_key
# AWS_REGION=us-east-1
# AWS_BUCKET=your-bucket-name
```

### 4. Update Docker Compose

Edit `docker-compose.yaml` to match your `.env` passwords:

```yaml
services:
  postgres:
    environment:
      - POSTGRES_PASSWORD=your_secure_postgres_password  # Match .env

  redis:
    command: ["sh", "-c", "redis-server --requirepass your_secure_redis_password"]
```

### 5. Initialize Database

```bash
# Prepare the database
docker compose run --rm rails bundle exec rails db:chatwoot_prepare
```

### 6. Start Services

```bash
# Start all services in background
docker compose up -d

# Check service status
docker compose ps
```

### 7. Verify Installation

```bash
# Check if Chatwoot is responding
curl -I localhost:3000/api

# Should return: HTTP/1.1 200 OK
```

## Production Configuration

### Docker Compose Setup

Here's a complete production-ready `docker-compose.yaml`:

```yaml
version: '3.8'

services:
  base: &base
    image: chatwoot/chatwoot:latest
    env_file: .env
    volumes:
      - ./data/storage:/app/storage
    depends_on:
      - postgres
      - redis

  rails:
    <<: *base
    container_name: chatwoot-rails
    command: ["sh", "-c", "bundle exec rails s -b 0.0.0.0 -p 3000"]
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      - NODE_ENV=production
      - RAILS_ENV=production
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/api"]
      interval: 30s
      timeout: 10s
      retries: 3

  sidekiq:
    <<: *base
    container_name: chatwoot-sidekiq
    command: ["sh", "-c", "bundle exec sidekiq -C config/sidekiq.yml"]
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "pgrep", "-f", "sidekiq"]
      interval: 30s
      timeout: 10s
      retries: 3

  postgres:
    image: postgres:14-alpine
    container_name: chatwoot-postgres
    restart: unless-stopped
    ports:
      - "127.0.0.1:5432:5432"
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=chatwoot
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=your_secure_postgres_password
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 30s
      timeout: 10s
      retries: 3

  redis:
    image: redis:7-alpine
    container_name: chatwoot-redis
    restart: unless-stopped
    command: ["sh", "-c", "redis-server --requirepass your_secure_redis_password"]
    ports:
      - "127.0.0.1:6379:6379"
    volumes:
      - ./data/redis:/data
    healthcheck:
      test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
      interval: 30s
      timeout: 10s
      retries: 3

volumes:
  postgres_data:
  redis_data:
  storage_data:
```

### Nginx Reverse Proxy

Create `/etc/nginx/sites-available/chatwoot.conf`:

```nginx
server {
    server_name your-domain.com;
    
    # Point upstream to Chatwoot App Server
    set $upstream 127.0.0.1:3000;
    
    # Nginx strips out underscore in headers by default
    # Chatwoot relies on underscore in headers for API
    underscores_in_headers on;
    
    # Increase client max body size for file uploads
    client_max_body_size 50M;
    
    location /.well-known {
        alias /var/www/ssl-proof/chatwoot/.well-known;
    }
    
    location / {
        proxy_pass_header Authorization;
        proxy_pass http://$upstream;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Ssl on;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        proxy_http_version 1.1;
        proxy_buffering off;
        proxy_read_timeout 36000s;
        proxy_redirect off;
    }
    
    listen 80;
}
```

Enable the site and configure SSL:

```bash
# Enable site
sudo ln -s /etc/nginx/sites-available/chatwoot.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

# Install Certbot and get SSL certificate
sudo apt install certbot python3-certbot-nginx
sudo mkdir -p /var/www/ssl-proof/chatwoot/.well-known
sudo certbot --webroot -w /var/www/ssl-proof/chatwoot/ -d your-domain.com -i nginx
```

## Advanced Configuration

### Environment Variables

Key environment variables for production:

```env
# Application
RAILS_ENV=production
NODE_ENV=production
SECRET_KEY_BASE=generate_64_character_secret
FRONTEND_URL=https://your-domain.com

# Database
DATABASE_URL=postgresql://postgres:password@postgres:5432/chatwoot
REDIS_URL=redis://redis:6379/0
REDIS_PASSWORD=your_redis_password

# Email
MAILER_SENDER_EMAIL=noreply@your-domain.com
SMTP_ADDRESS=smtp.your-provider.com
SMTP_PORT=587
SMTP_USERNAME=your_username
SMTP_PASSWORD=your_password
SMTP_AUTHENTICATION=plain
SMTP_ENABLE_STARTTLS_AUTO=true

# File Storage
ACTIVE_STORAGE_SERVICE=amazon
AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_key
AWS_REGION=us-east-1
AWS_BUCKET=your-bucket-name

# Security
FORCE_SSL=true
RAILS_LOG_TO_STDOUT=true

# Performance
RAILS_MAX_THREADS=5
WEB_CONCURRENCY=2
```

### Resource Limits

Add resource limits to your `docker-compose.yaml`:

```yaml
services:
  rails:
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 2G
        reservations:
          cpus: '1.0'
          memory: 1G

  sidekiq:
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 1G
        reservations:
          cpus: '0.5'
          memory: 512M

  postgres:
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 1G
        reservations:
          cpus: '0.5'
          memory: 512M

  redis:
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M
```

### Logging Configuration

Configure centralized logging:

```yaml
services:
  rails:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

  sidekiq:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
```

## Maintenance Operations

### Upgrading Chatwoot

```bash
# Pull latest images
docker compose pull

# Stop services
docker compose down

# Start with new images
docker compose up -d

# Run database migrations
docker compose run --rm rails bundle exec rails db:chatwoot_prepare
```

### Backup and Restore

**Database Backup:**
```bash
# Create backup
docker compose exec postgres pg_dump -U postgres chatwoot > backup_$(date +%Y%m%d_%H%M%S).sql

# Restore backup
docker compose exec -T postgres psql -U postgres chatwoot < backup_file.sql
```

**File Storage Backup:**
```bash
# Backup storage directory
tar -czf storage_backup_$(date +%Y%m%d_%H%M%S).tar.gz ./data/storage/
```

### Monitoring and Logs

**View logs:**
```bash
# All services
docker compose logs -f

# Specific service
docker compose logs -f rails
docker compose logs -f sidekiq

# Last 100 lines
docker compose logs --tail=100 rails
```

**Monitor resources:**
```bash
# Container stats
docker stats

# Service health
docker compose ps
```

### Rails Console Access

```bash
# Access Rails console
docker compose exec rails bundle exec rails console

# Run one-off commands
docker compose run --rm rails bundle exec rails runner "puts User.count"
```

## Troubleshooting

### Common Issues

**1. Permission Issues:**
```bash
# Fix file permissions
sudo chown -R 1000:1000 ./data/
```

**2. Database Connection Issues:**
```bash
# Check database connectivity
docker compose exec rails bundle exec rails db:version
```

**3. Memory Issues:**
```bash
# Check memory usage
docker stats --no-stream
```

**4. SSL Certificate Issues:**
```bash
# Renew certificates
sudo certbot renew --dry-run
```

### Performance Optimization

**1. Database Optimization:**
```sql
-- Connect to database
docker compose exec postgres psql -U postgres chatwoot

-- Check slow queries
SELECT query, mean_time, calls 
FROM pg_stat_statements 
ORDER BY mean_time DESC 
LIMIT 10;
```

**2. Redis Optimization:**
```bash
# Check Redis memory usage
docker compose exec redis redis-cli info memory
```

### Security Hardening

**1. Network Security:**
```yaml
# Add to docker-compose.yaml
networks:
  chatwoot:
    driver: bridge
    internal: true

services:
  rails:
    networks:
      - chatwoot
      - default  # Only rails needs external access
```

**2. Secrets Management:**
```bash
# Use Docker secrets for sensitive data
echo "your_secret_password" | docker secret create postgres_password -
```

## Community Edition vs Enterprise

This guide covers Chatwoot Community Edition (CE). For Enterprise features:

**CE Docker Tags:**
- `chatwoot/chatwoot:latest-ce` (latest CE)
- `chatwoot/chatwoot:v2.3.2-ce` (specific version CE)

**Enterprise Features:**
- Advanced reporting and analytics
- SAML SSO integration
- Advanced automation rules
- Priority support

---

<Warning>
Always test upgrades in a staging environment before applying to production. Keep regular backups of your database and file storage.
</Warning>

<Note>
For high-availability deployments, consider using Docker Swarm or Kubernetes instead of Docker Compose.
</Note> 