最常见错误是“tls: private key does not match public key”,实则多因私钥权限非0600(如0644)所致;真正密钥不匹配会panic或握手失败;可用openssl x509和rsa命令比对modulus hash验证是否为同一对。

私钥和证书不匹配会报什么错
最常见的是 tls: private key does not match public key,但这个错误名有误导性——它往往不是密钥真不匹配,而是私钥文件权限不对(比如是 0644 而非 0600),Go 的 TLS 库在读取前会做权限校验,失败就直接返回这句。真正的密钥不匹配(比如用 A 证书配 B 私钥)通常会在 tls.LoadX509KeyPair 阶段 panic:crypto/tls: failed to parse private key 或握手时客户端报 ERR_SSL_VERSION_OR_CIPHER_MISMATCH。
怎么验证私钥和证书是否真是一对
不用跑 Gin,直接用 OpenSSL 命令行就能确认:
-
openssl x509 -noout -modulus -in cert.pem | openssl md5→ 得到证书的 modulus hash -
openssl rsa -noout -modulus -in key.pem | openssl md5→ 得到私钥的 modulus hash
两个 hash 完全一致,才说明是同一对;不一致就说明证书和私钥来源不同,必须重新生成或核对。
RunTLS 启动前必须检查的三件事
Gin 的 RunTLS 不做路径存在性、格式合法性、权限检查,出错就 panic,线上容易挂。启动前建议加这几步:
- 用
os.Stat确认cert.pem和key.pem文件存在且可读 - 用
os.Stat检查私钥文件权限,stat.Mode().Perm() & 077应为0(即无 group/other 权限) - 调用
tls.LoadX509KeyPair(certPath, keyPath)预加载一次,捕获 error 并提前退出,避免服务起来后才崩
证书链不完整导致浏览器提示“不受信任”
只放 cert.pem(域名证书)不行,必须拼接中间证书成 fullchain.pem。Nginx 和浏览器都要求服务器在 TLS 握手时一次性发送“域名证书 + 中间证书”,顺序不能颠倒,也不能含根证书。
正确拼法:cat cert.pem intermediate.pem > fullchain.pem;Gin 的 RunTLS 参数要传这个 fullchain.pem,不是原始 cert.pem。
验证是否生效:运行 openssl s_client -connect localhost:8443 -showcerts,输出里第一个 BEGIN CERTIFICATE 块 Subject 必须是你域名,第二个块 Issuer 必须等于第一个块的 Subject —— 这才是链完整。


















