跳到正文

自动 HTTPS

Caddy 的默认行为就是自动 HTTPS。你把域名写进地址位,它就自己去搞定证书——这是它相对 Nginx 最大的省心之处。

example.com {
respond "ok"
}

这一行背后Caddy 做了:

  1. 监听 80 和 443
  2. 解析域名 → 确认指向本机
  3. ACME HTTP-01 验证,签发证书
  4. 存到 /var/lib/caddy/.local/share/caddy(或容器里的 /data)
  5. 自动续期(到期前 30 天开始)
  6. HTTP 308 跳转到 HTTPS

没公网 IP 时ACME 验证会失败。两个选择:

方案一:内部 CA(开发环境够用)

https://internal.example.com {
tls internal
respond "ok"
}

Caddy 会自签一张证书。用这个 CA 的根证书加进系统信任库,之后浏览器就不报错了。

方案二:DNS-01 验证(推荐,通配符必须用这个)

HTTP-01 需要公网可达 80 端口,DNS-01 只需要操作 DNS 记录。

*.example.com {
tls {
dns cloudflare {env.CF_API_TOKEN}
}
reverse_proxy localhost:9000
}

各家 DNS provider 的写法在 DNS Providers 模块文档 里,常见的有 cloudflare / route53 / digitalocean / duckdns。

example.com {
tls {
issuer acme {
ca https://acme.zerossl.com/v2/DV90
email admin@example.com
}
}
}

默认是 Let’s Encrypt 和 ZeroSSL 轮着用(保险起见,签发额度分开算)。

已经买好的证书:

example.com {
tls /etc/caddy/certs/fullchain.pem /etc/caddy/certs/privkey.pem
}
https://192.168.1.100 {
tls internal
respond "internal"
}

浏览器照样会警告自签证书,但可以手工导入根证书消除警告。

example.com {
auto_https off
respond "no tls"
}

或者在全局层面关:

{
auto_https off
}
example.com:8080 {
respond "plain http"
}
终端窗口
# 看证书链和有效期
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -dates -issuer -subject
# Caddy 的证书管理日志
sudo journalctl -u caddy -f | grep -i acme
报错 原因
no such host DNS 没解析到本机,或解析到了 CDN
connection refused (验证时) 80 端口被防火墙挡了,或被占用
too many certificates already issued 撞了Let’s Encrypt 每周 50 次的速率限制,等一周
cname ... noquots 用了代理但 CAA 记录没放行 CA