常见坑
用 Tab 缩进 Caddyfile
章节「用 Tab 缩进 Caddyfile」example.com { respond "hi"}Caddyfile 对空格敏感。报错:
Error: adapting config using caddyfile: parsing caddyfile tokens for 'example.com': tokenization error: line 2: token is not a valid token
Error: Caddyfile:2 (parse error...): unrecognized token: '修法:
caddy fmt --overwrite CaddyfileDocker 里连 localhost
章节「Docker 里连 localhost」reverse_proxy localhost:3000 # ✗容器里的 localhost 是容器自己。连宿主机要用:
reverse_proxy host.docker.internal:3000或直接用服务名(同一网络下):
reverse_proxy app:3000Docker volume 忘了挂/data
章节「Docker volume 忘了挂/data」容器每次重建都重新申请证书,很容易撞上 Let’s Encrypt 每周 50 次的限额,然后开始收获一串 429。
docker run -v caddy_data:/data -v caddy_config:/config ...上游只监听 127.0.0.1 导致 502
章节「上游只监听 127.0.0.1 导致 502」应用绑在 127.0.0.1:3000,Caddy 在另一个网络命名空间,连不上。
改成监听 0.0.0.0,然后用防火墙挡住外部访问:
sudo ufw allow from 172.17.0.0/16 to any port 3000指令顺序导致规则失效
章节「指令顺序导致规则失效」example.com { respond "hi" # 先终结了请求 reverse_proxy localhost:3000 # 永远执行不到}用 route 显式排序:
example.com { route { reverse_proxy localhost:3000 respond "hi" }}handle块顺序反了
章节「handle块顺序反了」example.com { handle { # 通配块在前,吃掉所有请求 root * /var/www file_server } handle /api/* { # 永远不会被匹配 reverse_proxy localhost:8080 }}具体永远在前。
重载后配置没变
章节「重载后配置没变」caddy reload 读的是默认路径 /etc/caddy/Caddyfile,而你改的是当前目录的文件。
sudo caddy reload --config /etc/caddy/Caddyfile# 或caddy reload --config ./Caddyfile --adapter caddyfile证书申请失败
章节「证书申请失败」| 报错 | 解法 |
|---|---|
no such host |
DNS 没指过来,或指到 CDN 了 |
connection refused |
80 端口不通 |
too many certificates |
撞速率限制,等 |
NXDOMAIN CAA |
加 CAA 记录或删掉现有的 |
查看 ACME 日志:
sudo journalctl -u caddy -f | grep -i acmeCloudflare 下申请不到证书
章节「Cloudflare 下申请不到证书」橙色云朵会阻断 HTTP-01 验证。两个方案:
- DNS-01(推荐,也支持通配符):
tls {dns cloudflare {env.CF_API_TOKEN}}
- 给
/.well-known/acme-challenge/加一条灰云 DNS 记录
环境变量改了不生效
章节「环境变量改了不生效」reload 不会重读环境变量,必须 restart:
sudo systemctl restart caddy301 循环
章节「301 循环」上游返回了 http:// 的 Location,但 Caddy 对外强制 https。改上游配置,或者在 Caddy 层重写:
reverse_proxy localhost:3000 { header_down Location "https://{http.request.host}{uri}"}静态文件 404
章节「静态文件 404」路径不对是最常见的。确认:
ls -la /var/www/html/index.html还有权限:Caddy 的 systemd 服务以 caddy 用户运行,读不到就是 403。
sudo -u caddy ls /var/www/html上传大文件 413
章节「上传大文件 413」三层限制都可能拦:
# Caddy 层request_body { max_size 100MB}# 前面如果有 Nginxclient_max_body_size 100m;# 上游应用自己(以 nginx 为例)client_max_body_size 100m;WebSocket 定时断开
章节「WebSocket 定时断开」某层代理的空闲超时(通常是 60 秒)。两个都要做:
reverse_proxy localhost:3000 { transport http { response_header_timeout 0 }}setInterval(() => client.ping(), 25_000); // 服务端心跳日志把磁盘写满
章节「日志把磁盘写满」同时检查两处:
df -h # 空间df -i # inode —— 小文件多了会先耗尽 inodesudo du -sh /var/log/caddyreload 失败但配置已改
章节「reload 失败但配置已改」reload 是「加载新配置 → 原子切换」。如果新配置语法错误,旧配置继续跑——这是好事,但也意味着你以为改上了其实没改上。
所以:先 validate。
sudo caddy validate --config /etc/caddy/Caddyfile && sudo caddy reload不知道路由为什么没命中
章节「不知道路由为什么没命中」example.com { debug}它会把每个请求的路由匹配过程打到 stderr。看到 no match 就知道是没匹配上,而不是请求根本没到这台机器。
find哪里最容易出错
章节「find哪里最容易出错」按被踩频率排:
- 指令/handle 顺序 → 规则写了但没生效
- Docker 网络 → localhost 指向错了地方
- 环境变量不重读 → 改了值没变化
- 权限 → 静态文件 403,证书目录读不到
- 中间代理超时 → 连接莫名断开