什么是 ALPN
ALPN(Application-Layer Protocol Negotiation,应用层协议协商)是 TLS 协议的一个扩展,定义于 RFC 7301。它允许客户端和服务器在 TLS 握手阶段就协商好使用哪个应用层协议,而无需额外的往返通信。
如果没有 ALPN,客户端只能先建立 TLS 连接,再通过 NPN(Next Protocol Negotiation,已废弃)或在 TLS 握手完成后通过额外协商来确定使用 HTTP/1.1 还是 HTTP/2。ALPN 将这个过程整合到 TLS 握手中,减少了延迟。
ALPN 的工作原理
在 TLS ClientHello 消息中,客户端通过 application_layer_protocol_negotiation 扩展发送自己支持的协议列表,按优先级排序。服务器从中选择一个双方都支持的协议,并在 ServerHello 中回显该选择。
整个协商过程在 TLS 握手内部完成,对应用层透明:
|
|
常见的 ALPN 协议标识符
| 协议标识符 | 说明 |
|---|---|
h2 |
HTTP/2 over TLS |
http/1.1 |
HTTP/1.1 |
http/1.0 |
HTTP/1.0(极少使用) |
h3 |
HTTP/3 over QUIC(不经过 TLS,使用 QUIC 自带协商) |
dot |
DNS over TLS |
acme-tls/1 |
ACME TLS-ALPN-01 验证方式 |
协议标识符的格式由 RFC 7301 Section 3.1 定义,是长度前缀的字节串。
使用 OpenSSL 测试 ALPN
基本测试
使用 openssl s_client 的 -alpn 参数可以指定客户端请求的协议列表(逗号分隔):
|
|
实际输出:
|
|
Cloudflare 服务器支持 HTTP/2,因此协商结果为 h2。
测试不支持 H2 的服务器
|
|
实际输出:
|
|
即使客户端请求了 h2,服务器不支持时会自动回退到 http/1.1。
仅请求 H2 时的表现
当客户端只请求 h2,而服务器不支持时:
|
|
实际输出:
|
|
这种情况下,服务器没有任何匹配协议,ALPN 协商失败,连接可能使用默认协议或断开。
不指定 ALPN 参数
|
|
实际输出:
|
|
不使用 -alpn 参数时,客户端不会发送 ALPN 扩展,因此不会进行协议协商。
使用 -tlsextdebug 查看扩展详情
添加 -tlsextdebug 参数可以查看 TLS 扩展的详细信息:
|
|
输出:
|
|
Nginx 中的 ALPN 配置
在 Nginx 中启用 ALPN 非常简单,只需在 listen 指令中添加 http2 参数:
|
|
当 Nginx 配置了 http2 后,它会在 TLS ServerHello 中发送 ALPN 扩展,告知客户端支持 h2 和 http/1.1。
验证 Nginx 配置
配置完成后,可以使用 OpenSSL 验证:
|
|
期望输出:
|
|
ALPN 与 NPN 的区别
NPN(Next Protocol Negotiation)是 Google 在 SPDY 协议中引入的早期方案,后被 ALPN 取代。两者的关键区别:
| 特性 | NPN | ALPN |
|---|---|---|
| 协商顺序 | 服务器发送协议列表,客户端选择 | 客户端发送协议列表,服务器选择 |
| 标准化 | Google 草案 | RFC 7301(IETF 标准) |
| 安全性 | 较低(客户端决定协议) | 较高(服务器决定协议) |
| 当前状态 | 已废弃 | 广泛使用 |
ALPN 将协议选择权交给服务器,这更安全——服务器可以根据自己的负载情况和策略决定使用哪个协议。
ALPN 的实际应用场景
HTTP/2 启用
这是 ALPN 最常见的用途。浏览器在 TLS 握手时发送 h2 请求,服务器支持则协商使用 HTTP/2,否则回退到 HTTP/1.1。整个过程对用户完全透明。
HTTP/3 的特别说明
HTTP/3 运行在 QUIC 协议之上,不经过传统 TLS 层。QUIC 有自己的应用层协议协商机制(在 CRYPTO frame 中交换),因此不使用 ALPN 扩展。但概念是相似的——在加密握手阶段完成协议协商。
ACME TLS-ALPN-01 验证
Let’s Encrypt 等 CA 机构提供 TLS-ALPN-01 验证方式。在证书申请过程中,ACME 服务器通过 ALPN 协商 acme-tls/1 协议来验证域名所有权:
|
|
DNS over TLS
DNS over TLS(RFC 7858)使用 ALPN 协议标识符 dot 来协商加密 DNS 连接:
|
|
排查 ALPN 相关问题
问题:HTTP/2 未生效
排查步骤:
-
确认 Nginx 配置了
http2:1grep -r "http2" /etc/nginx/conf.d/ -
检查 OpenSSL 版本:ALPN 需要 OpenSSL 1.0.2+:
1openssl version -
验证 ALPN 协商结果:
1echo | openssl s_client -connect yourdomain.com:443 -alpn h2 2>&1 | grep "ALPN"如果输出
No ALPN negotiated,说明服务器未正确配置 HTTP/2。
问题:浏览器显示 HTTP/1.1
使用浏览器开发者工具查看协议类型,或直接从命令行测试:
|
|
如果返回 HTTP/1.1 200 OK,说明 ALPN 协商未成功选择 HTTP/2。
小结
ALPN 是现代 TLS 通信中不可或缺的一环:
- 将应用层协议协商整合到 TLS 握手中,减少额外往返
- 服务器掌握协议选择权,比 NPN 更安全
- 是 HTTP/2 在 HTTPS 上广泛使用的基础
- 除 HTTP/2 外,还用于 DNS over TLS、ACME 验证等场景
理解 ALPN 有助于排查 HTTPS/HTTP2 相关问题,也是深入理解 TLS 握手过程的重要一环。