Websites & apps

Enable gzip compression in Apache with mod_deflate

Compress HTML, CSS, JavaScript and JSON in Apache with mod_deflate, add Brotli with mod_brotli for modern browsers and check the Content-Encoding header to prove it works.

BeginnerLinux server4 min read

Text files such as HTML, CSS, JavaScript and JSON shrink a lot when compressed, often to a fraction of their size. Smaller responses load faster, especially on mobile connections, and use less of your bandwidth. Apache does this with mod_deflate (gzip) and, on current versions, mod_brotli. This guide turns both on and shows how to confirm the result.

Before you start

  • Apache 2.4 running on Ubuntu, Debian, AlmaLinux or Rocky Linux.
  • sudo access and a site you can test, such as example.com.
  • If a CDN sits in front of your site, it may compress for you. Compressing at Apache as well is still useful for the CDN-to-origin traffic and for direct visitors.

Enable mod_deflate

Ubuntu and Debian

Bash
sudo a2enmod deflate

The Debian packages already include /etc/apache2/mods-available/deflate.conf, which compresses common text types. You can keep it or replace its contents with the config below.

AlmaLinux and Rocky Linux

mod_deflate is loaded by default. Check:

Bash
httpd -M | grep deflate

You should see deflate_module (shared). There is no compression rule by default, so you add one in the next step.

Choose which types to compress

Create a config file: /etc/apache2/conf-available/compression.conf on Ubuntu and Debian, or /etc/httpd/conf.d/compression.conf on AlmaLinux and Rocky.

Apache
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css
    AddOutputFilterByType DEFLATE text/javascript application/javascript application/x-javascript
    AddOutputFilterByType DEFLATE application/json application/ld+json application/xml
    AddOutputFilterByType DEFLATE application/rss+xml application/atom+xml
    AddOutputFilterByType DEFLATE image/svg+xml font/ttf font/otf application/vnd.ms-fontobject

    DeflateCompressionLevel 6
    Header append Vary Accept-Encoding env=!dont-vary
</IfModule>

Some notes:

  • Only list text formats. JPEG, PNG, WebP, MP4, ZIP and WOFF2 are already compressed. Compressing them again wastes CPU and saves nothing.
  • DeflateCompressionLevel 6 is a good balance. Higher levels cost more CPU for a tiny extra saving.
  • The Vary header tells caches to keep separate compressed and uncompressed copies. It needs mod_headers.

On Ubuntu and Debian, enable the headers module and the new file:

Bash
sudo a2enmod headers
sudo a2enconf compression

On AlmaLinux and Rocky, mod_headers is loaded by default.

Tip: If you use .htaccess instead of server config, the same AddOutputFilterByType lines work there, as long as AllowOverride includes FileInfo.

Add Brotli with mod_brotli

Brotli usually compresses text a little better than gzip, and every current browser supports it over HTTPS. Apache 2.4.26 and later include mod_brotli; whether your distribution builds it depends on the package.

Ubuntu and Debian

Bash
sudo a2enmod brotli

AlmaLinux and Rocky Linux

Check whether the module is present:

Bash
httpd -M | grep brotli
ls /usr/lib64/httpd/modules/ | grep brotli

If it is not shipped with your release, skip Brotli; gzip alone gives most of the benefit. Do not install modules from unknown third-party sources.

Where it is available, add this to the same compression.conf, above the deflate block so Apache prefers Brotli when the browser supports it:

Apache
<IfModule mod_brotli.c>
    AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/xml text/css
    AddOutputFilterByType BROTLI_COMPRESS text/javascript application/javascript
    AddOutputFilterByType BROTLI_COMPRESS application/json application/xml image/svg+xml
</IfModule>

Apache picks the encoding from the browser's Accept-Encoding header, so browsers without Brotli still get gzip.

Test and reload

Bash
sudo apachectl configtest
sudo systemctl reload apache2    # Ubuntu and Debian
sudo systemctl reload httpd      # AlmaLinux and Rocky

Enabling a new module on Ubuntu needs a restart rather than a reload: sudo systemctl restart apache2.

Check it works

Request a page and ask for gzip. curl shows response headers with -I, but some servers answer HEAD differently, so use a real GET and throw the body away:

Bash
curl -s -o /dev/null -D - -H "Accept-Encoding: gzip" https://example.com/ | grep -iE "content-encoding|vary"

You want:

Content-Encoding: gzip
Vary: Accept-Encoding

Test Brotli the same way with -H "Accept-Encoding: br"; the result should be Content-Encoding: br. Check a CSS and a JS file too, since a missing MIME type is the usual reason one file type is skipped.

In a browser, open developer tools, go to the Network tab, click a request and look at Response Headers.

Troubleshooting

  • No Content-Encoding header: the file's Content-Type is not in your list. Look at the response's Content-Type and add that exact type.
  • Header appears for HTML but not CSS or JS: older apps serve JavaScript as application/x-javascript or text/javascript. Include all three, as above.
  • Error Invalid command 'Header': mod_headers is not enabled. Run sudo a2enmod headers and restart.
  • Compression stops when PHP sends output: a PHP app may already compress its own output (zlib.output_compression). Use one or the other, not both, to avoid broken pages.
  • CPU rises noticeably: lower DeflateCompressionLevel, and make sure images and archives are not in the list.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.