在复杂的网络环境中,我们经常面临一个痛点:内网服务如何使用合法的 HTTPS 证书?
通常,Let’s Encrypt 等证书颁发机构需要验证 80 端口(HTTP-01 挑战),这要求服务器必须暴露在公网。如果你有一台公网服务器(Server A)和一台内网服务器(Server B),想让 Server B 也挂上合法的 SSL 证书(实现浏览器绿锁),传统的做法是手动复制证书或使用 DNS API。
本文将介绍一种自动化、高可用的方案:利用 Redis 作为 Caddy 的共享存储后端。Server A 负责申请和续期证书,Server B 通过 Redis 直接读取证书,实现无缝同步。
🎯 架构设计
- Server A (公网网关):
- IP:
1.2.3.4 (公网) / 192.168.10.10 (内网)
- 角色:负责接收公网流量,自动向 Let’s Encrypt 申请/续期证书,并将证书写入 Redis。
- Redis 服务:
- IP:
192.168.10.20
- 角色:作为中央证书仓库,存储加密的证书和私钥。
- Server B (内网服务):
- IP:
192.168.10.30
- 角色:运行内网业务(如 NAS、Immich 等),直接从 Redis 读取证书,无需公网权限即可提供合法的 HTTPS 服务。
🛠 第一步:准备 Redis 存储后端
Caddy 需要连接 Redis 存储证书。你需要确保 Redis 允许内网连接。
- 安装 Redis(略)。
- 修改配置 (
/etc/redis/redis.conf):
- 绑定内网 IP:找到
bind 127.0.0.1,修改为允许内网 IP 连接(例如绑定本机内网 IP 或 0.0.0.0)。
bind 0.0.0.0
- 关闭保护模式(或设置密码):
protected-mode no
(注:生产环境建议开启 protected-mode 并配置 requirepass 密码)
- 重启 Redis:
sudo systemctl restart redis
🛠 第二步:编译支持 Redis 的 Caddy
官方标准版 Caddy 不包含 Redis 存储插件,我们需要使用 xcaddy 工具编译一个定制版本。此步骤只需在任意一台机器执行,编译好的文件可复制到所有节点使用。
1. 安装 Go 和 xcaddy
# 安装 Go 语言环境
sudo apt install golang-go
# 设置国内 Go 代理 (加速下载)
go env -w GO111MODULE=on
go env -w GOPROXY=[https://goproxy.cn](https://goproxy.cn),direct
# 安装 xcaddy 编译工具
go install [github.com/caddyserver/xcaddy/cmd/xcaddy@latest](https://github.com/caddyserver/xcaddy/cmd/xcaddy@latest)
# 将 xcaddy 移动到系统路径
sudo cp ~/go/bin/xcaddy /usr/bin/
sudo chmod +x /usr/bin/xcaddy
2. 编译 Caddy
xcaddy build --with [github.com/gamalan/caddy-tlsredis](https://github.com/gamalan/caddy-tlsredis)
编译完成后,当前目录会生成一个 caddy 二进制文件。
3. 分发与安装
将生成的 caddy 文件分发到 Server A 和 Server B,并替换系统原有的 Caddy:
# 停止服务
sudo systemctl stop caddy
# 备份旧版本
sudo mv /usr/bin/caddy /usr/bin/caddy.bak
# 替换新版本
sudo mv ./caddy /usr/bin/caddy
sudo chmod +x /usr/bin/caddy
# 【关键】赋予端口绑定权限 (非 root 用户启动必须执行)
sudo setcap cap_net_bind_service=+ep /usr/bin/caddy
# 验证插件是否安装成功
caddy list-modules | grep redis
⚙️ 第三步:配置 Server A (公网/证书生产者)
Server A 能被公网访问,它负责“生产”证书。
编辑 /etc/caddy/Caddyfile:
{
# 全局配置:指定存储后端为 Redis
storage redis {
host 192.168.10.20
port 6379
# password "your_redis_password" # 如果设置了密码
key_prefix caddy_certs
}
}
# 你的公网域名
example.com {
reverse_proxy localhost:8080
}
重启 Server A 的 Caddy:sudo systemctl restart caddy。
此时访问 https://example.com,Caddy 会自动申请证书并将文件存入 Redis。
⚙️ 第四步:配置 Server B (内网/证书消费者)
Server B 在内网,无法进行 HTTP 验证,但它可以直接“消费” Redis 里的证书。
编辑 /etc/caddy/Caddyfile:
{
# 同样的全局存储配置
storage redis {
host 192.168.10.20
port 6379
key_prefix caddy_certs
}
}
# 同样的域名(内网解析)
example.com {
# 指向内网的具体服务
reverse_proxy localhost:3000
}
重启 Server B 的 Caddy:sudo systemctl restart caddy。
✅ 第五步:验证与测试
1. 检查 Redis 数据
在 Redis 服务器上查看 Key,确认证书已写入:
redis-cli keys "caddy_certs*"
输出应包含 .../example.com.crt 和 .../example.com.key。
2. 内网访问测试
在内网电脑上,通过 curl 验证 Server B 的响应:
curl -vv [https://example.com](https://example.com) --resolve example.com:443:192.168.10.30
观察日志:
- Issuer: 应该显示
Let's Encrypt(而不是 Caddy Local Authority)。
- SSL verify: 显示
ok。
如果看到以上信息,恭喜你!你已经成功实现了:
- 自动化管理:Server A 自动处理所有证书续期。
- 数据同步:Server B 实时共享最新证书,无需任何手动脚本。
- 内网绿锁:内网服务拥有了完全合法的 HTTPS 证书。