HTTP/2 sends many requests in parallel over a single TCP connection and compresses headers, which makes pages with lots of assets load faster than over HTTP/1.1. Browsers only use HTTP/2 over TLS, and the protocol is negotiated during the TLS handshake through ALPN, so enabling it is usually a one-line change once HTTPS works. In this tutorial you will enable HTTP/2 on Nginx and on Apache in Ubuntu 24.04, move Apache to the event MPM that HTTP/2 requires, and verify the result from the command line.

Prerequisites

To follow this tutorial you need:

  • A server running Ubuntu 24.04 LTS, for example a CubePath VPS, with a non-root user that has sudo privileges.
  • Nginx or Apache installed from the Ubuntu repositories, serving a site for your_domain (replace this placeholder with your domain).
  • A valid TLS certificate for the site, for example from Let's Encrypt with Certbot. HTTP/2 works with any certificate, but browsers refuse it over plain HTTP.
  • Port 443 open in UFW (sudo ufw allow 'Nginx Full' or sudo ufw allow 'Apache Full').

First, confirm whether HTTP/2 is already active. The -w '%{http_version}' option makes curl print the protocol it negotiated:

curl -s -o /dev/null -w '%{http_version}\n' https://your_domain
1.1

If it prints 2, HTTP/2 is already enabled and you only need the verification section.

Follow the Nginx section or the Apache section, depending on your web server.

Enabling HTTP/2 in Nginx

Step 1 - Checking the Nginx version

The syntax depends on the Nginx version. Ubuntu 24.04 ships Nginx 1.24:

nginx -v
nginx version: nginx/1.24.0 (Ubuntu)

The Ubuntu package is built with the HTTP/2 module. You can confirm it:

nginx -V 2>&1 | grep -o with-http_v2_module
with-http_v2_module

Step 2 - Adding HTTP/2 to the server block

Open the configuration of your HTTPS site:

sudo nano /etc/nginx/sites-available/your_domain

Find the listen 443 ssl lines. If Certbot configured the site, they end with # managed by Certbot. Add http2 to both the IPv4 and IPv6 lines:

server {
    server_name your_domain www.your_domain;

    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;

    # ... rest of your configuration
}

HTTP/2 is enabled per IP address and port, not per site. If several server blocks share port 443, enabling it on one enables it for all of them, and Nginx warns if they are inconsistent, so add http2 to every listen 443 line.

Step 3 - Testing and reloading Nginx

Check the syntax and reload:

sudo nginx -t
sudo systemctl reload nginx
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Continue with the verification section below.

Enabling HTTP/2 in Apache

Step 1 - Switching Apache to the event MPM

Apache's HTTP/2 support comes from mod_http2, which is included in the apache2 package on Ubuntu 24.04 (Apache 2.4.58). It does not work with the prefork MPM: if Apache runs with prefork, it logs a warning and keeps serving HTTP/1.1 only. Check which MPM is active:

sudo apache2ctl -V | grep -i mpm
Server MPM:     prefork

If the output is event, skip to Step 2.

Prefork is usually active because libapache2-mod-php (mod_php) requires it. The replacement is PHP-FPM, which runs PHP in a separate service and works with the event MPM. Install it (Ubuntu 24.04 ships PHP 8.3):

sudo apt update
sudo apt install php8.3-fpm

Disable mod_php and prefork, then enable the event MPM and the modules that connect Apache to PHP-FPM:

sudo a2dismod php8.3 mpm_prefork
sudo a2enmod mpm_event proxy_fcgi setenvif
sudo a2enconf php8.3-fpm

If your server doesn't use PHP, you only need to swap the MPM: sudo a2dismod mpm_prefork and sudo a2enmod mpm_event.

Make sure PHP-FPM is running, then restart Apache (changing the MPM requires a full restart, not a reload):

sudo systemctl enable --now php8.3-fpm
sudo apache2ctl configtest
sudo systemctl restart apache2

Confirm the change:

sudo apache2ctl -V | grep -i mpm
Server MPM:     event

