Skip to content

Instantly share code, notes, and snippets.

@GAS85
Last active March 7, 2024 16:11
Show Gist options
  • Star 37 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save GAS85/38eb5954a27d64ae9ac17d01bfe9898c to your computer and use it in GitHub Desktop.
Save GAS85/38eb5954a27d64ae9ac17d01bfe9898c to your computer and use it in GitHub Desktop.
How to Enable HTTP/2 in Apache 2.4 on Ubuntu 20.04

Based on https://gist.github.com/GAS85/8dadbcb3c9a7ecbcb6705530c1252831

Requirements

  • A self-managed VPS or dedicated server with Ubuntu 20.04 running Apache 2.4.xx.
  • A registered domain name with working HTTPS (TLS/SSL). HTTP/2 only works alongside HTTPS because most browsers, including Firefox and Chrome, don’t support HTTP/2 in cleartext (non-TLS) mode.

Step 1: Install Apache2

Per default it will be apache2 version 2.4.41 what is enought for http2 support.

  sudo apt install apache2

Step 2: Tell Apache to use PHP FastCGI

You want to make Apache use a compatible PHP implementation by changing mod_php to php-fpm (PHP FastCGI). If your website or app breaks on FastCGI, you can always revert back to mod_php until further troubleshooting.

Install PHP FastCGI module for PHP 7.4, it is default version for Ubuntu 20.04

sudo apt install php7.4-fpm 

Enable required modules, proxy_fcgi and setenvif:

sudo a2enmod proxy_fcgi setenvif

Enable php7.4-fpm:

sudo a2enconf php7.4-fpm 

Disable the mod_php module:

sudo a2dismod php7.4

Restart Apache:

sudo service apache2 restart

Step 3: Change MPM from "prefork" to "event"

(This step is not needed for Ubuntu 22.04 and above)

Since the default "prefork" MPM (Multi-Processing Module) is not fully compatible with HTTP/2, you’ll need to change Apache’s current MPM to "event" (or "worker"). This is shown by the error message in Apache versions greater than 2.4.27 as – AH10034: The mpm module (prefork.c) is not supported by mod_http2.

Keep in mind that your server requires more horsepower for HTTP/2 than for HTTP/1.1, due to the multiplexing feature and other factors. That said, smaller servers with low traffic may not see much difference in performance.

First, disable the "prefork" MPM:

sudo a2dismod mpm_prefork 

Enable the "event" MPM:

sudo a2enmod mpm_event 

Restart Apache2 and PHP 7.4:

sudo service apache2 restart && sudo service php7.4-fpm restart

Step 4: Add a line to your Virtual Host file

Add the following line to your site’s current Virtual Host config file. This can go anywhere between the ... tags. If you want to serve HTTP/2 for all your sites, add this to your global /etc/apache2/apache2.conf file instead of per each individual site’s Virtual Host file.

Protocols h2 h2c http/1.1

Explanation: h2 is TLS-encrypted HTTP/2, h2c is cleartext HTTP/2, and http/1.1 is ordinary HTTP/1.1.

Having http/1.1 at the end of the line provides a fallback to HTTP/1.1, while h2c is not strictly necessary.

Step 5: Enable the mod_http2 Apache module

Now you can enable the http2 module in Apache:

sudo a2enmod http2

Check Apache2 config and if no errors, restart Apache:

sudo apachectl configtest && sudo service apache2 restart

Step 6 create http2.conf for entire Server HTTP2

Create a new http2.conf

sudo nano /etc/apache2/conf-available/http2.conf

and add all the following rows:

<IfModule http2_module>
    Protocols h2 h2c http/1.1
    H2Direct on
</IfModule>

Enable the http2.conf by running

sudo a2enconf http2

Check Apache2 config and if no errors, restart your Apache2

sudo apachectl configtest && sudo service apache2 restart

and enhance your ssl-vhost file (default-ssl.conf):

sudo nano /etc/apache2/sites-available/default-ssl.conf

Amend in your configuration file:

...
Protocols h2 h2c http/1.1
H2Push on
H2PushPriority * after
H2PushPriority text/css before
H2PushPriority image/jpg after 32
H2PushPriority image/jpeg after 32
H2PushPriority image/png after 32
H2PushPriority application/javascript interleaved
...

P.S. All in one command (you still have to edit your VirtualHost and ssl config):

sudo apt update
sudo apt upgrade
sudo apt install apache2 php7.4-fpm 
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php7.4-fpm 
sudo a2dismod php7.4 
sudo service apache2 restart
sudo a2dismod mpm_prefork 
sudo a2enmod mpm_event 
sudo service apache2 restart 
sudo service php7.4-fpm restart
sudo a2enmod http2
sudo service apache2 restart
sudo echo "<IfModule http2_module>" > /etc/apache2/conf-available/http2.conf
sudo echo "Protocols h2 h2c http/1.1" >> /etc/apache2/conf-available/http2.conf
sudo echo "H2Direct on" >> /etc/apache2/conf-available/http2.conf
sudo echo "</IfModule>" >> /etc/apache2/conf-available/http2.conf
sudo a2enconf http2
sudo apachectl configtest && sudo service apache2 restart
@bci24
Copy link

bci24 commented Mar 13, 2021

Per default it will be apache2 version 2.4.29 what is enought for http2 support.

the default version in ubuntu 20.04 is apache 2.4.41

After config the apache2.4.46 (upgraded the apache2 from 2.4.41 -> 2.4.46 in ubuntu 20.04), php7.4.3 for http/2 still load the http/1.1

Testing:

curl -I --http2 https:/my-domain.com
HTTP/1.1 200 OK
Date: Sat, 13 Mar 2021 12:03:26 GMT
Server: Apache/2.4.46 (Ubuntu)
Upgrade: h2
Connection: Upgrade
Content-Type: text/html; charset=UTF-8

I am not using php-fpm. I am using php-cli ... for laravel apps.

Have any idea why it says

Upgrade: h2
Connection: Upgrade

?

@GAS85
Copy link
Author

GAS85 commented Mar 16, 2021

Not sure, I try with FPM and curl command works fine...

curl -I --http2 https://my-domain.com
HTTP/2 301 
date: Tue, 16 Mar 2021 15:50:58 GMT
server: Apache
x-robots-tag: none
strict-transport-security: max-age=15552000; includeSubDomains; preload
public-key-pins: pin-sha256="xxx"; pin-sha256="xxx"; pin-sha256="xxx"; pin-sha256="xxx"; includeSubDomains; max-age=2592000;
referrer-policy: strict-origin-when-cross-origin
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
x-frame-options: SAMEORIGIN
content-type: text/html; charset=UTF-8

Could be that you only sends HTTP2 headers, but no really possibility to upgrade?

@RobertMatkulcik
Copy link

RobertMatkulcik commented Dec 18, 2022

Hi, Thx for this great tutorial.
Can you tell me how to enhance ssl-vhost file (default-ssl.conf)? Where to put thath code?
Is this really necessary, or I can skip this step?
Sorry to many question marks :D

@delgh1
Copy link

delgh1 commented Mar 6, 2023

Hi, thanks for the tutorial.
On Ubuntu 22.04 LTS (with Apache 2.4.52 as of today), MPM is already "event", so step 3 is no longer necessary.

@GAS85
Copy link
Author

GAS85 commented Mar 6, 2023

Cool, thanks! I did update with a note.

@xTheSilentManx
Copy link

Hi, thx for the tutorial. however we have the same problem as bci where the h2 for upgrade is activated but still the site loads http/1.1
I also did other tutorials but still can't make it http2. It still shows this:
HTTP/1.1 200 OK
Cache-Control: no-cache, private
Keep-Alive: timeout=5, max=100
Upgrade: h2
Content-Type: text/html; charset=UTF-8
Age: 2949
Server: Apache/2.4.58 (Ubuntu) Microsoft-HTTPAPI/2.0
Referrer-Policy: strict-origin-when-cross-origin
Strict-Transport-Security: max-age=31536000; includeSubDomains
sw-invalidation-states:
X-Content-Type-Options: nosniff
X-Frame-Options: deny
Date: Wed, 29 Nov 2023 08:59:43 GMT

I checked our certificate and other things. Everything supports anything.

@bci24
@GAS85

@GAS85
Copy link
Author

GAS85 commented Nov 29, 2023

Why you think it is not working? You see Upgrade: h2 Line, this is an offer to upgrade to HTTP2 that telling your client about this possibility. You can check with curl if particular Server Supports HTTP 1.1. and / or HTTP 2:

# http1.1
curl -I --http1.1 https://github.com      
HTTP/1.1 200 OK
Server: GitHub.com
...
# http2
curl -I --http2 https://github.com
HTTP/2 200 
server: GitHub.com
...

If this command will work, then server supports http2, but client not.

@xTheSilentManx
Copy link

xTheSilentManx commented Nov 29, 2023

image

Those files with h2 and h3 are external data.

I understand that the server does support http2, but the domain will be loaded as http/1.1
we also used php-fpm and updated everything. with both curl commands in the first line there will be "HTTP/1.1 200 ok" but no "Http/2 200" :(

We can't see if we made a mistake, but we tested everything.

@GAS85
Copy link
Author

GAS85 commented Nov 30, 2023

  1. Just wondering if you call curls to check http2 from the LOCALHOST of the server. Will it work???
  2. How you terminate your TLS? It could be that your browser does not support it, like very old Safary. Try test is with https://www.ssllabs.com/ssltest, e.g. I have this output where I can clearly see that some browsers can update to h2 (green one)

image

@xTheSilentManx
Copy link

@GAS85 yes, I used curls to check http2.

well... ssllabs shows me this:
image
and this:
Screenshot 2023-12-12 113550

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment