CertMagic本地跑不通主因是ACME HTTP-01挑战失败:Let’s Encrypt不验证私有地址,需真实域名A记录指向公网IP、80端口开放且可外网访问/.well-known/acme-challenge/。

直接用 certmagic.HTTPS 跑不起来,大概率不是代码问题,而是没让 ACME 挑战通得过——Let’s Encrypt 根本连不到你的 /.well-known/acme-challenge/。
为什么 certmagic.HTTPS 本地跑不通
Let’s Encrypt 绝对不验证 localhost、127.0.0.1 或任何私有地址(如 192.168.x.x)。它只认公网可解析的域名,且必须能从外网 HTTP 访问到挑战路径。
- 别在开发机上直接跑
certmagic.HTTPS([]string{"localhost"}, nil)—— 它会静默跳过或报no domains provided - 临时测试也得配真实域名:A 记录指向你服务器的公网 IP,哪怕只是
test.yourdomain.com -
certmagic.HTTPPort必须设为80,且防火墙/云厂商安全组要放行 80 端口;ACME HTTP-01 挑战强制走 HTTP,不走 HTTPS - 如果你机器在 NAT 后(比如家用宽带),需做端口映射,否则外网根本连不到你的 80 端口
staging 环境必须显式配置
不设 staging,certmagic 默认直连 Let’s Encrypt 生产环境(https://acme-v02.api.letsencrypt.org/directory),5 分钟内失败 5 次就会触发速率限制,后续申请全被拒。
- 开发阶段务必加这行:
certmagic.DefaultACME.CA = certmagic.CAStaging - 邮箱不能留空或填假地址,否则注册失败,报错类似
acme: error code 400 "urn:ietf:params:acme:error:invalidContact" - 首次运行会生成账户密钥并绑定邮箱,删缓存目录(默认
~/.local/share/certmagic)才能重来 - 缓存目录建议显式指定,避免权限问题:
Storage: &certmagic.FileStorage{Path: "./certs"}
证书文件路径和权限踩坑点
Go 原生 http.ListenAndServeTLS 和 certmagic 都依赖文件系统读取,路径错、权限高、内容空都会崩,但错误提示极不友好。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
立即学习“go语言免费学习笔记(深入)”;
- 路径必须绝对:用
filepath.Abs("cert.pem")拼,别传相对路径"./cert.pem",工作目录一变就open ./cert.pem: no such file or directory - 私钥权限必须是
0600,Linux 下若为0644,Go 会报tls: failed to find any PEM data in certificate input(实际是权限拒绝,不是格式错) - 证书文件(
certFile)必须是完整链:Let’s Encrypt 的fullchain.pem,不是cert.pem;拼错顺序或漏中间证,浏览器就报NET::ERR_CERT_AUTHORITY_INVALID - 用
openssl verify -CAfile fullchain.pem cert.pem可验证链是否完整
自动续期为什么没反应
certmagic.ManageSync 或 HTTPS 启动后,证书续期是后台 goroutine 异步执行的,默认日志完全关闭。证书快过期了你也收不到任何通知。
- 必须手动启用调试日志:
certmagic.DefaultLogger = zap.NewStdLog(zap.L())(需引入go.uber.org/zap) - 续期检查默认每 24 小时一次,但失败只打日志,不 panic、不阻塞、不重试——这意味着你得自己监控日志里有没有
failed to obtain certificate或certificate expires in < 72h这类关键信息 - 如果 Nginx/Apache 已占着 80/443,
certmagic.HTTPS会直接失败;此时只能改用certmagic.ManageSync手动获取证书,再喂给其他 server
最常被忽略的其实是日志静默——证书过期前 3 天没告警,服务就突然开始报 SSL 错误,而排查点往往卡在 DNS 或端口,没人去看 certmagic 的 goroutine 日志输出是否被关了。

















