Updated March 2026 8 Services Explained

Dify Docker Compose Setup Guide

Everything you need to know about Dify's Docker architecture — from what each container does to production-hardening your deployment with custom configurations.

Dify's Docker Architecture

Dify's docker-compose.yaml spins up eight services. Understanding what each does helps you configure, troubleshoot and scale your deployment.

nginx Reverse proxy / web server

Routes incoming HTTP requests to the correct internal service (web UI or API). This is the only container that needs to be publicly accessible.

~50 MB
api Dify API server

The core Python/Flask backend. Handles all business logic, LLM calls, RAG pipeline execution and REST API endpoints.

~300 MB
worker Celery background worker

Processes async tasks: document indexing, dataset imports, long-running LLM chains. Shares code with the API container.

~300 MB
web Next.js frontend

The React-based user interface served as a Next.js app. Communicates with the API container.

~150 MB
db PostgreSQL database

Stores all persistent data: apps, conversations, datasets metadata, users and API keys.

~100 MB
redis Cache & message broker

Caches frequent queries, stores Celery task queue for the worker, and handles rate-limiting data.

~30 MB
weaviate Vector database

Stores document embeddings for RAG knowledge bases. The heaviest memory consumer. Can be replaced with pgvector or Qdrant.

~500 MB
sandbox Code execution sandbox

Isolated container for running user-defined code nodes in Dify workflows. Runs with restricted permissions.

~100 MB

Total RAM baseline: ~1.5 GB just for idle containers. On a 4GB server, this leaves ~2.5 GB for the OS and actual workloads. For production, 8GB RAM is recommended.

Environment Variables Guide

All Dify configuration lives in dify/docker/.env. Copy from .env.example and customize these key settings:

Security (Required)

# Generate with: openssl rand -base64 42
SECRET_KEY=your-very-long-random-secret-key

# Encryption key for sensitive stored data
# Generate with: openssl rand -hex 16
ENCRYPT_IV=your-16-char-hex-value

Database Settings

# PostgreSQL settings (internal Docker network)
DB_USERNAME=postgres
DB_PASSWORD=change-this-strong-password
DB_HOST=db
DB_PORT=5432
DB_DATABASE=dify

# Redis settings
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=change-this-redis-password
REDIS_DB=0

URL & CORS Settings

# Your domain (no trailing slash)
CONSOLE_URL=https://your-domain.com
APP_URL=https://your-domain.com
SERVICE_API_URL=https://your-domain.com

# CORS origins (comma-separated)
CONSOLE_CORS_ALLOW_ORIGINS=https://your-domain.com
WEB_API_CORS_ALLOW_ORIGINS=https://your-domain.com

File Storage

# Default: local filesystem (stored in ./volumes/app/storage)
STORAGE_TYPE=local

# For S3-compatible storage (recommended for production)
# STORAGE_TYPE=s3
# S3_ENDPOINT=https://s3.amazonaws.com
# S3_BUCKET_NAME=my-dify-bucket
# S3_ACCESS_KEY=your-access-key
# S3_SECRET_KEY=your-secret-key
# S3_REGION=us-east-1

LLM API Keys (optional at setup)

# You can also configure these in the Dify web UI
# These .env settings pre-configure providers on first launch

OPENAI_API_KEY=sk-your-openai-key
ANTHROPIC_API_KEY=sk-ant-your-key
GOOGLE_API_KEY=your-gemini-key

# For Ollama (local LLMs)
# Configure in UI: Settings → Model Provider → Ollama

Custom Configurations

Custom Port Mapping

If port 80 is taken, change the host port Dify's Nginx binds to by editing .env:

# Change Nginx container's host port
EXPOSE_NGINX_PORT=8080
EXPOSE_NGINX_SSL_PORT=8443

Disable Weaviate (use pgvector instead)

Weaviate uses ~500MB RAM. On low-memory servers, switch to pgvector (already available in the PostgreSQL container):

# In .env — switch vector store to pgvector
VECTOR_STORE=pgvector

# Then restart without Weaviate
docker compose up -d --scale weaviate=0

Enable GPU Support

To pass through an NVIDIA GPU (for local embedding models), add the GPU runtime to your docker-compose.override.yaml:

services:
  api:
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]

See the GPU hosting guide for full setup instructions.

Common Commands

Start all services docker compose up -d
Stop all services docker compose down
Restart a single service docker compose restart api
View logs (follow) docker compose logs -f api worker
Open shell in API container docker compose exec api bash
Check container health docker compose ps
Resource usage per container docker stats
Remove stopped containers docker compose down --remove-orphans
Pull latest images docker compose pull
Rebuild a service docker compose up -d --build api

Troubleshooting

Container keeps restarting / CrashLoopBackOff

Check logs: docker compose logs api. Usually caused by wrong SECRET_KEY format or a missing required environment variable. Ensure SECRET_KEY is at least 32 characters.

Out of memory — containers killed by OOM killer

Add swap space and/or upgrade to a larger server. Run dmesg | grep -i "killed process" to confirm OOM kills. The weaviate container is usually the culprit — consider switching to pgvector.

Database connection errors

Ensure the DB container is healthy before the API starts: docker compose ps db. The API has a depends_on with health check, but on slow servers the DB may not finish initializing in time. Try docker compose restart api.

Permission denied errors on ./volumes

The storage volume directory needs correct permissions. Run: sudo chown -R 1000:1000 ./volumes from the dify/docker directory.

Production Hardening

Before going live, apply these security measures:

1. Change all default passwords

Set strong unique values for DB_PASSWORD, REDIS_PASSWORD, and especially SECRET_KEY. Never use the .env.example defaults in production.

2. Secure your .env file

chmod 600 dify/docker/.env
# Never commit .env to version control

3. Enable automated backups

Add to crontab (crontab -e):

0 3 * * * cd ~/dify/docker && docker compose exec -T db pg_dump -U postgres dify > ~/backups/dify_$(date +\%Y\%m\%d).sql

4. Use S3 for file storage

Switch STORAGE_TYPE=s3 so uploaded documents are stored separately from your server and survive container rebuilds.