NoctisNode
← 指南安全2026-10-2310 分钟

Caddy 自动 HTTPS:Caddy 自动 TLS 的原理与故障排查

Caddy 通过 ACME 为配置中的每个域名自动申请并续期 TLS 证书。了解 HTTP-01、TLS-ALPN-01、DNS-01 通配符证书、按需 TLS 以及常见故障。

简答:只要站点地址是公网域名,Caddy 就会自动启用 HTTPS。它通过 ACME(默认使用 Let's Encrypt 或 ZeroSSL)申请证书,在 80 和 443 端口上通过 HTTP-01 或 TLS-ALPN-01 质询证明域名控制权,将 HTTP 重定向到 HTTPS,并在证书到期前自动续期,无需任何额外配置。

所谓 Caddy 反向代理,就是由 Caddy 终止 HTTPS 连接,再用 `reverse_proxy` 指令把请求转发到其他端口、容器或主机上的应用。TLS 加代理只需几行配置,这正是人们选择 Caddy 的主要原因。

三行配置实现带 SSL 的反向代理

只要 DNS 已指向服务器、80 和 443 端口可达,下面这个 Caddyfile 就是一个为两个主机名提供 HTTPS 的完整反向代理。Caddy 启动时会为两个域名获取证书,支持 HTTP/1.1、HTTP/2 和 HTTP/3,并向后端传递 `X-Forwarded-For`、`X-Forwarded-Proto` 和 `X-Forwarded-Host`。`email` 选项是可选的,但填写后 CA 可以就证书即将过期或被吊销等情况联系你。

通过官方 apt 仓库安装及 systemd 基础用法见 Caddy 反向代理指南;容器场景请参阅将 Caddy 用作 Docker 反向代理。修改后用 `sudo systemctl reload caddy` 生效。

# /etc/caddy/Caddyfile
{
	email [email protected]
}

example.com, www.example.com {
	reverse_proxy 127.0.0.1:8080
}

Caddy 自动 TLS 的底层原理

Caddy 加载配置时,会从站点地址中收集所有主机名,并决定每张证书由谁签发。公网域名交给公共 ACME 签发机构;`localhost`、IP 地址和仅限内网的名称则由 Caddy 自带的本地 CA 签发(等同于写 `tls internal`)。证书、私钥和 ACME 账户存放在 Caddy 的数据目录中:apt 包为 `/var/lib/caddy/.local/share/caddy`,官方 Docker 镜像为 `/data`。

续期在后台进行,远早于证书到期;在 CA 支持的情况下,Caddy 还会装订 OCSP 响应。如果签发失败,Caddy 会以指数退避重试,并在重试时使用 CA 的 staging 端点,以免耗尽生产环境的速率限制。多个共享同一存储的 Caddy 实例会相互协调,确保同一张证书只由一个实例申请。

质询方式CA 检查的内容前提条件支持通配符?
HTTP-01在 `http://domain/.well-known/acme-challenge/` 提供的令牌80 端口可从公网访问否
TLS-ALPN-01TLS 握手时出示的特殊证书443 端口可从公网访问否
DNS-01位于 `_acme-challenge.domain` 的 TXT 记录DNS 服务商 API 令牌,以及包含该服务商模块的 Caddy 构建是

用 DNS-01 申请通配符证书

`*.example.com` 这类通配符证书只能通过 DNS-01 质询签发。标准 Caddy 二进制不含 DNS 服务商插件,因此你需要用 xcaddy 自行构建(或在官方下载页面选择对应服务商),并给 Caddy 一个仅限编辑该区域 DNS 的 API 令牌。当 80 和 443 端口无法从公网访问时(例如纯内网服务器),DNS-01 同样可用。

不要把令牌写进 Caddyfile:把它放进 systemd 单元使用的环境文件中(`sudo systemctl edit caddy`,然后在 `[Service]` 下加入 `EnvironmentFile=/etc/caddy/caddy.env`),并用 `chmod 600` 限制该文件的权限。

# Build Caddy with a DNS provider module (example: Cloudflare)
xcaddy build --with github.com/caddy-dns/cloudflare

# Caddyfile: one wildcard certificate for all subdomains
*.example.com {
	tls {
		dns cloudflare {env.CF_API_TOKEN}
	}

	@app host app.example.com
	handle @app {
		reverse_proxy 127.0.0.1:3000
	}

	handle {
		respond "Unknown host" 404
	}
}

按需 TLS 与 staging 环境

按需 TLS(On-demand TLS)让 Caddy 在首次遇到某个陌生主机名的 TLS 握手时才去获取证书。它适用于客户把自己的域名指向你服务器的平台。务必配置 `ask` 端点:Caddy 会携带 `?domain=name` 调用它,只有返回 200 才继续。否则任何人都能把随意的域名指向你的 IP,让你触发速率限制。

调试阶段,可通过全局选项 `acme_ca` 切换到 Let's Encrypt 的 staging CA。staging 证书不受浏览器信任,但限额高得多,你可以放心折腾。完成后删除该选项,并可选择从数据目录中删除 staging 证书。

{
	on_demand_tls {
		ask http://127.0.0.1:5555/allowed
	}
}

https:// {
	tls {
		on_demand
	}
	reverse_proxy 127.0.0.1:8080
}

# Global options block for testing
{
	email [email protected]
	# Test against Let's Encrypt staging; remove when everything works
	acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}

Caddy TLS 常见故障及解决方法

  1. 01.DNS 未正确指向:A 或 AAAA 记录缺失、仍指向旧服务器或仍被缓存。过时的 AAAA 记录是经典陷阱,因为只要存在 IPv6,CA 会优先使用。用 `dig` 同时检查两者。
  2. 02.80 或 443 端口未开放:主机防火墙、云防火墙或路由器拦截了入站流量,导致 HTTP-01 和 TLS-ALPN-01 都无法完成。开放 80/tcp 和 443/tcp(HTTP/3 还需 443/udp)。
  3. 03.端口已被占用:Apache、nginx 或其他容器绑定了 80 或 443,Caddy 无法监听。停止该服务,或将其移到 Caddy 之后。
  4. 04.前置 CDN 代理:“橙色云朵”式的代理会在 Caddy 之前终止 TLS,可能导致 TLS-ALPN-01 失败。改用 DNS-01,或在签发期间将记录设为仅 DNS。
  5. 05.速率限制:反复失败或清空数据目录会触发 CA 限额(Let's Encrypt 限制每个主机名每小时的验证失败次数以及每周的重复证书数量)。先解决根本原因,使用 staging,并保持数据目录持久化。
  6. 06.CAA 记录:如果 CAA 记录只允许其他 CA,签发会被阻止。允许 `letsencrypt.org` 和 `sectigo.com`(ZeroSSL 使用),或移除该限制。
# Does the name resolve to this server (both IPv4 and IPv6)?
dig +short A example.com
dig +short AAAA example.com
curl -4 -s https://ifconfig.me ; echo

# Are ports 80 and 443 open in the host firewall?
sudo ufw status
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 443/udp

# Is something else already bound to 80/443?
sudo ss -ltnp '( sport = :80 or sport = :443 )'

# What does Caddy say?
sudo journalctl -u caddy --no-pager -n 100

到后端也使用 HTTPS

同一主机上的大多数后端在 localhost 上使用明文 HTTP,这没有问题。如果上游在另一台机器上或强制要求 TLS,请使用 `https://` 上游,并告诉 Caddy 要验证哪个名称、信任哪个 CA。除了快速测试外,避免使用 `tls_insecure_skip_verify`,因为它会移除代理与后端之间的防窃听保护。对于服务器之间的流量,私有的 WireGuard 隧道往往比管理后端证书更简单。

在拥有完整 root 权限和独立 IPv4 地址的 NoctisNode VPS 上,常规做法是:把 A 记录指向服务器(除非服务器有 IPv6,否则不要加 AAAA),开放 80 和 443,其余交给 Caddy。如需转发非 HTTP 流量,请参阅 Caddy TCP 与 SSH 代理。

example.com {
	reverse_proxy https://10.0.0.5:8443 {
		transport http {
			tls_server_name backend.internal
			tls_trust_pool file /etc/caddy/backend-ca.pem
		}
	}
}

常见问题

Q什么是 Caddy 反向代理?

A就是 Caddy Web 服务器接收客户端连接(通常终止 HTTPS),再通过 `reverse_proxy` 指令把请求转发给一个或多个后端服务。Caddy 会自动为其获取并续期 TLS 证书。

QCaddy 会自动续期证书吗?

A会。只要域名仍解析到该服务器且质询端口保持可达,Caddy 会在证书到期前很早就在后台续期,并在不重启的情况下重新加载。

Q为什么 Caddy 拿不到证书?

A最常见的原因是 DNS 记录指向别处(包括过时的 AAAA 记录)、80 和 443 端口被封、其他程序占用了这些端口,或反复失败后触发了速率限制。`journalctl -u caddy` 会显示具体的 ACME 错误。

QCaddy 能签发通配符证书吗?

A能,但只能通过 DNS-01 质询,这需要包含你的 DNS 服务商模块的 Caddy 构建,以及该区域的 API 令牌。

Q如何在 Caddy 中关闭自动 HTTPS?

A对单个站点使用 `http://` 站点地址,或设置全局选项 `auto_https off`。也可以使用 `auto_https disable_redirects`,保留证书但停止 HTTP 到 HTTPS 的重定向。

Caddy 自动 HTTPS:Caddy 自动 TLS 的原理与故障排查 · NoctisNode