> ## Content Index
> Fetch the complete content index at: https://snubmonkey.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# What  Does HTTP/3 Mean for NGINX?
- URL: https://snubmonkey.com/what-does-http-3-mean-for-nginx/
- Published: 2026-08-31T00:12:10.000Z
- Updated: 2026-08-31T00:12:11.000Z
- Description: HTTP/3 changes how NGINX handles web traffic. QUIC replaces TCP with UDP as its underlying transport, introducing a different connection and worker model while allowing HTTP/2 and HTTP/3 to run side by side.
- Author: yannick Coffi
- Tags: NGINX, https, how to 🪄, self-hosting 🪲

In our previous article, **“NGINX: HTTP/2 vs HTTP/3 — What Actually Changes Under the Hood?”**, we looked beneath the protocol versions to understand how HTTP/2 and HTTP/3 actually transport web traffic.

Now, let’s bring that down to the NGINX **configuration**.

**What does HTTP/3 actually mean when you’re running NGINX?**

The biggest change is simple:  
**HTTP/2 uses TCP.** 
**HTTP/3 uses QUIC over UDP.**

That difference changes how the operating system delivers connections to NGINX—and how NGINX workers handle them.

## **What This Means for NGINX**

With traditional HTTPS and HTTP/2, NGINX listens for TCP connections:

```nginx
listen 443 ssl;
listen [::]:443 ssl;

http2 on;
```

The operating system receives TCP connections on port `443`, and NGINX workers process those connections.  

**HTTP/3** introduces a second transport:

```nginx
listen 443 quic reuseport;
listen [::]:443 quic reuseport;
```

Now NGINX needs to receive **UDP traffic** on port `443`.

A production configuration can therefore support both protocols simultaneously:

```nginx
server {
    listen 443 ssl;
    listen [::]:443 ssl;

    listen 443 quic reuseport;
    listen [::]:443 quic reuseport;

    http2 on;

    server_name example.com;

    ssl_certificate     /path/to/fullchain.pem;
    ssl_certificate_key /path/to/privkey.pem;

    add_header Alt-Svc 'h3=":443"; ma=86400' always;

    ...
}
```

The result is not that HTTP/2 disappears.

Instead, the server can accept **both TCP and UDP traffic on port 443**:

```Text
                 HTTPS :443
                     │
             ┌───────┴────────┐
             │                │
          TCP/443           UDP/443
             │                │
             ▼                ▼
          HTTP/2            QUIC
                              │
                              ▼
                           HTTP/3
```

The browser can use HTTP/2 over TCP or HTTP/3 over QUIC, depending on what it supports and what the server advertises.

## **TCP and UDP Are Different Paths**

NGINX is now dealing with two fundamentally different transport paths.

With HTTP/2, the stack looks like:

```Text
HTTP/2
   │
   ▼
  TLS
   │
   ▼
  TCP          ← reliable, ordered byte stream
   │
   ▼
  IP
```

With HTTP/3:

```nginx
HTTP/3
   │
   ▼
  QUIC         ← reliable transport + TLS 1.3
   │
   ▼
  UDP          ← packet/datagram delivery
   │
   ▼
  IP
```

The important distinction is **UDP versus QUIC**.

UDP is intentionally simple. It sends independent datagrams without guaranteeing that they will arrive, arrive in order, or be retransmitted.

UDP does **not** provide:

- Guaranteed delivery
- Ordering
- Retransmission
- Loss recovery
- Congestion control

If a UDP datagram is lost, UDP itself does nothing about it.

### **So Where Does Reliability Come From?** 
**QUIC!**

QUIC uses UDP to move packets across the network, but implements the transport features needed for a reliable connection itself.

In essence:

```Text
UDP
 │
 └── provides basic packet delivery
          │
          ▼
        QUIC
          │
          ├── Acknowledgements
          ├── Loss detection
          ├── Retransmission
          ├── Congestion control
          ├── Connection management
          ├── Connection IDs
          ├── Independent streams
          └── TLS 1.3 integration
```

So QUIC isn’t *made reliable by UDP*.  
**QUIC provides its own reliability while using UDP as its underlying packet transport.**  
  
Basically:

**UDP moves the packets.** 
**QUIC manages the connection.** 
**HTTP/3 carries the HTTP semantics.**

```Text
HTTP/3   →  What the web application speaks
   │
QUIC     →  How the connection is managed
   │
UDP      →  How QUIC packets are transported
   │
IP       →  How packets are routed
```

That distinction is **fundamental** to understanding what actually changes when NGINX moves from HTTP/2 to HTTP/3.  

## **What is a Socket?** 

A **socket** is an operating-system endpoint that an application uses to **send and receive network traffic**.

Think of it as the **doorway between NGINX and the network**.

For example, when NGINX listens on HTTPS:

```Text
                NETWORK
                   │
                   ▼
              TCP :443
                   │
                   ▼
             ┌──────────┐
             │  SOCKET  │
             └──────────┘
                   │
                   ▼
                NGINX
```

The socket is the interface between NGINX and the operating system’s networking stack.

A socket is associated with an address, typically involving:

```nginx
IP address
    +
Port
    +
Protocol
```

For example:

```nginx
TCP 192.168.1.10:443
UDP 192.168.1.10:443
```

**Both** can use port `443` because TCP and UDP are different transport protocols. Therefore, they can have separate sockets on the same IP address and port number.

## **Why `reuseport` Matters**

With HTTP/3, NGINX receives QUIC traffic over UDP.   
This raises an important question:

**How does UDP traffic get distributed when NGINX has multiple worker processes?**

First, a **worker** is simply an NGINX process that handles network connections and requests.

A typical NGINX server might have:

```Text
                 NGINX
                    │
          ┌─────────┼─────────┐
          │         │         │
          ▼         ▼         ▼
       Worker 1  Worker 2  Worker 3
```

For TCP, the operating system has mechanisms for distributing incoming connections among NGINX workers.

UDP is different.   
There are no TCP-style connections for the OS to accept and distribute.

This is where `reuseport` becomes important.

```Text
listen 443 quic reuseport;
```

With `reuseport`, NGINX can create a **separate UDP listening socket for each worker**.

The operating system can then distribute incoming UDP packets across those sockets:

```Text
                    UDP :443
                       │
              ┌────────┼────────┐
              │        │        │
              ▼        ▼        ▼
           Socket 1  Socket 2  Socket 3
              │        │        │
              ▼        ▼        ▼
           Worker 1  Worker 2  Worker 3
              │        │        │
              └────────┼────────┘
                       │
                      QUIC
                       │
                    HTTP/3
```

## **What Happens Without `reuseport` ?**

Without:

```nginx
reuseport
```

you can still run HTTP/3.

`reuseport` is not required to make QUIC or HTTP/3 function.

The difference is how UDP traffic is distributed among NGINX workers.

Without `reuseport`, NGINX does not use the same **one-UDP-socket-per-worker** arrangement. With `reuseport`, each worker can have its own UDP listening socket, allowing the operating system to distribute incoming QUIC packets across them.

### **Why Does This Matter?**

The purpose of `reuseport` is **scaling UDP/QUIC processing across NGINX workers**.

On a lightly loaded server, the difference may be difficult to notice.

On a busy production server handling substantial HTTP/3 traffic, distributing UDP packet processing across multiple workers can make better use of available CPU cores and prevent a single worker/socket from becoming a bottleneck.

The simplest way to remember it:

**`reuseport` lets multiple NGINX workers listen for UDP traffic independently, giving the operating system a way to distribute incoming QUIC traffic across them.**

So, without `reuseport`:

```Text

                 UDP :443
                     │
                  Socket
                     │
              ┌──────┴──────┐
              │             │
          NGINX workers share
          the listening path
```

And with:

```Text
                 UDP :443
                     │
          ┌──────────┼──────────┐
          ▼          ▼          ▼
       Socket 1   Socket 2   Socket 3
          │          │          │
          ▼          ▼          ▼
       Worker 1   Worker 2   Worker 3
```

**HTTP/3 works without `reuseport`; `reuseport` helps NGINX scale the UDP/QUIC workload across its workers.**

## **HTTP/2 and HTTP/3 Can Coexist**

One of the most useful aspects of an NGINX HTTP/3 deployment is that you don’t have to choose between HTTP/2 and HTTP/3.

You can have:

```Text
                HTTPS :443
                     │
          ┌──────────┴──────────┐
          │                     │
       TCP/443               UDP/443
          │                     │
       HTTP/2                 QUIC
                                │
                             HTTP/3
```

This allows clients that support HTTP/3 to use QUIC while other clients can continue using HTTP/2.

That makes HTTP/3 an evolutionary deployment rather than a complete replacement of your existing HTTPS stack.

## **How Does the Browser Know HTTP/3 is Available?**

NGINX can advertise HTTP/3 using the **`Alt-Svc` (Alternative Service)** response header.

This is where `Alt-Svc` comes in:

```nginx
add_header Alt-Svc 'h3=":443"; ma=86400' always;
```

`Alt-Svc` tells a client:  
**This same resource is also available through another protocol or network endpoint.**

In this case, NGINX is telling the browser that the site is also available over HTTP/3.  
  
**`h3=":443"`**  
means:

- `h3` → HTTP/3
- `:443` → use port `443`

