← 返回

https_proxy:用 Rust 实现的隐身 HTTPS 正向代理

为什么需要隐身代理

上一篇文章中,我们介绍了用 Caddy + acme.sh 搭建 HTTPS 正向代理的方案。那套方案已经足够实用,但仍然依赖多个组件的拼装:Caddy 本体、forwardproxy 插件的特殊分支、acme.sh 的 cron 续证——任何一个环节出问题,都可能导致代理不可用。

https_proxy 是一个用 Rust 编写的单二进制 HTTPS 正向代理,把证书签发、TLS 终结、代理转发、隐身伪装全部内聚到一个不到 7 MB 的可执行文件里。它的核心思路很简单:

  • 对外看起来就是一台普通的 nginx 服务器
  • 只有持有正确凭证的客户端才能使用代理功能
  • 证书由 Let's Encrypt 自动签发和续期,无需额外工具

架构与工作原理

整个请求处理流程如下图所示:

客户端 TLS 终结 ACME 自动证书 TLS-ALPN-01 隐身检测 是否为代理请求? HTTP/1.1 & HTTP/2 认证检查 Basic Auth 多用户凭证 代理转发 CONNECT 隧道 HTTP 转发 伪装 404 nginx 风格页面 407 认证 要求提供凭证 目标 非代理 认证失败 转发 正常流程 拒绝/伪装

1. TLS 终结与自动证书

https_proxy 使用 tokio-rustls-acme 库实现 ACME 协议的 TLS-ALPN-01 验证。与常见的 HTTP-01 验证不同,TLS-ALPN-01 只需要 443 端口,不需要额外开放 80 端口。证书的签发和续期完全自动,由后台异步任务驱动:

RUST
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 协商支持 h2http/1.1,让浏览器和命令行工具都能正常连接。

2. 隐身层:伪装成 nginx

这是 https_proxy 最有趣的设计。隐身检测的逻辑非常精准:

  • 如果请求方法是 CONNECT → 这是代理请求
  • 如果是 HTTP/2 但不是 CONNECT → 一定不是代理请求(因为 HTTP/2 的 :authority 伪头始终存在,不能用于判断)
  • 如果是 HTTP/1.x 且 URI 包含 authority(绝对 URI 形式)→ 这是代理请求

下面的流程图展示了完整的隐身检测与认证判定逻辑:

收到 TLS 请求 方法是 CONNECT ? 代理请求 HTTP/2 ? 伪装 404 nginx 风格 URI 含 authority ? 代理请求 伪装 404 nginx 风格

不满足以上条件的所有请求,都会收到一个与 nginx 完全一致的 404 页面:

HTML
<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-AuthorizationProxy-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 服务器上直接编译:

Bash
# 安装 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 版本:

Bash
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 向导生成配置:

Bash
./target/release/https_proxy setup

也可以手动编辑 config.yaml

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
domainACME 证书对应的域名
acme.emailLet's Encrypt 联系邮箱
acme.staging是否使用 staging 环境(测试时建议开启,避免触发速率限制)
acme.cache_dir证书缓存目录
users授权用户列表,支持多组凭证
stealth.server_name伪装的 Server 响应头
fast_open启用 TCP Fast Open,减少连接建立延迟

启动

Bash
# 直接运行
./target/release/https_proxy run --config config.yaml

# 或使用默认 config.yaml
./target/release/https_proxy

安装为系统服务

在 Linux 上可以一键安装为 systemd 服务:

Bash
sudo ./target/release/https_proxy install

卸载:

Bash
sudo ./target/release/https_proxy uninstall

客户端使用

命令行

Bash
# 通过代理访问目标网站
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 页面:

Bash
curl https://proxy.example.com/
# 返回: 404 Not Found (Server: nginx/1.24.0)

与 Caddy 方案的对比

https_proxyCaddy + 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 的设计哲学是"做一件事,做到极致":

  1. 单二进制部署:不依赖外部工具,编译完成即可使用
  2. 自动证书管理:Let's Encrypt 证书自动签发和续期,无需 cron job
  3. 精准隐身:对 HTTP/1.1 和 HTTP/2 都能正确识别并伪装,不会被简单的扫描器发现
  4. 性能优化:TCP Fast Open、128 KiB 隧道缓冲区、连接池复用
  5. 安全认证:多用户 Basic Auth,浏览器原生支持凭证弹窗