Go 用 http.ListenAndServeTLS 启动 HTTPS 服务,需 PEM 格式证书(域名证+中间证)和未加密私钥;自签名证需含 SAN;生产推荐 certmagic 自动化 ACME;HTTP 重定向需单独 :80 server 并发运行。
ht
tp.ListenAndServeTLS 是启用 HTTPS 的核心函数Go 标准库不依赖外部 Web 服务器,直接用 http.ListenAndServeTLS 就能启动带 TLS 的 HTTP 服务。它要求传入两个参数:certFile(证书文件路径)和 keyFile(私钥文件路径),且必须是 PEM 格式。
常见错误是把证书链顺序搞错,比如把中间证书放在根证书前面,或漏掉中间证书——浏览器会报 x509: certificate signed by unknown authority。
cert.pem)应按「域名证书 → 中间证书」顺序拼接,不能包含私钥key.pem)必须是未加密的 PEM 格式;若用 openssl genrsa -aes256 生成过带密码的私钥,需先用 openssl rsa -in key.pem.enc -out key.pem 去密生产环境必须用 CA 签发的证书,但开发调试时可用 openssl req 生成自签名证书。关键点在于:Subject Alternative Name(SAN)必须包含你将访问的域名或 IP,否则现代浏览器(Chrome/Firefox)会拒绝连接,报 NET::ERR_CERT_INVALID。
生成命令示例(支持 localhost 和 127.0.0.1):
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/CN=localhost" -addext "subjectAltName = DNS:localhost,IP:127.0.0.1"
http.ListenAndServeTLS(":8443", "cert.pem", "key.pem", nil)
-k 跳过校验certmagic)Go 原生 http.ListenAndServeTLS 不支持自动申请/续期证书。若想零配置跑 HTTPS,推荐用 certmagic 库——它封装了 ACME 协议,能自动向 Let's Encrypt 申请、续订并热加载证书。
只需几行代码:
import "github.com/caddyserver/certmagic"
func main() {
certmagic.DefaultACME.Agreed = true
certmagic.DefaultACME.Email = "admin@example.com"
certmagic.HTTPPort = 80
certmagic.HTTPSPort = 443
http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello over HTTPS!"))
}))
log.Fatal(certmagic.HTTPS([]string{"example.com"}, nil))
}
:80 完成 HTTP-01 挑战,然后申请证书并监听 :443
只开 HTTPS 不够,用户可能仍从 http:// 访问。标准做法是在 HTTP 端口启动一个单独的 server,把所有请求 301 重定向到 HTTPS。
典型实现:
go func() {
http.RedirectHandler("https://"+r.Host+r.RequestURI, http.StatusMovedPermanently)
}()
http.ListenAndServe(":80", nil)
http.ListenAndServeTLS(":443", "cert.pem", "key.pem", nil)
ListenAndServe* 必须并发启动(用 go func() {...}() 或 goroutine)r.Host 要确保不含端口(如 example.com:80);生产中建议硬编码域名,避免 Host 头被篡改