Gzip compression in Nginx reduces text-based HTTP responses before they travel from your server to the browser. HTML, CSS, JavaScript, JSON, XML, and SVG often shrink enough to improve transfer time and bandwidth use, especially on pages with large templates or API payloads.
This guide focuses on the built-in ngx_http_gzip_module filter: where the main gzip directives are allowed, what their defaults are, how to enable gzip safely, and how to verify that the final response includes Content-Encoding: gzip.
How Gzip Compression Works in Nginx
To understand the benefit, consider how Nginx normally operates. Without compression, Nginx sends response data to clients exactly as stored on disk or generated by upstream applications. A 100 KB JavaScript file transfers as 100 KB over the network, consuming bandwidth and taking longer to download on slower connections.
When gzip compression is enabled, Nginx compresses the response body before sending it. The browser receives a smaller payload, decompresses it locally, and renders the content without requiring any action from the visitor.
According to the official Nginx gzip module documentation, the module compresses responses using the gzip method and can reduce transmitted data by half or more. Standard Nginx builds include this HTTP module unless they were compiled with it disabled.
Gzip compression works best on text-based content because text contains repetitive patterns that compress efficiently. Binary files like images, videos, and already-compressed archives such as ZIP, GZIP, PNG, and JPEG should not be compressed again because they usually gain little or no transfer-size benefit.
Nginx Gzip Directive Defaults and Contexts
Nginx gzip settings are small, but context matters. Start with the directive reference so you know which settings belong globally and which can be scoped to a virtual host or location.
| Directive | Allowed context | Default | Purpose |
|---|---|---|---|
gzip | http, server, location, if in location | off | Enables or disables gzip compression. |
gzip_comp_level | http, server, location | 1 | Sets the compression level from 1 to 9. |
gzip_min_length | http, server, location | 20 bytes | Skips compression until the response Content-Length meets the threshold. |
gzip_types | http, server, location | text/html | Adds MIME types beyond text/html, which Nginx always treats as eligible when gzip is on. |
gzip_vary | http, server, location | off | Adds Vary: Accept-Encoding for cache correctness. |
gzip_proxied | http, server, location | off | Controls compression for requests Nginx identifies as proxied through the Via request header. |
gzip_disable | http, server, location | No default value | Disables gzip for matching User-Agent patterns. |
Only the gzip directive is allowed in the if in location context. Keep settings such as gzip_min_length, gzip_types, and gzip_comp_level in http, server, or location blocks.
Be careful with compression on TLS responses that reflect secrets such as CSRF tokens or account-specific data. The Nginx gzip documentation notes that compressed SSL/TLS responses can be subject to BREACH-style attacks, so scope gzip to public or low-risk content when your application reflects sensitive values.
Check Whether Nginx Gzip Compression Is Enabled
Before modifying your configuration, test a real text-based page or asset that is larger than your gzip_min_length value. Replace the example URL with your own HTTP or HTTPS URL, then use curl to send Accept-Encoding: gzip, discard the body, and print the response headers:
curl -sS -H "Accept-Encoding: gzip" -o /dev/null -D - http://example.com/ | grep -iE "^(content-encoding|vary|content-type):"
The -H flag tells the server that the client accepts gzip, -D - prints headers to standard output, and grep keeps the verification output focused. With gzip and gzip_vary on enabled, a working response includes these relevant headers:
Content-Type: text/html; charset=UTF-8 Vary: Accept-Encoding Content-Encoding: gzip
If the response lacks Content-Encoding: gzip, gzip may be disabled, the response may be smaller than gzip_min_length, the MIME type may be missing from gzip_types, or a CDN/proxy layer may be changing compression before the response reaches the browser.
Enable Gzip Compression in Nginx
First, create a backup of your configuration file in case you need to revert changes:
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
Next, open the main Nginx configuration file. On most Linux distributions, you will find this file at /etc/nginx/nginx.conf:
sudo nano /etc/nginx/nginx.conf
Inside the http block, add the following directives to enable basic gzip compression:
http {
# Enable gzip compression
gzip on;
# Send Vary: Accept-Encoding for shared caches
gzip_vary on;
# Skip very small responses
gzip_min_length 256;
# MIME types to compress (text/html is always compressed)
gzip_types
application/javascript
application/json
application/xml
text/css
text/javascript
text/plain
text/xml;
# ... other directives
}
The gzip on directive activates compression, gzip_vary on keeps shared caches aware of gzip and non-gzip variants, and gzip_types specifies which MIME types to compress beyond text/html. Nginx always treats text/html as eligible when gzip is enabled, so you do not need to include it in the list.
Test and Apply the Configuration
After saving your changes, test the configuration for syntax errors before applying:
sudo nginx -t
A successful test displays output confirming the configuration has valid syntax:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
If the test passes, reload Nginx to apply the changes without dropping existing connections:
sudo systemctl reload nginx
Prefer
reloadoverrestartfor configuration changes. A reload gracefully applies the new configuration while allowing existing connections to complete, avoiding service interruption.
Verify Gzip Compression Is Working
Once Nginx has reloaded, verify that compression is active by repeating the header test against a text-based resource on your server:
curl -sS -H "Accept-Encoding: gzip" -o /dev/null -D - http://example.com/ | grep -iE "^(content-encoding|vary|content-type):"
You should now see Content-Encoding: gzip in the response, confirming that Nginx is compressing the content before sending it. If your site sits behind a CDN or managed proxy, also check that layer because it may compress, decompress, or replace the origin response headers.
Advanced Gzip Configuration Options
The basic configuration works well for many public pages and static assets, but Nginx provides additional directives for tuning CPU cost, proxy behavior, and legacy-client handling. Use a more complete configuration when you need those controls:
http {
# Enable gzip compression
gzip on;
# Compression level (1-9), 4-6 balances CPU usage and compression ratio
gzip_comp_level 5;
# Minimum response size to compress (bytes)
gzip_min_length 256;
# Compress selected proxied responses
gzip_proxied expired no-cache no-store private auth;
# Add Vary header for proper caching
gzip_vary on;
# Disable compression for old IE versions
gzip_disable "msie6";
# MIME types to compress
gzip_types
application/atom+xml
application/geo+json
application/javascript
application/x-javascript
application/json
application/ld+json
application/manifest+json
application/rdf+xml
application/rss+xml
application/xhtml+xml
application/xml
font/eot
font/otf
font/ttf
image/svg+xml
text/css
text/javascript
text/plain
text/xml;
# ... other directives
}
Choose Nginx Gzip Directive Values
gzip_comp_level
- Controls compression intensity on a scale from 1 (fastest, least compression) to 9 (slowest, most compression)
- The default value is 1, which provides minimal compression but uses the least CPU
- Higher levels use more CPU but produce smaller output
- Levels 4-6 are common starting points because they improve size reduction without pushing CPU cost as high as levels 8-9
- Levels above 6 often produce smaller gains per extra CPU cycle, so test them against real traffic before using them globally
gzip_min_length
- Sets the minimum response size (based on the
Content-Lengthheader) required to trigger compression - The default value is 20 bytes, which means Nginx would compress very small responses
- Compressing tiny files adds CPU overhead without meaningful bandwidth savings; 256-1000 bytes is a practical threshold
- Very small compressed responses may actually be larger than uncompressed due to gzip header overhead
gzip_proxied
- Controls whether to compress responses from proxied requests (requests with a
Viaheader) - The default is
off, which disables compression for proxied responses entirely - The value
anyenables compression for all requests that Nginx sees as proxied through aViarequest header - Other options include
expired,no-cache,no-store,private,no_last_modified,no_etag, andauthfor selective compression based on request or response headers
gzip_vary
- When enabled, adds a
Vary: Accept-Encodingheader to compressed responses - This header tells caches (CDNs, proxies, browsers) that the response varies based on whether the client accepts gzip
- Prevents caches from serving a compressed response to a client that cannot decompress it
gzip_disable
- Disables compression for requests matching specific
User-Agentpatterns - The special value
msie6matches Internet Explorer 4-6, which had buggy gzip handling - Modern browsers handle gzip correctly, so this directive is mainly for legacy compatibility
gzip_types
- Lists MIME types eligible for compression beyond the default
text/html - Include all text-based formats your site serves: JavaScript, CSS, JSON, XML, SVG, and web fonts
- Do not add image formats like
image/jpegorimage/pngbecause they use their own compression and gzip provides no benefit
Choose Nginx Gzip Content Types Carefully
Not all content benefits from gzip compression. Adding certain MIME types to gzip_types wastes CPU cycles without reducing transfer size:
Already-compressed formats
- JPEG, PNG, GIF, and WebP images use their own compression algorithms
- Video formats (MP4, WebM) and audio formats (MP3, AAC) use their own compression
- Archive formats (ZIP, GZIP, 7z, RAR) already use compression and cannot shrink further
- PDF files often contain compressed streams internally
Binary executables and downloads
- Application binaries, installers, and firmware files have low compression ratios
- The CPU cost outweighs the minimal savings
Stick to text-based content where gzip has a clear chance to help: HTML, CSS, JavaScript, JSON, XML, plain text, and SVG. For already-compressed downloads, let the file format carry its own compression instead of spending Nginx worker CPU on another gzip pass.
Troubleshoot Nginx Gzip Compression
If gzip compression is not working as expected, use the symptom to narrow the cause before changing more directives.
Content-Encoding Header Is Missing
If the response does not show gzip, first confirm that the tested resource is a text type and large enough to pass gzip_min_length:
curl -sS -H "Accept-Encoding: gzip" -o /dev/null -D - http://example.com/path/to/file.js | grep -iE "^(content-type|content-length|content-encoding|vary):"
If the output shows Content-Type: application/javascript but your gzip_types list only includes text/javascript, add the missing MIME type, run sudo nginx -t, reload Nginx, and repeat the header test.
Nginx Gzip Directive Is Not Allowed Here
If you place a directive in an unsupported context, sudo nginx -t reports an emergency-level syntax error similar to this:
nginx: [emerg] "gzip_min_length" directive is not allowed here in /etc/nginx/nginx.conf:42
The usual cause is placing a non-gzip setting inside if in location. Move gzip_min_length, gzip_types, gzip_comp_level, and similar settings to an http, server, or location block, then rerun the syntax test.
Nginx Reports Unknown Gzip Directive
A custom or minimal Nginx build may exclude the gzip module. In that case, the syntax test can fail with an unknown directive error:
nginx: [emerg] unknown directive "gzip" in /etc/nginx/nginx.conf:42
Check whether your build configuration lists the disable flag:
nginx -V 2>&1 | grep -o -- "--without-http_gzip_module"
If that command prints --without-http_gzip_module, install a standard Nginx package or rebuild Nginx with the gzip module enabled. Then run sudo nginx -t again before reloading the service.
Proxy or CDN Changes Gzip Headers
If your site uses a CDN, load balancer, reverse proxy, or hosting control panel in front of Nginx, that layer may own final compression. Test the origin and the public hostname separately when possible, then check the proxy’s compression setting before assuming the origin configuration failed.
Conflicting Nginx Gzip Settings Override Each Other
A more specific context can override a broader setting. For example, gzip off in one location block can disable compression there even when gzip on is set in the http block. Review the merged configuration to find every active gzip directive:
sudo nginx -T | grep -i gzip
This command outputs the full merged configuration with all includes, filtered to show only gzip-related directives.
Related Nginx Performance Optimizations
Gzip compression fits into a broader Nginx performance stack, but each directive optimizes a different part of delivery. For example, dynamically gzipped responses are transformed before they leave Nginx, while sendfile is most useful for files served without that body transformation.
- Enable Sendfile in Nginx to use zero-copy file transfers for static content
- Enable Open File Cache in Nginx to cache file descriptors and reduce disk I/O
- Enable TCP Fast Open in Nginx to reduce connection establishment latency
- Enable Reuseport in Nginx to improve load distribution across worker processes
- Configure Security Headers in Nginx to add protection against common web vulnerabilities
Use these related guides when the next bottleneck is file I/O, connection distribution, request routing, or response hardening rather than response-body size.
Conclusion
With Nginx gzip compression configured, your server can send smaller text responses while keeping binary downloads and already-compressed assets untouched. Keep directive context strict, enable gzip_vary for cache correctness, and verify the final response headers after each change. Then tune file I/O, caching, or connection settings separately where traffic patterns justify it.
Formatting tips for your comment
You can use basic HTML to format your comment. Useful tags currently allowed in published comments:
<code>command</code>command<strong>bold</strong><em>italic</em><blockquote>quote</blockquote>