在 Nginx 中配置启用多域名站点的 HTTP/3 支持

目录
[隐藏]

HTTP/3 是基于 QUIC 协议的新一代 HTTP 协议,具有高性能和可靠性的特点。Nginx 从 1.25.0 版本开始正式支持 HTTP/3。在基于源码编译安装 Nginx 时,增加 --with-http_v3_module 参数即可开启 HTTP/3 支持。

1 编译与配置 Nginx 支持 HTTP/3

首先下载 nginx 最新稳定版源码:

wget https://nginx.org/download/nginx-1.30.0.tar.gz
tar -zxvf nginx-1.30.0.tar.gz
cd nginx-1.30.0

然后解压进入 nginx 源码目录,编译安装 Nginx。示例:

# 安装依赖
sudo apt-get install -y build-essential libpcre3 libpcre3-dev zlib1g-dev openssl-dev

# 配置编译参数。注意:这里的 openssl 路径需要替换为实际的路径,openssl 版本需大于 3.5.1
/configure \
  --prefix=/usr/local/nginx \
  --with-http_ssl_module \
  --with-http_v2_module \
  --with-http_v3_module \
  --with-http_stub_status_module \
  --with-stream \
  --with-stream_ssl_module \
  --with-openssl=/path/to/openssl

# 编译与安装
make test # 测试
make
make install

接着配置 Nginx 站点启用 HTTP/3。示例:

http {
    server {
        # 配置域名
        server_name lzw.me www.lzw.me;

        listen 443 ssl;
        listen [::]:443 ssl; # ipv6 支持

        # 启用 QUIC 以启用 HTTP/3
        listen 443 quic reuseport;
        listen [::]:443 quic reuseport;

        # 配置 SLL 证书
        ssl_certificate /path/to/certificate.crt;
        ssl_certificate_key /path/to/private.key;

        # 添加 alt-svc header,告知访问客户端战站点已启用 HTTP/3
        add_header Alt-Svc 'h3=":443"; ma=86400';

        location / {
            root /var/www/html;
            index index.html;
        }
    }
}

以上即是开启 HTTP/3 的基本配置。

2 Nginx 多站点配置支持 HTTP/3 问题

当同一台服务器按照上述方法配置了多个站点时,nginx 配置重载会报如下错误:

nginx: [emerg] duplicate listen options for 0.0.0.0:443

2.1 报错根源:HTTP/3 的监听逻辑特殊性

与基于 TCP 的 HTTP/1.1 和 HTTP/2 不同,HTTP/3 采用 UDP 协议传输数据。在 Nginx 中,UDP 端口的监听规则更为严格:同一个 IP 和端口组合(如 0.0.0.0:443),quic reuseport 等高级监听选项只能在一个 server 块中声明一次

如果您为每个域名单独配置 listen 443 ssl http2 quic reuseport;,Nginx 会认为这些高级选项重复绑定,从而抛出 duplicate listen options 错误。这并非 Nginx 的设计缺陷,而是 UDP 协议的特性要求——单个 QUIC 监听器即可通过 SNI(服务器名称指示)自动区分不同域名的流量。

2.2 解决方案一:合并 Server 块(最简单易懂,但配置耦合)

如果多个站点的配置逻辑相似(如使用同一套 SSL 证书、基础路由规则一致),可以将所有域名合并到同一个 server 块中。这种方式不仅能避免监听冲突,还能简化配置维护。

配置示例

server {
    # 标准 HTTPS 监听(TCP,兼容 HTTP/2 和 HTTP/1.1)
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    # HTTP/3 监听(UDP,仅需声明一次)
    listen 443 quic reuseport;
    listen [::]:443 quic reuseport;

    # 定义所有需要启用 HTTP/3 的域名
    server_name example.com www.example.com blog.example.com;

    # SSL 证书配置(支持通配符证书或多域名证书)
    ssl_certificate     /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/key.pem;

    # 强制启用 TLS 1.3(HTTP/3 协议要求)
    ssl_protocols TLSv1.3;

    # 告知客户端支持 HTTP/3(关键响应头)
    add_header Alt-Svc 'h3=":443"; ma=86400';

    # 通用路由配置
    location / {
        root /usr/share/nginx/html;
        index index.html;

        # 可选:根据域名区分根目录
        if ($host = 'blog.example.com') {
            root /var/www/blog;
        }
    }
}

配置要点:

  1. 监听指令唯一性quicreuseport 仅在 UDP 监听中声明一次,TCP 监听保持常规配置。
  2. 多域名绑定:通过 server_name 同时绑定多个域名,Nginx 会自动根据请求域名分发流量。
  3. Alt-Svc 响应头:必须添加该头部,告知浏览器当前站点支持 HTTP/3,否则浏览器不会主动发起 HTTP/3 请求。

