自签名证书需为pem格式、无密码、含完整公钥链,生成命令为:openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/c=cn/st=bj/l=beijing/o=dev/cn=localhost",且cn须与访问域名一致,私钥权限必须为0600。

自签名证书怎么生成才可用
自签名证书必须是 PEM 格式、无密码、且包含完整公钥链(哪怕只有一级),否则 RunTLS 会 panic 或静默失败。常见错误是用 openssl req -x509 生成时漏掉 -nodes,导致私钥被加密;或用 openssl x509 签发后没合并中间证书——但自签名场景下中间证书不存在,所以只需确保 cert.pem 是纯公钥内容、key.pem 是纯 RSA 私钥内容。
- 开发最简命令:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/C=CN/ST=BJ/L=Beijing/O=Dev/CN=localhost" -
CN=localhost必须与你访问的域名一致(如用https://127.0.0.1访问,则 CN 应为127.0.0.1;否则浏览器报NET::ERR_CERT_COMMON_NAME_INVALID) - 生成后检查:用
openssl x509 -in cert.pem -text -noout | head -n 5确认输出有证书信息;用openssl rsa -in key.pem -check -noout确认私钥可读
RunTLS 启动时报错 tls: failed to find any PEM data 是什么问题
这个错误几乎 100% 不是证书内容问题,而是路径或权限问题。Go 的 TLS 初始化在读到空内容时就直接 panic,而空内容常来自:路径不存在、文件不可读、私钥权限太宽、或传了空字符串。
- 绝对不用相对路径:
r.RunTLS(":8443", "./cert.pem", "./key.pem")在 systemd 或 IDE 下极易失效;改用filepath.Abs("cert.pem")拼出绝对路径并提前os.Stat校验 - Linux 下私钥权限必须是
0600,0644会被 Go 拒绝加载,但错误仍显示为 PEM 数据未找到 - 两个参数都不能是空字符串:
r.RunTLS(":8443", "", "key.pem")会 panic,哪怕只填一个也崩 - Windows 用户注意:路径分隔符用
/或filepath.Join,别硬写\
HTTP 自动跳转 HTTPS 怎么写才不丢 Host 头
Gin 的 RunTLS 只监听 HTTPS 端口,HTTP 请求根本进不来,所以跳转必须另起一个 HTTP server,且不能靠中间件。常见坑是 http.Redirect 默认用 r.Request.URL.String() 构造跳转地址,结果把 http://localhost:8080/ 跳成 https://localhost:8080/ ——但你实际监听的是 :8443,或者用了域名却跳回 IP。
- 正确做法:开两个 goroutine,一个跑
r.RunTLS(":8443", cert, key),另一个跑http.ListenAndServe(":80", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "https://" + r.Host + r.RequestURI, http.StatusMovedPermanently) })) -
r.Host会保留原始 Host 头(如myapp.local:80),跳转后变成https://myapp.local:80/xxx——但端口不对,所以建议在跳转前统一处理:host := strings.TrimSuffix(r.Host, ":80") - 别在 HTTPS server 里写
router.Use拦截 HTTP 请求,它收不到
为什么浏览器始终提示“不安全”,点进去还说证书无效
自签名证书默认不被任何系统信任,这是设计使然,不是配置错。你看到的警告(如 Chrome 的“您的连接不是私密连接”)和详细页里的“此服务器无法证明其身份”都是正常现象。真正要排查的是证书是否被正确加载、是否匹配访问域名、以及是否被中间代理篡改。
- 确认访问 URL 的域名/CN 完全一致:用
https://localhost访问,证书 CN 就得是localhost;用https://127.0.0.1,CN 就得是127.0.0.1 - Mac 上可手动将
cert.pem拖入钥匙串,并设为“始终信任”;Windows 可双击安装到“受信任的根证书颁发机构” - 如果用 curl 测试:
curl -k https://localhost:8443/test成功,但浏览器失败,基本确定是信任链问题,不是服务端配置问题 - 别试图用 Let’s Encrypt 的
fullchain.pem替换自签名证书——它需要 ACME 协议支持,Gin 不内置,硬塞只会报x509: certificate signed by unknown authority











