为什么需要隐身代理
在上一篇文章中,我们介绍了用 Caddy + acme.sh 搭建 HTTPS 正向代理的方案。那套方案已经足够实用,但仍然依赖多个组件的拼装:Caddy 本体、forwardproxy 插件的特殊分支、acme.sh 的 cron 续证——任何一个环节出问题,都可能导致代理不可用。
https_proxy 是一个用 Rust 编写的单二进制 HTTPS 正向代理,把证书签发、TLS 终结、代理转发、隐身伪装全部内聚到一个不到 7 MB 的可执行文件里。它的核心思路很简单:
- 对外看起来就是一台普通的 nginx 服务器
- 只有持有正确凭证的客户端才能使用代理功能
- 证书由 Let's Encrypt 自动签发和续期,无需额外工具
架构与工作原理
整个请求处理流程如下图所示:
1. TLS 终结与自动证书
https_proxy 使用 tokio-rustls-acme 库实现 ACME 协议的 TLS-ALPN-01 验证。与常见的 HTTP-01 验证不同,TLS-ALPN-01 只需要 443 端口,不需要额外开放 80 端口。证书的签发和续期完全自动,由后台异步任务驱动:
let acme_config = AcmeConfig::new([domain])
.contact_push(format!("mailto:{}", config.acme.email))
.cache(DirCache::new(cache_dir))
.directory_lets_encrypt(!config.acme.staging);
TLS 配置同时支持 TLS 1.2 和 TLS 1.3,ALPN 协商支持 h2 和 http/1.1,让浏览器和命令行工具都能正常连接。
2. 隐身层:伪装成 nginx
这是 https_proxy 最有趣的设计。隐身检测的逻辑非常精准:
- 如果请求方法是
CONNECT→ 这是代理请求 - 如果是 HTTP/2 但不是
CONNECT→ 一定不是代理请求(因为 HTTP/2 的:authority伪头始终存在,不能用于判断) - 如果是 HTTP/1.x 且 URI 包含 authority(绝对 URI 形式)→ 这是代理请求
下面的流程图展示了完整的隐身检测与认证判定逻辑:
不满足以上条件的所有请求,都会收到一个与 nginx 完全一致的 404 页面:
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.24.0</center>
</body>
</html>
响应头中的 Server 字段也会设置为配置文件中指定的值(默认 nginx/1.24.0)。无论扫描器用 HTTP/1.1 还是 HTTP/2 访问,看到的都是一台普通的 nginx——返回 404 表示"没有配置任何网站"。
3. 认证层
通过隐身检测后,请求进入认证环节。https_proxy 使用标准的 HTTP Basic Auth,支持配置多组用户名/密码。认证失败时返回 407 Proxy Authentication Required,并携带 Proxy-Authenticate 头,这样 Chrome 等浏览器会弹出凭证输入框,而不是显示一个莫名其妙的错误页面。
4. 代理转发
认证通过后,根据请求类型分两条路径:
CONNECT 隧道:客户端发起 CONNECT host:port,代理返回 200 后升级连接,使用 tokio::io::copy_bidirectional 在客户端和目标服务器之间双向透传数据。隧道缓冲区设置为 128 KiB(是默认值的 16 倍),与 TLS record 大小匹配,减少系统调用次数。
HTTP 转发:对于明文 HTTP 请求,代理剥离 Proxy-Authorization 和 Proxy-Connection 等逐跳头后,将请求转发给上游服务器。未开启 TCP Fast Open 时使用连接池复用连接;开启时使用手动连接以支持 TFO。
5. HTTP/2 支持
https_proxy 实现了完整的 HTTP/2 支持,包括 RFC 8441 定义的扩展 CONNECT 协议。这意味着 Chrome 等现代浏览器可以通过 HTTP/2 使用代理功能,而不需要降级到 HTTP/1.1。
部署指南
前置条件
- 一台有公网 IP 的服务器
- 一个域名,A 记录已解析到服务器 IP
- 服务器的 443 端口可用
编译
https_proxy 使用 Rust 编写,需要 Rust 1.70+ 和 C 编译器。
在 Linux 服务器上直接编译:
# 安装 Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 安装编译依赖(Debian/Ubuntu)
apt install build-essential cmake
# 克隆并编译
git clone https://github.com/madeye/https_proxy.git
cd https_proxy
cargo build --release
在 macOS 上交叉编译 Linux 版本:
docker run --platform linux/amd64 --rm -v "$(pwd)":/src -w /src \
rust:latest cargo build --release --target x86_64-unknown-linux-gnu
编译产物开启了 LTO 和 strip,最终二进制大小约 7 MB。
配置
可以使用内置的 TUI 向导生成配置:
./target/release/https_proxy setup
也可以手动编辑 config.yaml:
listen: "0.0.0.0:443"
domain: "proxy.example.com"
acme:
email: "admin@example.com"
staging: false
cache_dir: "/var/lib/https_proxy/acme"
users:
- username: "alice"
password: "hunter2"
- username: "bob"
password: "correct-horse-battery-staple"
stealth:
server_name: "nginx/1.24.0"
fast_open: true
配置项说明:
| 字段 | 说明 |
|---|---|
listen | 监听地址,默认 0.0.0.0:443 |
domain | ACME 证书对应的域名 |
acme.email | Let's Encrypt 联系邮箱 |
acme.staging | 是否使用 staging 环境(测试时建议开启,避免触发速率限制) |
acme.cache_dir | 证书缓存目录 |
users | 授权用户列表,支持多组凭证 |
stealth.server_name | 伪装的 Server 响应头 |
fast_open | 启用 TCP Fast Open,减少连接建立延迟 |
启动
# 直接运行
./target/release/https_proxy run --config config.yaml
# 或使用默认 config.yaml
./target/release/https_proxy
安装为系统服务
在 Linux 上可以一键安装为 systemd 服务:
sudo ./target/release/https_proxy install
卸载:
sudo ./target/release/https_proxy uninstall
客户端使用
命令行
# 通过代理访问目标网站
curl --proxy https://alice:hunter2@proxy.example.com:443 https://httpbin.org/ip
# 设置环境变量,所有命令自动走代理
export https_proxy=https://alice:hunter2@proxy.example.com:443
export http_proxy=https://alice:hunter2@proxy.example.com:443
curl https://www.google.com
浏览器
Chrome、Firefox 等浏览器支持通过系统代理设置配置 HTTPS 代理,也可以使用 SwitchyOmega 等扩展。协议选择 HTTPS,填入域名、端口(443)、用户名和密码。首次访问时浏览器会弹出认证框。
验证隐身效果
直接访问代理域名,应该看到 nginx 风格的 404 页面:
curl https://proxy.example.com/
# 返回: 404 Not Found (Server: nginx/1.24.0)
与 Caddy 方案的对比
| https_proxy | Caddy + forwardproxy | |
|---|---|---|
| 组件数量 | 单二进制 | Caddy + xcaddy 编译 + acme.sh |
| 证书管理 | 内置 ACME(TLS-ALPN-01) | 依赖外部 acme.sh |
| HTTP/2 代理 | 支持(RFC 8441 扩展 CONNECT) | 支持 |
| 隐身伪装 | 内置 nginx 404 伪装 | 通过 probe_resistance + file_server |
| TCP Fast Open | 内置支持 | 不支持 |
| 配置复杂度 | 单个 YAML 文件 | Caddyfile + acme.sh 配置 + systemd |
| 二进制大小 | ~7 MB | ~40 MB(Caddy) |
两套方案各有优势。Caddy 方案的生态更成熟,可以同时托管网站和其他反向代理服务;https_proxy 则胜在部署极简——一个二进制、一份配置文件,开箱即用。
小结
https_proxy 的设计哲学是"做一件事,做到极致":
- 单二进制部署:不依赖外部工具,编译完成即可使用
- 自动证书管理:Let's Encrypt 证书自动签发和续期,无需 cron job
- 精准隐身:对 HTTP/1.1 和 HTTP/2 都能正确识别并伪装,不会被简单的扫描器发现
- 性能优化:TCP Fast Open、128 KiB 隧道缓冲区、连接池复用
- 安全认证:多用户 Basic Auth,浏览器原生支持凭证弹窗