Skip to content

Releases: benoitc/gunicorn

Gunicorn 25.3.0

26 Mar 23:58

Choose a tag to compare

Bug Fixes

  • HTTP/2 ASGI Body Duplication: Fix request body being received twice in HTTP/2
    ASGI requests, causing JSON parsing errors with "Extra data" messages
    (#3558)

  • ASGI Chunked EOF Handling: Add finish() method to callback parser to handle
    chunked encoding edge case where connection closes before final CRLF after zero-chunk

  • HTTP/2 Documentation: Fix http_protocols examples to use comma-separated string
    instead of list syntax (#3561)

  • Chunked Encoding: Reject chunk extensions containing bare CR bytes per RFC 9112
    (#3556)

  • Request Line Limit: Fix --limit-request-line 0 to mean unlimited as documented,
    instead of using default maximum. Works with both Python and fast C parser.
    (#3563)

Security

  • ASGI Parser Header Validation: Add security checks per RFC 9110/9112:
    • Reject duplicate Content-Length headers
    • Reject requests with both Content-Length and Transfer-Encoding
    • Reject chunked transfer encoding in HTTP/1.0
    • Reject stacked chunked encoding
    • Validate Transfer-Encoding values
    • Strict chunk size validation

Changes

  • Fast HTTP Parser: Update to gunicorn_h1c >= 0.6.3 for asgi_headers property
    and InvalidChunkExtension validation for bare CR rejection

  • ASGI PROXY Protocol: Add PROXY protocol v1/v2 support to callback parser

  • Docker Images: Update to Python 3.14

Gunicorn 25.2.0

24 Mar 22:45

Choose a tag to compare

New Features

  • Fast HTTP Parser (gunicorn_h1c 0.4.1): Integrate new exception types and limit parameters from gunicorn_h1c 0.4.1 for both WSGI and ASGI workers
    • Requires gunicorn_h1c >= 0.4.1 for http_parser='fast'
    • Falls back to Python parser in auto mode if version not met
    • Proper HTTP status codes for limit errors (414, 431)

Bug Fixes

  • uWSGI Async Workers: Fix InvalidUWSGIHeader: incomplete header error when using gevent or gthread workers with uwsgi protocol behind nginx. (#3552, PR #3554)

  • FileWrapper Iterator Protocol: Add __iter__ and __next__ methods to FileWrapper for full PEP 3333 compliance. (#3396, PR #3550)

Performance

  • ASGI HTTP Parser Optimizations: Improve ASGI worker HTTP parsing performance
    • Callback-based parsing with direct bytearray buffer operations
    • Use bytearray.find() directly instead of converting to bytes first
    • Use index-based iteration for header parsing instead of list.pop(0) (O(1) vs O(n))

Gunicorn 25.1.0

13 Feb 11:06

Choose a tag to compare

New Features

  • Control Interface (gunicornc): Add interactive control interface for managing
    running Gunicorn instances, similar to birdc for BIRD routing daemon
    (PR #3505)

    • Unix socket-based communication with JSON protocol
    • Interactive mode with readline support and command history
    • Commands: show all/workers/dirty/config/stats/listeners
    • Worker management: worker add/remove/kill, dirty add/remove
    • Server control: reload, reopen, shutdown
    • New settings: --control-socket, --control-socket-mode, --no-control-socket
    • New CLI tool: gunicornc for connecting to control socket
    • See Control Interface Guide for details
  • Dirty Stash: Add global shared state between workers via dirty.stash
    (PR #3503)

    • In-memory key-value store accessible by all workers
    • Supports get, set, delete, clear, keys, and has operations
    • Useful for sharing state like feature flags, rate limits, or cached data
  • Dirty Binary Protocol: Implement efficient binary protocol for dirty arbiter IPC
    using TLV (Type-Length-Value) encoding
    (PR #3500)

    • More efficient than JSON for binary data
    • Supports all Python types: str, bytes, int, float, bool, None, list, dict
    • Better performance for large payloads
  • Dirty TTIN/TTOU Signals: Add dynamic worker scaling for dirty arbiters
    (PR #3504)

    • Send SIGTTIN to increase dirty workers
    • Send SIGTTOU to decrease dirty workers
    • Respects minimum worker constraints from app configurations

Changes

  • ASGI Worker: Promoted from beta to stable
  • Dirty Arbiters: Now marked as beta feature

Documentation

  • Fix Markdown formatting in /configure documentation

25.0.3

07 Feb 16:43

Choose a tag to compare

What's Changed

Bug Fixes

  • Fix RuntimeError when StopIteration raised in ASGI coroutine (#3484)
  • Fix passing maxsplit in re.split() as positional argument (deprecated in Python 3.13)

Documentation

  • Updated sponsorship section and homepage

Full Changelog: 25.0.2...25.0.3

25.0.2

07 Feb 16:47

Choose a tag to compare

What's Changed

Bug Fixes

  • Fix ASGI concurrent request failures through nginx proxy
  • Graceful disconnect handling for ASGI worker
  • Lazy import dirty module for gevent compatibility

Other

  • Increase CI timeout for signal tests on PyPy
  • Remove trailing blank line in instrument/init.py

Full Changelog: 25.0.1...25.0.2

25.0.1

02 Feb 13:32

Choose a tag to compare

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

Gunicorn 25.0.0

01 Feb 13:37

Choose a tag to compare

New Features

  • Dirty Arbiters: Separate process pool for executing long-running, blocking
    operations (AI model loading, heavy computation) without blocking HTTP workers
    (PR #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)

    • 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)

    • 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]
    • 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)

    • 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)

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)

  • 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)

  • 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)

  • Fix ASGI: quick shutdown on SIGINT/SIGQUIT, graceful on SIGTERM

Deprecations

  • Eventlet Worker: The eventlet worker is deprecated and will be removed in
    Gunicorn 26.0. Eventlet itself is no longer actively maintained.
    Please migrate to gevent, gthread, or another supported worker type.

Changes

  • Remove obsolete Makefile targets
    (PR #3471)
  • Replace RST with markdown documentation format

24.1.1

24 Jan 01:13

Choose a tag to compare

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,
    PR #3459)

Full Changelog: 24.1.0...24.1.1

Gunicorn 24.1.0

23 Jan 20:48

Choose a tag to compare

New Features

  • Official Docker Image: Gunicorn now publishes official Docker images to GitHub Container Registry (PR #3454)

    • Available 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)

    • 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)

  • Socket Backlog Metric: New gunicorn.socket.backlog gauge metric reports the current socket backlog size on Linux systems (PR #3450)

  • InotifyReloader Enhancement: The inotify-based reloader now watches newly imported modules, not just those loaded at startup (PR #3447)

Bug Fixes

  • Fix signal handling regression where SIGCLD alias caused "Unhandled signal: cld" errors on Linux when workers fail during boot (#3453)
  • Fix socket blocking mode on keepalive connections preventing SSL handshake failures with async workers (PR #3452)
  • Use smaller buffer size in finish_body() for faster timeout detection on slow or abandoned connections (PR #3453)
  • Handle SSLWantReadError in finish_body() to prevent worker hangs during SSL renegotiation (PR #3448)
  • Log SIGTERM as info level instead of warning to reduce noise in orchestrated environments (PR #3446)
  • Print exception details to stderr when worker fails to boot (PR #3443)
  • Fix unreader.unread() to prepend data to buffer instead of appending (PR #3442)
  • Prevent RecursionError when pickling Config objects (PR #3441)
  • Use proper exception chaining with raise from in glogging.py (PR #3440)

Installation

pip install gunicorn==24.1.0

Or use the official Docker image:

docker pull ghcr.io/benoitc/gunicorn:24.1.0

24.0.0

23 Jan 00:40
3960372

Choose a tag to compare

New Features

  • ASGI Worker (Beta): Native asyncio-based ASGI support for running async Python frameworks like FastAPI, Starlette, and Quart without external dependencies

    • HTTP/1.1 with keepalive connections
    • WebSocket support
    • Lifespan protocol for startup/shutdown hooks
    • Optional uvloop for improved performance
  • uWSGI Binary Protocol: Support for receiving requests from nginx via uwsgi_pass directive

  • Documentation Migration: Migrated to MkDocs with Material theme

Security

Install

pip install gunicorn==24.0.0