### **`ma=86400`**

The `ma` parameter means **maximum age**.

The value is measured in **seconds**:

```nginx
86,400 seconds
÷ 60
= 1,440 minutes

1,440 minutes
÷ 60
= 24 hours
```

meaning the browser can cache this alternative-service information for **24 hours**.  
  
`**always**`  
The final parameter:  
tells NGINX to include the `Alt-Svc` header **regardless of the response status code**, including responses such as redirects or errors where `add_header` would otherwise not apply.

This ensures clients can still learn that HTTP/3 is available, even when the response isn’t a normal `2xx` success.

### **Putting it Together**

```nginx
add_header Alt-Svc 'h3=":443"; ma=86400' always;
```

means:  
Advertise HTTP/3 (`h3`) on port 443, allow the client to cache that information for 86,400 seconds (24 hours), and add the header regardless of the response status where NGINX’s `always` behavior applies.

The resulting flow looks like this:

```nginx
                  Browser
                     │
                     │ HTTPS / HTTP/2
                     ▼
                  NGINX
                     │
                     │ Alt-Svc: h3=":443"
                     ▼
              Browser learns:
           HTTP/3 is available
                     │
                     │
              Future connection
                     │
                     │ QUIC / UDP :443
                     ▼
                  NGINX
                     │
                     ▼
                  HTTP/3
```

The important detail is that **`Alt-Svc` does not itself switch the connection to HTTP/3**.

It advertises an **alternative service**.

The compatible client/browser decides whether and when to use that advertised HTTP/3 endpoint, then establishes a separate QUIC connection over UDP.  
  
For instance, Chrome supports HTTP/3 and can use it when the server advertises HTTP/3 and UDP/443 is reachable. If QUIC cannot be established, Chrome will fall back to another available HTTP version, such as HTTP/2.

## **HTTP/3 Still Uses TLS**

Another important point is that **HTTP/3 does not remove TLS**.

**TLS (Transport Layer Security)** is the protocol that provides encryption and authentication for network communications. It protects data from being read or modified while traveling between the client and server and uses digital certificates to authenticate the server.  
  
**QUIC** integrates TLS 1.3 directly into the QUIC connection establishment process.

So the stack looks roughly like this:

```nginx
HTTP/3
   │
   ▼
QUIC
   │
   ├── TLS 1.3
   │
   ▼
UDP
   │
   ▼
IP
```

This is one of the fundamental differences from HTTP/2, where TLS sits separately above TCP.  
  
While HTTP/2 traditionally looks like:

```nginx
HTTP/2
   │
TLS
   │
TCP
   │
IP
```

QUIC is therefore **encrypted by design**. HTTP/3 runs over QUIC, which means HTTP/3 connections use TLS 1.3 for their security.  
  
There is no unencrypted equivalent of **plain HTTP over QUIC**.  
This is one of the reasons HTTP/3 requires **HTTPS**.

## **The NGINX Configuration Is Only One Piece**

Enabling HTTP/3 in NGINX does not automatically guarantee that every client will use it.

The entire path must support UDP traffic.

That means checking:

```nginx
Client
   │
   ▼
Internet
   │
   ▼
Router / Firewall
   │
   ├── TCP :443 ──► NGINX
   │
   └── UDP :443 ──► NGINX
```

If TCP/443 is allowed but UDP/443 is blocked, HTTP/2 can work perfectly while HTTP/3 fails.

This is one of the easiest things to overlook when troubleshooting QUIC.

## **The Bigger Picture**

From NGINX’s perspective, HTTP/3 is not simply:

```nginx
http3 on;
```

It introduces another transport path into the server architecture.

You now have:

```nginx
                  NGINX
                    │
          ┌─────────┴─────────┐
          │                   │
       TCP :443            UDP :443
          │                   │
       HTTP/2                QUIC
                              │
                           HTTP/3
```

And that means administrators need to think about more than just the HTTP protocol.

They need to consider:

- UDP/443 firewall rules
- QUIC support
- TLS 1.3
- NGINX worker processes
- `reuseport`
- `Alt-Svc`
- client support
- router/NAT behavior
- monitoring and troubleshooting

HTTP/3 therefore changes the **network path into NGINX**, not just the syntax of the HTTP protocol.

**HTTP/3** gives NGINX a new transport path:  
The important part is understanding what happens underneath:

```Text
HTTP/2 → TCP → NGINX

HTTP/3 → QUIC → UDP → NGINX
```

NGINX can run both side by side, while directives like `quic`, `reuseport`, and `Alt-Svc` control how HTTP/3 traffic reaches and scales across the server.

Thanks for reading—and as always, keep experimenting, keep learning, and keep digging beneath the surface.