如果你像我一样不幸有一个 v6 单栈的服务器运行在家宽下,满心欢喜的配置好 wg1 准备连接,结果发现:在外的大多公共网络都不支持IPv6、英国运营商大多没有移动网络的 IPv6 支持、英国某市场占有率第二的宽带运营商也不支持 IPv6、公共网络封锁 UDP 和高端口,某些甚至仅开放 80,443 这俩基础端口、国内家宽又阻止 80,443 等端口的外部访问、wg 流量易被识别和拦截等种种种种问题。。。
wstunnel 正是你的救星!它通过将 wg 流量封装进 WebSocket 中,使流量看起来像正常的网页连接,并能够通过 Cloudflare 代理实现对单栈服务器的双栈访问。
本方法已在我校校园网中实践成功:我校校园网封锁除 80,443 以外的所有端口,阻止所有 UDP 连接,阻止所有常见 VPN 协议:市面上的 VPN 只要不是私有协议的均无法使用。我并不想费时费力自己写一个 VPN 协议,本文是我能想到有效方法中最简单快速的做法。
1. wg 即 WireGuard 的缩写,本文将会延续使用此缩写,并不再说明
开始之前
阅读本文之前,您应基本理解并熟悉 WireGuard 的配置方法。如果您还不知道如何在服务器上配置基本的 wg 服务,请先阅读以下文章:
本文将不再赘述 wg 的基本配置问题。
另外,你需要有
- 一台安装并配置了 WireGuard 服务的服务器,且有单栈公网 IP
- 一个使用 Cloudflare DNS 的域名
- 一点点基础的 Linux 操作常识
配置 wstunnel 服务器
安装 wstunnel
从 wstunnel 官方仓库中下载最新的发行版。
解压后赋予执行权限并将其放置到系统路径下:
chmod +x wstunnel
mv wstunnel /usr/local/bin
安装证书
这步理论上是可选的,但是我强烈建议您使用证书来加密 Cloudflare 与源服务器之间的通信以达到最大安全性。毕竟你用 wstunnel 一大原因就是为了规避防火墙,对吧?所以尽量加密所有通信环节当然是理所应当的。
进入 Cloudflare 域名控制面板 → SSL/TLS → 源服务器,在源证书选项中点击创建证书。
选择使用 Cloudflare 生成私钥和 CSR,私钥类型为 RSA (2048),覆盖的主机名我选择直接默认用通配符覆盖所有二级域(*.example.com),有效期最长15年。
点击创建后将证书和私钥分别复制并保存到文本文件中,在本例中证书为cert.pem,私钥为key.pem。
在服务器中新建一个目录存放证书和私钥:
sudo mkdir -p /etc/wstunnel
sudo cp origin.pem /etc/wstunnel/cert.pem
sudo cp origin.key /etc/wstunnel/key.pem
为了私钥的安全性,我们需要创建一个新用户使其作为证书目录的所有者。
创建名为wstunnel的新用户:
sudo adduser --system --no-create-home --group --shell /usr/sbin/nologin wstunnel
更新所有者和权限:
sudo chown -R wstunnel:wstunnel /etc/wstunnel
sudo chmod 400 /etc/wstunnel/key.pem
sudo chmod 444 /etc/wstunnel/cert.pem
配置 systemd 服务
新建一个 systemd 服务:
sudo vi /etc/systemd/system/wstunnel.service
写入如下配置:
[Unit]
Description=wg over wstunnel
After=network-online.target
Wants=network-online.target
[Service]
# 使用刚创建的wstunnel用户来执行,使其有权限访问私钥
User=wstunnel
Group=wstunnel
# 保留低端口绑定能力
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=yes
ExecStart=/usr/local/bin/wstunnel server \
--log-lvl INFO \
--restrict-to localhost:51820 \
--tls-certificate /etc/wstunnel/cert.pem \
--tls-private-key /etc/wstunnel/key.pem \
--restrict-http-upgrade-path-prefix "loremipsum" \
wss://[::]:2096
Restart=on-failure
RestartSec=2
[Install]
WantedBy=multi-user.target
此处--restrict-to localhost:51820指仅将流量转发给本地的51820端口,请根据你的服务器 wg 监听端口自行修改
--tls-certificate填入证书路径,--tls-private-key填入私钥路径
--restrict-http-upgrade-path-prefix是可选的密码项,客户端连接时需要使用相同字符串进行验证。不想要认证的话请删除此参数。
最后wss://[::]:2096代表监听本地 2096 端口传入的 IPv6 Websocket 连接,如果要监听来自 IPv4
的连接则需改成wss://0.0.0.0:2096
完成配置后启动服务:
sudo systemctl daemon-reload
sudo systemctl enable --now wstunnel
查看运行日志:
sudo journalctl -u wstunnel -f
成功启动输出:
INFO wstunnel::tunnel::server::server: Starting wstunnel server listening on [::]:2096
Cloudflare 配置
DNS 代理
请检查并确认 Cloudflare 域名控制面板 → DNS → 记录 中服务器的解析记录处于已代理状态(小橙云)。
WebSocket
请检查并确认 Cloudflare 域名控制面板 → 网络 → WebSockets 开关处于启用状态。
SSL/TLS
若您完成了前述证书安装步骤,推荐启用 SSL/TLS → 源服务器 → 经过身份验证的源服务器拉取开关,并在 SSL/TLS → 概述 → SSL/TLS 加密中将加密模式改为完全(严格),以获得更好的安全性。
Origin Rules 更改端口
为了使外部通过 443 端口连接,同时避开家宽的 80/443 端口限制,需要使用 Cloudflare Origin Rules 来转换端口。
在 Cloudflare 域名控制面板 → 规则 → 概述中创建一个新的 Origin Rules 规则。
使用自定义筛选表达式:当主机名等于你服务器所使用的主机名时,目标端口重写到2096。(2096没有被国内运营商封锁,你也可以使用其他没有被封锁的端口)
例如:服务器主机名为 server.example.com 上,那么筛选表达式则为:
(http.host eq "server.example.com")
所有对 server.example.com
的请求都会被重定向到主机的2096端口。
也就是客户端连接wss://server.example.com:443,实际请求会转发到你主机的2096端口上去。
客户端连接
连接 wstunnel
在客户端上同样安装 wstunnel,使用以下命令连接:
wstunnel client \
--log-lvl INFO \
--http-upgrade-path-prefix "loremipsum" \
-L 'udp://51820:127.0.0.1:51820?timeout_sec=0' \
wss://server.example.com
--http-upgrade-path-prefix填写之前服务器设置的认证字符串,若未设置则需删除此参数。
-L的用法和 SSH 隧道类似。前面的51820是本机本地的监听端口,本机的 wg 服务将会连接到
localhost:51820,后面的51820则是服务器上的本地51820(也就是 wg 的监听端口)。
连接 WireGuard
将已有 wg 配置中节点(Peer)的对端(Endpoint)改为localhost:51820。
确保路由的IP 地址(段)(AllowedIPs)中仅包含 wg 接口地址,比如10.0.0.0/8。这是因为如果 AllowedIPs
为0.0.0.0/0,wg 启动时会同时代理 wstunnel 的流量,而此时 wstunnel 却尝试在 wg
的代理中连接远程服务器,这样会造成死循环。
然而只能代理局域网意义不大,也有一些同时代理外网的解决方案:在 Linux 上可以将 wstunnel 的流量打标并从 wg 从排除。然而在我使用的 macOS 下,并不支持这么操作。有一个折中的解决方案:通过这个计算工具,设置 wg 的 AllowedIPs 以将所有 Cloudflare IP 以及你在使用的 DNS 地址排除在外。这样的缺点是但凡使用 Cloudflare 的站点一律都不会被代理,但是好在国内大多站点都不用 Cloudflare,所以单纯用作回国 VPN 问题不大。
补充说明
使用上述方法时,尽可能将 wg 配置中的 DNS 设置为和本地 DNS 不同的服务器,以确保 DNS 流量被一并代理。