mirror of
https://github.com/frappe/gunicorn.git
synced 2026-07-02 10:41:30 +08:00
Add HTTP/2 documentation
- Add docs/content/guides/http2.md with comprehensive HTTP/2 guide - Quick start and requirements - Configuration options and settings - Worker compatibility matrix - HTTP 103 Early Hints usage for WSGI and ASGI - Production deployment with nginx - Troubleshooting guide - Update docs/content/asgi.md to reflect HTTP/2 support - Update docs/content/2026-news.md with 25.0.0 release featuring HTTP/2 and Early Hints - Regenerate docs/content/reference/settings.md with HTTP/2 settings
This commit is contained in:
parent
75b46bf6cf
commit
955893b6ab
@ -16,6 +16,24 @@
|
|||||||
- Lifecycle hooks: `on_dirty_starting`, `dirty_post_fork`,
|
- Lifecycle hooks: `on_dirty_starting`, `dirty_post_fork`,
|
||||||
`dirty_worker_init`, `dirty_worker_exit`
|
`dirty_worker_init`, `dirty_worker_exit`
|
||||||
|
|
||||||
|
- **HTTP/2 Support (Beta)**: Native HTTP/2 (RFC 7540) support for improved performance
|
||||||
|
with modern clients ([PR #3462](https://github.com/benoitc/gunicorn/pull/3462))
|
||||||
|
- Multiplexed streams over a single connection
|
||||||
|
- Header compression (HPACK)
|
||||||
|
- Flow control and stream prioritization
|
||||||
|
- Works with gthread, gevent, eventlet, and ASGI workers
|
||||||
|
- New settings: `--http-protocols`, `--http2-max-concurrent-streams`,
|
||||||
|
`--http2-initial-window-size`, `--http2-max-frame-size`, `--http2-max-header-list-size`
|
||||||
|
- Requires SSL/TLS and h2 library: `pip install gunicorn[http2]`
|
||||||
|
- See [HTTP/2 Guide](guides/http2.md) for details
|
||||||
|
|
||||||
|
- **HTTP 103 Early Hints**: Support for RFC 8297 Early Hints to enable browsers to
|
||||||
|
preload resources before the final response
|
||||||
|
([PR #3462](https://github.com/benoitc/gunicorn/pull/3462))
|
||||||
|
- WSGI: `environ['wsgi.early_hints'](headers)` callback
|
||||||
|
- ASGI: `http.response.informational` message type
|
||||||
|
- Works with both HTTP/1.1 and HTTP/2
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 24.1.1 - 2026-01-24
|
## 24.1.1 - 2026-01-24
|
||||||
|
|||||||
@ -235,11 +235,14 @@ asgi_lifespan = "auto" # Auto-detect lifespan support
|
|||||||
| Feature | Gunicorn ASGI | Uvicorn | Hypercorn |
|
| Feature | Gunicorn ASGI | Uvicorn | Hypercorn |
|
||||||
|---------|---------------|---------|-----------|
|
|---------|---------------|---------|-----------|
|
||||||
| Process management | Built-in | External | Built-in |
|
| Process management | Built-in | External | Built-in |
|
||||||
| HTTP/2 | No | No | Yes |
|
| HTTP/2 | Yes | No | Yes |
|
||||||
| WebSocket | Yes | Yes | Yes |
|
| WebSocket | Yes | Yes | Yes |
|
||||||
| Lifespan | Yes | Yes | Yes |
|
| Lifespan | Yes | Yes | Yes |
|
||||||
| uvloop support | Yes | Yes | Yes |
|
| uvloop support | Yes | Yes | Yes |
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
HTTP/2 requires SSL/TLS and the h2 library. See [HTTP/2 Support](http2.md) for details.
|
||||||
|
|
||||||
Gunicorn's ASGI worker provides the same process management, logging, and
|
Gunicorn's ASGI worker provides the same process management, logging, and
|
||||||
configuration capabilities you're familiar with from WSGI deployments.
|
configuration capabilities you're familiar with from WSGI deployments.
|
||||||
|
|
||||||
|
|||||||
336
docs/content/guides/http2.md
Normal file
336
docs/content/guides/http2.md
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
# HTTP/2 Support
|
||||||
|
|
||||||
|
!!! warning "Beta Feature"
|
||||||
|
HTTP/2 support is a beta feature introduced in Gunicorn 25.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 supports HTTP/2 (RFC 7540) for improved performance with modern clients.
|
||||||
|
HTTP/2 provides multiplexed streams, header compression, and other optimizations
|
||||||
|
over HTTP/1.1.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install gunicorn with HTTP/2 support
|
||||||
|
pip install gunicorn[http2]
|
||||||
|
|
||||||
|
# Run with HTTP/2 enabled (requires SSL)
|
||||||
|
gunicorn myapp:app \
|
||||||
|
--worker-class gthread \
|
||||||
|
--threads 4 \
|
||||||
|
--certfile server.crt \
|
||||||
|
--keyfile server.key \
|
||||||
|
--http-protocols h2,h1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
HTTP/2 support requires:
|
||||||
|
|
||||||
|
- **SSL/TLS**: HTTP/2 uses ALPN (Application-Layer Protocol Negotiation) which
|
||||||
|
requires an encrypted connection
|
||||||
|
- **h2 library**: Install with `pip install gunicorn[http2]` or `pip install h2`
|
||||||
|
- **Compatible worker**: gthread, gevent, eventlet, or ASGI workers
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Enable HTTP/2
|
||||||
|
|
||||||
|
Enable HTTP/2 by setting the `--http-protocols` option:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gunicorn myapp:app --http-protocols h2,h1
|
||||||
|
```
|
||||||
|
|
||||||
|
Or in a configuration file:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# gunicorn.conf.py
|
||||||
|
http_protocols = ["h2", "h1"]
|
||||||
|
```
|
||||||
|
|
||||||
|
The order matters for ALPN negotiation - protocols are tried in order of preference.
|
||||||
|
|
||||||
|
| Protocol | Description |
|
||||||
|
|----------|-------------|
|
||||||
|
| `h2` | HTTP/2 over TLS |
|
||||||
|
| `h1` | HTTP/1.1 (fallback) |
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
Always include `h1` as a fallback for clients that don't support HTTP/2.
|
||||||
|
|
||||||
|
### SSL/TLS Configuration
|
||||||
|
|
||||||
|
HTTP/2 requires SSL/TLS. Configure certificates:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gunicorn myapp:app \
|
||||||
|
--certfile /path/to/server.crt \
|
||||||
|
--keyfile /path/to/server.key \
|
||||||
|
--http-protocols h2,h1
|
||||||
|
```
|
||||||
|
|
||||||
|
Or in a configuration file:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# gunicorn.conf.py
|
||||||
|
certfile = "/path/to/server.crt"
|
||||||
|
keyfile = "/path/to/server.key"
|
||||||
|
http_protocols = ["h2", "h1"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### HTTP/2 Settings
|
||||||
|
|
||||||
|
Fine-tune HTTP/2 behavior with these settings:
|
||||||
|
|
||||||
|
| Setting | Default | Description |
|
||||||
|
|---------|---------|-------------|
|
||||||
|
| `http2_max_concurrent_streams` | 100 | Maximum concurrent streams per connection |
|
||||||
|
| `http2_initial_window_size` | 65535 | Initial flow control window size (bytes) |
|
||||||
|
| `http2_max_frame_size` | 16384 | Maximum frame size (bytes) |
|
||||||
|
| `http2_max_header_list_size` | 65536 | Maximum header list size (bytes) |
|
||||||
|
|
||||||
|
Example configuration:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# gunicorn.conf.py
|
||||||
|
http_protocols = ["h2", "h1"]
|
||||||
|
http2_max_concurrent_streams = 200
|
||||||
|
http2_initial_window_size = 1048576 # 1MB
|
||||||
|
```
|
||||||
|
|
||||||
|
## Worker Compatibility
|
||||||
|
|
||||||
|
Not all workers support HTTP/2:
|
||||||
|
|
||||||
|
| Worker | HTTP/2 Support | Notes |
|
||||||
|
|--------|----------------|-------|
|
||||||
|
| `sync` | No | Single-threaded, cannot multiplex streams |
|
||||||
|
| `gthread` | Yes | Recommended for HTTP/2 |
|
||||||
|
| `gevent` | Yes | Requires gevent |
|
||||||
|
| `eventlet` | Yes | Requires eventlet |
|
||||||
|
| `asgi` | Yes | For async frameworks |
|
||||||
|
| `tornado` | No | Tornado handles its own protocol |
|
||||||
|
|
||||||
|
If you use the sync or tornado worker with HTTP/2 enabled, Gunicorn will log a
|
||||||
|
warning and fall back to HTTP/1.1.
|
||||||
|
|
||||||
|
### Recommended: gthread Worker
|
||||||
|
|
||||||
|
For HTTP/2, the gthread worker is recommended:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gunicorn myapp:app \
|
||||||
|
--worker-class gthread \
|
||||||
|
--threads 4 \
|
||||||
|
--workers 2 \
|
||||||
|
--http-protocols h2,h1 \
|
||||||
|
--certfile server.crt \
|
||||||
|
--keyfile server.key
|
||||||
|
```
|
||||||
|
|
||||||
|
## HTTP 103 Early Hints
|
||||||
|
|
||||||
|
Gunicorn supports HTTP 103 Early Hints (RFC 8297), allowing servers to send
|
||||||
|
resource hints before the final response. This enables browsers to preload
|
||||||
|
CSS, JavaScript, and other assets in parallel.
|
||||||
|
|
||||||
|
### WSGI Applications
|
||||||
|
|
||||||
|
Use the `wsgi.early_hints` callback in your WSGI application:
|
||||||
|
|
||||||
|
```python
|
||||||
|
def app(environ, start_response):
|
||||||
|
# Send early hints if available
|
||||||
|
if 'wsgi.early_hints' in environ:
|
||||||
|
environ['wsgi.early_hints']([
|
||||||
|
('Link', '</style.css>; rel=preload; as=style'),
|
||||||
|
('Link', '</app.js>; rel=preload; as=script'),
|
||||||
|
])
|
||||||
|
|
||||||
|
# Continue with the actual response
|
||||||
|
start_response('200 OK', [('Content-Type', 'text/html')])
|
||||||
|
return [b'<html>...</html>']
|
||||||
|
```
|
||||||
|
|
||||||
|
### ASGI Applications
|
||||||
|
|
||||||
|
Use the `http.response.informational` message type:
|
||||||
|
|
||||||
|
```python
|
||||||
|
async def app(scope, receive, send):
|
||||||
|
# Send early hints
|
||||||
|
await send({
|
||||||
|
"type": "http.response.informational",
|
||||||
|
"status": 103,
|
||||||
|
"headers": [
|
||||||
|
(b"link", b"</style.css>; rel=preload; as=style"),
|
||||||
|
(b"link", b"</app.js>; rel=preload; as=script"),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
# Send the actual response
|
||||||
|
await send({
|
||||||
|
"type": "http.response.start",
|
||||||
|
"status": 200,
|
||||||
|
"headers": [(b"content-type", b"text/html")],
|
||||||
|
})
|
||||||
|
await send({
|
||||||
|
"type": "http.response.body",
|
||||||
|
"body": b"<html>...</html>",
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
Early hints are only sent to HTTP/1.1+ clients. HTTP/1.0 clients silently
|
||||||
|
ignore the callback since they don't support 1xx responses.
|
||||||
|
|
||||||
|
## Production Deployment
|
||||||
|
|
||||||
|
### With Nginx
|
||||||
|
|
||||||
|
Configure nginx to proxy HTTP/2 connections to Gunicorn:
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
upstream gunicorn {
|
||||||
|
server 127.0.0.1:8443;
|
||||||
|
keepalive 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
http2 on;
|
||||||
|
server_name example.com;
|
||||||
|
|
||||||
|
ssl_certificate /path/to/server.crt;
|
||||||
|
ssl_certificate_key /path/to/server.key;
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
|
||||||
|
# Forward 103 Early Hints (requires nginx 1.29+)
|
||||||
|
location / {
|
||||||
|
proxy_pass https://gunicorn;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_ssl_verify off;
|
||||||
|
|
||||||
|
early_hints $http2;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
For nginx to forward 103 Early Hints from upstream, you need nginx 1.29+
|
||||||
|
and the `early_hints` directive.
|
||||||
|
|
||||||
|
### Direct TLS Termination
|
||||||
|
|
||||||
|
For simpler deployments, Gunicorn can terminate TLS directly:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# gunicorn.conf.py
|
||||||
|
bind = "0.0.0.0:443"
|
||||||
|
worker_class = "gthread"
|
||||||
|
threads = 4
|
||||||
|
workers = 4
|
||||||
|
|
||||||
|
# SSL
|
||||||
|
certfile = "/etc/letsencrypt/live/example.com/fullchain.pem"
|
||||||
|
keyfile = "/etc/letsencrypt/live/example.com/privkey.pem"
|
||||||
|
|
||||||
|
# HTTP/2
|
||||||
|
http_protocols = ["h2", "h1"]
|
||||||
|
http2_max_concurrent_streams = 100
|
||||||
|
```
|
||||||
|
|
||||||
|
### Recommended Settings
|
||||||
|
|
||||||
|
For production HTTP/2 deployments:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# gunicorn.conf.py
|
||||||
|
worker_class = "gthread"
|
||||||
|
workers = 4
|
||||||
|
threads = 4
|
||||||
|
keepalive = 120 # HTTP/2 connections are long-lived
|
||||||
|
|
||||||
|
# SSL/TLS
|
||||||
|
certfile = "/path/to/server.crt"
|
||||||
|
keyfile = "/path/to/server.key"
|
||||||
|
ssl_version = "TLSv1_2" # Minimum TLS 1.2 for HTTP/2
|
||||||
|
|
||||||
|
# HTTP/2
|
||||||
|
http_protocols = ["h2", "h1"]
|
||||||
|
http2_max_concurrent_streams = 100
|
||||||
|
http2_initial_window_size = 65535
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### HTTP/2 not negotiated
|
||||||
|
|
||||||
|
If clients fall back to HTTP/1.1:
|
||||||
|
|
||||||
|
1. Verify SSL is configured correctly
|
||||||
|
2. Check that `h2` is in `--http-protocols`
|
||||||
|
3. Ensure the h2 library is installed: `pip install h2`
|
||||||
|
4. Verify ALPN support: `openssl s_client -alpn h2 -connect host:port`
|
||||||
|
|
||||||
|
### Worker doesn't support HTTP/2
|
||||||
|
|
||||||
|
If you see "HTTP/2 is not supported by the sync worker":
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Switch to gthread worker
|
||||||
|
gunicorn myapp:app --worker-class gthread --threads 4
|
||||||
|
```
|
||||||
|
|
||||||
|
### Connection errors with large requests
|
||||||
|
|
||||||
|
Increase flow control window sizes:
|
||||||
|
|
||||||
|
```python
|
||||||
|
http2_initial_window_size = 1048576 # 1MB
|
||||||
|
http2_max_frame_size = 32768 # 32KB
|
||||||
|
```
|
||||||
|
|
||||||
|
### Too many concurrent streams
|
||||||
|
|
||||||
|
If clients report stream limit errors:
|
||||||
|
|
||||||
|
```python
|
||||||
|
http2_max_concurrent_streams = 200 # Increase from default 100
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing HTTP/2
|
||||||
|
|
||||||
|
### Using curl
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check HTTP/2 support
|
||||||
|
curl -v --http2 https://localhost:8443/
|
||||||
|
|
||||||
|
# Force HTTP/2
|
||||||
|
curl --http2-prior-knowledge https://localhost:8443/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using Python
|
||||||
|
|
||||||
|
```python
|
||||||
|
import httpx
|
||||||
|
|
||||||
|
with httpx.Client(http2=True, verify=False) as client:
|
||||||
|
response = client.get("https://localhost:8443/")
|
||||||
|
print(f"HTTP Version: {response.http_version}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Settings Reference](reference/settings.md#http2_max_concurrent_streams) - All HTTP/2 settings
|
||||||
|
- [ASGI Worker](asgi.md) - ASGI worker with HTTP/2 support
|
||||||
|
- [Deploy](deploy.md) - General deployment guidance
|
||||||
|
- [SSL Configuration](deploy.md#using-ssl) - SSL/TLS setup
|
||||||
@ -287,6 +287,111 @@ are force killed.
|
|||||||
|
|
||||||
!!! info "Added in 25.0.0"
|
!!! info "Added in 25.0.0"
|
||||||
|
|
||||||
|
## HTTP/2
|
||||||
|
|
||||||
|
### `http_protocols`
|
||||||
|
|
||||||
|
**Command line:** `--http-protocols STRING`
|
||||||
|
|
||||||
|
**Default:** `'h1'`
|
||||||
|
|
||||||
|
HTTP protocol versions to support (comma-separated, order = preference).
|
||||||
|
|
||||||
|
Valid protocols:
|
||||||
|
|
||||||
|
* ``h1`` - HTTP/1.1 (default)
|
||||||
|
* ``h2`` - HTTP/2 (requires TLS with ALPN)
|
||||||
|
* ``h3`` - HTTP/3 (future, not yet implemented)
|
||||||
|
|
||||||
|
Examples::
|
||||||
|
|
||||||
|
# HTTP/1.1 only (default, backward compatible)
|
||||||
|
--http-protocols=h1
|
||||||
|
|
||||||
|
# Prefer HTTP/2, fallback to HTTP/1.1
|
||||||
|
--http-protocols=h2,h1
|
||||||
|
|
||||||
|
# HTTP/2 only (reject HTTP/1.1 clients)
|
||||||
|
--http-protocols=h2
|
||||||
|
|
||||||
|
HTTP/2 requires:
|
||||||
|
|
||||||
|
* TLS (--certfile and --keyfile)
|
||||||
|
* The h2 library: ``pip install gunicorn[http2]``
|
||||||
|
* ALPN-capable TLS client
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
HTTP/2 cleartext (h2c) is not supported due to security concerns
|
||||||
|
and lack of browser support.
|
||||||
|
|
||||||
|
!!! info "Added in 25.0.0"
|
||||||
|
|
||||||
|
### `http2_max_concurrent_streams`
|
||||||
|
|
||||||
|
**Command line:** `--http2-max-concurrent-streams INT`
|
||||||
|
|
||||||
|
**Default:** `100`
|
||||||
|
|
||||||
|
Maximum number of concurrent HTTP/2 streams per connection.
|
||||||
|
|
||||||
|
This limits how many requests can be processed simultaneously on a
|
||||||
|
single HTTP/2 connection. Higher values allow more parallelism but
|
||||||
|
use more memory.
|
||||||
|
|
||||||
|
Default is 100, which matches common server configurations.
|
||||||
|
The HTTP/2 specification allows up to 2^31-1.
|
||||||
|
|
||||||
|
!!! info "Added in 25.0.0"
|
||||||
|
|
||||||
|
### `http2_initial_window_size`
|
||||||
|
|
||||||
|
**Command line:** `--http2-initial-window-size INT`
|
||||||
|
|
||||||
|
**Default:** `65535`
|
||||||
|
|
||||||
|
Initial HTTP/2 flow control window size in bytes.
|
||||||
|
|
||||||
|
This controls how much data can be in-flight before the receiver
|
||||||
|
sends WINDOW_UPDATE frames. Larger values can improve throughput
|
||||||
|
for large transfers but use more memory.
|
||||||
|
|
||||||
|
Default is 65535 (64KB - 1), the HTTP/2 specification default.
|
||||||
|
Maximum is 2^31-1 (2147483647).
|
||||||
|
|
||||||
|
!!! info "Added in 25.0.0"
|
||||||
|
|
||||||
|
### `http2_max_frame_size`
|
||||||
|
|
||||||
|
**Command line:** `--http2-max-frame-size INT`
|
||||||
|
|
||||||
|
**Default:** `16384`
|
||||||
|
|
||||||
|
Maximum HTTP/2 frame payload size in bytes.
|
||||||
|
|
||||||
|
This is the largest frame payload the server will accept.
|
||||||
|
Larger frames reduce framing overhead but may increase latency
|
||||||
|
for small messages.
|
||||||
|
|
||||||
|
Default is 16384 (16KB), the HTTP/2 specification minimum.
|
||||||
|
Range is 16384 to 16777215 (16MB - 1).
|
||||||
|
|
||||||
|
!!! info "Added in 25.0.0"
|
||||||
|
|
||||||
|
### `http2_max_header_list_size`
|
||||||
|
|
||||||
|
**Command line:** `--http2-max-header-list-size INT`
|
||||||
|
|
||||||
|
**Default:** `65536`
|
||||||
|
|
||||||
|
Maximum size of HTTP/2 header list in bytes (HPACK protection).
|
||||||
|
|
||||||
|
This limits the total size of headers after HPACK decompression.
|
||||||
|
Protects against compression bombs and excessive memory use.
|
||||||
|
|
||||||
|
Default is 65536 (64KB). Set to 0 for unlimited (not recommended).
|
||||||
|
|
||||||
|
!!! info "Added in 25.0.0"
|
||||||
|
|
||||||
## Logging
|
## Logging
|
||||||
|
|
||||||
### `accesslog`
|
### `accesslog`
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user