容器化 Caddy 代理部署实战
背景
今天在维护服务器时发现,之前用 docker-compose 部署的 Caddy 反向代理服务,其配置文件所在的工作目录不知何时被删除了。虽然容器还在正常运行(因为 bind mount 的文件在容器启动后会被加载到内存中),但一旦容器重启就会因为找不到配置文件而启动失败。
问题发现与排查
第一步:查看容器状态
首先查看运行中的 Caddy 容器:
docker ps --filter "name=caddy"
发现容器确实在运行,已经运行了 4 周,镜像为 caddy:2-alpine。
第二步:查看挂载配置
docker inspect caddy --format '{{json .Mounts}}' | python3 -m json.tool
输出显示:
{
"Type": "bind",
"Source": "/root/xxx/Caddyfile",
"Destination": "/etc/caddy/Caddyfile",
"Mode": "ro",
"RW": false
}
第三步:验证宿主机文件是否存在
ls -la /root/xxx/Caddyfile
果然,文件不存在了!
第四步:查看容器内当前生效的配置
还好容器还在运行,可以直接从容器内获取当前配置:
docker exec caddy cat /etc/caddy/Caddyfile
成功获取了当前正在运行的配置内容,这为后续重建提供了基础。
踩坑记录
坑一:Bind Mount 只读挂载无法直接修改
因为配置文件是以 bind mount (只读) 方式挂载到容器的,所以不能直接用 docker cp 覆盖:
docker cp /tmp/Caddyfile caddy:/etc/caddy/Caddyfile
报错:
Error response from daemon: mount /root/.../Caddyfile:... not a directory
也不能直接在容器内写入:
docker exec caddy sh -c 'cat > /etc/caddy/Caddyfile << "EOF" ...'
报错:
sh: can't create /etc/caddy/Caddyfile: Read-only file system
解决方案:必须删除旧容器,用新的配置路径重新创建容器。
坑二:Caddyfile 语法错误
Caddy 2 的 auto_https 配置语法需要注意。一开始我写的是:
{
auto_https on
}
结果报错:
Error: adapting config using caddyfile: parsing caddyfile tokens for 'auto_https': auto_https must be one of 'off', 'disable_redirects', 'disable_certs', or 'ignore_loaded_certs'
解决方案:Caddy 默认就是启用自动 HTTPS 的,不需要显式配置 auto_https on。删除这一行即可。
实际上,Caddy 2 的 auto_https 有效值只有:
off- 完全禁用自动 HTTPSdisable_redirects- 禁用 HTTP 到 HTTPS 重定向disable_certs- 禁用自动证书获取ignore_loaded_certs- 忽略已加载的证书
坑三:HTTP 到 HTTPS 重定向的自动处理
一开始我想显式配置 HTTP 重定向,但实际上 Caddy 默认就会自动将所有 HTTP 请求(80端口)重定向到 HTTPS(443端口),返回 308 Permanent Redirect。
如果显式配置了 :80 站点,反而会覆盖默认的重定向行为。
最终解决方案
第一步:创建新的配置目录和文件
在可靠的位置创建配置目录:
mkdir -p /root/caddy-config
第二步:编写新的 Caddyfile
# Matrix 服务
xxx.xxx.xx {
reverse_proxy conduit:6167
log {
output stdout
}
}
# Obsidian 笔记服务 (FNS)
xxx.xxx.xx {
reverse_proxy 172.19.0.1:9000
log {
output stdout
}
}
# HTTP 默认重定向到 HTTPS(Caddy 默认已启用)
:80 {
respond "Welcome - Please use HTTPS" 200
}
# 默认 HTTPS 站点(未匹配的域名)
https:// {
respond "Welcome to LiuForest Services" 200
}
主要变更:
- ✅ 保留 Matrix 服务反向代理
- ✅ 保留 Obsidian FNS 笔记服务反向代理
- ✅ 启用所有域名的自动 HTTPS 证书(Caddy 默认行为)
- ✅ HTTP 自动重定向到 HTTPS
第三步:停止并删除旧容器
docker stop caddy && docker rm caddy
第四步:用新配置启动容器
docker run -d --name caddy --network service_network -p 80:80 -p 443:443 -p 443:443/udp -v /root/caddy-config/Caddyfile:/etc/caddy/Caddyfile -v service_caddy-config:/config -v service_caddy-data:/data --restart unless-stopped caddy:2-alpine
关键参数说明:
--network service_network- 加入原有的网络,能够通过容器名(如conduit)访问 Matrix 服务-p 443:443/udp- 启用 HTTP/3 (QUIC) 支持-v service_caddy-config:/config- 保留原有的配置卷(包含证书缓存)-v service_caddy-data:/data- 保留原有的数据卷--restart unless-stopped- 设置自动重启
第五步:验证 HTTPS 证书获取
查看容器日志,确认 Caddy 正在自动获取证书:
docker logs caddy -f
三个域名的 HTTPS 证书都自动获取成功了!
第六步:验证所有服务
验证 HTTP 到 HTTPS 重定向:
curl -s -I http://xx.xxx.xx
返回:
HTTP/1.1 308 Permanent Redirect
Location: https://xx.xxx.xx/
Server: Caddy
完美!
最终架构
现在的服务架构:
┌─────────────────────────┐
│ Caddy 反向代理 (443) │
└──────────┬──────────────┘
│
┌────────────────────────┼────────────────────────┐
│ │ │
┌───────────▼──────────┐ ┌─────────▼───────────┐ ┌─────────▼───────────┐
│ xx.xxx.xx │ │ xx.xxx.xx │ │ xx.xxx.xx │
│ 聊天服务 │ │ 笔记服务 │ │ Agent服务 │
│ conduit:6167 │ │ 172.19.0.1:9000 │ │ 172.19.0.1:8648 │
└──────────────────────┘ └─────────────────────┘ └─────────────────────┘
经验总结
1. 重要配置文件的存放位置
- 不要把配置文件放在临时目录或可能被清理的目录中
- 建议专门建立
/root/docker-configs/[服务名]/目录存放配置 - 配置文件一定要备份!
2. Caddy 最佳实践
- 信任 Caddy 的默认行为(自动 HTTPS、自动重定向),不要过度配置
- 保留
/config和/data卷,证书会自动续期,不用手动管理 - 使用 docker logs 查看证书获取过程,非常详细
3. Docker 容器重建注意事项
- 重建前一定要先查看
docker inspect的网络和卷配置 - 确保加入正确的网络,否则容器间无法通过主机名通信
- 保留数据卷,不要轻易删除 named volume
4. 排障思路
- 先看日志 -
docker logs [容器名] - 检查网络连通性 -
docker exec [容器名] ping [目标] - 验证 DNS 解析 -
docker exec [容器名] nslookup [域名] - 从简单到复杂,逐步验证
配置文件位置备忘
| 项目 | 路径 |
|---|---|
| Caddyfile 宿主机 | /root/caddy-config/Caddyfile |
| Caddyfile 容器内 | /etc/caddy/Caddyfile |
| 配置卷 (证书缓存) | /var/lib/docker/volumes/service_caddy-config/_data |
| 数据卷 | /var/lib/docker/volumes/service_caddy-data/_data |
| 容器日志 | docker logs caddy |
后续维护命令
# 查看容器状态
docker ps
# 查看日志
docker logs caddy -f
# 修改配置后重新加载
docker exec caddy caddy reload --config /etc/caddy/Caddyfile
# 验证配置文件语法
docker exec caddy caddy fmt /etc/caddy/Caddyfile
# 重启容器
docker restart caddy