Caddy 反向代理使用笔记
为什么使用 Caddy
在此之前,我一直使用 Nginx Proxy Manager 管理我的 HTTPS 服务与证书申请,NPM 确实是一个不错的项目,它在我的服务器上稳定运行了两年多。
但即便如此,NPM 也存在一些不可忽视的问题。首先就是开发进度缓慢,v2 版本目前已经没有功能性开发了,承诺的 v3 版本一直难产。我从不对开源项目的 Roadmap 苛求,但是从个人角度出发确实有必要考虑迁移到其他项目之上。Caddy 一直是我的备选,因此在前不久 NPM 迁移过程中又遇到登陆界面提示 Bad Gateway
时,我选择放弃 NPM,尝试 Caddy。
Caddy 与 NPM 其实是两个完全不同的东西,Caddy 更像是 Nginx 本身,没有图形界面,不能在网页上点点鼠标就完成。但是 Caddyfile
的存在又简化了整体的配置流程,对于熟悉终端的人来说甚至配置起来会比 NPM 还要方便。当然对于有些人来说,SSH 到服务端是整件事里最大的障碍,当前版本的 Caddy 恐怕并不适合这些人去使用。
Docker Compose
在整个 Caddy 部署过程中,我遇到的第一个也是唯一一个坑就是 Caddy 的官方 Docker 镜像是最小化构建的,这就导致我所需要的 Cloudflare 模块并不包含在该镜像中。当然解决办法也很简单,就是自己使用官方提供的 builder
构建包含所需模块的镜像,我用 Github Action 每日构建最新镜像,并推送到了 ghcr.io/sixiaolong1117/my-caddy:latest
,这样就随时可以拉取到包含 Cloudflare 模块的 Caddy 镜像。
对于任何需要其他模块的人,可以 Fork 我的 Repo 并按照 README 中的要求修改脚本,来构建自己的镜像。
当解决了镜像问题之后,以下是我的 docker-compose.yml
:
1 | services: |
需要注意几点:
./conf
映射到了容器内的/etc/caddy
,这就是之后的Caddyfile
所在位置。/data
与/config
被我映射到了由 Docker 管理的卷中,这些目录的内容主要是证书和其他数据,因此需要持久化存储,但又不是特别重要(Caddyfile 保存了所有重要的配置信息,证书本身由 Caddy 负责管理即可)。- 环境变量中的
CLOUDFLARE_API_TOKEN=${CF_API_TOKEN}
要求在docker-compose.yml
同目录创建.env
文件,内容写CF_API_TOKEN=<你的 CF TOKEN>
,该 TOKEN 应有 DNS 编辑权限。 http_proxy=
、https_proxy=
、all_proxy=
与no_proxy=
所设置的代理是为了加速访问,否则 Caddy 可能会卡在 DNS 验证或证书申请。
Caddyfile
在 ./conf
创建文件 Caddyfile
,我们所有的反代配置都会写到这一个文件中。
联系邮箱(可选)
1 | { |
这部分是因为 Let’s Encrypt 需要提供一个邮箱用于接收证书到期提醒、紧急安全通知,同时作为证书注册的联系人信息。如果不设置,则 Caddy 默认会用一个匿名邮箱(如空邮箱),不过不推荐那样做。
Caddyfile 语法
Caddyfile实际上是很简单的,其语法如下:
1 | example1.com example2.com { |
简单来说就是给定域名,然后说需要 Caddy 负责处理什么。比如最简单的,我们需要 Caddy 为域名 example1.com
申请证书(通过 Cloudflare DNS-01 验证),并返回 “Hello, world!”,那我们可以这么写:
1 | example1.com { |
此处通过 {env.CLOUDFLARE_API_TOKEN}
调用前文配置要求填写的 TOKEN。
而对于反代的配置,也就是修改 respond
部分,比如反代本地端口 8080
的服务:
1 | example1.com { |
其他返回值同理。
通常情况下我们不会单独为每个域名申请证书,尤其是在只有一个域名的情况下使用子域名,因为证书信息是公开可查询的,一个域名下所有子域名证书都会被查询到。个人使用的情况下这相当于暴露了所有反代的服务,因此通常会使用泛域名来解决这个问题。Caddy 也支持泛域名证书的申请,不过如果是用作反代的话就需要单独写 respond
部分:
1 | *.example1.com { |
如此,我们就完成了对 *.example1.com
的泛域名证书申请,同时让 8080
端口的服务可以通过 service1.example1.com
访问。
一个相对完整的 Caddyfile
示例:
1 | { |
启动服务
在写完 Caddyfile
并保存之后,在 docker-compose.yml
同目录运行:
1 | docker compose up -d |
即可启动服务,日后修改 Caddyfile
之后也需要运行:
1 | docker compose restart |
来重启服务。
对于不方便 SSH 访问服务端的人来说,可以将 Caddyfile
远程挂载到其他设备(如通过 WebDAV 挂载到手机文件管理器上),然后通过 SSH 脚本(如苹果快捷指令)来运行 Docker 命令。需要注意远程挂载文件的安全性问题,这并非本笔记所涉及范围,不做赘述。
其他
很多服务在反代时都要求传递 header
,一些网盘服务需要修改上传文件大小,在 Caddy 下可以这么配置:
1 | openlist.example1.com { |