How to Enable Gzip Compression (Nginx, Apache, and .htaccess — With the Verify Step)

CodexFuse Team · 2026-11-04T06:53:19.235Z · 13 min read min read

If your site serves a 200 KB JavaScript bundle as a 200 KB download when the browser could have fetched it in 60 KB, the missing piece is almost always text compression. Learning how to enable gzip compression on your web server is one of the cheapest speed wins available: a few config lines, no code changes, and noticeably smaller responses for every visitor. This guide walks through the full server-side setup — the Nginx arc, the Apache arc, the .htaccess variant for shared hosting, and the verify step that proves it is working.

If you have never managed a web server before, the VPS hosting guide explains the self-hosted world this article lives in, and the Nginx server-block guide covers the config files you will be editing. If you just want to check whether a site is already compressed without touching a terminal, run it through a gzip compression checker first — the curl and DevTools checks below teach you to read the same evidence yourself.

What Does Enabling Gzip Compression Do?

Enabling gzip compression tells your web server to shrink text-based responses — HTML, CSS, JavaScript, JSON, SVG, XML — with the gzip algorithm before sending them to the visitor's browser. The browser advertises support with an Accept-Encoding: gzip request header, the server compresses the response and labels it with a Content-Encoding: gzip header, and the browser decompresses it invisibly. Pages render identically; the bytes on the wire are a fraction of the size.

The nginx documentation puts the payoff plainly: compression "often helps to reduce the size of transmitted data by half or even more." That is not a marketing figure — it is the reason text compression has been a standard PageSpeed recommendation for over a decade. Compression happens per response at request time, so there is nothing to pre-generate and no build step to add.

How Do I Enable Gzip Compression on Nginx?

Gzip on Nginx is a small set of directives in the http block of nginx.conf (or a file included by it). If you came here looking for how to enable gzip nginx, this is your section. Here is the full arc, then a table of what each line means:

  1. Open the main config. On Debian/Ubuntu that is usually /etc/nginx/nginx.conf; your site config in /etc/nginx/sites-available/ works too. The gzip directive is valid in the http, server, and location contexts.
  2. Add the gzip block inside the http block:
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 256;
gzip_buffers 16 8k;
gzip_types text/plain text/css text/xml text/javascript
           application/javascript application/json application/xml+rss
           image/svg+xml;
  1. Test and reload. Run sudo nginx -t to validate the config, then sudo systemctl reload nginx to apply it without dropping connections.

The directive table below pairs each line with its official default from the nginx documentation, so you know exactly what you changed:

DirectiveOfficial defaultWhat we set (and why)
gzipoffon — compression is disabled by default; nothing is compressed until you turn it on.
gzip_varyoffon — inserts Vary: Accept-Encoding so caches and CDNs do not serve a compressed response to a client that cannot handle it.
gzip_proxiedoffany — enables compression for responses going through proxies and CDNs; with the default, proxied responses skip compression entirely.
gzip_comp_level16 — scale of 1 to 9; the default 1 is deliberately conservative. Level 6 is the widely used balance between size and CPU.
gzip_min_length20256 — responses shorter than this are not compressed (compressing tiny payloads costs CPU for no visible gain). Length is measured only from the Content-Length response header.
gzip_typestext/htmlThe MIME types listed above. Note that text/html is always compressed once gzip is on — you never need to list it yourself.
gzip_buffers32 4k|16 8k16 8k — compression buffer sizing; defaults to one memory page (4K or 8K depending on platform).

One gotcha to be aware of: nginx logs the achieved ratio in the $gzip_ratio variable, which is handy for tuning. And if you later wonder why a type is not compressed, re-read the default row for gzip_types — with gzip on and no gzip_types line, only text/html responses are compressed, so CSS and JavaScript silently go out uncompressed.

How Do I Enable Gzip Compression on Apache?

On Apache, compression is handled by mod_deflate, and the steps are: enable the module, then declare which content types to compress. The arc differs slightly by distribution:

  1. Enable the module. On Debian/Ubuntu: sudo a2enmod deflate. On RHEL-family systems the module is usually present already — confirm with apache2ctl -t -D DUMP_MODULES | grep deflate (or httpd -M | grep deflate).
  2. Declare what to compress in your virtual host (or the server config). This is the module documentation's own sample configuration for common text-based content:
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/json
    DeflateCompressionLevel 6
</IfModule>
  1. Test and reload. Run sudo apachectl configtest, then sudo systemctl reload apache2.

Three details from the official documentation are worth knowing. First, DeflateCompressionLevel takes a value from 1 (less compression) to 9 (more compression); its default is simply "Zlib's default", so setting 6 is the explicit, readable choice. Second, mod_deflate sends a Vary: Accept-Encoding response header automatically — "to alert proxies that a cached response should be sent only to clients that send the appropriate Accept-Encoding request header" — so unlike nginx you do not need a separate vary directive. Third, the module documentation is explicit that "the gzip encoding is the only one supported to ensure complete compatibility with old browser implementations."

Also exclude images from compression at the config level. The docs' own pattern uses a request-URI match:

SetOutputFilter DEFLATE
SetEnvIfNoCase Request_URI "\.(?:gif|jpe?g|png)$" no-gzip

The next section explains why images belong in the skip list.

How Do I Enable Gzip Compression on Shared Hosting (.htaccess)?

On shared hosting you cannot edit the server config, but you do not need to. The AddOutputFilterByType directive is valid in .htaccess files (its context list explicitly includes .htaccess with an Override FileInfo requirement), so you can enable compression per directory:

<IfModule mod_deflate.c>
    # Compress text-based content
    AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css
    AddOutputFilterByType DEFLATE text/javascript application/javascript application/json
    AddOutputFilterByType DEFLATE image/svg+xml application/xml+rss
</IfModule>

Drop that block into the .htaccess file in your site's document root (often public_html/). Online this approach is usually called the enable gzip apache htaccess method, and the block above is the complete version of it. The <IfModule> wrapper is deliberate: on hosts where mod_deflate is not loaded, the block is silently skipped instead of throwing a 500 error. This is the same pattern WordPress caching plugins inject, which is why it pairs well with the broader WordPress speed guide — plugins and server config must not double-compress the same content.

One limitation to note: some fine-tuning directives (notably DeflateCompressionLevel) may only take effect from the main server config depending on how your host has configured overrides. The type list itself works fine from .htaccess.

How Do I Check That Gzip Compression Is Enabled?

The verify step is what separates a working setup from a hopeful one. It takes ten seconds and catches the mistakes the next section covers. If you are wondering how to check gzip compression enabled on any site, the canonical answer is: request the page with an Accept-Encoding: gzip header and look for Content-Encoding: gzip in the response. Run it right after every config change:

  1. Ask for a compressed response with curl. The Accept-Encoding: gzip header is the browser's compression handshake; this command replays it:
    curl -sI -H "Accept-Encoding: gzip" https://example.com | grep -i "Content-Encoding"
    You should see Content-Encoding: gzip in the response headers. If the header is missing, compression is not active for that URL — do not assume the whole site is compressed from one passing page.
  2. Read the same header in DevTools. Open your browser's developer tools, go to the Network tab, reload the page, click any HTML, CSS, or JS file, and look under Response Headers for content-encoding: gzip. This is the fastest check on a page you did not deploy yourself.
  3. Spot-check one of each type. Test an HTML page, a CSS file, and a JavaScript file. Nginx's default of compressing only text/html means the homepage can pass while every asset fails — the most common "but I enabled gzip" support thread on the internet.
  4. Confirm the Vary header. While you are in DevTools, look for vary: Accept-Encoding. If it is missing on nginx, you skipped gzip_vary on, and caches between your server and the visitor can serve compressed bytes to clients that cannot decompress them.

If curl is not your tool of choice, the online gzip compression checker runs the same header inspection from the browser — useful when you want to check someone else's site without a terminal.

What Should I Compress — and What Should I Skip?

The rule is simple: compress text, skip everything that is already compressed. Gzip shrinks content by finding repeated patterns; formats that are already compressed have no patterns left to find, so recompressing them wastes CPU and can even make files slightly larger.

Compress theseSkip theseWhy
HTML, CSS, JavaScript, JSON, XML, RSS—Text-based formats compress dramatically — often to half or less of their original size (nginx documentation).
SVG, web fonts (WOFF)WOFF2SVG and WOFF are text-ish and compress well; WOFF2 is already compressed internally (siteseoaudit.com).
—Images: JPEG, PNG, WebP, AVIF, GIFAlready compressed. "Never try to Gzip images (JPG, PNG) or videos, as they are already compressed. Re-compressing them can actually increase file size and waste CPU" (frontendchecklist.io).
—Video and audio: MP4, WebM, MP3Already compressed; "do not benefit much" from text compression (screpy.com).
—Archives and binaries: ZIP, .gz, RAR, executablesZIP and .gz are literally gzip-family output — compressing them again is pure CPU burn (screpy.com).
—Very small files (under ~1 KB)The gzip header overhead can exceed the savings; that is the point of gzip_min_length.

The official Apache documentation makes the same point in config form, excluding image extensions from its deflate filter with SetEnvIfNoCase Request_URI "\.(?:gif|jpe?g|png)$" no-gzip. When in doubt, measure with $gzip_ratio on nginx or your server logs rather than guessing.

