Web hosting · Practical guide

Enable HTTP compression and verify gzip, cache variation and payload savings

Configure text compression in Apache or NGINX, compare identity and gzip responses and avoid cache and security mistakes in production.

Programming code on a computer screen

HTTP compression reduces the bytes needed to transfer text such as HTML, CSS, JavaScript and JSON. It does not fix slow database queries, oversized images or a distant origin, and a configuration line is not proof that the response is compressed. Verify negotiation, cache behavior and the actual size difference on representative content.

Measure the uncompressed response first

Save identity and gzip representations of a public text page
curl --silent --show-error --fail \
  -H 'Accept-Encoding: identity' -D identity.headers \
  -o identity.body https://example.com/
curl --silent --show-error --fail \
  -H 'Accept-Encoding: gzip' -D gzip.headers \
  -o gzip.body https://example.com/
grep -Ei '^(HTTP/|content-type:|content-encoding:|vary:)' gzip.headers
wc -c identity.body gzip.body

The second command requests gzip without curl's automatic decompression option, so a correctly encoded response is saved as compressed bytes. Confirm Content-Encoding before treating the byte counts as a compression comparison. A server can legally choose an identity response, and dynamic page changes can make two requests differ for reasons unrelated to encoding.

Use public, non-personalized content for this comparison. Save temporary response files outside the document root and remove them when finished if they contain anything sensitive. A small number of requests is enough to establish basic behavior.

Configure Apache text compression at the supported scope

Example Apache configuration with mod_deflate enabled
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/css
    AddOutputFilterByType DEFLATE application/javascript application/json
    AddOutputFilterByType DEFLATE application/xml text/xml image/svg+xml
</IfModule>

Place the rules in the virtual-host configuration or an allowed .htaccess context according to your hosting setup. The module must be loaded and the relevant overrides permitted. An IfModule block avoids a configuration error when the module is absent, but it can also silently do nothing; always test the response.

Apache mod_deflate adds Vary: Accept-Encoding for its negotiation. Preserve that behavior through reverse proxies and caches so a compressed representation is not incorrectly served to a client that cannot decode it. Check the final public headers rather than assuming the origin headers survive every intermediary.

Configure NGINX at the correct layer

Example NGINX http or server configuration
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 4;
gzip_types text/plain text/css application/javascript application/json
           application/xml text/xml image/svg+xml;

NGINX handles text/html with gzip without adding it to gzip_types. Review inherited settings, proxy behavior and any CDN compression before applying this example. A moderate level is a starting point for measuring CPU cost against transfer savings, not a universal optimum.

Validate before reloading the installed server
sudo nginx -t
# Reload only after the configuration test succeeds:
sudo systemctl reload nginx

For Apache on Ubuntu, use apache2ctl configtest and reload the apache2 service instead. Run only the branch for the service you administer. A successful syntax check does not prove that a particular response passes through the intended location or virtual host.

Check integrity, caching and client decoding

Inspect and test the gzip body only after confirming its encoding
gzip -t gzip.body
gzip -dc gzip.body > decoded.body
cmp identity.body decoded.body

# curl negotiates a supported encoding and decodes it automatically here:
curl --compressed --silent --show-error --fail \
  --output /dev/null https://example.com/

The comparison is meaningful only when the underlying content stayed identical. Dynamic timestamps, tokens or personalized data can cause cmp to differ even when compression is correct. Use a stable CSS file or another controlled text resource when you need a deterministic check.

Inspect Vary, Content-Encoding and the cache policy at the customer-facing endpoint. Some caches normalize encodings internally; follow that product's documented behavior. Do not manually set a fixed Content-Length for a response that a compression filter transforms.

Choose content types and security boundaries deliberately

Already compressed formats such as JPEG, WebP and ZIP usually provide little benefit from another compression pass. Small responses may also cost more CPU and latency than they save. Measure representative files and preserve appropriate cache lifetimes for versioned assets.

Compressing responses that combine secrets with attacker-controlled reflected input can expose compression side channels. Review sensitive authenticated responses with the application's security guidance rather than enabling compression indiscriminately everywhere. Compression is an optimization, not encryption or an access-control boundary.

Evaluate the result alongside application performance

Compare transferred bytes, total request time and server CPU under normal authorized traffic. If the first byte remains slow while the body becomes smaller, investigate application work, cache misses or backend dependencies. If images dominate the page weight, image sizing and format choices may matter more than another gzip level.

Record the configuration location and the endpoint checked so future CDN or server changes can be tested the same way. The deployment is complete when the public response negotiates correctly, caches safely and improves the measured workload without an unacceptable resource cost.

Primary documentation

← Back to all guidesDiscuss your hosting setup ↗