Caddy 反向代理实战:配置三行就自动签好 HTTPS 证书(2026)

Caddy 2 的核心优势是「把 HTTPS 变成默认行为」:Caddyfile 里只要写 域名 { reverse_proxy 127.0.0.1:8080 } 这三行,它就会自动向 Let's Encrypt 申请证书、自动续期、自动把 HTTP 跳转到 HTTPS,并默认启用 HTTP/2 与 HTTP/3。 对比 Nginx 需要装 Certbot、写 server 块、配续期定时任务,Caddy 把这些全部内置——证书存在 /var/lib/caddy/.local/share/caddy,续期在证书到期前 30 天自动触发。我在 2026 年 10 月用它替换了一台小 VPS 上的 Nginx,配置从 60 行缩到 8 行,证书再也没有手动碰过。

上面这段是结论块。下面是 Caddy 与 Nginx 的取舍、完整配置、验证方式,以及三个真会踩的坑。

Caddy 反向代理的自动 HTTPS 链路

Caddy 和 Nginx 该怎么选?

结论:新站、个人项目、自建服务优先 Caddy;需要深度调优、复杂 rewrite、或团队既有的 Nginx 生态时留在 Nginx。 这不是谁替代谁的问题,是维护成本的取舍:

维度 Nginx Caddy
证书 装 Certbot + 定时续期 内置,全自动
配置复杂度 高(server 块、header 细节) 低(域名 + 后端两行)
HTTP/2、HTTP/3 需显式开启 默认开启
WebSocket 要手写 Upgrade 两行 自动处理
性能 高并发场景更强 日常场景完全够
生态与文档 海量 相对少
可扩展 模块多、成熟 部分功能要靠插件

一句话判断:如果你配 Nginx 时会去百度「Upgrade 那两行怎么写」,那 Caddy 更适合你;如果你已经在维护一套复杂的 Nginx 配置且有团队共识,别为了省几行去迁。

Caddy 部署五个步骤

Caddy 反向代理部署步骤

第一步:从官方源安装

$ sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
$ curl -1sLf https://dl.cloudsmith.io/public/caddy/stable/gpg.key \
    | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
$ sudo apt update && sudo apt install -y caddy
$ caddy version

安装后 systemd 里就有 caddy.service,它默认监听 80 和 443,并且开机自启——这一点和 Nginx 一样,但要记住它已经占了这两个端口。

步骤 1:安装 Caddy

第二步:写 Caddyfile

主配置在 /etc/caddy/Caddyfile:

app.example.com {
    encode gzip
    reverse_proxy 127.0.0.1:8080
}

就这么多。Caddy 看到域名后会自动: 申请证书、监听 443、把 80 上的请求 301 跳到 443、启用 HTTP/2。

改完先校验再重载,别直接把服务重启断了:

$ sudo caddy validate --config /etc/caddy/Caddyfile
$ sudo systemctl reload caddy

步骤 2:写 Caddyfile

第三步:放行端口并验证

证书申请需要 80 端口可达(HTTP-01 挑战),这是最容易被忽略的一步。

$ sudo ufw allow 80,443/tcp
$ sudo systemctl reload caddy
$ curl -I https://app.example.com
# 期望:HTTP/2 200,且有有效证书

我建议用 curl -vI 看一眼证书链,确认签发者是 Let's Encrypt(或 ZeroSSL)。

步骤 3:放行端口并验证

第四步:加日志与基础防护

app.example.com {
    log {
        output file /var/log/caddy/app.log
    }
    encode gzip
    reverse_proxy 127.0.0.1:8080
}

关于限流要说清楚:标准版 Caddy 并不内置 rate_limit 指令,它是第三方模块 caddy-ratelimit,需要自己用 xcaddy build --with github.com/mholt/caddy-ratelimit 重新编译。所以想要限流,三条路更省事:

  1. 把限流交给上游——如果站点前面挂了 Cloudflare,直接用 Cloudflare Rate Limiting 在边缘限,性能更好。
  2. 用 Nginx 专门做限流层,Caddy 只做 TLS 终结和反代。
  3. 确实需要 Caddy 内限流,就用 xcaddy 打插件,接受"非标准构建"的维护成本。

步骤 4:加日志与基础防护

第五步:反代到 HTTPS 后端(特殊场景)

如果后端自己也是 HTTPS(比如某些自建服务强制 HTTPS),写法不同:

app.example.com {
    reverse_proxy https://127.0.0.1:8443 {
        transport http {
            tls_insecure_skip_verify
        }
    }
}

