SNIProxy
🧷 自用的简单 SNIProxy(常用于网站负载均衡、基于域名(SNI)的端口转发等
Install / Use
/learn @XIU2/SNIProxyREADME
XIU2/SNIProxy
🧷 自用的一个功能很简单的 SNIProxy 顺便分享出来给有同样需求的人,用得上的话可以点个⭐支持下~
SNIProxy 是一个根据传入的域名(SNI)来自动转发数据至该域名源服务器的工具,常用于网站多服务器负载均衡,而且因为是通过明文的 SNI 来获取目标域名,因此不需要 SSL 解密再加密,转发速度和效率自然也大大提高了。
[!IMPORTANT] 注意!SNIProxy 只是起到一个端口转发、负载均衡的作用。简单的来说就是 SNIProxy 收到的所有数据都会被原封不动的转发给目标源服务器(包括明文的 SNI 域名信息,任何第三方例如墙依然能直接看到),因此 SNIProxy 是
无法用来番墙的(否则就是脱裤子放屁 —— 多此一举! 毕竟墙早就可以 域名(SNI)阻断 了)。
分享我其他开源项目:TrackersList.com - 全网热门 BT Tracker 列表!有效提高 BT 下载速度~ <img src="https://img.shields.io/github/stars/XIU2/TrackersListCollection.svg?style=flat-square&label=Star&color=4285dd&logo=github" height="16px" />
CloudflareSpeedTest - 🌩「自选优选 IP」测试 Cloudflare CDN 延迟和速度,获取最快 IP~ <img src="https://img.shields.io/github/stars/XIU2/CloudflareSpeedTest.svg?style=flat-square&label=Star&color=4285dd&logo=github" height="16px" />
UserScript - 🐵 Github 高速下载、知乎增强、自动无缝翻页、护眼模式 等十几个油猴脚本~ <img src="https://img.shields.io/github/stars/XIU2/UserScript.svg?style=flat-square&label=Star&color=4285dd&logo=github" height="16px" />
# 软件介绍
- 支持 全平台、全系统(Go 语言特性)
- 支持 Socks5 前置代理(比如可以再套一层 WARP,这样 SNIProxy 的出口 IP 就是 Cloudflare 的了)
- 支持 允许转发所有域名 或 仅允许转发指定域名(包含域名自身及其所有子域名)
- 支持 单独或同时监听及传输 IPv4、IPv6 流量
- 支持 将 HTTP 重定向为 HTTPS
- 支持 HTTP/1.1、HTTP/2 传输协议
- 支持 根据明文 SNI(域名/主机名) 来自动转发流量到该域名的源服务器,无需加解密流量,无需 SSL 密钥或证书
[!WARNING] 注意!SNIProxy 仅为我个人自写自用,可靠性、稳定性等方面不如专业的商业软件(如 Nginx、HAProxy),因此在正式的生产环境下不建议使用本软件,如造成损失,根据 GPL-3.0 本项目无需承担责任(溜了溜了~
[!TIP] ✅ 支持 HTTP/2(当然源站本身也要支持 HTTP/2 )
- 虽然 HTTP/2 有个特性可以在单个 TCP 连接中复用多个域名,这看似会导致 SNIProxy 无法根据域名来正确转发流量,但好消息是现代浏览器只有在多个域名同时满足这些条件时才会复用连接:
解析到相同的 IP(服务器) + 使用相同的 TLS 证书(如通配符证书或包含多个域名的证书)+ 相同的端口(如 443),而对于这种情况是没问题的(或者说压根不需要特殊处理,程序只需要正常转发流量,浏览器和服务器会自行协商处理)。
[!NOTE] ❌ 不支持 HTTP/3 (QUIC)
- 因为 HTTP/3 (QUIC) 改用了 UDP 协议传输,这和 TCP 协议是完全不同的,并且解析 SNI 的方式也需要大改。SNIProxy 不支持 UDP 协议,也不打算去添加支持,因为这会使项目变得非常复杂(也超出了我的能力,毕竟我只是为了方便自己使用而边学边写的,代码精简到也才几百行罢了)。
SNIProxy 的工作流程大概如下:
- 解析传入连接中的 TLS/SSL 握手消息(明文),以获取访客发送的 SNI 域名信息。
- 检查域名是否在允许列表中(或开启了
allow_all_hosts),如果不在将中断连接,反之继续。 - 使用系统 DNS 解析 SNI 域名获得 IP 地址(即该域名的源站服务器 IP 地址)。
- 将收到的数据原封不动的转发给该域名的源站 IP:443,在访客和源站之间建立一个 "桥梁" 进行持续的相互数据传输(即 透传/透明转发/TCP 中转/端口转发)。
// 将 example.com 域名指向 SNIProxy 服务器的 IP,然后:
访问 example.com <=> SNIProxy(解析 SNI 获得目标域名) <=> 源站(example.com)
// 按照工作流程更详细一点的:
访问 example.com <=> SNIProxy [ 解析 SNI 获得 example.com 域名 <=> 检查该域名是否在允许转发 <=> 系统 DNS 解析该域名获得 IP 地址 ] <=> 源站(example.com)
// 例如:当有多台服务器配置 SNIProxy 后,可以在域名 DNS 解析中指向这些服务器 IP,这样访客就会被随机分配到其中一个服务器上,实现分流负载均衡等。
// 也可以依靠 DNS 区域解析来给不同地区、运营商的访客指向离它们更近、线路更优的服务器 IP,来间接提高网站的访问速度,提升用户体验。
// 如果 SNIProxy 开启了前置代理,那么就是这样:
访问 example.com <=> SNIProxy <=> Socks5(解析 SNI 获得目标域名) <=> 源站(example.com)
[!TIP] SNIProxy 本质上也是一种端口转发(中转),但不同于端口转发只能指定一个固定的目标 IP,SNIProxy 可以通过 DNS 解析传入的域名来获得灵活的目标 IP(传入不同的域名走不同目标 IP,可同时存在且互不干扰)。
# 使用方法
<details> <summary><code><strong>「 点击查看 Linux 系统下的使用示例 」</strong></code></summary>以下命令仅为示例,版本号和文件名请前往 Releases 查看。
# 如果是第一次使用,则建议创建新文件夹(后续更新时,跳过该步骤)
mkdir sniproxy
# 进入文件夹(后续更新,只需要从这里重复下面的下载、解压命令即可)
cd sniproxy
# 下载 sniproxy 压缩包(自行根据需求替换 URL 中 [版本号] 和 [文件名])
wget -N https://github.com/XIU2/SNIProxy/releases/download/v1.0.6/sniproxy_linux_amd64.tar.gz
# 如果你是在国内服务器上下载,那么请使用下面这几个镜像加速:
# wget -N https://wget.la/https://github.com/XIU2/SNIProxy/releases/download/v1.0.6/sniproxy_linux_amd64.tar.gz
# wget -N https://ghfast.top/https://github.com/XIU2/SNIProxy/releases/download/v1.0.6/sniproxy_linux_amd64.tar.gz
# wget -N https://ghproxy.it/https://github.com/XIU2/SNIProxy/releases/download/v1.0.6/sniproxy_linux_amd64.tar.gz
# wget -N https://gh-proxy.org/https://github.com/XIU2/SNIProxy/releases/download/v1.0.6/sniproxy_linux_amd64.tar.gz
# wget -N https://cdn.gh-proxy.org/https://github.com/XIU2/SNIProxy/releases/download/v1.0.6/sniproxy_linux_amd64.tar.gz
# 如果下载失败的话,尝试删除 -N 参数(如果是为了更新,则记得提前删除旧压缩包 rm sniproxy_linux_amd64.tar.gz )
# 解压(不需要删除旧文件,会直接覆盖,自行根据需求替换 文件名)
tar -zxf sniproxy_linux_amd64.tar.gz
# 赋予执行权限
chmod +x sniproxy
# 编辑配置文件(根据下面的 配置文件说明 来自定义配置内容并保存(按下 Ctrl+X 然后再按 2 下回车)
nano config.yaml
# 运行(不带参数)
./sniproxy
# 运行(带参数示例)
./sniproxy -c "config.yaml"
# 后台运行(带参数示例)
nohup ./sniproxy -c "config.yaml" > "sni.log" 2>&1 &
另外,强烈建议顺便提高一下 系统文件句柄数上限,避免遇到报错 too many open files
</details>另外,如果你希望 开机启动、守护进程(异常退出自动恢复)、后台运行、方便管理 等,那么可以将其 注册为系统服务。
<details> <summary><code><strong>「 点击查看 Windows 系统下的使用示例 」</strong></code></summary>
下载
下载已编译好的可执行文件并解压:
- Github Releases
- 蓝奏云(密码:xiu2)
配置
找到配置文件 config.yaml 右键菜单 - 打开方式 - 记事本。
根据下面的 配置文件说明 来自定义配置内容并保存。
运行
双击运行 sniproxy.exe 文件。
或者在 CMD 命令行中进入软件所在目录并运行 sniproxy.exe:
# CMD 命令行中进入解压后的 sniproxy 程序所在目录(记得修改下面示例路径)
cd /d C:\xxx\sniproxy
# 运行(不带参数)
sniproxy.exe
# 运行(带参数示例)
sniproxy.exe -c "config.yaml"
</details>
<details> <summary><code><strong>「 点击查看 Mac 系统下的使用示例 」</strong></code></summary>
下载已编译好的可执行文件并解压:
- Github Releases
- 蓝奏云(密码:xiu2)
# 通过命令行进入 sniproxy 压缩包所在目录(记得修改下面示例路径)
cd /xxx/xxx
# 解压(不需要删除旧文件,会直接覆盖,自行根据需求替换 文件名)
tar -zxf sniproxy_linux_amd64.tar.gz
# 赋予执行权限
chmod a+x sniproxy
# 编辑配置文件(根据下面的 配置文件说明 来自定义配置内容并保存(按下 Contrl+X 然后再按 2 下回车)
nano config.yaml
# 运行(不带参数)
./sniproxy
# 运行(带参数示例)
./sniproxy -c "config.yaml"
</details>
home@xiu:~# ./sniproxy -h
SNIProxy vX.X.X
https://github.com/XIU2/SNIProxy
参数:
-c config.yaml
配置文件 (默认 config.yaml)
-l sni.log
日志文件 (默认 无)
-d
调试模式 (默认 关)
-v
程序版本
-h
帮助说明
# 其他说明
# 配置文件说明 (config.yaml)
<details> <summary><code><strong>「 点击展开 查看内容 」</strong></code></summary>注意: 配置文件是 YAML 格式,即按照缩进(即每行前面的空格数量)来确定层级关系的,因此不懂的话请按照默认配置文件内示例的格式为准,其中
#的是注释(会被程序忽略),不需要的配置可以注释掉。
目前配置文件中的配置项没几个,分别为:
# 监听端口(注意需要引号),常见示例如下:
# ":443" 省略 IP 只写端口,代表监听本机所有 IPv4+IPv6 地址的 443 端口
# "0.0.0.0:443" 代表监听本机所有 IPv4 地址的 443 端口
# "127.0.0.1:443" 代表监听本机本地 IPv4 地址的 443 端口(只有本机可访问)
# "[::]:443" 代表监听本机所有 IPv6 地址的 443 端口
# "[::1]:443" 代表监听本机本地 IPv6 地址的 443 端口(只有本机可访问)
# 上面示例中的 IP 地址也可以换成例如你的外网 IP,这样的话就只能从该外网 IP 访问了
listen_addr: ":443"
# 可选:下面这个的作用是用来将传入的 HTTP 重定向为 HTTPS(固定的 443 端口和上面配置无关),如果没写将不监听及处理 HTTP 连接
listen_addr_http: ":80"
# 可选:启用 Socks5 前置代理
# (启用前:访客 <=> SNIProxy <=> 目标网站
# (启用后:访客 <=> SNIProxy <=> Socks5 <=> 目标网站
# (比如可以套 WARP,那样就变成:访客 <=> SNIProxy <=> WARP <=> 目标网站
enable_socks5: true
# 可选:配置 Socks5 代理地址
socks_addr: 127.0.0.1:40000
# 可选:配置 Socks5 代理的账号和密码(如果有的话)
socks_username: admin
socks_password: abc123
# 二选一:允许所有域名(开启后会忽略下面的 rules 列表,二选一)
allow_all_hosts: true
# 二选一:仅允许指定域名(和上面的 allow_all_hosts 二选一)
# 指定域名后,则代表允许 域名自身 及其 所有子域名 访问服务(以下方两个为例,√ 代表允许,× 代表阻止)
# 如果有非允许的域名请求访问,日志将显示为红色醒目的(这样可以检查是否泄露或被扫描了):
# 2025/06/16 10:44:55 域名 xxx 不在允许规则中, 忽略(且会注明是来自 http 或 https)...
rules:
- example.com # example.com √ 、a.example.com √ 、a.a.example.com √
- b.example2.com # example2.com × 、b.example2.com √ 、c.b.example2.com √
一些示例:
- 允许所有域名访问
listen_addr: ":443"
listen_addr_http: ":80"
allow_all_hosts: true
注意,开启 allow_all_hosts 时,可能会被他人扫描到而滥用,请悉知!
建议做一些限制,例如只使用 IPv6("[::]:443")或防火墙限制 443 端口的可访问 IP。
- 仅允许指定域名
listen_addr: ":443"
listen_addr_http: ":80"
rules:
- example.com
- b.example2.com
- 允许所有域名访问 + 启用前置代理
listen_addr: ":443"
listen_addr_http: ":80"
enable_socks5: true
socks_addr: 127.0.0.1:40000
allow_all_hosts: true
- 仅允许指定域名 + 启用前置代理 + 代理账号密码
listen_addr: ":443"
listen_addr_http: ":80"
enable_socks5: true
socks_addr: 127.0.0.1:40000
socks_username: admin
socks_password: abc123
rules:
- example.com
- b.example2.com
</details>
# Linux 配置为系统服务 (systemd - 以支持开机启动、守护进程等)
<details> <summary><code><strong>「 点击展开 查看内容 」</strong></code></summary>新建一个空的名叫 sniproxy 的系统服务配置文件:
nano /etc/systemd/system/sniproxy.service
修改以下内容后(ExecStart= 后面的程序路径、参数)后粘贴进文件内:
[Unit]
Description=SNI Proxy
After=network.target
[Service]
ExecStart=/home/sniproxy/sniproxy -c /home/sniproxy/config.yaml -l /home/sniproxy/sni.log
Restart=on-failure
[Install]
WantedBy=multi-user.target
如果你需要详细日志(调试模式),那么可以加上
-d运行参数到ExecStart=...行末尾(注意加上空格分隔)。
其中
Restart=on-failure表示,当程序非正常退出时,会自动恢复启动,也就是常说的守护进程。
设置 sniproxy 开机启动并立即启动:
# 启用该系统服务 并 允许开机启动
systemctl enable sniproxy
# 立即启动
systemctl start sniproxy
其他可能会用到的命令:
# 停止
systemctl stop sniproxy
# 重启
systemctl restart sniproxy
