9

I'm working with nginx 1.4.4 running on Ubuntu 12.04.4.
nginx is reverse-proxing a cluster of Rails application servers.

Static files (mostly assets) are served directly, without hitting the application servers.
I've set it up to gzip responses and to use pre-compressed files when available.

http {
  gzip on;
  gzip_http_version 1.0;
  gzip_proxied any;
  # other ngx_http_gzip_module directives...

  server {
    # proxy configuration

    location ^~ /assets/ {
      gzip_static on;
      expires max;
      add_header Cache-Control public;
      # root is inherited
      try_files $uri =404;
      error_page 404 /404.html;
    }
  }
}

This works.
I've tested it using a real pre-gzipped asset and a dummy non-compressed asset with the same name but different content:

/assets/application-a45d6...e2593.css         # dummy content
/assets/application-a45d6...e2593.css.gz      # real CSS

I could see that toggling gzip_static on and off would cause nginx to correctly serve the expected version of the file.
So far, so good.

However, this setup only works if the non-compressed version of the file is also present. Having only the pre-compressed version will cause a 404.

The documentation says:

gzip_static
With the “always” value (1.3.6), gzipped file is used in all cases, without checking if the client supports it. It is useful if there are no uncompressed files on the disk anyway or the ngx_http_gunzip_module is used.

(yes: I've tried both on and always, and I've also tried to add gunzip on. Nothing changed)

It seems to suggest that having only the compressed versions of the files is ok. Is this really the case? Is there anything wrong in my configuration?

3 Answers 3

7

It's possible that you've found a bug. But in general you want both files anyway, for three reasons:

  1. A few clients won't request compressed data, and if you force it on them with gzip_static always; they might not understand it.
  2. To ensure that the file is always found, and the request isn't passed upstream to Rails or being caught by the 404 handler (the possible bug). One of which is probably what's happening.
  3. Having nginx compress or uncompress the file at runtime means it must do so repeatedly, eating up valuable CPU that could be used to run your application. It's much less CPU intensive to simply send a static resource.
6
  • Thanks. Yes, the request is being caught by the handler. I'm pretty sure because when I replaced the try_files directive with try_files $uri @named_proxy_loc; the request was sent to Rails.
    – tompave
    Feb 3, 2014 at 2:15
  • Also, yes, I'm aware of the advantages, and I am indeed happy to have both versions of the assets on the server. I was just wondering if my configuration is ok or if I'm missing something.
    – tompave
    Feb 3, 2014 at 2:15
  • As long as you have gzip_static on; and not always, and have both versions of the file, you should be fine. Feb 3, 2014 at 2:16
  • 4
    try_files works before gzip_static therefore it looks for uncompressed file.
    – Alexey Ten
    Jul 11, 2014 at 4:56
  • @AlexeyTen Maybe that was true for some older nginx versions? Checked this on OpenResty 1.17.8.2 using gzip_static on; try_files $uri =404;, and received correct responses for both requests (with and without the Accept-Encoding: gzip header). Nov 15, 2021 at 12:47
7

Uncompressed files are not required on Nginx 1.6 with:

    location ~ \.txt$ {
        gzip_static on;
        gunzip on;
    }

Both curl http://localhost/index.txt and curl -H "Accept-Encoding: gzip" http://localhost/index.txt | gunzip now work fine with just /srv/www/localhost/index.txt.gz in my root directory.

3
  • 4
    The gunzip directive is relatively new. And it had some bugs prior to the 1.6 stable release. Anyway, if you have the extra CPU to spend on it, go ahead, but it will almost always be faster to have the resource already (un)compressed and available to sendfile() immediately. Jul 10, 2014 at 23:28
  • Have you benchmarked "it will almost always be faster". My own hunch is that it will be slower to have an uncompressed copy because, for a static HTTP server, CPU isn't traditionally the bottleneck compared to disk IO. As most clients will be using the compressed version, it is likely that it will already be cached. Even if it isn't, it's less data to read from the disk, so will be read quicker.
    – rjmunro
    Aug 23, 2017 at 8:43
  • 2
    On Linux servers, the most accessed/recent files are cached on RAM thus, when doing benchmarks, after the first request, the subsequent ones will also be reading the file's content from RAM. So, my conclusion is that having both compressed and uncompressed is the optimal option, as no CPU time is involved and, practically, no slow disk I/O for the great majority of the requests (+99.999%). Aug 23, 2018 at 16:00
1

Contrary to what @hendry says, I need to keep original files.

I use nginx 1.15.9 (Ubuntu).

gzip_static is compiled in:

nginx -V 2>&1 | grep "\-\-with\-http_gzip_static_module

gunzip is compiled in:

nginx -V 2>&1 | grep "\-\-with\-http_gunzip_module".

I have found this, though it may be outdated:

try_files is not aware of gzip_static; but nginx will still honour it if both the non-gz and .gz files exist. This differs from the "normal" gzip_static handling which will serve the .gz version if appropriate, whether or not non-gz exists. - http://mailman.nginx.org/pipermail/nginx/2012-June/034102.html

It seems that try_files requires the original file to work there and is not affected by gzip_static always. That's because try_files $uri =404 requires the $uri file to exist. - https://trac.nginx.org/nginx/ticket/1570

This is my nginx.conf:

events {
    worker_connections 768;
}

http {
    server {
        # Enable static gzip
        gzip_static on;
        gunzip on;

        listen 8080 default_server;
        listen [::]:8080 default_server;

        root /home/user/projects/project1/build;

        location / {
            try_files $uri /index.html;
        }
    }
}

Run it with sudo nginx -t -c nginx.conf -p $PWD.

Restart with sudo killall -9 nginx; sudo nginx -c nginx.conf -p $PWD; ps aux | grep nginx.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .