mirror of
https://github.com/frappe/gunicorn.git
synced 2026-07-01 18:21: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`,
|
||||
`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
|
||||
|
||||
@ -235,11 +235,14 @@ asgi_lifespan = "auto" # Auto-detect lifespan support
|
||||
| Feature | Gunicorn ASGI | Uvicorn | Hypercorn |
|
||||
|---------|---------------|---------|-----------|
|
||||
| Process management | Built-in | External | Built-in |
|
||||
| HTTP/2 | No | No | Yes |
|
||||
| HTTP/2 | Yes | No | Yes |
|
||||
| WebSocket | Yes | Yes | Yes |
|
||||
| Lifespan | 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
|
||||
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"
|
||||
|
||||
## 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
|
||||
|
||||
### `accesslog`
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user