Upgrading Ubuntu 22 LAMP Docker Image to HTTP/2
Introduction
I've been re-learning about Server Sent Events recently. One of the key aspects about them is that you soon get to a point where you realize you probably want to make sure that your webserver is serving up HTTP/2 connections rather than HTTP/1. This is because your browser will only allow a certain number of simultanous persistent connections to a single server/proxy. Typically this is 6, but is dependent on a per-browser basis so it may be more or less as outlined on this Stack Overflow post. HTTP/2 gets around this because it supports multiplexing. This means that we can utilize one connection for handling multiple responses.
Web Sockets Require HTTP/1
If your web application requires web-sockets, then it is worth knowing that they require HTTP/1 connections and are not supported by HTTP/2. Please bear this in mind if you also make use web-sockets. You may have luck switching to HTTP/3 in the future, which may support web sockets in future.
This Tutorial
This tutorial will outline how I converted my traditional Linux Apache MySQL PHP (LAMP) Docker image/container to switch over to supporting HTTP/2 and outline the various hiccups that had to be overcome, which explains why certain thing changed.
In a future tutorial, I will outline the steps to get HTTP/2 working in Nginx.
Steps
The first thing I did was enable the http2
module:
sudo a2enmod http2
...before then adding the following lines to any virtual host configs:
Protocols h2 http/1.1
After building and running with this setup, I was still getting http 1.1 back, so checked apache error logs which showed the following output:
The mpm module (prefork.c) is not supported by mod_http2. The mpm determines how things are processed in your server. HTTP/2 has more demands in this regard and the currently selected mpm will just not do. This is an advisory warning. Your server will continue to work, but the HTTP/2 protocol will be inactive.
Switching From Prefork To MPM Event
So I updated Dockerfile to do this:
RUN a2dismod mpm_prefork && a2enmod mpm_event
Unfortunately, that alone didn't work as build showed this error:
ERROR: The following modules depend on mpm_prefork and need to be disabled first: php8.2
... so in order to have http2 we would need to switch from the Apache PHP mod, to using FastCGI.
Switching To FastCGI
We need to remove the command to run a2enmod php8.2
...
...and removed the installation of the libapache2-mod-php8.2
package and replace it with the installation of php-fpm
Then we need to do:
a2enmod proxy_fcgi setenvif
We also need to enable the FPM configuraton
a2enconf php8.2-fpm
All of those changes resulted in the following diff in my Dockerfile:
New Php.ini Path
If you have any parts of your Dockerfile that edits the PHP ini file at /etc/php/8.2/apache2/php.ini
, you need to change the path to: /etc/php/8.2/fpm/php.ini
Don't Forget To Start The FPM Service!
Finally, now that we are using FPM instead of the built-in apache module, we need to make sure we start the FPM service in addition to apache now:
service php8.2-fpm start
I have my container run a BASH startup script, which is where it starts the services, so this change can be seen below:
Testing It Worked
Finally, build and run your Docker image with all of the changes. Open your browser and have the web development tools open (F12 in Firefox), before then navigating to your site.
- Make sure that you are using HTTPS. Although HTTP/2 does not explicitly require TLS/SSL, most browsers require it to be enabled, which pretty much makes it mandatory.
- Click on your Network tab.
- Click on one of the requests that hit your webserver, e.g. the root document.
- Click on the Headers tab.
- You should see HTTP/2 which shows that your webserver served up an HTTP/2 request.
Optional - Configuring Nginx Reverse Proxy
If you are running behind an Nginx reverse proxy that you manually deployed (rather than something like
Nginx Proxy Manager), then you will need to
update it to listen for HTTP2 requests by simply adding http2
to your server's listen statement like so:
Conclusion
We now have an Apache web server that's capable of serving up HTTP/2 requests. It will fall back to HTTP/1 if it needs to, which can be seen if we connect without HTTPS. Next time, we will look at doing the same thing for Nginx.
References
- Apache Docs - HTTP/2 guide
- Ricmedia - Enable HTTP/2 on an Apache Virtual Host & Ubuntu 22.04
- TutorialsPoint - How to Enable HTTP2.0 in Apache on Ubuntu?
- Enable HTTP/2 with Apache+PHP on Ubuntu
First published: 9th October 2023