How To Enable HTTP/2 in Apache on Ubuntu 16.04

The internet is awesome. It can be used by governments to very efficiently spy on their citizens, it got Donald elected, and it’ll be mentioned in future history books as the main tool used in the second rise of fascism. There are also a few funny cat pictures.

Today’s internet connections are amazingly fast. You younglings might not believe this, but there was a time when we actually had to sit and wait for a website to appear. If you want to experience the internet speeds of the past, give 56k Emulator a try. It will give you the basic idea. And keep in mind that 56K modems were freakin’ fast when they became available.

But I digress. Sorta. Even though today’s internet connections are fast, the technology used to push propaganda around inside the tubes is old and slow. HTTP/1.1 was never intended to be used with the kind of content-heavy website we have today. Thankfully, there’s a new option available, the marvelous RFC-7540. Or HTTP/2, if you will.

HTTP/2 is a major revision of HTTP/1.1. Its main goal is to make web sites appear in your browser quicker, and with the need to send less data than with HTTP/1.1. The “number one HTTP server on the internet”, Apache 2 only has experimental support for HTTP/2. This means that it’s not available in the version Ubuntu 16.04 includes by default.

Once again, we have to turn to our PPA packaging hero Ondřej Surý for support. Not only does he maintain packages for the latest and greatest version of PHP (that we used here), he also makes sure Ubuntu users can be on the bleeding edge of Apache goodness.

Getting on the HTTP/2 Highway

Warning: As always when I give away free advice, I have to point out that you’re following them at your own risk. If your Ubuntu box catches fire when following the instructions below, you have only yourself to blame. Think about it: You’re following advice you got from some random guy on the internet. That’s not the best idea ever, is it?

These instructions assume that you’ve already got Apache2 installed, and that the sites you want to enable HTTP/2 for has TLS (HTTPS) enabled. If you don’t, and have no idea how to do this, please consult the internet. Log in to your Ubuntu box (if you’re doing it over SSH, your account is of course secured with 2FA). Then, run the following commands:

# Install add-apt-repository.
sudo apt-get install software-properties-common
# Add Surý's Apache2 PPA repository.
sudo add-apt-repository ppa:ondrej/apache2
# Update your local package list.
sudo apt-get update
# Upgrade Apache2 with the new packages from Surý.
sudo apt-get upgrade

When running the “upgrade” command, APT might tell you that a lot of the Apache2 packages are being kept back. If that’s the case, run the following commands:

# Force install of held back Apache2 packages
sudo apt-get install COPY-LIST-OF-KEPT-BACK-APACHE2-PACKAGES-HERE

Next, enable HTTP/2.

sudo a2enmod http2

Then, add the Protocols directive to the VirtualHost configuration of the sites you want to server over HTTP/2:

<VirtualHost *:443>
  ServerName your-awesome-site.com
  Protocols h2 http/1.1
</VirtualHost>

Finally, restart Apache2.

# Restart Apache2.
sudo service apache2 restart

All done. Your site is now being served using HTTP/2.

Or is it!?

Before we start the celebrations, we should probably check if your site is actually being served with HTTP/2. To do this, go to this HTTP/2 test tool, enter your site URL, and hit Test. If the test fails, we still have a little work to do. If it reports success, then good on you. There is no real reason to read any further.

For the unfortunate of you: For some weird reason, and I have absolutely no idea why, mod_http2 doesn’t work well with mod_php. Instead, Apache has to use PHP FastCGI to get HTTP/2 to work. To check if you’re using mod_php, run the following command:

sudo apache2ctl -M | grep php

If the command returns php7_module, or something similar, then mod_php is enabled. Let’s jump through the hoops to configure Apache to use PHP FastCGI instead.

First, we’ll disable mod_php. Write the following command all the way up to php, then press tab. This will fill out the blanks.

sudo a2dismod php[press tab]

I’m using running PHP 7.1, so in my case, the complete command is sudo a2dismod php7.1. From now on, I’ll use that version in all the examples. If you’re running another version, simply replace the version number in all commands where it’s used. The following set of commands installs all the necessary packages, enables required modules, and disables modules that are incompatible with the new modules. Then it restarts Apache and PHP FastCGI.

sudo apt install php7.1-fpm
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php7.1-fpm
sudo a2dismod mpm_prefork
sudo a2enmod mpm_event
sudo service apache2 restart
sudo service php7.1-fpm restart

Now, check your site in a browser to see if it still loads. If you’re getting error messages, typically 500 errors, then reverse the changes with the following commands:

sudo a2dismod mpm_event
sudo a2enmod mpm_prefork
sudo a2enmod php7.1
sudo service apache2 restart

Halp!

Calm down. Check your logs. The most likely culprit is the use of php_value and/or php_flag in your .htaccess files. At least that was the issue when my site started malfunctioning. These keywords are not supported in .htaccess by PHP FastCGI for some reason. Instead, they have to be in your php.ini file, or even better, .user.ini. I will not provide detailed instructions on how to fix these errors, since they can be fixed in different ways. Also, it’s not certain that your problem is the same as mine, it might be something entirely different. The internet is your best friend in this case.

There’s another major gotcha here as well. When you were using Apache’s mod_php, Apache itself handled everything PHP, including the configuration. Now, when you’re using PHP FastCGI, the php.ini files used is the one provided by PHP FastCGI. So if you had anything configured in /etc/php/7.1/apache2/php.ini, make sure you move it to /etc/php/7.1/fpm/php.ini. Or, create a symlink.

Also, if you change anything in the PHP FastCGI php.ini file, running sudo service apache2 reload has absolutely no effect. Now you have to reload the PHP FastCGI configuration instead with sudo service php7.1-fpm reload.

When you think you’ve solved all the errors, run the following commands to disable mod_php and enable PHP FastCGI again.

sudo a2dismod php7.1
sudo a2dismod mpm_prefork
sudo a2enmod mpm_event
sudo service apache2 restart

Well, that was quite the mouthful. Now it’s time to check your site with the HTTP/2 test tool again. The test should be successful now.

If it’s not then screw this shit. HTTP/2 isn’t mainstream yet anyway. Let’s watch some TV instead.


Feedback

This post has no feedback yet.

Do you have any thoughts you want to share? A question, maybe? Or is something in this post just plainly wrong? Then please send an e-mail to vegard at vegard dot net with your input. You can also use any of the other points of contact listed on the About page.


Caution

It looks like you're using Google's Chrome browser, which records everything you do on the internet. Personally identifiable and sensitive information about you is then sold to the highest bidder, making you a part of surveillance capitalism.

The Contra Chrome comic explains why this is bad, and why you should use another browser.