Skip to content

Instantly share code, notes, and snippets.

@GAS85
Last active February 10, 2025 08:45
Show Gist options
  • Save GAS85/89be86e482651e804f0fa2b04ce60083 to your computer and use it in GitHub Desktop.
Save GAS85/89be86e482651e804f0fa2b04ce60083 to your computer and use it in GitHub Desktop.
How to Enable HTTP/3 in Apache 2.4 on Ubuntu 24.04

Requirements

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

Architecture

After multiple tries with apche2 recompiling with a different modules to support quic and http3, I simply run nginx container that will overtake only UDP traffic and forward it to the apache2 as http2 via TCP. So, no, it is not real "http3 apache2 support", but works pretty well and you do not need to change anything on your Apache2 sever.

     User                                                                
┌────── http                                                             
│┌───── https (http2)                                                    
││    - https (http3)──────────────3────────────────────────────────────┐
1│                 ┌───────────────────┐    ┌────────────────────────┐  │
││                 │                   │    │                        │  │
│2                 │    Apache2        │    │       Docker           │  │
││                 │                   │    │                        │  │
└┼─────────────────┼  http  - 80  TCP  │    │ ┌────────────────────┐ │  │
 │                 │                   │    │ │                    │ │  │
 └─────────────────┼  https - 443 TCP──┼─4┐ │ │     nginx          │ │  │
                   │                   │  │ │ │                    │ │  │
                   ├───────────────────┘  └─┼─┼───https - 443 UDP ─┼─┼──┘
                   │        ┌───────5───────┼─┼                    │ │   
                   │        │               │ └────────────────────┘ │   
                   │        │               └────────────────────────┘   
                   │        │                                            
                   └─6──────┴─/etc/letsencrypt/live/FQDN                 

I tries to paint how it works. We do have our Apache2 server that runs on ports 80 and 443 for TCP traffic. Now we will create simple nginx configuration to enable http3 support via UDP and forward it to our apache2 in a http2 form.

  1. User called our service via http and get an aswer to redirect traffic to the https - port 443.
  2. User called our apache2 via https now it is still TCP, but port 443 and get response header that we do support http3 on port 443 UDP.
  3. User called our service via https on port 443 via UDP and goes to the nginx with http3 support.
  4. Nginx will forward all traffic to fixed apache2 address as http2
  5. To ensure transparent encryption nginx has read only access to the Server Certificate
  6. As apache2 has this access too

Step 1: Enable http2 on apache2

Check this out https://gist.github.com/GAS85/38eb5954a27d64ae9ac17d01bfe9898c

Additionally it is recommended to add header that will tell browsers that we can support http3. Add to your virtual host:

Header always set alt-svc 'h3=":443"; ma=86400'

Step 2: Firewall

Please enable incomming UDP traffic on port 443. Depends on your system it could be done via different commands, for iptables it is:

iptables -I INPUT -p udp --dport 443 -j ACCEPT

Step 4: Nginx container

I will use official nginx image with docker-compose, my compose file looks following:

version: "3.7"
services:
  quic:
    container_name: quic
    image: nginx:alpine
    restart: unless-stopped
    ports:
      # Open 443 UDP port to listen http3 traffic
      - 443:443/udp
    volumes:
      # Configuration
      - /var/docker/quic/conf.d:/etc/nginx/conf.d
      # Logs
      - /var/docker/quic/logs:/var/log/nginx/
      # Access to Certificated
      - /etc/letsencrypt:/etc/letsencrypt:ro
    healthcheck:
      test: ls -l /proc/*/exe | grep nginx
      interval: 5m00s
      timeout: 10s
      retries: 2
      start_period: 30s
    deploy:
      resources:
        limits:
          cpus: '0.20'
          memory: 100M

Save it e.g. under your home directory as quic-compose.yml and run:

docker compose -f ~/quic-compose.yaml up -d

Step 5: Configure nginx

After we run our compose file docker will create 2 folders:

/var/docker/quic/conf.d
/var/docker/quic/logs

We need to create config iside conf.d folder. E.g. sudo needed because nginx container runned as privilidget user inside:

sudo nano /var/docker/quic/conf.d/defalut.conf

Then add following config into it:

server {
    # for better compatibility it's recommended
    # to use the same port for quic and https
    listen 443 quic reuseport;
    listen 443 ssl;

    ssl_certificate     /etc/letsencrypt/live/sitnikov.eu/cert.pem;
    ssl_certificate_key /etc/letsencrypt/live/sitnikov.eu/privkey.pem;

    location / {
        # required for browsers to direct them to quic port
        add_header Alt-Svc 'h3=":443"; ma=86400';

        proxy_pass https://<APACHE2 IP>:443;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;
    }
}

After save you can apply config by telling nginx to reload himself (docker exec quic nginx -s reload), or via docker restart quic.

Step 6: Test it

Visit your site and check if http3 enabled via console.

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