Run Django With Hypercorn
Run Django in production with Hypercorn, an ASGI and WSGI server with HTTP/2 and HTTP/3 support: configure workers and worker class, bind behind Nginx, set timeouts and graceful shutdown, and compare it with Uvicorn and Gunicorn.
Problem statement
Hypercorn is an ASGI server (it also serves WSGI apps) that supports HTTP/1.1, HTTP/2, WebSockets, and HTTP/3, with asyncio or Trio. Django teams consider it when they want HTTP/2 directly from the app server, Trio support, or an alternative to Uvicorn for async views and Channels. Running it in production needs the same care as any app server: the right worker model, binding behind a reverse proxy, process supervision, and graceful shutdown.
pip install hypercornand serve the ASGI app:hypercorn config.asgi:application --bind unix:/run/hypercorn/app.sock --workers 3.- Use the default
asyncioworker class (oruvloopfor speed); usetrioonly if your code uses Trio. - Put Nginx in front for TLS, static files, and buffering; proxy to the socket.
- Configure with a TOML file for repeatability (
--config hypercorn.toml). - Run under systemd with
Restart=on-failureand a stop timeout abovegraceful_timeout. - Serve WSGI instead with
config.wsgi:applicationif you have no async code.
Step-by-step solution
1. Install and test
pip install "hypercorn[uvloop]"
hypercorn config.asgi:application --bind 127.0.0.1:8000
Your config/asgi.py is the standard get_asgi_application() (or a Channels ProtocolTypeRouter). Sync views work under ASGI; Django runs them in a thread pool.
2. Configure with TOML
# /srv/app/hypercorn.toml
bind = ["unix:/run/hypercorn/app.sock"]
workers = 3
worker_class = "uvloop"
keep_alive_timeout = 75
graceful_timeout = 30
accesslog = "-"
errorlog = "-"
umask = 0o007
workers are separate processes; each runs an event loop. Start with roughly the number of CPU cores and adjust based on memory and load. Each worker handles many concurrent connections, so async views and WebSockets scale within a worker.
3. Supervise with systemd
# /etc/systemd/system/hypercorn.service
[Unit]
Description=Django via Hypercorn
After=network.target
[Service]
User=deploy
Group=www-data
WorkingDirectory=/srv/app
EnvironmentFile=/etc/myapp/env
RuntimeDirectory=hypercorn
ExecStart=/srv/app/.venv/bin/hypercorn --config /srv/app/hypercorn.toml config.asgi:application
Restart=on-failure
TimeoutStopSec=40
KillSignal=SIGTERM
[Install]
WantedBy=multi-user.target
TimeoutStopSec above graceful_timeout lets in-flight requests finish during restarts.
4. Put Nginx in front
upstream hypercorn { server unix:/run/hypercorn/app.sock; }
server {
listen 443 ssl;
http2 on;
server_name example.com;
location /static/ { alias /srv/app/staticfiles/; }
location / {
proxy_pass http://hypercorn;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
Nginx provides HTTP/2 to browsers and speaks HTTP/1.1 to Hypercorn, which is the usual and simplest setup. Hypercorn's own HTTP/2 and HTTP/3 support matters when it faces clients directly, which is uncommon in production.
5. Settings for the proxy
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
ALLOWED_HOSTS = ["example.com"]
Hypercorn can also apply forwarded headers itself; with Nginx overwriting them, Django's setting is enough.
Verification check: systemctl status hypercorn is active, curl -I https://example.com returns 200 over HTTP/2 from Nginx, and a WebSocket test (if you use Channels) connects through the proxy. Restart the service during a slow request and confirm it completes.
Explanation
Hypercorn implements the ASGI specification with protocol handling based on the h11, h2, and optional aioquic libraries, and supports both asyncio and Trio event loops. For Django, it plays the same role as Uvicorn: it turns network traffic into ASGI events and passes them to Django's ASGI handler. Performance is broadly similar for typical Django workloads, which are dominated by database and Python time rather than protocol parsing, so the choice usually comes down to features such as HTTP/2 and Trio.
Edge cases / notes
- Lifespan. Django does not implement ASGI lifespan events; Hypercorn handles this quietly, but log noise can occur on some versions.
- Static files through Hypercorn work with WhiteNoise but are better served by Nginx.
- WSGI apps run in a thread pool inside Hypercorn; Gunicorn is more battle-tested for pure WSGI.
- Max requests. Hypercorn has
max_requestswith jitter to recycle workers, useful for memory growth.
Next steps
- The most common ASGI choice: Deploy Django With Uvicorn and Nginx.
- A Rust-based alternative: Deploy Django With Granian.
FAQ
Is Hypercorn production-ready for Django?
Yes. It is a mature ASGI server; run it behind Nginx with systemd like any app server.
Hypercorn or Uvicorn for Django?
Uvicorn is more common. Choose Hypercorn for built-in HTTP/2 and HTTP/3 or Trio support.
Can Hypercorn serve WSGI Django?
Yes, by pointing it at config.wsgi:application. Gunicorn remains the more common WSGI choice.
Do I still need Nginx with Hypercorn?
Yes, for TLS, static files, buffering, and protection from slow clients.