为什么选择 Caddy
常见的代理方案(Squid、Nginx)配置繁琐,TLS 支持往往需要额外折腾。Caddy 通过 forwardproxy 插件原生支持 HTTPS 正向代理(CONNECT 隧道),配合 Basic Auth 认证,整套方案配置简洁、维护成本低。
选用 acme.sh 而非 Caddy 内置 ACME,是因为在某些场景下我们需要更灵活地控制证书签发流程——比如使用 DNS-01 验证、指定 CA(ZeroSSL / Let's Encrypt / Buypass)、或者在防火墙不开放 80/443 的机器上获取证书。
准备工作
- 一台有公网 IP 的服务器(本文以 Debian/Ubuntu 为例)
- 一个域名,且已将 A 记录解析到服务器 IP
- 域名 DNS 服务商支持 API 操作(用于 DNS-01 验证)
一键脚本
如果你不想手动操作,可以直接使用自动化安装脚本:
sudo DOMAIN=proxy.example.com \
EMAIL=your@email.com \
PROXY_USER=myuser \
PROXY_PASS=mypassword \
CF_Token=xxx \
CF_Zone_ID=xxx \
bash <(curl -fsSL https://gist.githubusercontent.com/madeye/9a578ad8c9b8166f999719aa7784aa6f/raw/setup-caddy-proxy.sh)
以下是手动步骤的详细说明。
1. 安装 acme.sh 并签发证书
# 安装 acme.sh
curl https://get.acme.sh | sh -s email=your@email.com
# 以 Cloudflare DNS 为例,设置 API Token
export CF_Token="your_cloudflare_api_token"
export CF_Zone_ID="your_zone_id"
# 签发证书(使用 DNS-01 验证)
~/.acme.sh/acme.sh --issue --dns dns_cf -d proxy.example.com
# 安装证书到指定目录
mkdir -p /etc/caddy/certs
~/.acme.sh/acme.sh --install-cert -d proxy.example.com \
--cert-file /etc/caddy/certs/cert.pem \
--key-file /etc/caddy/certs/key.pem \
--fullchain-file /etc/caddy/certs/fullchain.pem \
--reloadcmd "systemctl restart caddy"
如果你使用其他 DNS 服务商,acme.sh 支持数十种 DNS API,参考其 wiki 替换 dns_cf 及相关环境变量即可。
2. 编译带 forwardproxy 插件的 Caddy
官方发布的 Caddy 二进制不包含 forwardproxy 插件,需要使用 xcaddy 自行编译。
# 安装 Go(如果还没有)
sudo apt install -y golang
# 安装 xcaddy
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
# 编译带 forwardproxy 的 Caddy
~/go/bin/xcaddy build --with github.com/caddyserver/forwardproxy=github.com/klzgrad/forwardproxy@naive
# 移动到系统路径
sudo mv caddy /usr/bin/caddy
sudo chmod +x /usr/bin/caddy
这里使用的是 klzgrad 维护的 forwardproxy 分支,它支持 naive 协议的流量混淆,抗探测能力更强。如果不需要此特性,可以直接使用官方
github.com/caddyserver/forwardproxy。
3. 配置 Caddy
创建 Caddyfile:
sudo mkdir -p /etc/caddy
编辑 /etc/caddy/Caddyfile:
{
order forward_proxy before file_server
admin off
}
:443, proxy.example.com {
tls /etc/caddy/certs/fullchain.pem /etc/caddy/certs/key.pem
forward_proxy {
basic_auth user password123 # 替换为你自己的用户名和密码
hide_ip
hide_via
probe_resistance secret.localhost # 防主动探测
}
file_server {
root * /var/www/html # 伪装成普通网站
}
}
几个关键配置说明:
basic_auth:设置代理认证的用户名和密码,阻止未授权访问hide_ip/hide_via:隐藏客户端真实 IP 和代理标识probe_resistance:当收到非代理请求时,伪装成普通网站返回内容,防止主动探测file_server:配合probe_resistance使用,放一个普通网页作为伪装
4. 配置 systemd 服务
创建 /etc/systemd/system/caddy.service:
[Unit]
Description=Caddy
After=network.target network-online.target
Requires=network-online.target
[Service]
Type=notify
User=root
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
[Install]
WantedBy=multi-user.target
启动服务:
sudo systemctl daemon-reload
sudo systemctl enable --now caddy
5. 客户端使用
配置完成后,在客户端使用 HTTPS 代理连接:
https://user:password123@proxy.example.com:443
浏览器
大多数浏览器支持通过系统代理设置来配置 HTTPS 代理。也可以使用 SwitchyOmega 等扩展,协议选择 HTTPS,填入域名、端口、用户名和密码即可。
命令行
export https_proxy=https://user:password123@proxy.example.com:443
export http_proxy=https://user:password123@proxy.example.com:443
curl -I https://www.google.com
NaiveProxy 客户端
如果服务端编译时使用了 klzgrad 的 forwardproxy 分支,推荐使用 NaiveProxy 客户端以获得更好的流量混淆效果:
{
"listen": "socks://127.0.0.1:1080",
"proxy": "https://user:password123@proxy.example.com"
}
6. 验证与排查
# 查看 Caddy 运行状态
sudo systemctl status caddy
# 查看实时日志
sudo journalctl -u caddy -f
# 测试证书是否正常
openssl s_client -connect proxy.example.com:443 -servername proxy.example.com
# 测试代理是否工作
curl -x https://user:password123@proxy.example.com:443 https://httpbin.org/ip
证书自动续期
acme.sh 安装时会自动创建 cron job,证书到期前会自动续期并通过 --reloadcmd 重启 Caddy 加载新证书,无需手动干预。
可以手动检查 cron 是否生效:
crontab -l | grep acme
小结
整套方案的优势:
- 配置简单:Caddyfile 十几行搞定,远比 Nginx + Squid 方案省心
- TLS 加密:所有代理流量都走 HTTPS,中间人无法窥探
- 认证机制:Basic Auth 防止代理被滥用
- 抗探测:
probe_resistance+ 伪装网站,非授权访问只能看到普通网页 - 自动续证:acme.sh 的 cron job 保证证书始终有效