# Changelog - 2026 ## 25.0.1 - 2026-02-02 ### Bug Fixes - Fix ASGI streaming responses (SSE) hanging: add chunked transfer encoding for HTTP/1.1 responses without Content-Length header. Without chunked encoding, clients wait for connection close to determine end-of-response. ### Changes - Update celery_alternative example to use FastAPI with native ASGI worker and uvloop for async task execution ### Testing - Add ASGI compliance test suite with Docker-based integration tests covering HTTP, WebSocket, streaming, lifespan, framework integration (Starlette, FastAPI), HTTP/2, and concurrency scenarios --- ## 25.0.0 - 2026-02-01 ### New Features - **Dirty Arbiters**: Separate process pool for executing long-running, blocking operations (AI model loading, heavy computation) without blocking HTTP workers ([PR #3460](https://github.com/benoitc/gunicorn/pull/3460)) - Inspired by Erlang's dirty schedulers - Asyncio-based with Unix socket IPC - Stateful workers that persist loaded resources - New settings: `--dirty-app`, `--dirty-workers`, `--dirty-timeout`, `--dirty-threads`, `--dirty-graceful-timeout` - Lifecycle hooks: `on_dirty_starting`, `dirty_post_fork`, `dirty_worker_init`, `dirty_worker_exit` - **Per-App Worker Allocation for Dirty Arbiters**: Control how many dirty workers load each app for memory optimization with heavy models ([PR #3473](https://github.com/benoitc/gunicorn/pull/3473)) - Set `workers` class attribute on DirtyApp (e.g., `workers = 2`) - Or use config format `module:class:N` (e.g., `myapp:HeavyModel:2`) - Requests automatically routed to workers with the target app - New exception `DirtyNoWorkersAvailableError` for graceful error handling - Example: 8 workers × 10GB model = 80GB → with `workers=2`: 20GB (75% savings) - **HTTP/2 Support (Beta)**: Native HTTP/2 (RFC 7540) support for improved performance with modern clients ([PR #3468](https://github.com/benoitc/gunicorn/pull/3468)) - Multiplexed streams over a single connection - Header compression (HPACK) - Flow control and stream prioritization - Works with gthread, gevent, 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 - New example: `examples/http2_gevent/` with Docker and tests - **HTTP 103 Early Hints**: Support for RFC 8297 Early Hints to enable browsers to preload resources before the final response ([PR #3468](https://github.com/benoitc/gunicorn/pull/3468)) - WSGI: `environ['wsgi.early_hints'](headers)` callback - ASGI: `http.response.informational` message type - Works with both HTTP/1.1 and HTTP/2 - **uWSGI Protocol for ASGI Worker**: The ASGI worker now supports receiving requests via the uWSGI binary protocol from nginx ([PR #3467](https://github.com/benoitc/gunicorn/pull/3467)) ### Bug Fixes - Fix HTTP/2 ALPN negotiation for gevent and eventlet workers when `do_handshake_on_connect` is False (the default). The TLS handshake is now explicitly performed before checking `selected_alpn_protocol()`. - Fix setproctitle initialization with systemd socket activation ([#3465](https://github.com/benoitc/gunicorn/issues/3465)) - Fix `Expect: 100-continue` handling: ignore the header for HTTP/1.0 requests since 100-continue is only valid for HTTP/1.1+ ([PR #3463](https://github.com/benoitc/gunicorn/pull/3463)) - Fix missing `_expected_100_continue` attribute in UWSGIRequest - Disable setproctitle on macOS to prevent segfaults during process title updates - Publish full exception traceback when the application fails to load ([#3462](https://github.com/benoitc/gunicorn/issues/3462)) ### Deprecations - **Eventlet Worker**: The `eventlet` worker is deprecated and will be removed in Gunicorn 26.0. Eventlet itself is [no longer actively maintained](https://eventlet.readthedocs.io/en/latest/asyncio/migration.html). Please migrate to `gevent`, `gthread`, or another supported worker type. ### Changes - Remove obsolete Makefile targets ([PR #3471](https://github.com/benoitc/gunicorn/pull/3471)) --- ## 24.1.1 - 2026-01-24 ### Bug Fixes - Fix `forwarded_allow_ips` and `proxy_allow_ips` to remain as strings for backward compatibility with external tools like uvicorn. Network validation now uses strict mode to detect invalid CIDR notation (e.g., `192.168.1.1/24` where host bits are set) ([#3458](https://github.com/benoitc/gunicorn/issues/3458), [PR #3459](https://github.com/benoitc/gunicorn/pull/3459)) --- ## 24.1.0 - 2026-01-23 ### New Features - **Official Docker Image**: Gunicorn now publishes official Docker images to GitHub Container Registry at `ghcr.io/benoitc/gunicorn` - Based on Python 3.12 slim image - Uses recommended worker formula (2 × CPU + 1) - Configurable via environment variables - **PROXY Protocol v2 Support**: Extended PROXY protocol implementation to support the binary v2 format in addition to the existing text-based v1 format ([PR #3451](https://github.com/benoitc/gunicorn/pull/3451)) - New `--proxy-protocol` modes: `off`, `v1`, `v2`, `auto` - `auto` mode (default when enabled) detects v1 or v2 automatically - v2 binary format is more efficient and supports additional metadata - Works with HAProxy, AWS NLB/ALB, and other PROXY protocol v2 sources - **CIDR Network Support**: `--forwarded-allow-ips` and `--proxy-allow-from` now accept CIDR notation (e.g., `192.168.0.0/16`) for specifying trusted networks ([PR #3449](https://github.com/benoitc/gunicorn/pull/3449)) - **Socket Backlog Metric**: New `gunicorn.socket.backlog` gauge metric reports the current socket backlog size on Linux systems ([PR #3450](https://github.com/benoitc/gunicorn/pull/3450)) - **InotifyReloader Enhancement**: The inotify-based reloader now watches newly imported modules, not just those loaded at startup ([PR #3447](https://github.com/benoitc/gunicorn/pull/3447)) ### Bug Fixes - Fix signal handling regression where SIGCLD alias caused "Unhandled signal: cld" errors on Linux when workers fail during boot ([#3453](https://github.com/benoitc/gunicorn/discussions/3453)) - Fix socket blocking mode on keepalive connections preventing SSL handshake failures with async workers ([PR #3452](https://github.com/benoitc/gunicorn/pull/3452)) - Use smaller buffer size in `finish_body()` for faster timeout detection on slow or abandoned connections ([PR #3453](https://github.com/benoitc/gunicorn/pull/3453)) - Handle `SSLWantReadError` in `finish_body()` to prevent worker hangs during SSL renegotiation ([PR #3448](https://github.com/benoitc/gunicorn/pull/3448)) - Log SIGTERM as info level instead of warning to reduce noise in orchestrated environments ([PR #3446](https://github.com/benoitc/gunicorn/pull/3446)) - Print exception details to stderr when worker fails to boot ([PR #3443](https://github.com/benoitc/gunicorn/pull/3443)) - Fix `unreader.unread()` to prepend data to buffer instead of appending ([PR #3442](https://github.com/benoitc/gunicorn/pull/3442)) - Prevent `RecursionError` when pickling Config objects ([PR #3441](https://github.com/benoitc/gunicorn/pull/3441)) - Use proper exception chaining with `raise from` in glogging.py ([PR #3440](https://github.com/benoitc/gunicorn/pull/3440)) --- ## 24.0.0 - 2026-01-23 ### New Features - **ASGI Worker (Beta)**: Native asyncio-based ASGI support for running async Python frameworks like FastAPI, Starlette, and Quart without external dependencies ([PR #3444](https://github.com/benoitc/gunicorn/pull/3444)) - HTTP/1.1 with keepalive connections - WebSocket support - Lifespan protocol for startup/shutdown hooks - Optional uvloop for improved performance - New settings: `--asgi-loop`, `--asgi-lifespan`, `--root-path` - **uWSGI Binary Protocol**: Support for receiving requests from nginx via `uwsgi_pass` directive, enabling efficient binary protocol communication ([PR #3444](https://github.com/benoitc/gunicorn/pull/3444)) - New settings: `--protocol uwsgi`, `--uwsgi-allow-from` - **Documentation Migration**: Migrated documentation from Sphinx to MkDocs with Material theme for improved navigation and mobile experience ([PR #3426](https://github.com/benoitc/gunicorn/pull/3426)) ### Security - **eventlet**: Require eventlet >= 0.40.3 to address CVE-2021-21419 (websocket memory exhaustion) and CVE-2025-58068 (HTTP request smuggling) ([PR #3445](https://github.com/benoitc/gunicorn/pull/3445)) - **gevent**: Require gevent >= 24.10.1 to address CVE-2023-41419 (HTTP request smuggling) and CVE-2024-3219 (socket.socketpair vulnerability) ([PR #3445](https://github.com/benoitc/gunicorn/pull/3445)) - **tornado**: Require tornado >= 6.5.0 to address CVE-2025-47287 (HTTP request smuggling) and other security fixes ([PR #3445](https://github.com/benoitc/gunicorn/pull/3445)) ### Changes - Documentation now hosted at https://gunicorn.org - Updated license configuration to PEP 639 format for uv compatibility !!! warning "ASGI Worker Beta" The ASGI worker is a beta feature. While tested, the API and behavior may change in future releases. Please report any issues on GitHub.