« Back to Web

Block HTTP requests for clients that don't offer data compression

This article has last been updated at .

Nginx has so many options, that it is easy to see some never in practice. One of those is checking incoming HTTP requests for the presence of the Accept-Encoding header. This header defines what types of data encoding is supported. For modern clients this often means compressed data transfers with brotli, deflate, gzip, or zstd. In other words, the server can look what it supports and choose one of the algorithms to send back data compressed. This translates in shorter data transfers, saving bandwidth, and a smoother browsing experience.

Example of header provided by the client:

Accept-Encoding: gzip, deflate, br, zstd

Block requests with missing Accept-Encoding header

If we want to block all HTTP requests where is no support for data encoding, then we have to look at this Accept-Encoding header. If it is empty, then we can decide to block it.

Next step is to return an error to the client. This is especially important for legitimate requests and clients, so that they know why they could not visit a page. Ironically, a modern browser does have all support for data encoding, so chances to see this are very small. Still, we should be good for other humans. For this reason we respond with HTTP code 406.

The HTTP 406 Not Acceptable client error response status code indicates that the server could not produce a response matching the list of acceptable values defined in the request’s proactive content negotiation headers and that the server was unwilling to supply a default representation.

This error code comes very close to why we won’t offer any data in return on the request.

Let’s implement this within the nginx configuration. Usually this is within the context of a location:

location / {

    # Block HTTP requests without data encoding support
    if ($http_accept_encoding = '') {
        return 406 "Please configure your HTTP client to enable data compression (see Accept-Encoding header)";
    }

    # ... other directives ...
}

After implementing the change, check your nginx configuration with nginx and the -t option:

nginx -t

Then restart the service, for Linux systems that is usually with systemctl.

systemctl restart nginx.service

Testing if things work as expected, is easy using curl:

# curl --head https://example.com/
HTTP/2 406 
date: Wed, 25 Dec 2024 12:41:41 GMT
content-type: application/octet-stream
content-length: 90
strict-transport-security: max-age=31536000; includeSubDomains; preload

Add the --compressed option to the command to test with data encoding enabled.

# curl --compressed --head https://example.com/
HTTP/2 200 
date: Wed, 25 Dec 2024 12:43:42 GMT
content-type: text/html
content-length: 7344
last-modified: Wed, 25 Dec 2024 00:11:44 GMT
...snipped output...

References

Relevant commands in this article

Like to learn more about the commands that were used in this article? Have a look, for some there is also a cheat sheet available.

See the full list of Linux commands for additional system administration tools.

Feedback

Small picture of Michael Boelen

This article has been written by our Linux security expert Michael Boelen. With focus on creating high-quality articles and relevant examples, he wants to improve the field of Linux security. No more web full of copy-pasted blog posts.

Discovered outdated information or have a question? Share your thoughts. Thanks for your contribution!

Mastodon icon

Related articles

Like to learn more? Here is a list of articles within the same category or having similar tags.