Daphne and/or Gunicorn: ASGI, HTTP/2, WebSockets

2021-07-30 2 min read

Gunicorn is a WSGI HTTP server for Python applications. It can serve your dynamic Python application with the help of a reverse-proxy program like Nginx.

Daphne is like Gunicorn but for ASGI. It also supports the HTTP/2.0 and WebSocket protocols in addition to Gunicorn.

Which one should be preferred, and when?

Imagine you are going to write a Django chat app. You would have to use WebSocket for a real-time and non-polling chat app. Gunicorn cannot do this alone. You can still serve your Django application with Gunicorn, but you should at least use Daphne to handle requests sent over the WebSocket protocol and a reverse-proxy like Nginx to send those requests to the Daphne service. For example, you can redirect all the connections on the path /ws/ to your Daphne service, while redirecting the rest to Gunicorn.

Daphne vs Gunicorn

Although this comparison may seem like comparing apples and oranges at first glance, it's still important. That's because unlike Gunicorn, Daphne can also do what Gunicorn can, like handling traditional HTTP requests. This makes it possible to use only Daphne for any type of request in your, say, chat application. However, you might wonder if it's worth choosing Daphne while everyone else seems to be using Gunicorn for HTTP requests.

Daphne

+ Handles any type of requests like HTTP, HTTP/2, WebSocket
+ You don't have to reverse-proxy WebSocket requests by the path (like /ws/)
- No proven stability?
- No enough community support?

Gunicorn

+ Proven stability
+ Community support
- No support for HTTP/2, WebSocket
- You'll need a reverse-proxy + another server for unsupported request types

Using both at the same time

This is another solution. We can redirect incoming requests to appropriate services via Nginx. Below is an example Nginx configuration:

upstream server_http {
    server backend:8000;
}

upstream server_ws {
    server daphne:9001;
}

server {
    listen 80;
    # ...

    location / {
        proxy_pass http://server_http;
        # ...
    }

    location /ws/ {
        proxy_pass http://server_ws;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # ...
    }

    # ...
}

With this Nginx configuration, the connections to the /ws/ path will be redirected to the daphne service running on the port 9001, while the rest will be handled by the backend service, which could be a Gunicorn server running on the port 8000.

Date: 2021-07-30
Categories: developmentpython