Using HTTP/2 in a Docker Compose system with Apache

The HTTP/2 network protocol already has a very good support since it was officially published in May 2015. It is great because it brings many benefits over HTTP/1.1 which include multiplexing, server-push, streaming prioritization, etc. This means that websites load faster because the resources get grouped in a single connection.

You can verify if a website is using HTTP/2 with the command line. For example, using the widely available curl command:

curl -I https://www.google.com

It will print the protocol in the first line of the output:

HTTP/2 200
content-type: text/html; charset=ISO-8859-1
...

This means that the website supports using HTTP/2. You can also check the protocol in Chrome's devtools, in the network tab, where you can add the "Protocol" column for each request. If it prints h2, it means that it is requesting the resource using HTTP/2.

If you have to set up a server with Apache and it is using reverse proxies to Docker containers, (which complicate it), you can get some tips here for what to change.

I will assume that there is an Apache server already configured to support HTTPS requests (by using SSLEngine on). This Apache server is in a Docker container within a Docker Compose network, and is the entry point for the requests.

First of all we have to enable the module in the Apache's site configuration:

LoadModule http2_module modules/mod_http2.so

This will load the core Apache module, but if you are also using reverse proxies like in this case, it also requires to use an additional module:

LoadModule proxy_http2_module modules/mod_proxy_http2.so

In Ubuntu systems you can enable the module with the a2enmod command.

Once the module has been loaded, you have to specify the protocols that the site can support:

Protocols h2 http/1.1

The order is important, it will give preference from left to right, starting from h2 if supported, then h2c (the unencrypted version) and then fallback to http/1.1.

We can define two reverse proxies to peer containers in the docker network with these lines:

ProxyPass /api h2c://api:5000
ProxyPassReverse /api http://api:5000

ProxyPass / h2c://static-site/
ProxyPassReverse / http://static-site/

Here it is using h2c because the internal containers don't have encryption. The reverse directive can use http directly. If you have to proxy to sevices using SSL, you will have to enable SSLProxyEngine from mod_ssl but that is not covered in this tutorial.

You can read more about the h2c properties in the Apache http2 and proxy_http2 modules docs.

We can't forget to also enable HTTP/2 in the proxied services, otherwise we will encounter a 503 response code when requesting our site because the proxied services can't handle the request.

If the proxied container is also using Apache, for example let's imagine that the container handling http://static-site/ in the block above is, it will be necessary to update the configuration in that container too. In this case it doesn't need the h2 protocol since the requests are proxied using h2c, so the changes would be:

LoadModule http2_module modules/mod_http2.so
# ...
Protocols h2c http/1.1

Now you can restart the Apache server in the containers for the configuration to take effect, and you should see that the clients start to use HTTP/2. This is a big benefit, which will improve loading times and also SEO for your website.

Back to the posts list
Loading ...