Skip to content

HTTP/2 support in Apache

The HTTP/2 protocol:

HTTP/2 is the evolution of the world’s most successful application layer protocol, HTTP. It focuses on making more efficient use of network resources. It does not change the fundamentals of HTTP, the semantics. There are still request and responses and headers and all that. So, if you already know HTTP/1, you know 95% about HTTP/2 as well.

There has been a lot written about HTTP/2 and how it works. The most normative is, of course, its RFC 7540 (also available in more readable formatting, YMMV). So, there you’ll find the nuts and bolts.

But, as RFC do, it’s not really a good thing to read first. It’s better to first understand what a thing wants to do and then read the RFC about how it is done. A much better document to start with is http2 explained by Daniel Stenberg, the author of curl. It is available in an ever growing list of languages, too!

HTTP/2 support is included in Apache 2.4.17 and upwards.

Enabling http2 support in apache httpd on Debian Stretch is very simple:

ns:~# a2enmod http2
Enabling module http2.
To activate the new configuration, you need to run:
  systemctl restart apache2

The HTTP/2 protocol is implemented by its own httpd module, aptly named mod_http2. It implements the complete set of features described by RFC 7540 and supports HTTP/2 over cleartext (http:), as well as secure (https:) connections. The cleartext variant is named ‘h2c’, the secure one ‘h2’. For h2c it allows the direct mode and the Upgrade: via an initial HTTP/1 request.

After module activation, you need some basic configuration for it becoming active. I prefer to do the configuration per virtual host

Virtual host example (https)

<VirtualHost *:443>
 Protocols h2 http/1.1
 DocumentRoot /var/www/mydomain.tld
 ServerName mydomain.tld
 ServerAlias www.mydomain.tld
 ServerAdmin admin@mydomain.tld
 SSLCertificateFile /path/to/ssl_certs/fullchain.pem
 SSLCertificateKeyFile /path/to/ssl_certs//privkey.pem
 ErrorLog ${APACHE_LOG_DIR}/mydomain.tld-error_log
 CustomLog ${APACHE_LOG_DIR}/mydomain.tld-access_log combined env=!dontlog
</VirtualHost>

Virtual host example (http)

<VirtualHost *:80>
 Protocols h2c http/1.1
 DocumentRoot /var/www/mydomain.tld
 ServerName mydomain.tld
 ServerAlias www.mydomain.tld
 ServerAdmin admin@mydomain.tld
 ErrorLog ${APACHE_LOG_DIR}/mydomain.tld-error_log
 CustomLog ${APACHE_LOG_DIR}/mydomain.tld-access_log combined env=!dontlog
</VirtualHost>

Server PUSH

The HTTP/2 protocol allows the server to PUSH responses to a client it never asked for. The tone of the conversation is: “here is a request that you never sent and the response to it will arrive soon…”

But there are restrictions: the client can disable this feature and the server may only ever PUSH on a request that came from the client.

The intention is to allow the server to send resources to the client that it will most likely need: a CSS or javascript resource that belongs to an HTML page the client requested. A set of images that are referenced by a CSS, etc.

The advantage for the client is that it saves the time to send the request which may range from a few milliseconds to half a second, depending on where on the globe both are located. The disadvantage is that the client may get sent things it already has in its cache. Sure, HTTP/2 allows for the early cancellation of such requests, but still, there are resources wasted.

To summarize: there is no one good strategy on how to make the best use of this feature of HTTP/2 and everyone is still experimenting. So, how do you experiment with it in Apache httpd?

mod_http2 inspect response header for Link headers in a certain format:

Link ;rel=preload, ; rel=preload

If the connection supports PUSH, these two resources will be sent to the client. As a web developer, you may set these headers either directly in your application response or you configure the server via:

<Location /xxx.html>
    Header add Link ";rel=preload"
    Header add Link ";rel=preload"
</Location>

If you want to use preload links without triggering a PUSH, you can use the nopush parameter, as in:

Link ;rel=preload;nopush

or you may disable PUSHes for your server entirely with the directive

H2Push Off

And there is more:
The module will keep a diary of what has been PUSHed for each connection (hashes of URLs, basically) and will not PUSH the same resource twice. When the connection closes, this information is discarded.

References:

http://httpd.apache.org/docs/2.4/de/howto/http2.html
https://bagder.gitbooks.io/http2-explained/content/en/
https://en.wikipedia.org/wiki/HTTP/2

Published inLinuxWebservers