本页目录

Caddy 操作手册

Caddy 是用 Go 写的 Web 服务器/反向代理,核心卖点是自动 TLS(ACME + Let's Encrypt 零配置)和简洁的 Caddyfile 配置语法。配置文件位置取决于安装方式:包管理器装的一般在 /etc/caddy/Caddyfile,手动部署的在 ./Caddyfile

配置

静态文件服务器

example.com {
    root * /var/www/html                 # * 匹配所有路径
    file_server                          # 静态文件服务 (自动 directory listing)
    encode gzip zstd                     # 响应压缩
}

反向代理

grafana.example.com {
    reverse_proxy 127.0.0.1:3000 {
        # 传给后端的 headers (后端日志能看到真实 client)
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-For {remote_host}
        header_up X-Forwarded-Proto {scheme}
        header_up Host {upstream_hostport}
    }
}

多个后端 (负载均衡)

api.example.com {
    reverse_proxy backend-1:8080 backend-2:8080 backend-3:8080 {
        lb_policy least_conn               # round_robin / least_conn / random
        health_uri /health                  # 健康检查端点
        health_interval 30s
    }
}

mTLS (双向认证)

otlp.example.com {
    tls /etc/caddy/certs/server.crt /etc/caddy/certs/server.key {
        client_auth {
            mode require_and_verify
            trusted_ca_cert_file /etc/caddy/certs/ca.crt     # 信任的 CA
            trusted_leaf_cert_file /etc/caddy/certs/revoked.caddy  # 吊销列表
        }
    }
    # 只放行特定路径, 其余 403
    @otlp path /api/v1/otlp/*
    reverse_proxy @otlp 127.0.0.1:4318
    respond 403
}

重载与热更新

# 验证配置语法 (改了 Caddyfile 后先验证再 reload)
caddy validate --config /etc/caddy/Caddyfile
# → 输出 "Valid configuration" 或错误详情

# 热重载 (不中断现有连接, 新连接用新配置)
systemctl reload caddy
# 或 caddy reload --config /etc/caddy/Caddyfile

# 查看最终生成的 JSON 配置 (Caddy 内部把 Caddyfile 翻译为 JSON)
caddy adapt --config /etc/caddy/Caddyfile

# 查看当前加载的配置
caddy fmt --overwrite /etc/caddy/Caddyfile   # 格式化 Caddyfile

证书管理

Caddy 默认自动管理 Let's Encrypt 证书——首次启动时通过 ACME HTTP-01 或 TLS-ALPN-01 challenge 签发,到期前自动续期。

# 查看管理的证书
caddy list-certificates

# 数据目录 (证书 + OCSP staple + account key):
# /var/lib/caddy/.local/share/caddy/

# 使用静态证书 (不自签 LE)——在 tls 中指定文件路径:
tls /etc/caddy/certs/example.crt /etc/caddy/certs/example.key

# 多域名 SAN 证书
example.com, *.example.com {
    tls /etc/caddy/certs/wildcard.crt /etc/caddy/certs/wildcard.key
    ...
}

日志

# 默认 JSON 格式输出到 stderr (由 systemd journal 收集)
journalctl -u caddy -f

# 或配置 Caddyfile 写文件:
# log {
#     output file /var/log/caddy/access.log {
#         roll_size 100mb
#         roll_keep 5
#     }
#     format json
# }

故障排查

# 启动失败
caddy validate --config /etc/caddy/Caddyfile   # 先查语法
journalctl -u caddy --since "5 min ago" --no-pager | tail -50

# TLS 证书错误
curl -vI https://example.com 2>&1 | grep -E 'SSL|cert|verify'
# → 证书过期/域名不匹配/ACME challenge 失败 (看 journalctl)

# 502 Bad Gateway (后端不可达)
# → Caddy 能连到 upstream 吗?
curl -I http://127.0.0.1:3000
# → 检查后端健康: systemctl status <backend>

# HTTP/3 不工作
# → Caddy 默认开 h3, 但需要:
#   - 443 端口 UDP 被防火墙放行
#   - Caddy 的 internal port = external port (否则 alt-svc 端口不对)