A production Django deployment has several layers, each with a specific role. Here is the full stack I deploy for client projects and why each component is chosen.
The stack:
- Server: Ubuntu 24.04 LTS on DigitalOcean (EUR 6-24/month) or Hetzner (EUR 4-15/month). Hetzner offers significantly better price-to-performance for European projects. A 2 vCPU / 4GB RAM server handles most applications comfortably.
- Application server: Gunicorn — a Python WSGI HTTP server that runs your Django application. Configured with 2-4 workers per CPU core. Handles concurrent requests efficiently without the complexity of alternatives like uWSGI.
- Reverse proxy: Nginx sits in front of Gunicorn, handling SSL termination, static file serving, request buffering, and basic rate limiting. Nginx serves static files 10-50x faster than Django and protects Gunicorn from slow clients.
- Database: PostgreSQL 16 — the standard for Django projects. Runs on the same server for small projects (up to 50,000 daily users) or as a managed service (DigitalOcean Managed Database, EUR 15/month) for projects that need automated backups and failover.
- Cache: Redis for session storage, Celery task queue, and application caching. Runs alongside the application on the same server. Memory usage is typically 50-200MB.
- Task queue: Celery with Redis broker for background tasks — sending emails, processing webhooks, generating reports, running scheduled jobs.
This stack is intentionally simple. Every component is well-documented, widely used, and easy to debug. I avoid over-engineering with Kubernetes or microservices unless the project genuinely requires horizontal scaling.