How to Enable Gzip Compression in Nginx

Last updated Monday, April 27, 2026 9:40 pm Joshua James 8 min read

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.

DirectiveAllowed contextDefaultPurpose
gziphttp, server, location, if in locationoffEnables or disables gzip compression.
gzip_comp_levelhttp, server, location1Sets the compression level from 1 to 9.
gzip_min_lengthhttp, server, location20 bytesSkips compression until the response Content-Length meets the threshold.
gzip_typeshttp, server, locationtext/htmlAdds MIME types beyond text/html, which Nginx always treats as eligible when gzip is on.
gzip_varyhttp, server, locationoffAdds Vary: Accept-Encoding for cache correctness.
gzip_proxiedhttp, server, locationoffControls compression for requests Nginx identifies as proxied through the Via request header.
gzip_disablehttp, server, locationNo default valueDisables 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 reload over restart for 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-Length header) 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 Via header)
  • The default is off, which disables compression for proxied responses entirely
  • The value any enables compression for all requests that Nginx sees as proxied through a Via request header
  • Other options include expired, no-cache, no-store, private, no_last_modified, no_etag, and auth for selective compression based on request or response headers

gzip_vary

  • When enabled, adds a Vary: Accept-Encoding header 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-Agent patterns
  • The special value msie6 matches 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/jpeg or image/png because 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.

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.

Search LinuxCapable

Need another guide?

Search LinuxCapable for package installs, commands, troubleshooting, and follow-up guides related to what you just read.

Found this guide useful?

Support LinuxCapable to keep tutorials free and up to date.

Buy me a coffee Buy me a coffee

Before commenting, please review our Comments Policy.
Formatting tips for your comment

You can use basic HTML to format your comment. Useful tags currently allowed in published comments:

You type Result
<code>command</code> command
<strong>bold</strong> bold
<em>italic</em> italic
<blockquote>quote</blockquote> quote block

Got a Question or Feedback?

We read and reply to every comment - let us know how we can help or improve this guide.

Let us know you are human: