The CIDR network support added in 24.1.0 changed forwarded_allow_ips
and proxy_allow_ips from string lists to ipaddress.ip_network objects.
This broke external tools like uvicorn that expect strings.
This fix validates IP/CIDR format during config parsing but keeps the
string representation. Network objects are cached in Config methods
(forwarded_allow_networks() and proxy_allow_networks()) for efficient
IP checking without repeated conversions.
Also uses strict mode for ip_network validation to detect mistakes like
192.168.1.1/24 where host bits are set (should be 192.168.1.0/24).
Fixes#3458
On Linux, SIGCLD and SIGCHLD are aliases for the same signal number (17).
The SIG_NAMES dict iteration order can map to either name, causing
"Unhandled signal: cld" errors when workers fail during boot.
Fixes#3453
- Add docker/Dockerfile with non-root user and configurable environment
- Add GitHub Actions workflow to build multi-platform images (amd64/arm64)
- Publish to ghcr.io/benoitc/gunicorn on version tags
- Update documentation with official image usage examples
- Bump version to 24.1.0
- Add PROXY protocol v2 documentation to deploy guide
- Add 24.1.0 changelog with new features and bug fixes
- Update all docs.gunicorn.org URLs to gunicorn.org
Extend --proxy-protocol to accept version values (off, v1, v2, auto) instead
of being boolean-only. This allows explicit control over which PROXY protocol
versions are accepted.
Changes:
- Add InvalidProxyHeader exception for v2 binary header errors
- Add validate_proxy_protocol() validator with backwards compatibility
- Update ProxyProtocol setting with nargs="?" and const="auto"
- Add PROXY v2 constants (PP_V2_SIGNATURE, PPCommand, PPFamily, PPProtocol)
- Add _parse_proxy_protocol_v1() and _parse_proxy_protocol_v2() methods
- Update both sync (message.py) and async (asgi/message.py) parsers
- Add hex escape handling in treq.py for v2 binary test data
- Add test cases for v2 TCPv4 and TCPv6
Backwards compatible: --proxy-protocol alone (or True) maps to "auto".
Closes#2912
On keepalive connections, finish_request() sets the socket to non-blocking
for selector registration. When the connection is reused, handle() calls
conn.init() which returns early (already initialized) without restoring
blocking mode. This caused SSLWantReadError when WSGI apps read the
request body on SSL connections.
Fix by explicitly setting blocking mode at the start of handle().
Fixes#3448
Add --enable-backlog-metric option to emit a gunicorn.backlog histogram
metric showing connections waiting in the socket backlog. This helps
identify worker saturation and concurrency issues.
Also distinguishes between timer (|ms) and histogram (|h) statsd metric
types per the statsd spec.
Note: Only works on Linux using TCP_INFO from getsockopt.
Closes#2407
Partially fixes#2057
Use Python's ipaddress module to support IP networks in allow lists.
Individual IP addresses are converted to /32 (IPv4) or /128 (IPv6)
networks. CIDR notation (e.g., 192.168.0.0/16) is now supported.
Fixes#1485Closes#2390
Refactor reloader to share code via ReloaderBase class. InotifyReloader
now calls refresh_dirs() on each event loop timeout (~1 sec) to watch
directories for dynamically loaded modules (e.g., Django dynamic imports).
Fixes#1790Closes#1791
SIGTERM is expected during graceful shutdown and reload operations.
Logging it as warning level causes unnecessary noise in error logs.
SIGKILL remains at error level (suggests OOM), other signals at warning.
Closes#3094
When a worker fails to boot, the exception is now printed to stderr
(in addition to being logged), consistent with AppImportError handling.
This makes boot failures more visible to users.
Closes#2933
The unread method was incorrectly appending data to the end of the
buffer instead of prepending it to the beginning. This caused issues
when reading partial data and then unreading it.
Closes#2915Closes#2346
On Python 3.8+ with macOS, the multiprocessing module uses 'spawn' by
default which pickles objects. When pickle.load tries to read
__setstate__ before __dict__ is restored, it hits __getattr__ causing
infinite recursion. Adding a special case for 'settings' prevents this.
Closes#2401
Use 'raise X from e' syntax instead of just 'raise X' when wrapping
exceptions. This provides more accurate exception chaining messages
("The above exception was the direct cause of" vs "During handling of").
Closes#2360
The description incorrectly stated the callable accepts two parameters
(Worker and Request), but the signature shows four parameters including
environ and resp.
Closes#2592
The syslog_addr setting has different defaults depending on the
platform (macOS, FreeBSD, OpenBSD, Linux). Added default_doc to
show all platform-specific defaults in the documentation, ensuring
consistent output regardless of which platform generates the docs.
Also kept the diagnostic git diff in CI for future debugging.
The finish_body() function can raise ssl.SSLWantReadError when
discarding unread request body data on SSL connections. This causes
TLS requests to fail intermittently with "Invalid request" errors.
Handle SSLWantReadError by treating it as "no more data to read".
This is safe because finish_body() only discards leftover data before
keepalive - if SSL says "need to wait for more data", there's nothing
left to discard.
Fixes#3448
Redirect issue creation to GitHub Discussions for proper triage:
- Disable blank issues, redirect to discussion categories
- Add structured discussion templates for bugs, features, questions
- Add preapproved issue template for maintainer use only
- Update CONTRIBUTING.md to reflect new workflow