2.3 解决方案二:独立 Server 块

特别注意:该方案仅理论参考,个人实际配置实践时发现,会导致所有站点在基于 H3 请求时都变成访问配置了 quic reuseport 的站点!!!

如果您的多个站点配置差异较大(如使用不同 SSL 证书、独立的日志规则或复杂路由),可以保留独立的 server 块,但需严格遵循监听规则:仅在一个 server 块中声明 quicreuseport,其他站点仅保留基础监听配置。

配置示例

主站点(承载 QUIC 监听器)

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

    # 仅在主站点声明 HTTP/3 监听
    listen 443 quic reuseport;
    listen [::]:443 quic reuseport;

    server_name example.com;

    ssl_certificate     /etc/nginx/ssl/example.com.pem;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;
    ssl_protocols TLSv1.3;

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

    location / {
        root /var/www/example.com;
        index index.html;
    }
}

副站点(无需声明 QUIC 监听)

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

    # 注意:此处不要添加 quic 和 reuseport 参数
    server_name blog.example.com;

    ssl_certificate     /etc/nginx/ssl/blog.example.com.pem;
    ssl_certificate_key /etc/nginx/ssl/blog.example.com.key;
    ssl_protocols TLSv1.3;

    # 副站点也必须添加 Alt-Svc 响应头
    add_header Alt-Svc 'h3=":443"; ma=86400';

    location / {
        root /var/www/blog.com;
        index index.html;
    }
}

配置要点:

  1. 监听器唯一性:仅在主站点的 server 块中声明 quic reuseport,其他站点仅保留 TCP 监听。
  2. SNI 自动分发:Nginx 的 QUIC 监听器会自动根据请求的 SNI 信息,将流量转发到对应的 server 块,无需额外配置。
  3. 全局 Alt-Svc:所有站点都必须添加 Alt-Svc 响应头,否则浏览器只会对主站点发起 HTTP/3 请求,副站点仍会使用 HTTP/2。

3 配置 HTTP/3 后的关键检查

1. 防火墙配置

HTTP/3 使用 UDP 443 端口,务必确保服务器防火墙开放该端口:

  • Ubuntu/UFWsudo ufw allow 443/udp
  • CentOS/Firewalldsudo firewall-cmd --permanent --add-port=443/udp && sudo firewall-cmd --reload
  • 云服务器:在云服务商的安全组规则中,添加 UDP 443 端口的入站许可。

2. 配置验证

修改配置后,先测试语法正确性,再重载 Nginx:

# 测试配置语法sudo nginx -t
# 重载配置(无需重启服务)sudo systemctl reload nginx`

3. HTTP/3 可用性验证

  • 浏览器验证:打开 Chrome 开发者工具 → Network 面板 → 刷新页面 → 查看 "Protocol" 列,若显示 h3 则表示 HTTP/3 已生效。
  • 命令行验证:使用支持 HTTP/3 的 curl 版本测试:

    curl -I --http3 https://example.com

    若返回 HTTP/3 200 状态码,则说明配置成功。

4 常见问题解答

Q:为什么副站点没有使用 HTTP/3?

A:请检查副站点是否添加了 Alt-Svc 响应头。浏览器需要通过该头部判断站点是否支持 HTTP/3,否则会默认使用 HTTP/2。

Q:可以为不同站点配置不同的 HTTP/3 端口吗?

A:可以,但不推荐。HTTP/3 默认使用 443 端口,使用非标准端口会增加用户端的配置复杂度,且大多数浏览器优先尝试 443 端口的 HTTP/3 连接。

Q:Nginx 1.30.0 之前的版本支持多站点 HTTP/3 吗?

A:Nginx 1.25.0 开始原生支持 HTTP/3,但 1.30.0 之前的版本可能存在一些兼容性问题,建议升级到最新稳定版。

5 总结

Nginx 1.30.0 多站点 HTTP/3 配置的核心是理解 UDP 监听的特殊性:单个 QUIC 监听器即可处理多个域名的流量。通过合并 server 块或保留单个 QUIC 监听器的方式,即可轻松解决 duplicate listen options 报错。

无论选择哪种方案,都需确保所有站点添加 Alt-Svc 响应头,并开放 UDP 443 端口。HTTP/3 带来的低延迟体验,将为您的用户带来更流畅的访问体验,同时提升网站的核心竞争力。 (AI生成)

相关参考:

  • https://quic.nginx.org
  • https://www.echo.cool/docs/middleware/nginx/nginx-advanced-features/nginx-http3-support/