1. 安装 SSLH
Ubuntu/Debian
sudo apt updatesudo apt install sslh默认选择 Standalone 模式
2. 配置 SSLH
编辑 /etc/default/sslh(Debian/Ubuntu)或 /etc/sslh.cfg(CentOS/RHEL):
# 监听 443 端口(IPv4 + IPv6)DAEMON_OPTS="--user sslh --listen 0.0.0.0:443 --listen [::]:443 --ssh 127.0.0.1:22 --tls 127.0.0.1:443 --http 127.0.0.1:80 --openvpn 127.0.0.1:1194"参数说明:
--listen 0.0.0.0:443:SSLH 监听 443 端口(外部访问)。--tls 127.0.0.1:443:HTTPS 流量转发到本机 Nginx/Apache(443)。--openvpn 127.0.0.1:1194:OpenVPN 流量转发到本机 OpenVPN 服务器(默认 1194)。--ssh 127.0.0.1:22(可选):SSH 流量转发到本机 SSH 服务(22)。
支持的协议
SSLH 支持多种协议的自动识别和转发:
| 参数 | 协议 | 说明 |
|---|---|---|
--ssh=<host:port> | SSH | SSH 连接 |
--tls=<host:port> | TLS/SSL | HTTPS 等 TLS 加密流量 |
--ssl=<host:port> | TLS/SSL | 同 --tls,别名 |
--openvpn=<host:port> | OpenVPN | OpenVPN TCP 连接 |
--tinc=<host:port> | tinc | tinc VPN 连接 |
--wireguard=<host:port> | WireGuard | WireGuard VPN 连接 |
--xmpp=<host:port> | XMPP | Jabber/XMPP 即时通讯 |
--http=<host:port> | HTTP | 明文 HTTP 请求 |
--adb=<host:port> | ADB | Android 调试桥 |
--socks5=<host:port> | SOCKS5 | SOCKS5 代理协议 |
--syslog=<host:port> | Syslog | 系统日志协议 |
--msrdp=<host:port> | MS-RDP | 微软远程桌面协议 |
--anyprot=<host:port> | 默认 | 无法识别时的默认转发目标 |
提示:
--anyprot用于处理无法识别的协议,通常作为兜底选项。
3. 启动 SSLH
sudo systemctl enable sslhsudo systemctl start sslh检查状态:
sudo systemctl status sslh查看日志:
journalctl -u sslh -f4. 高级用法:SSTP 分流与 Nginx 端口复用
通过 SSLH 的 SNI(Server Name Indication)分流功能,可以实现更精细的流量控制。例如:让特定域名的 TLS 流量转发给 SSTP VPN,其他 HTTPS 流量回落到 Nginx。
配置示例
verbose: false;foreground: false;inetd: false;numeric: false;transparent: false;timeout: 10; /* 建议:将超时从 5 秒改为 10 秒,VPN 握手需要更多时间 */user: "sslh";
listen:( { host: "0.0.0.0"; port: "443"; }, { host: "::"; port: "443"; });
protocols:( { name: "ssh"; host: "127.0.0.1"; port: "22"; },
/* 🟢 OpenVPN 规则:必须放在 TLS 之前 */ /* SSLH 会识别 OpenVPN 独特的握手包头 */ { name: "openvpn"; host: "127.0.0.1"; port: "1194"; },
/* 🟢 规则 A:SSTP 流量(利用 SNI 分流)*/ /* 只有当客户端请求 tw.hideservers.net 时,才转发给 VPN */ { name: "tls"; host: "127.0.0.1"; port: "4433"; sni_hostnames: ["sstp.server.com"]; },
/* 🟢 规则 B:普通 HTTPS 流量(默认回落)*/ /* 其他域名的请求,或者直接 IP 访问,都给本地 Nginx */ { name: "tls"; host: "127.0.0.1"; port: "8443"; },
{ name: "http"; host: "127.0.0.1"; port: "8080"; });关键原理解析
1. 致命语法错误:丢失逗号
配置文件中每条规则之间必须用逗号分隔,漏掉逗号会导致 SSLH 启动失败:
/* 错误 */{ name: "tls"; host: "127.0.0.1"; port: "8443"; }{ name: "http"; ...
/* 正确 */{ name: "tls"; host: "127.0.0.1"; port: "8443"; },{ name: "http"; ...2. 逻辑误区:UDP 监听不适用于 SSTP/OpenVPN TCP
虽然 SSLH v2.0+ 增加了 UDP 支持,但它主要用于 QUIC 协议。SSLH 并不是通用的 UDP 转发器:
- 即使监听了 UDP 443 端口,SSLH 无法识别 OpenVPN 的 UDP 包头
- SSTP 本身就是纯 TCP 协议
- 保留无用的 UDP 监听只会增加攻击面
结论:如果你只需要 SSTP + OpenVPN TCP + HTTPS,删除 is_udp: true 配置。
3. OpenVPN 规则位置
建议将 openvpn 规则放在 tls 规则之前:
- OpenVPN 有特定的握手指纹,SSLH 可以快速识别
- 先判断”是否为 VPN”,不是再进入 TLS SNI 流程,效率更高
4. SSTP SNI 分流的生效条件
使用 sni_hostnames 实现 SSTP 分流的完整流程:
- 在本地电脑修改
hosts文件,将tw.hideservers.net指向服务器 IP - Windows SSTP 客户端握手时会发送该域名作为 SNI
- SSLH 识别 SNI 后转发到指定的 VPN 后端
- 其他域名或直接 IP 访问则回落到 Nginx
下一步操作
1. 修改 Nginx 监听端口
确保 Nginx 不再监听 443,改为监听 8443:
server { listen 127.0.0.1:8443 ssl; listen [::1]:8443 ssl; # ...}2. 测试配置
# 检查配置语法(不启动)sslh -v --config /etc/sslh.cfg --test
# 重启服务systemctl restart sslh3. 客户端连接
| 协议 | 服务器地址 | 端口 | 协议类型 |
|---|---|---|---|
| SSTP | tw.hideservers.net(需配合 hosts) | 443 | TCP |
| OpenVPN | 服务器公网 IP | 443 | TCP |
| HTTPS | 任意绑定域名 | 443 | TCP |
5. 启用 UDP 支持
默认的命令行参数方式(/etc/default/sslh)不支持 UDP,如需 UDP 功能(如 WireGuard、OpenVPN UDP),必须使用配置文件格式。
配置文件对比
| 文件 | 格式 | UDP 支持 |
|---|---|---|
/etc/default/sslh | 命令行参数(DAEMON_OPTS="--xxx") | ❌ 不支持 |
/etc/sslh.cfg | libconfig 结构化格式 | ✅ 支持 |
创建配置文件
sudo nano /etc/sslh.cfgverbose: false;foreground: false;inetd: false;numeric: false;transparent: false;timeout: 5;user: "sslh";
listen:( { host: "0.0.0.0"; port: "443"; }, # IPv4 TCP { host: "0.0.0.0"; port: "443"; is_udp: true; }, # IPv4 UDP { host: "::"; port: "443"; }, # IPv6 TCP { host: "::"; port: "443"; is_udp: true; } # IPv6 UDP);
protocols:( { name: "ssh"; host: "127.0.0.1"; port: "22"; }, { name: "tls"; host: "127.0.0.1"; port: "8443"; }, { name: "http"; host: "127.0.0.1"; port: "8080"; }, { name: "openvpn"; host: "127.0.0.1"; port: "1194"; }, { name: "openvpn"; host: "127.0.0.1"; port: "1194"; is_udp: true; }, { name: "wireguard"; host: "127.0.0.1"; port: "51820"; is_udp: true; }, { name: "anyprot"; host: "127.0.0.1"; port: "9999"; });注意:
is_udp: true表示只监听 UDP,不是同时监听 TCP 和 UDP。要同时支持两种协议,需要分别写两条配置。
切换到 sslh-ev
重要:默认的 sslh-fork 不支持 UDP,必须使用 sslh-ev。
检查可用版本:
ls -la /usr/sbin/sslh*| 版本 | TCP | UDP | 推荐 |
|---|---|---|---|
| sslh-fork | ✅ | ❌ | 不推荐 |
| sslh-select | ✅ | ✅ | 可用 |
| sslh-ev | ✅ | ✅ | ⭐ 推荐 |
修改启动参数(二选一)
以下两种方法任选其一即可:
方法 1:修改 /etc/default/sslh(推荐)
sudo nano /etc/default/sslhRUN=yesDAEMON=/usr/sbin/sslh-evDAEMON_OPTS="-F /etc/sslh.cfg"方法 2:修改 systemd 服务
sudo systemctl edit --full --force sslh.service修改:
[Service]ExecStart=/usr/sbin/sslh-ev --foreground -F /etc/sslh.cfg说明:方法 2 会直接覆盖 systemd 的
ExecStart,此时/etc/default/sslh将被忽略。推荐使用方法 1,更简单且便于维护。
重启服务
sudo systemctl daemon-reloadsudo systemctl stop sslhsudo pkill -9 sslh # 清理残留进程sudo systemctl start sslh验证 UDP 监听
# 检查 TCPsudo ss -tlnp | grep 443
# 检查 UDPsudo ss -ulnp | grep 4436. 总结
✅ SSLH 成功运行后:
- 外部访问
443端口时:- HTTPS 请求 → 交给 Nginx/Apache(127.0.0.1:443)。
- OpenVPN 请求 → 交给 OpenVPN 服务器(127.0.0.1:1194)。
- SSH 请求(可选) → 交给 SSH 服务器(127.0.0.1:22)。
🚀 适用场景:
- 绕过公司/学校防火墙(因为 443 端口通常开放)。
- 在单 IP 服务器上同时运行 HTTPS + OpenVPN + SSH。
⚠️ 注意事项:
- 如果 OpenVPN 使用 UDP,需确保 SSLH 支持 UDP 模式(较新版本支持)。
- 如果 Nginx 已经占用 443,需先修改 Nginx 监听地址(127.0.0.1:443)。
7. 如不需要 Apache2
解决方案
✅ 方案 1:停止并禁用 Apache2
sudo systemctl stop apache2 # 停止 Apache2sudo systemctl disable apache2 # 禁止开机自启然后检查 80 端口是否释放:
sudo ss -tulnp | grep ':80' # 应该无输出✅ 方案 2:卸载 Apache2(如果不需用它)
sudo apt remove apache2 apache2-utils # Debian/Ubuntu清理残留配置:
sudo apt autoremove --purge # Debian/Ubuntu