docs: Add ASGI worker and uWSGI protocol documentation

This commit is contained in:
Benoit Chesneau 2026-01-22 22:11:55 +01:00
parent 19a2efec63
commit 0a697cde7f
3 changed files with 509 additions and 0 deletions

241
docs/content/asgi.md Normal file
View File

@ -0,0 +1,241 @@
# ASGI Worker
!!! warning "Beta Feature"
The ASGI worker is a beta feature introduced in Gunicorn 24.0.0. While it has been tested,
the API and behavior may change in future releases. Please report any issues on
[GitHub](https://github.com/benoitc/gunicorn/issues).
Gunicorn includes a native ASGI worker that enables running async Python web frameworks
like FastAPI, Starlette, and Quart without external dependencies like Uvicorn.
## Quick Start
```bash
# Install gunicorn
pip install gunicorn
# Run an ASGI application
gunicorn myapp:app --worker-class asgi --workers 4
```
For FastAPI applications:
```bash
gunicorn main:app --worker-class asgi --bind 0.0.0.0:8000
```
## Features
The ASGI worker provides:
- **HTTP/1.1** with keepalive connections
- **WebSocket** support for real-time applications
- **Lifespan protocol** for startup/shutdown hooks
- **Optional uvloop** for improved performance
- **SSL/TLS** support
## Configuration
### Worker Class
Set the worker class to `asgi`:
```bash
gunicorn myapp:app --worker-class asgi
```
Or in a configuration file:
```python
# gunicorn.conf.py
worker_class = "asgi"
```
### Event Loop
Control which asyncio event loop implementation to use:
| Value | Description |
|----------|-------------|
| `auto` | Use uvloop if available, otherwise asyncio (default) |
| `asyncio`| Use Python's built-in asyncio event loop |
| `uvloop` | Use uvloop (must be installed separately) |
```bash
gunicorn myapp:app --worker-class asgi --asgi-loop uvloop
```
To use uvloop, install it first:
```bash
pip install uvloop
```
### Lifespan Protocol
The lifespan protocol lets your application run code at startup and shutdown.
This is essential for frameworks that need to initialize database connections,
caches, or background tasks.
| Value | Description |
|--------|-------------|
| `auto` | Detect if app supports lifespan, enable if so (default) |
| `on` | Always run lifespan protocol (fail if unsupported) |
| `off` | Never run lifespan protocol |
```bash
gunicorn myapp:app --worker-class asgi --asgi-lifespan on
```
Example FastAPI application using lifespan:
```python
from contextlib import asynccontextmanager
from fastapi import FastAPI
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup: initialize resources
print("Starting up...")
yield
# Shutdown: cleanup resources
print("Shutting down...")
app = FastAPI(lifespan=lifespan)
```
### Root Path
When running behind a reverse proxy that mounts your application at a subpath,
set `root_path` so your application knows its mount point:
```bash
gunicorn myapp:app --worker-class asgi --root-path /api
```
This is equivalent to the `SCRIPT_NAME` in WSGI applications.
### Worker Connections
Control the maximum number of concurrent connections per worker:
```bash
gunicorn myapp:app --worker-class asgi --worker-connections 1000
```
!!! note
Unlike sync workers, the `--threads` option has no effect on ASGI workers.
Use `--worker-connections` to control concurrency.
## WebSocket Support
The ASGI worker supports WebSocket connections out of the box. No additional
configuration is required.
Example with Starlette:
```python
from starlette.applications import Starlette
from starlette.routing import WebSocketRoute
async def websocket_endpoint(websocket):
await websocket.accept()
while True:
data = await websocket.receive_text()
await websocket.send_text(f"Echo: {data}")
app = Starlette(routes=[
WebSocketRoute("/ws", websocket_endpoint),
])
```
## Production Deployment
### With Nginx
```nginx
upstream gunicorn {
server 127.0.0.1:8000;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://gunicorn;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# WebSocket support
location /ws {
proxy_pass http://gunicorn;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}
```
### Recommended Settings
For production ASGI deployments:
```python
# gunicorn.conf.py
worker_class = "asgi"
workers = 4 # Number of worker processes
worker_connections = 1000 # Max connections per worker
keepalive = 5 # Keepalive timeout
timeout = 120 # Worker timeout
graceful_timeout = 30 # Graceful shutdown timeout
# Performance tuning
asgi_loop = "auto" # Use uvloop if available
asgi_lifespan = "auto" # Auto-detect lifespan support
```
## Comparison with Other ASGI Servers
| Feature | Gunicorn ASGI | Uvicorn | Hypercorn |
|---------|---------------|---------|-----------|
| Process management | Built-in | External | Built-in |
| HTTP/2 | No | No | Yes |
| WebSocket | Yes | Yes | Yes |
| Lifespan | Yes | Yes | Yes |
| uvloop support | Yes | Yes | Yes |
Gunicorn's ASGI worker provides the same process management, logging, and
configuration capabilities you're familiar with from WSGI deployments.
## Troubleshooting
### Lifespan startup failed
If you see "ASGI lifespan startup failed", your application may not properly
implement the lifespan protocol. Either fix the application or set
`--asgi-lifespan off`.
### Connection limits
If you're hitting connection limits, increase `--worker-connections` or add
more workers with `--workers`.
### Slow responses under load
Try using uvloop for better performance:
```bash
pip install uvloop
gunicorn myapp:app --worker-class asgi --asgi-loop uvloop
```
## See Also
- [Settings Reference](reference/settings.md#asgi_loop) - All ASGI-related settings
- [Deploy](deploy.md) - General deployment guidance
- [Design](design.md) - Worker architecture overview

266
docs/content/uwsgi.md Normal file
View File

@ -0,0 +1,266 @@
# uWSGI Protocol
Gunicorn supports the uWSGI binary protocol, allowing it to receive requests from
nginx using the `uwsgi_pass` directive. This provides efficient communication
between nginx and Gunicorn without HTTP overhead.
!!! note
This is the **uWSGI binary protocol**, not the uWSGI server. Gunicorn
implements the protocol to receive requests from nginx, similar to how
the uWSGI server would.
## Quick Start
Enable uWSGI protocol support:
```bash
gunicorn myapp:app --protocol uwsgi --bind 127.0.0.1:8000
```
Configure nginx to forward requests:
```nginx
upstream gunicorn {
server 127.0.0.1:8000;
}
server {
listen 80;
server_name example.com;
location / {
uwsgi_pass gunicorn;
include uwsgi_params;
}
}
```
## Why Use uWSGI Protocol?
The uWSGI binary protocol offers several advantages over HTTP proxying:
- **Lower overhead** - Binary format is more compact than HTTP headers
- **Better integration** - nginx's native uwsgi module is highly optimized
- **Simpler configuration** - No need to reconstruct HTTP headers
## Configuration
### Protocol Setting
Switch from HTTP to uWSGI protocol:
```bash
gunicorn myapp:app --protocol uwsgi
```
Or in a configuration file:
```python
# gunicorn.conf.py
protocol = "uwsgi"
```
### Allowed IPs
By default, uWSGI protocol requests are only accepted from localhost
(`127.0.0.1` and `::1`). This prevents unauthorized hosts from sending
requests directly to Gunicorn.
To allow additional IPs:
```bash
gunicorn myapp:app --protocol uwsgi --uwsgi-allow-from 10.0.0.1,10.0.0.2
```
To allow all IPs (not recommended for production):
```bash
gunicorn myapp:app --protocol uwsgi --uwsgi-allow-from '*'
```
!!! warning
Only allow IPs from trusted sources. The uWSGI protocol does not provide
authentication, so anyone who can connect can send requests.
!!! note
UNIX socket connections are always allowed regardless of this setting.
### Using UNIX Sockets
For better performance and security, use UNIX sockets instead of TCP:
```bash
gunicorn myapp:app --protocol uwsgi --bind unix:/run/gunicorn.sock
```
Nginx configuration:
```nginx
upstream gunicorn {
server unix:/run/gunicorn.sock;
}
server {
listen 80;
location / {
uwsgi_pass gunicorn;
include uwsgi_params;
}
}
```
## Nginx Configuration
### Basic Setup
Create or verify the `uwsgi_params` file exists (usually at `/etc/nginx/uwsgi_params`):
```nginx
uwsgi_param QUERY_STRING $query_string;
uwsgi_param REQUEST_METHOD $request_method;
uwsgi_param CONTENT_TYPE $content_type;
uwsgi_param CONTENT_LENGTH $content_length;
uwsgi_param REQUEST_URI $request_uri;
uwsgi_param PATH_INFO $document_uri;
uwsgi_param DOCUMENT_ROOT $document_root;
uwsgi_param SERVER_PROTOCOL $server_protocol;
uwsgi_param REQUEST_SCHEME $scheme;
uwsgi_param HTTPS $https if_not_empty;
uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
uwsgi_param SERVER_PORT $server_port;
uwsgi_param SERVER_NAME $server_name;
```
### With SSL Termination
When nginx handles SSL and forwards to Gunicorn:
```nginx
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
uwsgi_pass gunicorn;
include uwsgi_params;
uwsgi_param HTTPS on;
}
}
```
### Load Balancing
Distribute requests across multiple Gunicorn instances:
```nginx
upstream gunicorn {
least_conn;
server 127.0.0.1:8000;
server 127.0.0.1:8001;
server 127.0.0.1:8002;
}
server {
listen 80;
location / {
uwsgi_pass gunicorn;
include uwsgi_params;
}
}
```
### Static Files
Serve static files directly from nginx:
```nginx
server {
listen 80;
location /static/ {
alias /path/to/static/;
}
location / {
uwsgi_pass gunicorn;
include uwsgi_params;
}
}
```
## Protocol Details
The uWSGI protocol uses a compact binary format:
| Bytes | Field | Description |
|-------|-------|-------------|
| 0 | modifier1 | Packet type (0 = WSGI request) |
| 1-2 | datasize | Size of vars block (little-endian) |
| 3 | modifier2 | Additional flags (usually 0) |
After the header, the vars block contains CGI-style key-value pairs:
```
[2-byte key_size][key][2-byte val_size][value]...
```
Standard CGI variables like `REQUEST_METHOD`, `PATH_INFO`, and `QUERY_STRING`
are extracted from this block to construct the WSGI environ.
## Combining with HTTP
You can run Gunicorn with both HTTP and uWSGI protocol support by running
separate instances:
```bash
# HTTP for direct access
gunicorn myapp:app --bind 127.0.0.1:8080
# uWSGI for nginx
gunicorn myapp:app --protocol uwsgi --bind 127.0.0.1:8000
```
## Troubleshooting
### ForbiddenUWSGIRequest Error
If you see "Forbidden uWSGI request from IP", the connecting IP is not in
the allowed list. Either:
1. Add the IP to `--uwsgi-allow-from`
2. Use UNIX sockets instead
3. Ensure nginx is connecting from an allowed IP
### Invalid uWSGI Header
This usually means:
1. HTTP traffic is being sent to a uWSGI endpoint
2. The packet is malformed or truncated
3. Network issues caused data corruption
Verify that nginx is using `uwsgi_pass` (not `proxy_pass`) and that the
`uwsgi_params` file is being included.
### Headers Missing
If certain headers aren't reaching your application, verify they're included
in `uwsgi_params`. Custom headers should be passed as:
```nginx
uwsgi_param HTTP_X_CUSTOM_HEADER $http_x_custom_header;
```
## See Also
- [Settings Reference](reference/settings.md#protocol) - Protocol and uWSGI settings
- [Deploy](deploy.md) - General deployment guidance
- [Design](design.md) - Worker architecture overview

View File

@ -12,6 +12,8 @@ nav:
- Run: run.md
- Configure: configure.md
- Deploy: deploy.md
- ASGI Worker: asgi.md
- uWSGI Protocol: uwsgi.md
- Signals: signals.md
- Instrumentation: instrumentation.md
- Custom: custom.md