docker.recipes

Django Production Stack

advanced

Production Django with Gunicorn, Celery, PostgreSQL, and Redis.

Overview

Django is a high-level Python web framework that follows the "batteries included" philosophy, providing a robust foundation for building complex web applications. Originally developed at a newspaper company in 2003, Django emphasizes rapid development, clean pragmatic design, and the DRY (Don't Repeat Yourself) principle. Its built-in admin interface, ORM, authentication system, and security features have made it the framework of choice for content-heavy sites like Instagram, Pinterest, and The Washington Post. This production stack combines Django's web framework with Gunicorn as the WSGI server, providing better performance and stability than Django's development server. PostgreSQL serves as the primary database, offering ACID compliance and advanced querying capabilities that complement Django's ORM perfectly. Redis handles caching, session storage, and serves as Celery's message broker for background task processing. Celery workers and beat scheduler enable asynchronous task processing, while Nginx acts as a reverse proxy and static file server. Flower provides real-time monitoring of Celery tasks and workers. This configuration addresses the core challenges of production Django deployments: database performance, background task processing, static file serving, and horizontal scaling. The stack is ideal for content management systems, e-commerce platforms, and data-driven applications that require robust background processing capabilities. Startups scaling beyond development environments, established companies modernizing legacy systems, and teams building API-heavy applications will find this combination provides the reliability and performance needed for production workloads.

Key Features

  • Gunicorn multi-worker WSGI server with 4 default workers for handling concurrent requests efficiently
  • Celery distributed task queue with separate worker and beat scheduler containers for background job processing
  • PostgreSQL 15 with Alpine Linux providing ACID-compliant storage with advanced JSON and full-text search capabilities
  • Redis 7 serving dual roles as Django cache backend and Celery message broker with data persistence
  • Nginx reverse proxy with static file serving, eliminating Django's overhead for CSS, JavaScript, and media files
  • Flower web-based Celery monitoring dashboard accessible on port 5555 for real-time task inspection
  • Django collectstatic integration with shared volumes for efficient static asset management
  • Multi-container architecture enabling independent scaling of web workers, background workers, and database components

Common Use Cases

  • 1Content management systems requiring background image processing and email notifications
  • 2E-commerce platforms with inventory updates, order processing, and payment webhook handling
  • 3Social media applications needing user-generated content moderation and notification systems
  • 4Data analytics dashboards with scheduled report generation and CSV export functionality
  • 5API-driven applications serving mobile apps with caching and session management requirements
  • 6Multi-tenant SaaS platforms requiring database isolation and background tenant maintenance tasks
  • 7News and publishing websites with automated content aggregation and social media posting

Prerequisites

  • Minimum 2GB RAM for all services combined (PostgreSQL 1GB, Redis 512MB, Django containers 512MB total)
  • Docker Engine 20.10+ and Docker Compose V2 for proper networking and volume management
  • Basic understanding of Django settings.py configuration and environment variables
  • Familiarity with PostgreSQL connection strings and Redis URL formatting
  • Knowledge of Nginx configuration for custom SSL certificates and domain routing
  • Understanding of Celery task decorators and Django signal handlers for background processing

For development & testing. Review security settings, change default credentials, and test thoroughly before production use. See Terms

docker-compose.yml

docker-compose.yml
1services:
2 postgres:
3 image: postgres:15-alpine
4 environment:
5 - POSTGRES_USER=django
6 - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
7 - POSTGRES_DB=django_app
8 volumes:
9 - postgres_data:/var/lib/postgresql/data
10 networks:
11 - django_net
12
13 redis:
14 image: redis:7-alpine
15 volumes:
16 - redis_data:/data
17 networks:
18 - django_net
19
20 django:
21 build:
22 context: .
23 dockerfile: Dockerfile
24 command: gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 4
25 environment:
26 - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app
27 - REDIS_URL=redis://redis:6379/0
28 - SECRET_KEY=${DJANGO_SECRET_KEY}
29 - DEBUG=false
30 - ALLOWED_HOSTS=localhost,127.0.0.1
31 volumes:
32 - static_files:/app/staticfiles
33 - media_files:/app/media
34 depends_on:
35 - postgres
36 - redis
37 networks:
38 - django_net
39
40 celery-worker:
41 build:
42 context: .
43 dockerfile: Dockerfile
44 command: celery -A config worker -l info
45 environment:
46 - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app
47 - REDIS_URL=redis://redis:6379/0
48 - SECRET_KEY=${DJANGO_SECRET_KEY}
49 depends_on:
50 - postgres
51 - redis
52 networks:
53 - django_net
54
55 celery-beat:
56 build:
57 context: .
58 dockerfile: Dockerfile
59 command: celery -A config beat -l info
60 environment:
61 - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app
62 - REDIS_URL=redis://redis:6379/0
63 - SECRET_KEY=${DJANGO_SECRET_KEY}
64 depends_on:
65 - postgres
66 - redis
67 networks:
68 - django_net
69
70 nginx:
71 image: nginx:alpine
72 ports:
73 - "80:80"
74 - "443:443"
75 volumes:
76 - ./nginx.conf:/etc/nginx/nginx.conf:ro
77 - static_files:/app/staticfiles:ro
78 - media_files:/app/media:ro
79 depends_on:
80 - django
81 networks:
82 - django_net
83
84 flower:
85 build:
86 context: .
87 dockerfile: Dockerfile
88 command: celery -A config flower --port=5555
89 ports:
90 - "5555:5555"
91 environment:
92 - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app
93 - REDIS_URL=redis://redis:6379/0
94 - SECRET_KEY=${DJANGO_SECRET_KEY}
95 depends_on:
96 - celery-worker
97 networks:
98 - django_net
99
100volumes:
101 postgres_data:
102 redis_data:
103 static_files:
104 media_files:
105
106networks:
107 django_net:

.env Template

.env
1# Django Production
2POSTGRES_PASSWORD=secure_postgres_password
3DJANGO_SECRET_KEY=your_very_long_secret_key_here
4
5# Django at http://localhost
6# Flower at http://localhost:5555

Usage Notes

  1. 1Django at http://localhost
  2. 2Flower (Celery monitor) at http://localhost:5555
  3. 3Run migrations before start
  4. 4Collect static files
  5. 54 Gunicorn workers default

Individual Services(7 services)

Copy individual services to mix and match with your existing compose files.

postgres
postgres:
  image: postgres:15-alpine
  environment:
    - POSTGRES_USER=django
    - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    - POSTGRES_DB=django_app
  volumes:
    - postgres_data:/var/lib/postgresql/data
  networks:
    - django_net
redis
redis:
  image: redis:7-alpine
  volumes:
    - redis_data:/data
  networks:
    - django_net
django
django:
  build:
    context: .
    dockerfile: Dockerfile
  command: gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 4
  environment:
    - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app
    - REDIS_URL=redis://redis:6379/0
    - SECRET_KEY=${DJANGO_SECRET_KEY}
    - DEBUG=false
    - ALLOWED_HOSTS=localhost,127.0.0.1
  volumes:
    - static_files:/app/staticfiles
    - media_files:/app/media
  depends_on:
    - postgres
    - redis
  networks:
    - django_net
celery-worker
celery-worker:
  build:
    context: .
    dockerfile: Dockerfile
  command: celery -A config worker -l info
  environment:
    - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app
    - REDIS_URL=redis://redis:6379/0
    - SECRET_KEY=${DJANGO_SECRET_KEY}
  depends_on:
    - postgres
    - redis
  networks:
    - django_net
celery-beat
celery-beat:
  build:
    context: .
    dockerfile: Dockerfile
  command: celery -A config beat -l info
  environment:
    - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app
    - REDIS_URL=redis://redis:6379/0
    - SECRET_KEY=${DJANGO_SECRET_KEY}
  depends_on:
    - postgres
    - redis
  networks:
    - django_net
nginx
nginx:
  image: nginx:alpine
  ports:
    - "80:80"
    - "443:443"
  volumes:
    - ./nginx.conf:/etc/nginx/nginx.conf:ro
    - static_files:/app/staticfiles:ro
    - media_files:/app/media:ro
  depends_on:
    - django
  networks:
    - django_net
flower
flower:
  build:
    context: .
    dockerfile: Dockerfile
  command: celery -A config flower --port=5555
  ports:
    - "5555:5555"
  environment:
    - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app
    - REDIS_URL=redis://redis:6379/0
    - SECRET_KEY=${DJANGO_SECRET_KEY}
  depends_on:
    - celery-worker
  networks:
    - django_net

Quick Start

terminal
1# 1. Create the compose file
2cat > docker-compose.yml << 'EOF'
3services:
4 postgres:
5 image: postgres:15-alpine
6 environment:
7 - POSTGRES_USER=django
8 - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
9 - POSTGRES_DB=django_app
10 volumes:
11 - postgres_data:/var/lib/postgresql/data
12 networks:
13 - django_net
14
15 redis:
16 image: redis:7-alpine
17 volumes:
18 - redis_data:/data
19 networks:
20 - django_net
21
22 django:
23 build:
24 context: .
25 dockerfile: Dockerfile
26 command: gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 4
27 environment:
28 - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app
29 - REDIS_URL=redis://redis:6379/0
30 - SECRET_KEY=${DJANGO_SECRET_KEY}
31 - DEBUG=false
32 - ALLOWED_HOSTS=localhost,127.0.0.1
33 volumes:
34 - static_files:/app/staticfiles
35 - media_files:/app/media
36 depends_on:
37 - postgres
38 - redis
39 networks:
40 - django_net
41
42 celery-worker:
43 build:
44 context: .
45 dockerfile: Dockerfile
46 command: celery -A config worker -l info
47 environment:
48 - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app
49 - REDIS_URL=redis://redis:6379/0
50 - SECRET_KEY=${DJANGO_SECRET_KEY}
51 depends_on:
52 - postgres
53 - redis
54 networks:
55 - django_net
56
57 celery-beat:
58 build:
59 context: .
60 dockerfile: Dockerfile
61 command: celery -A config beat -l info
62 environment:
63 - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app
64 - REDIS_URL=redis://redis:6379/0
65 - SECRET_KEY=${DJANGO_SECRET_KEY}
66 depends_on:
67 - postgres
68 - redis
69 networks:
70 - django_net
71
72 nginx:
73 image: nginx:alpine
74 ports:
75 - "80:80"
76 - "443:443"
77 volumes:
78 - ./nginx.conf:/etc/nginx/nginx.conf:ro
79 - static_files:/app/staticfiles:ro
80 - media_files:/app/media:ro
81 depends_on:
82 - django
83 networks:
84 - django_net
85
86 flower:
87 build:
88 context: .
89 dockerfile: Dockerfile
90 command: celery -A config flower --port=5555
91 ports:
92 - "5555:5555"
93 environment:
94 - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app
95 - REDIS_URL=redis://redis:6379/0
96 - SECRET_KEY=${DJANGO_SECRET_KEY}
97 depends_on:
98 - celery-worker
99 networks:
100 - django_net
101
102volumes:
103 postgres_data:
104 redis_data:
105 static_files:
106 media_files:
107
108networks:
109 django_net:
110EOF
111
112# 2. Create the .env file
113cat > .env << 'EOF'
114# Django Production
115POSTGRES_PASSWORD=secure_postgres_password
116DJANGO_SECRET_KEY=your_very_long_secret_key_here
117
118# Django at http://localhost
119# Flower at http://localhost:5555
120EOF
121
122# 3. Start the services
123docker compose up -d
124
125# 4. View logs
126docker compose logs -f

One-Liner

Run this command to download and set up the recipe in one step:

terminal
1curl -fsSL https://docker.recipes/api/recipes/django-production/run | bash

Troubleshooting

  • django.db.utils.OperationalError: FATAL: password authentication failed: Verify POSTGRES_PASSWORD environment variable matches in all Django containers
  • Celery workers not processing tasks: Check Redis connectivity and ensure REDIS_URL points to redis:6379, not localhost
  • Static files not loading (404 errors): Run docker-compose exec django python manage.py collectstatic before starting nginx service
  • Gunicorn timeout errors under load: Increase worker count in command or add --timeout 120 flag for long-running requests
  • PostgreSQL container fails to start: Remove postgres_data volume if changing POSTGRES_USER or database initialization parameters
  • Flower dashboard showing no workers: Ensure celery-worker container is running and Redis connection is established before starting Flower

Community Notes

Loading...
Loading notes...

Download Recipe Kit

Get all files in a ready-to-deploy package

Includes docker-compose.yml, .env template, README, and license

Ad Space