配置 SSLH 在 443 端口同时处理多种服务

使用 SSLH 在单一 443 端口上同时运行 HTTPS、SSH、OpenVPN 等多种服务

周三 1月 08 2025
1639 字 · 9 分钟

1. 安装 SSLH

Ubuntu/Debian

Terminal window
sudo apt update
sudo 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>SSHSSH 连接
--tls=<host:port>TLS/SSLHTTPS 等 TLS 加密流量
--ssl=<host:port>TLS/SSL--tls,别名
--openvpn=<host:port>OpenVPNOpenVPN TCP 连接
--tinc=<host:port>tinctinc VPN 连接
--wireguard=<host:port>WireGuardWireGuard VPN 连接
--xmpp=<host:port>XMPPJabber/XMPP 即时通讯
--http=<host:port>HTTP明文 HTTP 请求
--adb=<host:port>ADBAndroid 调试桥
--socks5=<host:port>SOCKS5SOCKS5 代理协议
--syslog=<host:port>Syslog系统日志协议
--msrdp=<host:port>MS-RDP微软远程桌面协议
--anyprot=<host:port>默认无法识别时的默认转发目标

提示--anyprot 用于处理无法识别的协议,通常作为兜底选项。

3. 启动 SSLH

Terminal window
sudo systemctl enable sslh
sudo systemctl start sslh

检查状态:

Terminal window
sudo systemctl status sslh

查看日志:

Terminal window
journalctl -u sslh -f

4. 高级用法: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 分流的完整流程:

  1. 在本地电脑修改 hosts 文件,将 tw.hideservers.net 指向服务器 IP
  2. Windows SSTP 客户端握手时会发送该域名作为 SNI
  3. SSLH 识别 SNI 后转发到指定的 VPN 后端
  4. 其他域名或直接 IP 访问则回落到 Nginx

下一步操作

1. 修改 Nginx 监听端口

确保 Nginx 不再监听 443,改为监听 8443

server {
listen 127.0.0.1:8443 ssl;
listen [::1]:8443 ssl;
# ...
}

2. 测试配置

Terminal window
# 检查配置语法(不启动)
sslh -v --config /etc/sslh.cfg --test
# 重启服务
systemctl restart sslh

3. 客户端连接

协议服务器地址端口协议类型
SSTPtw.hideservers.net(需配合 hosts)443TCP
OpenVPN服务器公网 IP443TCP
HTTPS任意绑定域名443TCP

5. 启用 UDP 支持

默认的命令行参数方式(/etc/default/sslh不支持 UDP,如需 UDP 功能(如 WireGuard、OpenVPN UDP),必须使用配置文件格式。

配置文件对比

文件格式UDP 支持
/etc/default/sslh命令行参数(DAEMON_OPTS="--xxx"❌ 不支持
/etc/sslh.cfglibconfig 结构化格式✅ 支持

创建配置文件

Terminal window
sudo nano /etc/sslh.cfg
verbose: 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

检查可用版本:

Terminal window
ls -la /usr/sbin/sslh*
版本TCPUDP推荐
sslh-fork不推荐
sslh-select可用
sslh-ev⭐ 推荐

修改启动参数(二选一)

以下两种方法任选其一即可:

方法 1:修改 /etc/default/sslh(推荐)

Terminal window
sudo nano /etc/default/sslh
RUN=yes
DAEMON=/usr/sbin/sslh-ev
DAEMON_OPTS="-F /etc/sslh.cfg"

方法 2:修改 systemd 服务

Terminal window
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,更简单且便于维护。

重启服务

Terminal window
sudo systemctl daemon-reload
sudo systemctl stop sslh
sudo pkill -9 sslh # 清理残留进程
sudo systemctl start sslh

验证 UDP 监听

Terminal window
# 检查 TCP
sudo ss -tlnp | grep 443
# 检查 UDP
sudo ss -ulnp | grep 443

6. 总结

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

Terminal window
sudo systemctl stop apache2 # 停止 Apache2
sudo systemctl disable apache2 # 禁止开机自启

然后检查 80 端口是否释放:

Terminal window
sudo ss -tulnp | grep ':80' # 应该无输出

✅ 方案 2:卸载 Apache2(如果不需用它)

Terminal window
sudo apt remove apache2 apache2-utils # Debian/Ubuntu

清理残留配置:

Terminal window
sudo apt autoremove --purge # Debian/Ubuntu

Thanks for reading!

配置 SSLH 在 443 端口同时处理多种服务

周三 1月 08 2025
1639 字 · 9 分钟