Why is the gzip minimum length directive not being respected?

Jonathan picture Jonathan · Oct 21, 2015 · Viewed 9.9k times · Source

If I understand correctly it's better not to gzip small resources as they might actually get bigger while still having a performance hit on the CPU. So using the gzip_min_length directive is an obvious solution to that. However, when trying this on a server that runs a REST API I'm working on this doesn't seem to work. When I receive an empty json response, or a very small one, the Content-Encoding header is still present and reading "gzip".

HTTP Response headers

My question is why this setting is not being respected by NginX and what can I do to fix it?

The API is built on the Lumen microframework.

I have attached the Gzip setting I'm using in my nginx.conf:

  # Compression

  # Enable Gzip compressed.
  gzip on;

  # Enable compression both for HTTP/1.0 and HTTP/1.1.
  gzip_http_version  1.1;

  # Compression level (1-9).
  # 5 is a perfect compromise between size and cpu usage, offering about
  # 75% reduction for most ascii files (almost identical to level 9).
  gzip_comp_level    5;

  # Don't compress anything that's already small and unlikely to shrink much
  # if at all (the default is 20 bytes, which is bad as that usually leads to
  # larger files after gzipping).
  gzip_min_length    1000;

  # Compress data even for clients that are connecting to us via proxies,
  # identified by the "Via" header (required for CloudFront).
  gzip_proxied       any;

  # Tell proxies to cache both the gzipped and regular version of a resource
  # whenever the client's Accept-Encoding capabilities header varies;
  # Avoids the issue where a non-gzip capable client (which is extremely rare
  # today) would display gibberish if their proxy gave them the gzipped version.
  gzip_vary          on;

  # Compress all output labeled with one of the following MIME-types.
  gzip_types
    application/atom+xml
    application/javascript
    application/json
    application/rss+xml
    application/vnd.ms-fontobject
    application/x-font-ttf
    application/x-web-app-manifest+json
    application/xhtml+xml
    application/xml
    font/opentype
    image/svg+xml
    image/x-icon
    text/css
    text/plain
    text/x-component;
  # text/html is always compressed by HttpGzipModule

Answer

Chad Barth picture Chad Barth · Oct 26, 2015

Confirming my note above, this does seem to correspond to the note in the NGINX gzip module documentation stating "The length is determined only from the “Content-Length” response header field."

With gzip_min_length 1000;, my JSON responses were being gzip'ed, even if they were only 100 bytes.

I changed my application to add the Content-Length: 100 header and NGINX sends the JSON response without using the gzip encoding.

If I change the configuration to gzip_min_length 80; with the same 100-byte Content-Length, then NGINX applies the gzip encoding as expected.

Short story: you need to apply the Content-Length header for NGINX to properly handle the gzip_min_length check.