Nginx and Gunicorn are the standard way to serve Django in production — and "standard" hides a dozen small decisions that separate a fast, stable deployment from one that times out under load. Our Django Nginx deployment in Uttarakhand is the stack engagement: the reverse proxy, the application server, and everything between your code and your users, configured deliberately and documented.
This page is about the stack itself — what each layer does, the configuration choices that matter, and how zero-downtime deploys work on it. Delivered remotely across Uttarakhand, with screen-shared working sessions throughout.
What each layer does
| Layer | Its job | What goes wrong when it's misconfigured |
|---|---|---|
| Nginx | Faces the internet: terminates TLS, serves static files and media directly, rate-limits abusive traffic, and proxies application requests back to Gunicorn | Slow clients tie up application workers; static files served slowly; no protection against login hammering |
| Gunicorn | Runs your Django code in worker processes, with timeouts and graceful restarts | Too few workers queue requests under load; too many exhaust memory; long requests get killed mid-work |
| systemd | Supervises Gunicorn: starts it on boot, restarts it on failure, captures logs | A reboot or a crashed worker means downtime until someone notices and intervenes manually |
| PostgreSQL | Holds your data with proper backup and restore discipline | Data loss or corruption when backups exist only as untested configuration |
The configuration checklist we apply
- Worker count matched to the server — starting from the conventional rule of thumb (roughly twice the CPU cores plus one), then tuned to your workload's actual memory and request profile. The number is derived, not copied.
- Timeouts set for your longest legitimate requests — reports and imports get the time they need; hung requests get killed instead of accumulating.
- Static files served by Nginx, never Django — Django's development server has no business serving files in production.
- Media uploads stored with backup in mind — outside the application directory, on a path that's part of the backup routine.
- Security headers set at the proxy — the straightforward set, configured once for every site.
- Rate limiting on login and admin endpoints — cheap protection against credential-stuffing noise.
- SSL with automatic renewal — certificates that renew themselves, monitored so expiry can't surprise you.
- Log rotation configured — because an unmanaged log filling the disk is one of the more embarrassing ways to take down a server.
Zero-downtime deploys on this stack
Deploying Django without dropping requests follows a discipline, not a trick. Database migrations run first and are kept backwards-compatible — the old code must keep working against the new schema until the new code is live. Then the new code deploys, static files are collected, and Gunicorn workers restart gracefully: each worker finishes its in-flight requests before picking up the new code. Health checks confirm the new workers are serving before the deploy is considered done. We rehearse this full sequence on staging — the first time it runs shouldn't be on your production traffic.
Delivered remotely, across Uttarakhand
The engagement runs on screen-shared working sessions: configuration built live where you can watch and question, staging validation you can click through, and a scheduled cutover window with rollback ready. The annotated configurations stay with you — every non-obvious setting carries a comment explaining why it's set that way, so the stack remains understandable months later.
When this stack isn't right
Real-time features — WebSockets, live updates, persistent connections — don't belong on Gunicorn's synchronous workers; that workload calls for an ASGI server, and we'll say so rather than force-fit. A single tiny brochure-style site doesn't need this stack either — simpler hosting is the economical answer. And if the Django application itself still needs building, the Django development decision comes before deployment.
Frequently asked questions
Why put Nginx in front of Gunicorn — can't Gunicorn serve directly?
Technically it can, but it shouldn't face the internet. Nginx handles TLS efficiently, serves static files without bothering your Python workers, buffers slow clients so workers aren't tied up waiting on bad connections, and absorbs abusive traffic patterns. Gunicorn does one job — running your Django code — and Nginx lets it do that job well. It's a division of labour, not redundancy.
How many Gunicorn workers do we actually need?
It depends on your server's CPUs, your workers' memory footprint, and what your requests do. The conventional starting point is roughly twice the CPU cores plus one, but that's a starting point — memory-hungry workers or long-running requests change the math. We derive the number from your workload during the engagement and document the reasoning, so it's a decision rather than a copied default.
What about WebSockets or real-time features?
Gunicorn's standard synchronous workers aren't the right tool for persistent connections — each held connection occupies a worker. For genuinely real-time needs, the answer is an ASGI server, which is a different stack decision we'll advise on plainly. For the occasional "live-ish" requirement, there are often simpler patterns (polling, server-sent events) that work fine on this stack without re-architecting.
Do you handle DNS and SSL?
Yes. We plan the DNS cutover with you — including TTL lowering ahead of the move so the switch propagates quickly — and set up certificates with automatic renewal plus monitoring. Certificate expiry taking down a site is an entirely preventable failure, and we treat it as such.
Can this stack run multiple Django sites on one server?
Yes. Nginx routes each domain to its own Gunicorn service via separate server blocks, and each application runs as an isolated service under systemd with its own workers, logs, and resource boundaries. One site's traffic spike or misbehaving deploy doesn't take down the others. The per-site isolation is part of the configuration, not an afterthought.
Scope the stack for your application
Tell us about the Django application and its traffic — we'll map the Nginx + Gunicorn configuration it needs, including where we'd advise a different approach. Contact us to start. For the Dehradun business engagement, see Django deployment in Dehradun; for the serving-layer specialty, Nginx and Gunicorn deployment; for health checks after go-live, server monitoring setup.