主要变更: - WebSocket 代理支持 (internal/proxy/websocket.go) - OCSP stapling 实现 (internal/ssl/ocsp.go) - 监控状态端点 (internal/server/status.go) - 新增 nginx 模块文档 (19-24) - UDP 代理超时配置支持 - 多模块代码注释完善和功能增强 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
19 KiB
19 KiB
NGINX HTTP/2 与 HTTP/3 (QUIC) 配置详解
1. HTTP/2 基础
1.1 HTTP/2 特性
HTTP/2 是 HTTP 协议的重大升级,主要特性包括:
| 特性 | 说明 |
|---|---|
| 多路复用 | 单一 TCP 连接上并发处理多个请求/响应 |
| 头部压缩 | HPACK 算法压缩请求头,减少传输开销 |
| 服务器推送 | 服务器主动推送资源到客户端 |
| 二进制分帧 | 二进制协议替代文本协议,更高效解析 |
| 流优先级 | 允许客户端指定请求优先级 |
1.2 版本要求
- NGINX 1.9.5+ 支持 HTTP/2
- 需要编译
--with-http_v2_module模块 - OpenSSL 1.0.2+ 推荐(支持 ALPN)
2. ngx_http_v2_module 指令详解
2.1 基础启用配置
listen 指令中的 http2 参数
server {
listen 443 ssl http2;
server_name www.example.com;
ssl_certificate /etc/nginx/ssl/www.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/www.example.com.key;
location / {
root /var/www/html;
}
}
注意:NGINX 1.25.1+ 起,http2 参数从 listen 指令移至 http2 指令。
# NGINX 1.25.1+ 推荐写法
server {
listen 443 ssl;
http2 on;
# ...
}
2.2 http2 指令
| 语法 | 默认值 | 上下文 |
|---|---|---|
http2 on | off; |
off |
http, server |
启用或禁用 HTTP/2 协议支持。
# 全局启用
http {
http2 on;
server {
listen 443 ssl;
# ...
}
}
# 单个服务器启用
server {
listen 443 ssl;
http2 on;
# ...
}
2.3 http2_recv_buffer_size
| 语法 | 默认值 | 上下文 |
|---|---|---|
http2_recv_buffer_size size; |
256k |
http, server |
设置每个 worker 进程的 HTTP/2 连接接收缓冲区大小。
# 高并发场景下增大缓冲区
http2_recv_buffer_size 512k;
2.4 http2_max_concurrent_streams
| 语法 | 默认值 | 上下文 |
|---|---|---|
http2_max_concurrent_streams number; |
128 |
http, server |
设置单个 HTTP/2 连接中最大并发流数量。
# 增加并发流数量
http2_max_concurrent_streams 256;
注意事项:
- 值越大,内存消耗越多
- 根据服务器资源和客户端需求调整
2.5 http2_max_field_size
| 语法 | 默认值 | 上下文 |
|---|---|---|
http2_max_field_size size; |
4k |
http, server |
设置压缩后的请求头字段最大大小。
# 支持较大的 Cookie 头部
http2_max_field_size 16k;
2.6 http2_max_header_size
| 语法 | 默认值 | 上下文 |
|---|---|---|
http2_max_header_size size; |
16k |
http, server |
设置压缩后的整个请求头最大大小。
# 支持大量自定义头部
http2_max_header_size 32k;
2.7 http2_max_requests
| 语法 | 默认值 | 上下文 |
|---|---|---|
http2_max_requests number; |
1000 |
http, server |
设置单个 HTTP/2 连接上最大请求数量,超过后连接关闭。
# 长连接场景下增加请求数
http2_max_requests 5000;
2.8 http2_chunk_size
| 语法 | 默认值 | 上下文 |
|---|---|---|
http2_chunk_size size; |
8k |
http, server, location |
设置响应体分块大小,太小会增加开销,太大会影响优先级。
# 大文件传输优化
http2_chunk_size 16k;
2.9 http2_body_preread_size
| 语法 | 默认值 | 上下文 |
|---|---|---|
http2_body_preread_size size; |
64k |
http, server |
设置请求体预读缓冲区大小。
2.10 http2_idle_timeout
| 语法 | 默认值 | 上下文 |
|---|---|---|
http2_idle_timeout time; |
3m |
http, server |
设置 HTTP/2 连接空闲超时时间。
# 缩短空闲超时
http2_idle_timeout 60s;
3. HTTP/2 服务器推送
3.1 http2_push 指令
| 语法 | 默认值 | 上下文 |
|---|---|---|
http2_push uri; |
- | http, server, location |
预推送指定 URI 的资源到客户端。
server {
listen 443 ssl http2;
server_name www.example.com;
ssl_certificate /etc/nginx/ssl/www.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/www.example.com.key;
location = /index.html {
http2_push /style.css;
http2_push /script.js;
http2_push /logo.png;
alias /var/www/html/index.html;
}
}
3.2 http2_push_preload 指令
| 语法 | 默认值 | 上下文 |
|---|---|---|
http2_push_preload on | off; |
off |
http, server, location |
根据 Link 响应头自动推送资源。
location = /index.html {
http2_push_preload on;
add_header Link "</style.css>; rel=preload; as=style" always;
add_header Link "</script.js>; rel=preload; as=script" always;
alias /var/www/html/index.html;
}
注意:NGINX 1.25.0+ 已弃用 http2_push 和 http2_push_preload,推荐使用 Early Hints (103 状态码)。
4. HTTP/2 完整配置示例
4.1 基础配置
http {
# HTTP/2 全局设置
http2_recv_buffer_size 512k;
http2_max_concurrent_streams 256;
http2_idle_timeout 60s;
server {
listen 443 ssl http2;
server_name www.example.com;
ssl_certificate /etc/nginx/ssl/www.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/www.example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
root /var/www/html;
index index.html;
}
}
}
4.2 高并发优化配置
http {
http2_recv_buffer_size 1m;
http2_max_concurrent_streams 512;
http2_max_field_size 16k;
http2_max_header_size 32k;
http2_max_requests 10000;
http2_chunk_size 16k;
http2_idle_timeout 180s;
server {
listen 443 ssl http2 reuseport;
server_name api.example.com;
ssl_certificate /etc/nginx/ssl/api.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/api.example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
}
}
}
5. HTTP/3 (QUIC) 基础
5.1 HTTP/3 特性
| 特性 | 说明 |
|---|---|
| 基于 QUIC | 使用 QUIC 替代 TCP + TLS |
| 0-RTT 连接 | 连接建立时可立即发送数据 |
| 连接迁移 | 网络切换时保持连接(如 WiFi -> 4G) |
| 无队头阻塞 | 单流丢包不影响其他流 |
| 内置加密 | 安全性内置于协议 |
5.2 版本要求
- NGINX 1.25.0+ 实验性支持 HTTP/3
- 需要编译
--with-http_v3_module模块 - 需要
--with-http_quic_module模块(QUIC 传输) - OpenSSL 3.5.1+ 推荐(支持 TLS 1.3 Early Data)
- 或 BoringSSL、LibreSSL、QuicTLS
5.3 编译配置
# 下载源码
wget https://nginx.org/download/nginx-1.25.5.tar.gz
tar -xzf nginx-1.25.5.tar.gz
cd nginx-1.25.5
# 配置编译选项
./configure \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_v3_module \
--with-http_quic_module \
--with-cc-opt="-I/path/to/openssl/include" \
--with-ld-opt="-L/path/to/openssl/lib"
make
sudo make install
6. ngx_http_v3_module 指令详解
6.1 http3 指令
| 语法 | 默认值 | 上下文 |
|---|---|---|
http3 on | off; |
off |
http, server |
启用或禁用 HTTP/3 协议支持。
server {
listen 443 quic reuseport;
listen 443 ssl;
http3 on;
# ...
}
6.2 quic_gso 指令
| 语法 | 默认值 | 上下文 |
|---|---|---|
quic_gso on | off; |
off |
http, server |
启用 Generic Segmentation Offloading,提升 UDP 性能。
quic_gso on;
要求:Linux 5.0+ 内核和网卡支持 GSO。
6.3 quic_host_key 指令
| 语法 | 默认值 | 上下文 |
|---|---|---|
quic_host_key file; |
- | http, server |
指定 QUIC 主机密钥文件,用于生成连接 ID 令牌。
quic_host_key /etc/nginx/quic/host.key;
生成密钥:
openssl rand -out /etc/nginx/quic/host.key 32
6.4 quic_retry 指令
| 语法 | 默认值 | 上下文 |
|---|---|---|
quic_retry on | off; |
off |
http, server |
启用地址验证重试,防止连接放大攻击。
quic_retry on;
6.5 quic_max_udp_payload_size
| 语法 | 默认值 | 上下文 |
|---|---|---|
quic_max_udp_payload_size size; |
65527 |
http, server |
设置最大 UDP 负载大小,影响 QUIC 数据包大小。
# 标准以太网 MTU
quic_max_udp_payload_size 1200;
7. 0-RTT 连接配置
7.1 ssl_early_data 指令
| 语法 | 默认值 | 上下文 |
|---|---|---|
ssl_early_data on | off; |
off |
http, server |
启用 TLS 1.3 0-RTT Early Data,允许连接建立时发送数据。
server {
listen 443 quic reuseport;
listen 443 ssl;
http3 on;
ssl_certificate /etc/nginx/ssl/www.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/www.example.com.key;
ssl_protocols TLSv1.3; # 必须 TLS 1.3
ssl_early_data on; # 启用 0-RTT
add_header Alt-Svc 'h3=":443"; ma=86400' always;
}
7.2 0-RTT 安全注意事项
# 限制 0-RTT 请求(防止重放攻击)
server {
listen 443 quic reuseport;
listen 443 ssl;
http3 on;
ssl_early_data on;
# 拒绝 0-RTT 中的非幂等请求
if ($ssl_early_data = "1") {
return 425; # Too Early
}
location /api/ {
# API 接口处理
proxy_pass http://backend;
}
}
8. HTTP/3 完整配置示例
8.1 基础配置
http {
server {
listen 443 quic reuseport;
listen 443 ssl;
server_name www.example.com;
ssl_certificate /etc/nginx/ssl/www.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/www.example.com.key;
ssl_protocols TLSv1.3;
ssl_early_data on;
http3 on;
quic_gso on;
quic_retry on;
# 告知客户端支持 HTTP/3
add_header Alt-Svc 'h3=":443"; ma=86400' always;
location / {
root /var/www/html;
}
}
}
8.2 生产环境配置
http {
# HTTP/2 和 HTTP/3 共存
http2_recv_buffer_size 512k;
server {
# HTTP/3 QUIC 监听
listen 443 quic reuseport;
# HTTP/2 HTTPS 监听
listen 443 ssl;
server_name www.example.com;
# SSL 配置
ssl_certificate /etc/nginx/ssl/www.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/www.example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
# HTTP/2 启用
http2 on;
# HTTP/3 启用
http3 on;
quic_gso on;
quic_retry on;
quic_host_key /etc/nginx/quic/host.key;
quic_max_udp_payload_size 1350;
# 0-RTT
ssl_early_data on;
# 协议升级提示
add_header Alt-Svc 'h3=":443"; ma=2592000' always;
# 安全头部
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
location / {
root /var/www/html;
index index.html;
}
}
# HTTP 重定向到 HTTPS
server {
listen 80;
server_name www.example.com;
return 301 https://$server_name$request_uri;
}
}
9. HTTP/1.1 vs HTTP/2 vs HTTP/3 对比
9.1 特性对比表
| 特性 | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| 传输层 | TCP | TCP | QUIC/UDP |
| 多路复用 | 否(串行或连接池) | 是 | 是 |
| 头部压缩 | 否 | HPACK | QPACK |
| 服务器推送 | 否 | 是(已弃用) | 否 |
| 队头阻塞 | 有 | TCP 层 | 无 |
| 连接建立 | 1-2 RTT | 1-2 RTT + TLS | 0-1 RTT |
| 连接迁移 | 否 | 否 | 是 |
| 加密要求 | 可选 | TLS 推荐 | 强制 |
| 握手延迟 | 高 | 中 | 低 |
| NAT 友好 | 是 | 是 | 需特殊处理 |
9.2 性能对比
| 场景 | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| 首屏加载 | 基准 | 20-50% 提升 | 30-60% 提升 |
| 高延迟网络 | 基准 | 30-40% 提升 | 50-80% 提升 |
| 丢包网络 | 基准 | 轻微下降 | 显著提升 |
| 移动网络切换 | 需重连 | 需重连 | 无缝迁移 |
9.3 适用场景
| 协议 | 推荐场景 |
|---|---|
| HTTP/1.1 | 兼容旧客户端、简单代理、健康检查 |
| HTTP/2 | 现代 Web 应用、API 服务、服务器推送(遗留) |
| HTTP/3 | 移动应用、实时通信、高延迟网络、视频流 |
10. 迁移指南和兼容性
10.1 渐进式迁移策略
http {
# 同时支持 HTTP/2 和 HTTP/3
server {
listen 443 quic reuseport;
listen 443 ssl;
server_name www.example.com;
ssl_certificate /etc/nginx/ssl/www.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/www.example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
# HTTP/2
http2 on;
# HTTP/3(实验性)
http3 on;
# 告知客户端支持 HTTP/3
add_header Alt-Svc 'h3=":443"; ma=86400' always;
location / {
root /var/www/html;
}
}
}
10.2 Alt-Svc 头部详解
# 基础声明
add_header Alt-Svc 'h3=":443"; ma=86400' always;
# 多协议声明
add_header Alt-Svc 'h3=":443"; h3-29=":443"; ma=86400' always;
# 指定不同端口
add_header Alt-Svc 'h3=":8443"; ma=3600' always;
参数说明:
h3:HTTP/3 协议h3-29:HTTP/3 草案版本(兼容旧客户端)ma:最大有效期(秒)
10.3 浏览器兼容性
| 浏览器 | HTTP/2 | HTTP/3 |
|---|---|---|
| Chrome 49+ | 支持 | 87+ 实验性,后续稳定 |
| Firefox 36+ | 支持 | 88+ 实验性,后续稳定 |
| Safari 11+ | 支持 | 14+ 实验性,后续稳定 |
| Edge 79+ | 支持 | 87+ 实验性,后续稳定 |
10.4 回退策略
map $http_user_agent $supports_http3 {
default 0;
"~*Chrome/8[0-9]" 1;
"~*Firefox/8[0-9]" 1;
"~*Safari/1[4-9]" 1;
}
server {
listen 443 ssl http2;
location / {
# 根据客户端能力调整
if ($supports_http3) {
add_header Alt-Svc 'h3=":443"; ma=86400' always;
}
proxy_pass http://backend;
}
}
11. 性能优化建议
11.1 HTTP/2 优化
http {
# 1. 调整 worker 进程数
worker_processes auto;
# 2. 优化连接参数
http2_max_concurrent_streams 256;
http2_recv_buffer_size 512k;
http2_idle_timeout 180s;
server {
listen 443 ssl http2;
# 3. 启用 TLS 会话复用
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets on;
# 4. 长连接优化
keepalive_timeout 65;
keepalive_requests 1000;
location / {
# 5. 资源文件缓存
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
root /var/www/html;
}
}
}
11.2 HTTP/3 优化
http {
server {
listen 443 quic reuseport;
listen 443 ssl;
http3 on;
# 1. 启用 GSO 提升 UDP 性能
quic_gso on;
# 2. 启用地址验证(防止攻击)
quic_retry on;
# 3. 优化 UDP 包大小
quic_max_udp_payload_size 1350;
# 4. 使用 0-RTT
ssl_early_data on;
# 5. 会话缓存
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
location / {
proxy_pass http://backend;
}
}
}
11.3 内核参数优化
# /etc/sysctl.conf
# UDP 缓冲区优化(HTTP/3)
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.udp_rmem = 4096 87380 16777216
net.ipv4.udp_wmem = 4096 65536 16777216
# TCP 缓冲区优化(HTTP/2)
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_congestion_control = bbr
# 连接跟踪
net.netfilter.nf_conntrack_udp_timeout = 60
net.netfilter.nf_conntrack_udp_timeout_stream = 120
# 应用配置
sysctl -p
11.4 监控指标
# 在日志中记录协议版本
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $server_protocol '
'ssl=$ssl_protocol http2=$http2 http3=$http3';
server {
access_log /var/log/nginx/access.log main;
}
11.5 调试检查
# 检查 HTTP/2 支持
curl -I --http2 https://www.example.com
# 检查 HTTP/3 支持(需要支持 HTTP/3 的 curl)
curl -I --http3 https://www.example.com
# 使用 quiche 客户端测试
# https://github.com/cloudflare/quiche
# 查看 NGINX HTTP/3 统计
curl https://www.example.com/nginx_stats
# 检查 Alt-Svc 头部
curl -I https://www.example.com | grep -i alt-svc
12. 常见问题排查
12.1 HTTP/2 问题
| 问题 | 原因 | 解决 |
|---|---|---|
| 浏览器降级 HTTP/1.1 | ALPN 未启用 | OpenSSL 1.0.2+ |
| 大量 STREAM_CLOSED 错误 | 客户端提前关闭 | 正常行为,无需处理 |
| 内存占用高 | 流数量过多 | 减少 http2_max_concurrent_streams |
12.2 HTTP/3 问题
| 问题 | 原因 | 解决 |
|---|---|---|
| 无法建立连接 | 防火墙阻断 UDP | 开放 UDP 443 |
| 连接不稳定 | MTU 设置不当 | 调整 quic_max_udp_payload_size |
| 0-RTT 失败 | 会话票据无效 | 检查 ssl_session_ticket_key |
| NAT 超时 | UDP 连接被清理 | 缩短 http3_idle_timeout |