从 Nginx 迁移到 Caddy
我的家庭内网中部署了若干 http 服务,为了使用方便,统一使用 Nginx 做了反代以及 https 证书分配,最近我发现 Caddy 在我的使用场景下比 Nginx 更简洁、方便管理。
After
我的家庭内网是在 2024 年搭建的,当时为了给 Nginx 反代配置 h3 和 https 证书自动更新,费了好大一番手脚。 尤其是这个 https 证书自动更新,更是让我吃了一番苦头。
刚开始我便尝试使用过 Traefik 和 Caddy,因为它们两可以自动托管并更新 https 证书。我的域名托管在 Cloudflare 上,因此需要通过 DNS-01 来生成证书。
但在初期的部署过程中,Traefik、Caddy、ACME.sh 都存在获取不到 DNS 记录导致超时的问题,我百般排查不得其解。
排查良久后认为是 DNS 的问题,使用 AI 结合 go-acme 做了一个生成 https 证书的网关程序:https://github.com/vhvy/acme-gateway-go 。
原理也很简单,在 Docker 容器内通过 iptables 劫持 lego 客户端的 DNS 请求,强制递归转发给 Cloudflare 的 DoH,以便获取最新的 DNS 记录信息。
问题虽然是解决了,但我总觉得这套配置太过冗余,直到前不久,我发现了 Caddy 的 propagation_timeout 参数。
Before
Caddy 的 propagation_timeout 参数可以跳过 DNS 传播检查,直接让 ACME 服务器去 Cloudflare 那边查询,免去了本地 DNS 各种异常的问题。
说干就干,结合 AI 花了半小时将 Nginx 迁移到了 Caddy,不得不说 Caddy 的配置真的是简洁,h3、websockets 不用任何额外配置,https 证书续期配置也非常方便,Caddy 真好用!
需要注意的是,Caddy 没有直接集成 Cloudflare 的 DNS Challenge 服务,需要手动编译,或者使用社区提供的 Docker 镜像: ghcr.io/caddy-dns/cloudflare
在内网环境下,还可以使用静态文件服务提供生成的泛域名证书,让一些不需要反代的服务如 Mikrotik Web 服务、群晖 NAS 等也可以方便的定时拉取并更新证书。
这里贴一下我的大概配置:
Docker compose 配置文件:
services:
caddy:
image: ghcr.io/caddy-dns/cloudflare:v0.2.4
container_name: caddy
restart: unless-stopped
network_mode: host
env_file: ./.env
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./data:/data
- ./config:/config
Caddy 配置文件:
{
email example@example.com
}
(cf) {
tls {
dns cloudflare {env.CF_API_TOKEN}
propagation_delay 60s
propagation_timeout -1
}
}
(insecure_tls) {
transport http {
tls_insecure_skip_verify
}
}
*.example.com {
import cf
abort
}
demo.example.com {
reverse_proxy 192.168.1.111:36180
}
demo2.example.com {
redir / /web 301
reverse_proxy https://192.168.1.112:44233 {
import insecure_tls
}
}
# curl https://ssl.example.com/example.com/cert.key
# curl https://ssl.example.com/example.com/cert.crt
ssl.example.com {
root * /data/caddy/certificates/acme-v02.api.letsencrypt.org-directory
@cert {
remote_ip 192.168.1.0/24
header X-Token "THISISMYTOKEN"
path_regexp c ^/([^/]+)/cert\.(crt|key)$
}
handle @cert {
rewrite * /wildcard_.{re.c.1}/wildcard_.{re.c.1}.{re.c.2}
file_server
}
handle {
respond 404
}
}