🚀 How I Upgraded My Site from HTTP/1.1 to HTTP/2 (and Why You Should Too)
TL;DR
My site was serving everything over plain old HTTP/1.1. Lighthouse yelled at me. I enabled HTTP/2 on Apache, reloaded the server, and improved performance (especially for users on slower networks) — without touching a single line of frontend code. 🔥
In this post I'll walk you through:
- What the Lighthouse warning means
- Why HTTP/2 matters
- How to enable HTTP/2 on Apache step by step
- How to confirm it worked
All examples use mock domains like mybrand.dev. Replace them with your real domain when you do it yourself 👇
1. The Problem Lighthouse Found 😬
When I ran a Lighthouse performance audit, I got this finding:
Modern HTTP HTTP/2 and HTTP/3 offer many benefits over HTTP/1.1, such as multiplexing.
The report listed all my assets (CSS, JS, SVG icons, favicon, PWA manifest, etc.) and showed they were all delivered with the protocol http/1.1.
Example from the audit:
| URL | Protocol |
|---|---|
| https://mybrand.dev/ | http/1.1 |
| https://mybrand.dev/css/style.css | http/1.1 |
| https://mybrand.dev/js/app.js | http/1.1 |
| https://mybrand.dev/img/logo.svg | http/1.1 |
| https://mybrand.dev/site.webmanifest | http/1.1 |
| https://mybrand.dev/android-chrome-512x512.png | http/1.1 |
And Lighthouse basically said:
“You could save ~40ms and improve LCP by ~50ms.”
⏱️ 40ms doesn’t sound like much on desktop Wi-Fi… …but on a mobile network with higher latency, HTTP/2 can be the difference between “fast” and “why is this site sticky and slow?”
2. Why HTTP/2 Is Better (in human language 🧠)
HTTP/1.1
- Browser opens several parallel connections.
- It requests files in a kind of queue.
- Lots of tiny round trips = overhead.
HTTP/2
- One secure connection.
- Many files delivered in parallel over that single connection (multiplexing).
- Smarter header compression.
- Lower latency especially on image/JS/CSS-heavy pages.
Think of HTTP/1.1 as “one item per trip to the kitchen” 🍽️ and HTTP/2 as “I brought a tray.” 🛎️
So if your homepage loads 20+ assets (icons, logos, scripts, favicons, manifests… all the usual stuff), HTTP/2 is free money.
3. The Good News 💡
My site was already using HTTPS (for example https://mybrand.dev/js/app.js), which means:
- SSL/TLS was configured ✅
- I didn’t need a CDN or to migrate to nginx ✅
- I just needed to turn on HTTP/2 in Apache
In other words: this is mostly a server configuration task, not an application rewrite.
4. The Server Setup 🖥️
The server in this example:
- Ubuntu 24.04
- Apache 2.4.x
- PHP-FPM 8.3 via a Unix socket
- VirtualHost on
:80(HTTP) and:443(HTTPS)
Here’s a (simplified) version of the HTTPS vhost before changes:
<VirtualHost *:443>
ServerName mybrand.dev
ServerAlias www.mybrand.dev
DocumentRoot /var/www/mybrand/public
<Directory /var/www/mybrand/public>
AllowOverride None
Require all granted
Options +FollowSymLinks -MultiViews
</Directory>
# Send only .php requests to PHP-FPM via socket
<FilesMatch "\.php$">
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost/"
</FilesMatch>
# Basic rewrite to front controller (Symfony/Laravel/custom app/etc.)
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
RewriteRule ^ index.php [QSA,L]
# TLS config (certificate paths are an example)
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/mybrand.dev/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/mybrand.dev/privkey.pem
</VirtualHost>
At this point, the site works over HTTPS… but it’s still serving http/1.1.
Let’s change that.
5. Step-by-step: Enabling HTTP/2 🔧
All commands below are run as
rootor withsudo.
Step 1. Make sure Apache has the HTTP/2 module
apachectl -M | grep http2
- If you get
http2_module (shared)→ perfect ✅ - If you get nothing → enable it:
a2enmod http2
We’ll reload Apache later.
Step 2. (Recommended) Use the modern Apache worker
Apache can run in different “MPM” modes. The one we want is usually mpm_event, because it handles many concurrent connections better — and that’s exactly what HTTP/2 does (lots of streams over one connection).
Check which MPM is active:
apachectl -M | grep mpm
If you see:
mpm_event_module→ you’re good ✅mpm_prefork_module→ that’s the old model, mainly for mod_php
If you're still on prefork and you’re using PHP-FPM (not mod_php), you can switch:
a2dismod mpm_prefork
a2enmod mpm_event
systemctl restart apache2
⚠️ Restart will briefly interrupt traffic. Do this during a quiet window.
If you’re already on mpm_event, skip this step.
Step 3. Tell Apache to actually speak HTTP/2
Edit your TLS vhost (/etc/apache2/sites-available/mybrand-ssl.conf, or similar — names vary).
Inside the <VirtualHost *:443> block, add this line:
Protocols h2 http/1.1
Now the vhost looks like this:
<VirtualHost *:443>
ServerName mybrand.dev
ServerAlias www.mybrand.dev
DocumentRoot /var/www/mybrand/public
<Directory /var/www/mybrand/public>
AllowOverride None
Require all granted
Options +FollowSymLinks -MultiViews
</Directory>
<FilesMatch "\.php$">
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost/"
</FilesMatch>
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
RewriteRule ^ index.php [QSA,L]
# 👇 This line enables HTTP/2 alongside HTTP/1.1
Protocols h2 http/1.1
# TLS config (example paths)
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/mybrand.dev/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/mybrand.dev/privkey.pem
</VirtualHost>
Why keep both?
h2= HTTP/2 for modern browsershttp/1.1= graceful fallback for older clients (some crawlers, embedded devices, etc.)
We do not add Protocols to the port 80 vhost. Browsers don't really use HTTP/2 over plain HTTP anyway.
Step 4. Reload Apache safely ✅
Before reloading, always lint the config:
apachectl configtest
If you see Syntax OK, apply the change:
systemctl reload apache2
(reload applies new config without fully stopping the service.)
6. How to Verify That HTTP/2 Is Live 🔍
Option A: curl (terminal nerd way 👨💻)
curl -I --http2 https://mybrand.dev/
If the request succeeds with no complaint, your server negotiated HTTP/2.
There’s also:
curl -I --http2-prior-knowledge https://mybrand.dev/
This one is stricter. If it fails, curl is basically saying “the server didn’t speak pure h2.”
Option B: Browser DevTools (designer-friendly way 🎨)
- Open Chrome.
- Go to your site.
- DevTools → Network tab.
- Right click the table header → enable the
Protocolcolumn. - Reload the page (Ctrl/Cmd + R).
You should now see h2 for requests instead of http/1.1.
That’s how you know Lighthouse will stop complaining about “Modern HTTP.”
7. What About HTTP/3? 🌐
- HTTP/2 runs over TCP.
- HTTP/3 runs over QUIC (UDP).
- HTTP/3 is even more resilient on mobile / high-loss networks.
Do you need it right now? Probably not for an MVP or portfolio site. Many teams ship HTTP/2 first and only add HTTP/3 later by:
- putting nginx or Caddy in front of Apache as a reverse proxy, or
- using a CDN that terminates HTTP/3 at the edge.
So: ship HTTP/2 first, celebrate, then evaluate HTTP/3 when you’re working on global performance or mobile-first traffic.
8. How to Explain This to Non-Infra People 👔
You can copy-paste this in a report / Slack / client email:
We enabled HTTP/2 support on the server, so the website can deliver multiple files (CSS, JS, icons, etc.) in parallel over a single secure connection. This reduces loading overhead, especially for mobile and slower connections, and improves metrics like Largest Contentful Paint. The change was done at the web server (Apache) level. No application code needed to change. ✅
That’s it. Sounds calm, sounds professional, sounds like value. 💼
9. Final Checklist ✅
- Site was serving all assets with
http/1.1 - Lighthouse warned about “Modern HTTP”
- We confirmed HTTPS was already active
- We enabled Apache’s
http2module - We added
Protocols h2 http/1.1to the TLS vhost (:443) - We reloaded Apache
- We verified
h2in DevTools / curl
Result: better perceived performance, better Lighthouse score, more modern infrastructure… with basically one config line and one module. 🏁
Bonus tip 🤓
If you’re still on mpm_prefork and mod_php, and you're serious about performance, consider moving to:
- PHP-FPM via socket
mpm_event- HTTP/2
That trio is the current “boring and good” stack for a lot of professional Apache + PHP servers.
👋 If you found this helpful and want a similar audit (performance, accessibility, SEO basics, Lighthouse scoring, PWA readiness), you can absolutely productize this as a service. You’re not “just fixing a header,” you’re helping clients serve faster pages — and that’s money in their conversion funnel. 💸