If you use PHP, open a PHP page and check that it still works. PHP-FPM reads its settings from /etc/php/8.3/fpm/php.ini, not /etc/php/8.3/apache2/php.ini, so copy over any custom values such as upload_max_filesize or memory_limit and run sudo systemctl restart php8.3-fpm.

Step 2 - Enabling mod_http2

Enable the module:

sudo a2enmod http2

Verify that it is loaded after the next restart with sudo apache2ctl -M | grep http2, which should print http2_module (shared).

Step 3 - Enabling the h2 protocol

Loading the module isn't enough; you also have to allow the protocol with the Protocols directive. You can set it globally for every virtual host or only for one site. To enable it globally, create a configuration snippet:

sudo nano /etc/apache2/conf-available/http2.conf
Protocols h2 http/1.1

The order sets preference: Apache offers h2 first and falls back to HTTP/1.1 for clients that don't support it. Enable the snippet, test and restart:

sudo a2enconf http2
sudo apache2ctl configtest
sudo systemctl restart apache2
Syntax OK

To enable HTTP/2 for a single site instead, put the same Protocols h2 http/1.1 line inside its <VirtualHost *:443> block, for example in /etc/apache2/sites-available/your_domain-le-ssl.conf if Certbot created it.

Verifying HTTP/2

Run the curl check again. Ubuntu's curl is built with HTTP/2 support:

curl -sI https://your_domain | head -n 1
HTTP/2 200

You can also see the ALPN negotiation directly with OpenSSL. This asks the server for h2 during the TLS handshake:

echo | openssl s_client -connect your_domain:443 -servername your_domain -alpn h2 2>/dev/null | grep ALPN
ALPN protocol: h2

If the server doesn't offer HTTP/2, the line reads No ALPN negotiated.

In a browser, open the developer tools, go to the Network tab, right-click the column headers to enable the Protocol column and reload the page. Requests to your domain should show h2.

Settings that no longer apply

Older HTTP/2 guides recommend a few things you should skip today:

  • Server push (http2_push in Nginx, H2Push in Apache). Chrome and Firefox removed support for it, and since Nginx 1.25.1 the push directives are obsolete and ignored. Use <link rel="preload"> in your HTML or 103 Early Hints instead.
  • Cipher blacklists specific to HTTP/2. With TLS 1.2 and 1.3 and the default cipher lists of Ubuntu 24.04, or the Certbot options file, all offered ciphers are acceptable for HTTP/2.
  • Domain sharding and asset concatenation. These were workarounds for HTTP/1.1's connection limits. With HTTP/2, a single connection carries all requests, and splitting assets across hostnames makes things slower.

Troubleshooting

curl still shows HTTP/1.1 on Nginx. Check that every listen 443 line for that IP and port has http2, and that you reloaded Nginx. Run sudo nginx -T | grep "listen.*443" to see the effective configuration of all sites.

Apache logs "The mpm module (prefork.c) is not supported by mod_http2". Prefork is still active. Repeat Step 1 of the Apache section; a2dismod php8.3 must succeed first, because mod_php keeps prefork enabled.

Apache configtest fails after disabling mod_php with "Invalid command 'php_value'". Your virtual host or an .htaccess file contains php_value or php_flag directives, which only exist in mod_php. Move those settings to /etc/php/8.3/fpm/php.ini or to a .user.ini file in the document root.

PHP files download instead of running after switching to PHP-FPM. The php8.3-fpm configuration isn't enabled. Run sudo a2enconf php8.3-fpm and sudo systemctl reload apache2, and check that php8.3-fpm is active with systemctl status php8.3-fpm.

HTTP/2 works directly but not through a proxy or CDN. The protocol is negotiated per connection. If a load balancer or CDN terminates TLS in front of your server, HTTP/2 must be enabled there as well.

Conclusion

Your web server now negotiates HTTP/2 with browsers through ALPN, and falls back to HTTP/1.1 for older clients. On Apache, the switch to the event MPM and PHP-FPM also lowers memory usage under load. As next steps, review your TLS settings with the SSL Labs Server Test, enable compression and caching headers for static assets, and consider putting Nginx in front of your application as a reverse proxy.