tls_insecure_skip_verify 是跳过对后端自签证书的校验——只在后端证书是自签且你确定内网可信时用,否则链路校验就断了。

Caddyfile 常用片段:多站点、重定向与基本认证

结论:Caddyfile 的片段(snippet)用 (名字) 定义、import 名字 引用,能把重复配置收敛成一处。 下面是四个高频片段,抄了就能改:

# 1) 多站点共用一组配置
(common) {
    encode gzip
    log {
        output file /var/log/caddy/{args[0]}.log
    }
}

a.example.com {
    import common a
    reverse_proxy 127.0.0.1:8080
}

b.example.com {
    import common b
    reverse_proxy 127.0.0.1:9090
}

# 2) 老域名整站 301
old.example.com {
    redir https://new.example.com{uri} permanent
}

# 3) 纯静态目录
static.example.com {
    root * /var/www/site
    file_server
}

# 4) 基本认证(Caddy 2.8+ 指令名为 basic_auth)
admin.example.com {
    basic_auth {
        用户名 用 hash-password 生成的哈希
    }
    reverse_proxy 127.0.0.1:8080
}

密码哈希这样生成:

$ caddy hash-password --plaintext '你的密码'
# 把输出整段粘到 basic_auth 里

注意 Caddy 2.8 把 basicauth 改名为 basic_auth,用旧名字会直接报 unrecognized directive——这是升级后最常见的"配置突然失效"原因。redir ... permanent 写老域名的 301 尤其有用:换域名时用它把旧链接的权重整体迁移过去。

三个真会踩的坑

  1. 80/443 被 Nginx / Apache 占用。 系统里如果已经装了 Nginx 占着 443,Caddy 会启动失败,日志里是 bind: address already in use。二选一:要么 systemctl stop nginx && systemctl disable nginx 彻底让位,要么让 Caddy 只做反代、Nginx 在前。 两台 Web 服务器抢同一个端口是新手最常见的翻车点。

  2. 云安全组没放行 80,证书一直申请失败。 HTTP-01 挑战必须从公网访问 http://app.example.com/.well-known/acme-challenge/...。ufw 放行了但安全组没放,Caddy 日志里会反复出现 challenge failed,域名 DNS 检查却完全正常——判断方法就是 curl -v http://app.example.com 从外部能不能通。

  3. 域名没解析到本机就写进了 Caddyfile。 Caddy 会去申请证书,但 ACME 服务器验证失败,于是反复重试、触发 Let's Encrypt 的速率限制。正确顺序是:先让 DNS 生效(dig +short app.example.com 确认返回本机 IP),再写 Caddyfile、再 reload。

自建服务怎么配合 Caddy?

Caddy 是自建服务的「统一入口」——所有服务都只绑 127.0.0.1,公网入口全部交给 Caddy。 这是我给自建服务定的默认姿势:比如 Vaultwarden 密码库 强制要求 HTTPS,把它绑在 127.0.0.1:8080,用 Caddy 一句 reverse_proxy 接上即可;数据库、面板这类不该公网直接访问的服务,也只暴露给 Caddy。唯一入口意味着唯一要加固的地方,比每个服务各自暴露一个端口安全得多——如果需要连入口都不开放,就换成 Cloudflare Tunnel 的零端口方案。

Caddy 常见问题(2026)

Q:Caddy 免费吗?
A:Caddy 是开源软件(Apache-2.0),个人和商业使用都免费。它自动申请的 Let's Encrypt 证书也免费。

Q:Caddy 和 Nginx 哪个性能好?
A:极端高并发场景 Nginx 略优且调优空间更大;日常中小流量两者没有可感知差异。多数人选 Caddy 是为了省证书和配置的维护成本,不是为性能。

Q:Caddyfile 里怎么配多个站点?
A:每个域名一个块,平铺即可。Caddy 会为每个域名分别申请证书,互不影响。

Q:证书存在哪?能备份吗?
A:默认在 /var/lib/caddy/.local/share/caddy,备份这个目录就等于备份了证书和 ACME 账号。迁移服务器时带上它,能避免重新申请的频率限制。

Q:WebSocket 要额外配置吗?
A:不用。reverse_proxy 会自动透传 Upgrade 头,这是 Caddy 相比 Nginx 省心的地方之一。

一句总结

Caddy 用「约定优于配置」把 HTTPS 的样板工作全部吃掉:写域名、指后端、reload,剩下交给它。它的代价是生态比 Nginx 小、部分高级功能要靠插件——但对绝大多数个人站和自建服务,这个代价换来的省心是值得的。

相关阅读

上一篇 Aider 终端 AI 编程:接国产模型,每步自动 git 提交(2026)