Enable & Configure Gzip Compression on Nginx
What you’ll get out of this
In the next few minutes you’ll see how to turn on gzip in Nginx, tweak the settings so they actually help your site, and test that everything is working. I’ll also point out a couple of common pitfalls that waste CPU cycles or break assets.
Why bother with gzip?
If you’ve ever opened Chrome’s dev tools and saw a 200 KB JavaScript file being sent uncompressed, you know the pain. Enabling gzip can shave 60‑80 % off the payload without any code changes. The trade‑off is a tiny CPU hit on the server – but on a typical VPS that cost is negligible compared to the bandwidth savings.
Quick sanity check
Before touching the config, make sure your Nginx was built with the --with-http_gzip_module flag. Run:
nginx -V 2>&1 | grep -o http_gzip_module
If nothing prints, you’re stuck with a binary that can’t do gzip and you’ll need to recompile or install a package that includes it.
Turn on gzip – the minimal config
Add this block inside the http { … } context of your main nginx.conf (or in an include file like /etc/nginx/conf.d/gzip.conf):
gzip on; # actually enable compression
gzip_comp_level 5; # reasonable quality‑speed balance
gzip_min_length 256; # don’t bother with tiny files
gzip_proxied any; # compress even when behind a reverse proxy
gzip_types text/plain text/css application/json application/javascript text/xml application/xml+rss;
Why these values?
- gzip_comp_level defaults to 1 (fast but weak) and maxes at 9 (slow, high compression). Level 5 is the sweet spot for most sites.
- Anything under 256 bytes is usually already tiny; compressing it wastes CPU.
- The gzip_types list tells Nginx which MIME types to touch. If you forget to add application/javascript, your scripts will be sent raw, and you’ll wonder why the page feels sluggish.
Fine‑tuning for real‑world traffic
Exclude already compressed assets – files ending in .gz or delivered with a Content-Encoding: gzip header should be left alone. Add:
gzip_static on;
This makes Nginx serve pre‑compressed .gz files if they exist, avoiding the runtime CPU cost entirely.
Avoid double compression – some CDNs or load balancers also compress. If you know something upstream already gzips, switch gzip_proxied to off:
gzip_proxied off;
Control Vary header – browsers cache compressed vs. uncompressed responses differently. Enable it so caches behave correctly:
gzip_vary on;
Set a reasonable buffer size – small buffers can cause Nginx to fall back to uncompressed output for large responses.
gzip_buffers 16 8k;
Test that it works
After reloading (nginx -s reload), fire up curl:
curl -H "Accept-Encoding: gzip" -I https://yourdomain.com/style.css
Look for Content-Encoding: gzip. If you see it, congratulations. No header? Double‑check your gzip_types and make sure the request actually matches one of them.
A quick sanity test I ran on a low‑end VPS showed CPU usage tick up by about 0.3 % per core while serving a 50 MB static site – completely acceptable for the bandwidth savings.
When not to use gzip
If you’re serving already compressed media (MP4, WebP, JPEG) or tiny JSON APIs under 200 bytes, turning gzip on just adds latency. In those cases I simply leave it off for that location block:
location ~* \.(png|jpe?g|gif|webp)$ {
gzip off;
}
Wrap‑up
Turn the feature on, tweak the level and types to match your content, test with curl, and you’ll be saving bandwidth without breaking anything. If you ever notice high CPU spikes after enabling it, dial the gzip_comp_level back down or switch to pre‑compressed static files.