Configuration: HTTP compression

This page documents the Ferron HTTP compression system. It covers the algorithm preference order, supported algorithms, and configuration options.

Info

The http-compression module handles compression. For static file compression specifically, see Static file serving.

Algorithm preference⁠#

When a client sends an Accept-Encoding header, Ferron selects the best compression algorithm based on a preference order:

  1. Zstandard: the preferred algorithm. Offers the best compression ratio for text content and fast decoding.
  2. Brotli: excellent compression ratio, widely supported.
  3. gzip: the most universally supported compression algorithm.
  4. Deflate: similar to gzip but without the CRC checksum overhead. Less common in practice.

The server iterates through the Accept-Encoding header values that the client sends. It selects the first algorithm that matches the preference order. For example, if a client sends:

Accept-Encoding: gzip, br, zstd

The server selects Zstandard because it appears first in the preference order, even though the client listed gzip first.

If the client does not send an Accept-Encoding header, the server serves the response without compression (identity). The same applies when none of the supported algorithms appear in the header.

Configuration⁠#

Ferron uses two separate directives for the two response paths. Do not mix them up.

Static file compression⁠#

The compressed directive (http-static) enables on-the-fly compression for static file responses only. It applies when Ferron serves files from root. Ferron compresses files larger than 256 bytes with compressible extensions. Host isolation: a named host does not inherit compressed from the wildcard * host. It still inherits from global defaults, and a location block inherits it from its own host. Default: compressed true

Dynamic response compression⁠#

The dynamic_compressed directive (http-compression) enables on-the-fly compression for dynamic response bodies, such as reverse proxy, FastCGI, and CGI responses. Use it when backends return compressible text without their own compression. Default: dynamic_compressed false

Note

Ferron never compresses 101 Switching Protocols or 304 Not Modified responses. Protocol upgrades such as WebSockets pass through unchanged when dynamic_compressed is on.

Pre-compressed sidecar files⁠#

  • precompressed [bool: boolean] (http-static)
    • Enables serving pre-compressed sidecar files (for example, style.css.zst, app.js.br) instead of compressing on the fly. The server checks for a pre-compressed file alongside the original based on which algorithms the client lists in Accept-Encoding. Host isolation: a named host does not inherit precompressed from the wildcard * host. It still inherits from global defaults, and a location block inherits it from its own host. Default: precompressed false

Configuration example:

example.com {
    root /srv/www/example
    compressed
    dynamic_compressed
    precompressed
}

Algorithm details⁠#

AlgorithmContent-Encoding valuePre-compressed file extensionETag suffixEncoding parameters
Zstandardzstd.zst-zstd (static files), -dynamic-zstd (dynamic responses)Quality level 4, window log 17, hash log 10
Brotlibr.br-br (static files), -dynamic-br (dynamic responses)Quality level 4, window size 17, block size 18
gzipgzip.gz-gzip (static files), -dynamic-gzip (dynamic responses)Quality level 4
Deflatedeflate.deflate-deflate (static files), -dynamic-deflate (dynamic responses)Quality level 4

Browser compatibility⁠#

Ferron detects and handles browsers with known compression bugs:

  • Netscape 4.x (non-IE): Ferron disables compression for text/html content.
  • w3m/0.5.x: Ferron disables HTML compression.
  • IE masquerading as Netscape 4.x: Ferron allows compression (MSIE in the user agent indicates it is safe).

ETag handling⁠#

When Ferron applies compression, it modifies the ETag to distinguish compressed variants:

  • Static files: Ferron appends a suffix to the ETag (for example, W/"abc123-zstd" for zstd-compressed files). Pre-compressed sidecar files receive their own ETag. That ETag derives from the metadata of the sidecar file.
  • Dynamic responses: Ferron appends a -dynamic- prefixed suffix (for example, W/"abc123-dynamic-zstd").

When the If-None-Match header is present, the server checks both the base ETag and the compressed variant. This determines whether to return 304 Not Modified.

Vary header⁠#

When compression is possible (based on file size and extension), the server adds Accept-Encoding to the Vary header. This makes sure caches serve the correct compressed variant to each client.

Observability⁠#

Access log fields⁠#

The compression module contributes the following field to the HTTP access log line:

FieldTypeDescription
ferron.compression.algorithmstringCompression algorithm: gzip, br, deflate, zstd, or identity.

Trace spans⁠#

The dynamic compression stage sets the following attributes on its ferron.stage.dynamic_compression span:

AttributeTypeDescription
ferron.compression.algorithmstringCompression algorithm used: gzip, br, deflate, zstd, or identity.
ferron.compression.precompressedboolWhether the server served a precompressed file variant.