
本文详解 Nginx 反向代理 Go 服务(同时监听 HTTP/HTTPS)时,因 proxy_pass 协议不匹配导致的 TLS 握手错误(如 first record does not look like a TLS handshake),重点说明如何正确配置 proxy_pass https://、证书链验证、SNI 传递及信任锚设置。
本文详解 nginx 反向代理 go 服务(同时监听 http/https)时,因 `proxy_pass` 协议不匹配导致的 tls 握手错误(如 `first record does not look like a tls handshake`),重点说明如何正确配置 `proxy_pass https://`、证书链验证、sni 传递及信任锚设置。
在您提供的场景中,Go 服务自身已启用 HTTPS 监听(ListenAndServeTLS),绑定在 localhost:9007;而 Nginx 配置却使用 proxy_pass http://localhost:9007 将加密请求降级为明文转发——这直接导致 Go 服务器收到非 TLS 数据流,从而抛出经典错误:
http: TLS handshake error from 127.0.0.1:54037: tls: first record does not look like a TLS handshake
根本原因在于:协议错配。Nginx 作为反向代理,若后端是 HTTPS 服务,则 proxy_pass 必须显式使用 https:// 协议前缀,否则 Nginx 会以纯 HTTP 方式发起连接,而 Go 服务期望的是 TLS 握手起始字节(0x16 0x03...),实际收到的是 HTTP 请求头(如 GET / HTTP/1.1),自然拒绝并报错。
✅ 正确做法是将 proxy_pass 改为 HTTPS,并补充关键安全配置:
location / {
# ✅ 关键:必须使用 https:// 指向 Go 的 HTTPS 端口
proxy_pass https://localhost:9007;
# ✅ 启用 SNI(确保 Go 服务能根据域名选择正确证书)
proxy_ssl_server_name on;
# ✅ 显式指定目标域名(必须与 Go 证书的 SAN 完全一致)
proxy_ssl_name "somedomain";
# ✅ 启用证书校验(生产环境强制要求)
proxy_ssl_verify on;
# ✅ 指向可信 CA 证书文件(如系统根证书或自签名 CA)
proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
# 其他必要头信息
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# HTTP/1.1 是 TLS 握手和长连接基础
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade"; # 若需支持 WebSocket
# 超时调大,避免空闲断连
proxy_read_timeout 300;
proxy_send_timeout 300;
}
⚠️ 注意事项:
-
proxy_ssl_verify on不可省略:若临时设为off可绕过错误(仅用于调试),但会失去证书信任链保护,严禁用于生产环境; -
证书链完整性:确保 Go 服务加载的
fullchain.pem包含域名证书 + 所有中间证书(不含根证书),可用以下命令验证:openssl s_client -connect localhost:9007 -servername somedomain -showcerts 2>/dev/null | grep "BEGIN CERTIFICATE" | wc -l
输出应 ≥ 2(域名证书 + 至少一个中间证书);
-
SNI 必须开启且精准匹配:
proxy_ssl_name值必须与 Go 证书的Subject Alternative Name字段完全一致(大小写、通配符、www.前缀均敏感); -
信任证书路径权限:
proxy_ssl_trusted_certificate文件需为 PEM 格式,仅含 CA 证书(每段以-----BEGIN CERTIFICATE-----开头),且 Nginx 工作进程(如www-data)有读取权限(建议644); -
避免混合代理模式:切勿让 Nginx 终止 TLS 后再以 HTTP 转发给 HTTPS 后端(即
https → http),这是典型配置陷阱。
? 补充建议:若 Go 服务仅用于内网,且证书为私有 CA 签发,可将该 CA 证书追加至系统信任库(/etc/ssl/certs/ca-certificates.crt)并更新,或单独存放并指向它,而非复用前端 Nginx 的站点证书。
综上,修复核心仅一步:proxy_pass https://localhost:9007 —— 但要实现健壮、安全、可维护的 HTTPS 代理,必须同步配置 SNI、证书验证与信任链,缺一不可。











