TL;DR
bad_record_mac 是 TLS 加密层 HMAC 校验失败。四大根因:(1) 客户端 / 服务端时间偏差 > 5 分钟;(2) 证书链不完整 (用了 cert.pem 而不是 fullchain.pem);(3) OpenSSL 版本差异;(4) QUIC 路径上 MTU/UDP 问题。本文按这四个层级排查。本文 2026-05-20 实测核对。
bad_record_mac 是 V2Ray / Xray + TLS 部署最容易出但最难排查的错误。本文按”症状识别 → 四层根因 → 修复脚本”梳理。
一、识别症状
错误日志
服务端 Xray 日志 (verbose 模式):
[Warning] [xxxx] proxy/vless/inbound: connection ends >
proxy/vless/encoding: tls: bad record MAC
客户端日志:
[Warning] proxy/vless/outbound: failed to dial >
tls: bad record MAC
现象特点
- 握手能完成 (TLS 1.3 SCT 都过)
- 第一个应用数据包就报错
- 偶发性 (某些时段更频繁)
- 一旦报错连接立即断开
二、排查 1: 时间偏差
TLS 1.3 的密钥派生 (HKDF) 在某些边缘场景下对时间敏感。
检查时间偏差
# 服务端
date
# 输出当前时间
# 客户端
date
# 两者差距应 < 1 秒
修复时间同步
# Linux 服务端
sudo timedatectl set-ntp true
sudo systemctl restart systemd-timesyncd
# 验证
timedatectl status
# 输出应包含 "System clock synchronized: yes"
# Windows 客户端
w32tm /resync
# macOS 客户端
sudo sntp -sS pool.ntp.org
如果偏差 > 5 分钟,强制重新同步:
sudo ntpdate -u pool.ntp.org
三、排查 2: 证书链完整性
最常见的”低级错误”。
检查证书链
# 服务端
CERT="/etc/letsencrypt/live/yourdomain.com/fullchain.pem"
# 查看证书数量 (应 >= 2: leaf + 中间)
openssl crl2pkcs7 -nocrl -certfile $CERT | openssl pkcs7 -print_certs -noout | grep -c "subject="
# 应输出 2 或更多
如果只有 1 个证书,说明用错了文件。
Let’s Encrypt 证书文件区分
/etc/letsencrypt/live/yourdomain.com/
├── cert.pem # 只有 leaf 证书 (错!)
├── chain.pem # 只有中间证书
├── fullchain.pem # leaf + 中间 (正确)
└── privkey.pem # 私钥
Xray / V2Ray 配置应用
{
"streamSettings": {
"security": "tls",
"tlsSettings": {
"certificates": [{
"certificateFile": "/etc/letsencrypt/live/yourdomain.com/fullchain.pem",
"keyFile": "/etc/letsencrypt/live/yourdomain.com/privkey.pem"
}]
}
}
}
必须用 fullchain.pem,不能用 cert.pem。
客户端验证证书链
# 模拟客户端连接
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com -showcerts
# 应输出 2 个 "BEGIN CERTIFICATE"
# 第一个是 leaf,第二个是中间
# 最后输出 "Verify return code: 0 (ok)"
如果 Verify return code 不是 0,证书链有问题。
四、排查 3: 密码套件兼容性
某些密码套件在特定 OpenSSL 版本下有 HMAC 兼容性 bug。
检查当前用的密码套件
# 客户端连接时看 cipher
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com < /dev/null 2>&1 | grep "Cipher :"
常见输出:
Cipher : TLS_AES_128_GCM_SHA256(TLS 1.3 默认,最稳)Cipher : TLS_AES_256_GCM_SHA384(TLS 1.3 高强度)Cipher : TLS_CHACHA20_POLY1305_SHA256(TLS 1.3 ChaCha,有时有问题)
ChaCha20 兼容性问题
ChaCha20-Poly1305 在 OpenSSL 1.1.1 与 3.0 之间偶尔有 HMAC 边缘 bug。如果你的服务端是 OpenSSL 1.1.1 编译,客户端是 OpenSSL 3.0,可以临时禁用 ChaCha20:
{
"tlsSettings": {
"cipherSuites": "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384"
}
}
强制 TLS 1.2 (临时定位)
{
"tlsSettings": {
"minVersion": "1.2",
"maxVersion": "1.2"
}
}
如果 TLS 1.2 不报错,说明问题在 TLS 1.3 实现层。
五、排查 4: QUIC 路径上的 MTU / UDP 问题
如果你用的是 Hysteria 2/3 / TUIC v5 (基于 QUIC):
MTU 问题
QUIC 走 UDP,中间路由器可能对超过 MTU 的包做 IP 分片,造成包损坏。
# 检测 MTU
ping -M do -s 1472 服务器IP
# 1472 = 1500 (默认以太网) - 28 (IP+ICMP header)
# 如果失败,尝试更小 MTU
ping -M do -s 1452 服务器IP # 1480 - 28
ping -M do -s 1420 服务器IP # 1448 - 28
找到能通的最大 MTU 后,在 Hysteria 配置里限制包大小:
# hysteria-server config.yaml
quic:
initStreamReceiveWindow: 26843545
maxStreamReceiveWindow: 26843545
initConnReceiveWindow: 67108864
maxConnReceiveWindow: 67108864
maxIdleTimeout: 30s
keepAlivePeriod: 10s
disablePathMTUDiscovery: false
UDP 端口冲突
# 检查 443/udp 是否被其他服务占用
sudo ss -ulnp | grep ":443"
# 应只有 Xray / Hysteria
如果有 systemd-resolved 或其他服务占用,换端口或停止冲突服务。
六、排查 5: 服务端与客户端版本
# 服务端版本
/usr/local/bin/xray version
# 推荐: Xray 1.8.16 或更高
# 客户端版本 (sing-box 系)
sing-box version
# 推荐: 1.13.0 或更高
# 客户端 (Mihomo 系)
mihomo -v
# 推荐: 1.19.0 或更高
如果服务端是 1.8.10 + 客户端是 1.8.16,可能因为 utls 库版本差导致密钥派生路径不同。
修复
服务端 + 客户端都升级到最新稳定版本。Xray-core 1.8.16+ / sing-box 1.13+ / Mihomo 1.19+。
七、用 Wireshark 抓包定位
如果上述都不能定位:
# 服务端抓包
sudo tcpdump -i any -w xray.pcap port 443
# 让客户端复现错误几次
# 停止抓包 (Ctrl+C),传 xray.pcap 到本地
用 Wireshark 打开 xray.pcap:
- Edit → Preferences → Protocols → TLS → 加 RSA Keys List (如果有私钥)
- 找到客户端 IP 的 TLS 流
- 看 Client Hello → Server Hello → 加密握手完成
- 第一个 Application Data 包就是出错的
- 看 length 字段与实际 bytes 是否一致
通常能直接看到”包长度对不上”或”加密内容异常”。
八、systemd 自动重启 + 监控
bad_record_mac 偶发性高,加自动重启:
[Service]
Type=simple
ExecStart=/usr/local/bin/xray run -c /etc/xray/config.json
Restart=always
RestartSec=5
StartLimitInterval=600
StartLimitBurst=10
防止短时间内频繁重启 (StartLimitBurst=10 表示 600 秒内最多重启 10 次)。
九、配套订阅的稳定性
订阅商对 V2Ray/Xray 的部署质量直接影响 bad_record_mac 频率。一些订阅用旧 OpenSSL 1.1.1 + Let’s Encrypt 证书但只配 cert.pem,bad_record_mac 概率高。冲浪笔记长期跟踪的兼容 Clash / Singbox / V2Ray 的订阅在服务端用 Xray-core 1.8.16+ + 完整 fullchain + TLS 1.3 默认套件,bad_record_mac 几乎不出现。
总结
bad_record_mac 的五层排查:
- 时间同步 (timedatectl set-ntp true)
- 证书链完整 (用 fullchain.pem 不是 cert.pem)
- 密码套件兼容 (临时禁用 ChaCha20 或降级 TLS 1.2)
- QUIC 路径 MTU (ping -M do -s 测最大)
- 服务端 + 客户端版本 (都升 Xray-core 1.8.16+)
90% 问题在 (1) 与 (2)。本文 2026-05-20 实测核对。