Gzip vs Brotli: Which Should I Use?

Gzip and Brotli are the two text-compression algorithms browsers support, and the comparison has a clear hierarchy. Brotli is Google's newer algorithm — the Google Open Source Blog announced in 2015 that the team had "developed and open sourced a new algorithm, the Brotli compression algorithm," noting it achieves "20–26% higher compression ratios over Zopfli" while being "roughly as fast as zlib's Deflate implementation."

Google's own Lighthouse guidance states the policy plainly: "If the browser supports Brotli (br) you should use Brotli because it can reduce the file size of the resources more than the other compression algorithms." And the fallback rule: "Use GZIP as a fallback to Brotli. GZIP is supported in all major browsers, but is less efficient than Brotli." So the correct answer is not either/or — it is Brotli first, gzip as the universal fallback.

The catch is setup effort. On Apache, Brotli is a stock module since 2.4.26 (mod_brotli), configured almost identically to gzip:

<IfModule mod_brotli.c>
    AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/xml text/css text/javascript application/javascript
</IfModule>

The quality setting defaults to 5 — "a reasonable balance for dynamic content" per the documentation — and notably, "quality 4 is roughly equivalent to gzip level 6", which makes the tuning math easy. On nginx, however, there is no stock Brotli module: it does not appear anywhere in the official module index, so you must build or install the third-party ngx_brotli module first (Clearleft: "Nginx still does not have brotli support built in"). That installation cost is why this guide's config blocks lead with gzip — gzip is batteries-included everywhere, and a working gzip setup beats a half-finished Brotli migration.

5 Common Gzip Mistakes

Every one of these shows up in real support threads, and every one is caught by the verify step above:

  1. Only HTML is compressed. On nginx, gzip on; with no gzip_types compresses text/html and nothing else — CSS and JS go out full-size. Always declare your types explicitly.
  2. Missing Vary header behind a CDN. Without gzip_vary on (nginx) — Apache sends it automatically — an edge cache can serve your compressed response to a client that never asked for compression.
  3. Compression level left at the default. nginx's default gzip_comp_level is 1, the most conservative setting; most guides recommend 4–6 for the balance between size and CPU. The default exists to protect busy servers, not to be optimal.
  4. Proxied responses skip compression. nginx's gzip_proxied defaults to off; if your app sits behind a reverse proxy or CDN, compression silently does nothing until you set it.
  5. Double compression. A CDN, a WordPress plugin, and the web server can all try to compress the same response. Verify with curl against the origin directly and against the CDN URL, and keep one layer responsible.

Sources

Frequently Asked Questions

Does enabling gzip compression slow down my server?

Slightly, in exchange for much faster transfers. Compression trades a little CPU per response for a much smaller download — and the nginx documentation notes responses often shrink "by half or even more", which matters far more than the CPU cost on typical hardware. If CPU is your constraint, keep gzip_comp_level at the default 1 or move compression to static pre-compression; for most sites, level 4–6 is the accepted balance.

Why is my site still failing text-compression audits after I enabled gzip?

The most common cause is the gzip_types trap: on nginx, gzip on; alone compresses only text/html, so audit tools flag your CSS and JavaScript. Add the types explicitly and re-run the curl check per asset type. Other causes: the response came from a cache or CDN layer (set gzip_vary on and gzip_proxied any), or the URL you tested serves already-compressed content.

Can I enable gzip compression on shared hosting?

Yes — that is what the .htaccess variant is for. Add the <IfModule mod_deflate.c> block from this guide to your document root's .htaccess file; no server restart needed, and the <IfModule> wrapper means nothing breaks if your host lacks the module. You just cannot tune directives like DeflateCompressionLevel from .htaccess on most hosts.

Is Brotli better than gzip?

Yes, for size — Brotli compresses 20–26% better than gzip's close cousin Zopfli at roughly the same speed, per Google's announcement, and Lighthouse recommends Brotli first with gzip as fallback. The catch is effort: Apache ships mod_brotli since 2.4.26, but nginx needs the third-party ngx_brotli module installed. Enable gzip everywhere first; add Brotli when the easy win is banked.

Do I still need gzip if I use a CDN?

Usually yes, at the origin. Many CDNs compress at the edge, but if your origin sends uncompressed responses, dynamic content that bypasses the cache travels full-size. Set gzip_proxied any and gzip_vary on on nginx so origin compression works correctly with the proxy layer, then verify with curl both directly against the origin and through the CDN URL.

Featured on Twelve Tools Hunt for Tools Featured on LaunchBuff Launch Llama Tools Launch your MCP Top Web Development Companies in the US - OnToplist.com Designer Listings Listed on SeeWhatNewAI