Django Production Stack
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-alpine4 environment: 5 - POSTGRES_USER=django6 - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}7 - POSTGRES_DB=django_app8 volumes: 9 - postgres_data:/var/lib/postgresql/data10 networks: 11 - django_net1213 redis: 14 image: redis:7-alpine15 volumes: 16 - redis_data:/data17 networks: 18 - django_net1920 django: 21 build: 22 context: .23 dockerfile: Dockerfile24 command: gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 425 environment: 26 - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app27 - REDIS_URL=redis://redis:6379/028 - SECRET_KEY=${DJANGO_SECRET_KEY}29 - DEBUG=false30 - ALLOWED_HOSTS=localhost,127.0.0.131 volumes: 32 - static_files:/app/staticfiles33 - media_files:/app/media34 depends_on: 35 - postgres36 - redis37 networks: 38 - django_net3940 celery-worker: 41 build: 42 context: .43 dockerfile: Dockerfile44 command: celery -A config worker -l info45 environment: 46 - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app47 - REDIS_URL=redis://redis:6379/048 - SECRET_KEY=${DJANGO_SECRET_KEY}49 depends_on: 50 - postgres51 - redis52 networks: 53 - django_net5455 celery-beat: 56 build: 57 context: .58 dockerfile: Dockerfile59 command: celery -A config beat -l info60 environment: 61 - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app62 - REDIS_URL=redis://redis:6379/063 - SECRET_KEY=${DJANGO_SECRET_KEY}64 depends_on: 65 - postgres66 - redis67 networks: 68 - django_net6970 nginx: 71 image: nginx:alpine72 ports: 73 - "80:80"74 - "443:443"75 volumes: 76 - ./nginx.conf:/etc/nginx/nginx.conf:ro77 - static_files:/app/staticfiles:ro78 - media_files:/app/media:ro79 depends_on: 80 - django81 networks: 82 - django_net8384 flower: 85 build: 86 context: .87 dockerfile: Dockerfile88 command: celery -A config flower --port=555589 ports: 90 - "5555:5555"91 environment: 92 - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app93 - REDIS_URL=redis://redis:6379/094 - SECRET_KEY=${DJANGO_SECRET_KEY}95 depends_on: 96 - celery-worker97 networks: 98 - django_net99100volumes: 101 postgres_data: 102 redis_data: 103 static_files: 104 media_files: 105106networks: 107 django_net: .env Template
.env
1# Django Production2POSTGRES_PASSWORD=secure_postgres_password3DJANGO_SECRET_KEY=your_very_long_secret_key_here45# Django at http://localhost6# Flower at http://localhost:5555Usage Notes
- 1Django at http://localhost
- 2Flower (Celery monitor) at http://localhost:5555
- 3Run migrations before start
- 4Collect static files
- 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 file2cat > docker-compose.yml << 'EOF'3services:4 postgres:5 image: postgres:15-alpine6 environment:7 - POSTGRES_USER=django8 - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}9 - POSTGRES_DB=django_app10 volumes:11 - postgres_data:/var/lib/postgresql/data12 networks:13 - django_net1415 redis:16 image: redis:7-alpine17 volumes:18 - redis_data:/data19 networks:20 - django_net2122 django:23 build:24 context: .25 dockerfile: Dockerfile26 command: gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 427 environment:28 - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app29 - REDIS_URL=redis://redis:6379/030 - SECRET_KEY=${DJANGO_SECRET_KEY}31 - DEBUG=false32 - ALLOWED_HOSTS=localhost,127.0.0.133 volumes:34 - static_files:/app/staticfiles35 - media_files:/app/media36 depends_on:37 - postgres38 - redis39 networks:40 - django_net4142 celery-worker:43 build:44 context: .45 dockerfile: Dockerfile46 command: celery -A config worker -l info47 environment:48 - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app49 - REDIS_URL=redis://redis:6379/050 - SECRET_KEY=${DJANGO_SECRET_KEY}51 depends_on:52 - postgres53 - redis54 networks:55 - django_net5657 celery-beat:58 build:59 context: .60 dockerfile: Dockerfile61 command: celery -A config beat -l info62 environment:63 - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app64 - REDIS_URL=redis://redis:6379/065 - SECRET_KEY=${DJANGO_SECRET_KEY}66 depends_on:67 - postgres68 - redis69 networks:70 - django_net7172 nginx:73 image: nginx:alpine74 ports:75 - "80:80"76 - "443:443"77 volumes:78 - ./nginx.conf:/etc/nginx/nginx.conf:ro79 - static_files:/app/staticfiles:ro80 - media_files:/app/media:ro81 depends_on:82 - django83 networks:84 - django_net8586 flower:87 build:88 context: .89 dockerfile: Dockerfile90 command: celery -A config flower --port=555591 ports:92 - "5555:5555"93 environment:94 - DATABASE_URL=postgres://django:${POSTGRES_PASSWORD}@postgres:5432/django_app95 - REDIS_URL=redis://redis:6379/096 - SECRET_KEY=${DJANGO_SECRET_KEY}97 depends_on:98 - celery-worker99 networks:100 - django_net101102volumes:103 postgres_data:104 redis_data:105 static_files:106 media_files:107108networks:109 django_net:110EOF111112# 2. Create the .env file113cat > .env << 'EOF'114# Django Production115POSTGRES_PASSWORD=secure_postgres_password116DJANGO_SECRET_KEY=your_very_long_secret_key_here117118# Django at http://localhost119# Flower at http://localhost:5555120EOF121122# 3. Start the services123docker compose up -d124125# 4. View logs126docker compose logs -fOne-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 | bashTroubleshooting
- 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
Components
djangogunicorncelerypostgresqlredisnginx
Tags
#django#python#gunicorn#celery#production
Category
Full Web StacksAd Space
Shortcuts: C CopyF FavoriteD Download