Serve pre-compressed gzip assets with Nginx
Created:
目次
Overview
This article describes how to serve files that are already gzip-compressed using Nginx.
Static HTML and CSS files rarely change, so you can pre-compress them instead of compressing them on the fly.
- Lower CPU use at request time
- Higher compression ratios (for example, using
gzip -9orzopfli) - Better cacheability
Real-time compression can be enabled with gzip on;, but higher-compression tools like zopfli are slow, so pre-compressing is preferable when possible.
References:
Assumed layout
Simple structure under test/, with HTML loading a CSS file:
.
└── test
├── test.css
└── test.htmlRequirements:
- Access without extensions (e.g.,
/test/testshould serve/test/test.html) - Keep only pre-gzipped files if possible
- Ignore clients without gzip support (modern browsers support it)
On omitting extensions, see the W3C article: https://www.w3.org/Provider/Style/URI
“cgi”, even “.html” is something which will change. You may not be using HTML for that page in 20 years time, but you might want today’s links to it to still be valid. The canonical way of making links to the W3C site doesn’t use the extension.
Final layout after compression
.
└── test
├── test.css.gz
├── test.html
└── test.html.gzNotes:
test.html.gzwill be served, buttest.htmlstill needs to exist (explained later)test.csscould be removed; only the.gzversion will be served
Nginx config example
Depending on the situation, you may also need to set gzip_vary or gzip_proxied. For details, please refer to the link provided earlier.
events {
worker_connections 1024;
}
http {
include mime.types;
gzip on;
gzip_static on;
gzip_types text/css text/javascript;
server {
listen 80;
root /usr/share/nginx/html;
location ~* \.(js|css?)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
location / {
add_header Cache-Control "no-cache, must-revalidate";
try_files $uri.html $uri $uri/ =404;
}
}
}Notes:
gzip_static on;serves.gzfiles when present- If you only serve pre-gzipped files,
gzip on;can be omitted try_filesmakes Nginx look for$uri.htmlso you can drop extensions
HTML still needs the non-gz file
If you remove test.html and keep only test.html.gz, you get 404.
Working set:
test.html→ must exist (could probably be empty)test.html.gz→ the content actually served
gzip_static does use the .gz file, but try_files still needs the .html to exist. Changing test.html did not change the served content (it kept using the gzipped one), so an empty placeholder might be fine. My guess is try_files simply requires the .html to resolve.