Nginx 开启 HTTP3 与 DNS SVCB 的设置
发布时间:
最后更新:
最近给本站升级 HTTP3,这个东西出来有两年了,浏览器和很多平台都支持完毕,可惜本站所用的 Node.js 仍没支持,没办法还得在前头整个 Nginx。
升级完成之后的效果还是很可观的:
可以看出 h3 协议的首屏图片加载用时在 200ms 左右,而 h2 的在 400ms 到 500ms 之间,说实话提升这么大我是没想到的,应该跟本站服务器在美国有关,这也展现出了 HTTP3 的威力,新技术,赶紧冲!
Nginx 配置 #
开启 HTTP3 的过程其实不复杂,本文以本站使用的 Nginx 反代为例,同时它也是最流行的 HTTP 服务器,要是你用的库还没支持的话也可以搞一个放前面反代。
Nginx 从 1.25 版本开始才支持 HTTP3,可以使用以下命令先检查一下:
nginx -V 2>&1
打印的输出中有--with-http_v3_module
即支持 HTTP3,也可以用grep
命令来搜索。在写本文时 Nginx 官方源的版本是 1.26,Debian stable 才到 1.24,如果你的源太旧可以切过去。
至于怎么反代就不讲了,教程到处都是,这里仅说下如何开启 HTTP3 。给反代加上 HTTP3 只需两行:
# 这是 Nginx 的站点配置文件。
server {
server_name blog.kaciras.com;
listen 443 ssl;
listen 443 quic reuseport;
http2 on;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
add_header Alt-Svc 'h3=":443"';
# 其它的反代设置照旧……
}
首先用listen
配置端口监听,协议写quic
,由于跟 HTTP 1/2 使用同样的端口所以还要加上个reuseport
。
然后再加一个 HTTP 头,表明服务器支持 h3,端口还是 443,这样浏览器访问过一次之后就会记住,下次直接就用 QUIC 协议连接了。
最后注意看一下 nginx.conf 里 ssl_protocols
是否写了 TLSv1.3
,这是 HTTP3 支持的最低版本。
是否配置成功可以用 https://http3check.net 之类的工具检查:
DNS 配置 #
到此为止就差不多了,但还有一点瑕疵,就是首次访问的时候无法确定握手的方式。
这是由于 HTTP3 跟之前的版本在传输层的协议是不一样的,HTTP3 使用 UDP 而之前的都是 TCP。这就有个问题:当首次访问一个网站时,还不知道它支不支持 HTTP3,应该发那种包?
-
如果发起 TCP 握手,网站肯定都是支持的,不太可能有网站仅用 HTTP3。但这样第一次访问就无法享受新版的协议。
-
如果发 UDP 包做 QUIC 握手,那么一旦网站不支持 HTTP3,就会白白浪费时间。
经测试 Firefox 对首次访问的站点仅使用 TCP 握手,其它浏览器也有不同的处理方式:
Chrome 在 HTTP/3 可用时,总是优先使用 HTTP/3 协议,当失败后再回退至 HTTP/2。而 Safari 则是并发尝试使用 HTTP/2 和 HTTP/3,并优先选择最先完成连接建立过程的连接。这可能使得在测试时发现 Safari 经常甚至永不使用 HTTP/3。
要解决这个问题,就得在建立连接之前就获知服务器是否支持 HTTP3,于是 DNS 成为了最好的选择,新的 SVCB 和 HTTPS 记录运营而生。
SVCB 记录能够给一个域名定义多个“服务”,每个“服务”都有一个域名和一组参数,客户端可以通过参数来选择服务,以及提前得知一些信息。
HTTPS 记录属于 SVCB 的一种,专门用于 HTTP,配置都是一样的。
上图是本站的 DNS HTTPS 记录:
-
第一行的 Name 是 DNS 记录的域名,这里就是
blog.kaciras.com
。 -
第二行的 Priority 优先级设为最高的 1 即可,因为也没有多个服务;注意 0 是特殊值。
-
Target 指的是服务的域名,它可以用来发现其它服务,但本站用不到所以设为
.
,表示跟上面 DNS 记录的域名相同。 -
Value 就是服务的参数了:
-
alpn 应用层协议协商,在以前都是放在 TLS 握手中,现在可以在 DNS 阶段就发送了。这里填
h3,h2
表明服务器支持 HTTP3 和 HTTP2. -
ipv4hint 能够将 IP 地址也发送给客户端,这样可以尽快连接而不必等到 A 类查询返回。
-
综合一下就是从blog.kaciras.com
能查询到一个 HTTPS 服务,域名就是自己,支持 HTTP3 和 HTTP2,IP 地址是 66.103.210.238
,是不是通俗易懂?
经测试 Edge 浏览器能够发送 HTTPS 查询,并在第一次就走 h3 连接;Firefox 也会查但并不一定使用 HTTP3,不知道怎么回事。
为什么有了 ipv4hint 还要查 A 记录?
上图确实能看到有两个 DNS 查询,分别是 HTTPS 和 A,这是因为 ipv4hint 只是提示(Hint),根据 RFC 9460 Section 7.3 的描述:
The "ipv4hint" and "ipv6hint" keys convey IP addresses that clients MAY use to reach the service. If A and AAAA records for TargetName are locally available, the client SHOULD ignore these hints. Otherwise, clients SHOULD perform A and/or AAAA queries for TargetName per Section 3, and clients SHOULD use the IP address in those responses for future connections. Clients MAY opt to terminate any connections using the addresses in hints and instead switch to the addresses in response to the TargetName query.
客户端可以先建立 ipv4hint 的连接,但同时也要查询服务域名的 A 记录,最终仍以 A 记录为准,ipv4hint 仅用于加速。
另外 SVCB 记录还有很多强大的用途,比如让 HTTP 使用任何端口,不在卡死 80 和 443,也终于不用靠反代来复用端口了;以及 ECH 加密。这些超出了本文的范围,就不说了。
基建有待升级 #
最后还有一点可惜的是 SVCB 属于较新的协议,很多老古董都不支持,比如我这默认的 DNS 是联通的 218.104.111.114
,根本就查不了:
遇到这种情况可以考虑换大厂的公共 DNS,比如:
- 腾讯 Public DNS+「119.29.29.29」:承诺信息隐私,访问更加快速、稳定,完全无劫持。
- 阿里 DNS「223.5.5.5 / 223.6.6.6」:提供“快速”、“稳定”、“智能”的免费 DNS 递归解析 服务。
- 百度 DNS「180.76.76.76」:云防护、无劫持、更精准。
- 114 DNS「114.114.114.114 / 114.114.115.115」:国内首家云安全 DNS。
但是换了之后延迟会高一点,ping 时间从 4ms 变成了 32 ms,到底值不值得还有待观察。