Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

1 为什么要用 TCP 来传输?

WireGuard 是一种简洁、高效的 VPN 协议。它使用 UDP 传输,协议封装较少,在网络环境良好时通常能够获得较低的延迟和较高的传输效率。对于大多数场景而言,直接使用原生 WireGuard 就已经足够。

但在部分运营商网络、校园网或公司网络中,UDP 流量可能受到特殊限制。例如,网络设备可能会对长时间、大流量的 UDP 连接进行 QoS 限速,也可能直接丢弃特定端口或特征明显的 UDP 数据包。某些 NAT 环境对 UDP 会话的保持时间也比较短,最终表现为连接不稳定、速度异常,甚至数据包完全不可达。

这时,可以在 WireGuard 外面再增加一层基于 TCP 的传输:先让 Xray 接收 WireGuard 的 UDP 数据,再将其封装进一条 TCP 连接中发送。由于 TCP 流量在绝大多数网络中都能正常通过,这种方式可以提高 WireGuard 在受限网络环境中的可达性,并减少 UDP 被针对性限速的可能。

2 为什么选择 Xray?

能够将 UDP 流量封装到其他传输协议中的开源项目并不少,但许多工具只解决单一场景,项目活跃度、客户端支持和后续维护情况也各不相同。一旦上游停止更新,遇到新系统兼容性或网络环境变化时,处理起来会比较被动。

相比之下,Xray 拥有更成熟的协议实现和较完整的生态,能够在常见桌面与服务器系统上运行,也提供了灵活的入站、出站和路由配置。除了本文使用的 VLESS 与 TCP 组合外,还可以根据网络环境调整外层传输方式,不需要为每一种场景重新引入一套工具。

因此,选择 Xray 并不是因为它能让 WireGuard 本身变得更快,而是因为它可以作为稳定、通用的传输层,为 WireGuard 提供更好的网络适应能力,同时方便后续维护和扩展。

3 Wireguard over Vless

WireGuard 流量可以被 Xray 内核接收并封装到 VLESS 协议中传输,实际承载 WireGuard 数据的是 VLESS over Xray 提供的传输链路。

话不多说,直接开始部署教学:

3.1 安装 Xray

Xray Core 支持 Linux、macOS 和 Windows。三种系统的安装方式略有不同,但后续使用的配置格式基本一致。安装完成后可以先执行 xray version,确认程序已经能够正常运行。

对于使用 systemd 的 Linux 发行版,例如 Debian、Ubuntu、CentOS 和 openSUSE,可以直接使用 Xray 官方安装脚本

1
sudo bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install

脚本会同时安装 Xray Core、GeoIP、GeoSite 和 systemd 服务。主要文件位置如下:

1
2
3
4
程序:/usr/local/bin/xray
配置:/usr/local/etc/xray/config.json
服务:/etc/systemd/system/xray.service
日志:/var/log/xray/

编辑好配置文件后,启用并启动 Xray:

1
sudo systemctl enable --now xray

常用的服务管理命令如下:

1
2
3
4
5
6
7
8
# 重启服务,使新配置生效
sudo systemctl restart xray

# 查看运行状态
sudo systemctl status xray

# 查看最近的服务日志
sudo journalctl -u xray -e --no-pager

macOS 可以通过 Homebrew 安装:

1
brew install xray

Homebrew 会把配置文件安装到:

1
$(brew --prefix)/etc/xray/config.json

因此,Apple Silicon Mac 上通常是:

1
/opt/homebrew/etc/xray/config.json

Intel Mac 上通常是:

1
/usr/local/etc/xray/config.json

使用 Homebrew Services 启动并设置为登录后自动运行:

1
brew services start xray

其他常用命令:

1
2
3
4
5
6
7
8
# 重启服务
brew services restart xray

# 查看服务状态
brew services list

# 停止服务
brew services stop xray

Windows 没有对应的官方安装脚本,需要前往 Xray Core Releases 下载与系统架构匹配的压缩包。常见的 64 位 Windows 设备选择 Xray-windows-64.zip,ARM 设备则选择对应的 ARM64 版本。

下载后将压缩包解压到固定目录,例如:

1
C:\xray\

然后在该目录中创建 config.json,最终结构类似:

1
2
3
4
5
C:\xray\
├── xray.exe
├── config.json
├── geoip.dat
└── geosite.dat

在 PowerShell 中进入该目录并启动 Xray:

1
2
cd C:\xray
.\xray.exe run --config .\config.json

该命令会让 Xray 在当前终端前台运行,关闭窗口后进程也会结束。官方 ZIP 包不会自动注册 Windows 系统服务;如果需要开机自启或长期后台运行,可以再使用 WinSW、NSSM 等服务管理工具进行托管。

3.2 核心配置

Xray 本身不区分服务端和客户端。这里所谓服务端就是流量的出口,有公网 ip ;客户端就是流量入口,一般为移动设备。

服务端负责接收客户端发来的 VLESS + REALITY + TCP 连接,再把其中承载的 WireGuard UDP 数据转发到服务端本机的 WireGuard 监听端口:

1
客户端 Xray → VLESS + REALITY + TCP → 服务端 Xray → Freedom UDP 出站 → 服务端 WireGuard

下面是带注释的服务端配置,字段结构与前面的客户端配置相对应:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
{
"log": {
// 服务端长期运行时使用 warning,避免产生过多调试日志
"loglevel": "warning"
},

"inbounds": [
{
// 入站标签,用于标识这条 VLESS 入站
"tag": "vless-in",

// 监听所有 IPv4 地址,允许外部客户端连接
"listen": "0.0.0.0",

// VLESS + REALITY 对外监听的 TCP 端口
// 需要在服务器防火墙和云平台安全组中放行
"port": 443,

"protocol": "vless",

"settings": {
"clients": [
{
// 客户端和服务端必须填写相同的 UUID
"id": "替换为客户端使用的 UUID",

// 必须与客户端的 flow 保持一致
"flow": "xtls-rprx-vision"
}
],

// VLESS 固定填写 none,传输安全由 REALITY 提供
"decryption": "none"
},

"streamSettings": {
// 使用已经实际验证过的 TCP 传输方式
"network": "tcp",

// 启用 REALITY
"security": "reality",

"realitySettings": {
// 是否在日志中显示 REALITY 调试信息
"show": false,

// REALITY 握手失败时转发到的伪装目标
// 目标需要支持 TLS,并且通常使用 443 端口
"dest": "www.apple.com:443",

// 允许客户端使用的 SNI
// 客户端的 serverName 必须是这里的其中一项
"serverNames": [
"www.apple.com"
],

// 服务端持有的 REALITY 私钥
// 与它对应的公钥填写到客户端的 publicKey
"privateKey": "替换为服务端 REALITY 私钥",

// 允许客户端使用的 Short ID 列表
// 客户端的 shortId 必须与其中一项完全一致
"shortIds": [
"0123456789abcdef"
]
}
}
}
],

"outbounds": [
{
// 这个标签表示 WireGuard 流量的出口
// 实际使用 freedom 协议把 UDP 数据发送到目标地址
"tag": "wireguard",
"protocol": "freedom",

"settings": {
// 域名目标优先解析为 IP 后再建立连接
"domainStrategy": "UseIP"
}
}
],

"routing": {
"rules": [
{
"type": "field",

// 匹配客户端通过 VLESS 送来的 UDP 流量
"network": "udp",

// 将 UDP 流量交给上方 tag 为 wireguard 的 freedom 出站
"outboundTag": "wireguard"
}
]
}
}

完成 Xray 配置后,还需要修改部分 WireGuard 配置:

1
2
3
4
[Interface]
# 为 Xray、VLESS 和 TCP 的额外封装预留空间
MTU = 1300

客户端的流量路径如下:

1
WireGuard → 本机 Xray UDP 入站 → VLESS + REALITY + TCP → 服务端 Xray → 服务端 WireGuard

下面是一份带注释的客户端配置。示例端口仅用于说明,请根据自己的环境修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
{
"log": {
// 调试阶段建议使用 debug,确认运行正常后可改为 warning
"loglevel": "debug",

// Linux 和 macOS 日志路径
// Windows 可改为 C:\\xray\\xray-access.log
"access": "/tmp/xray-access.log",
"error": "/tmp/xray-error.log"
},

"inbounds": [
{
// 入站标签,供后面的路由规则引用
"tag": "wg",

// 只允许本机 WireGuard 将数据交给 Xray
"listen": "127.0.0.1",

// Xray 在本机监听的 UDP 转发端口
// WireGuard Peer 的 Endpoint 应指向 127.0.0.1:51821
// 该端口不能与本机 WireGuard 的 ListenPort 冲突
"port": 51821,

// 使用任意门入站接收 WireGuard 发出的 UDP 数据
"protocol": "dokodemo-door",

"settings": {
// 此入站只接收 WireGuard 使用的 UDP 流量
"network": "udp",

// 数据到达服务端 Xray 后要访问的 WireGuard 地址
// 如果服务端 WireGuard 与 Xray 在同一台机器上,一般填写 127.0.0.1
"address": "127.0.0.1",

// 服务端 WireGuard 实际监听的 UDP 端口
"port": 51820
}
}
],

"outbounds": [
{
// 出站标签,与 routing.rules 中的 outboundTag 对应
"tag": "server",
"protocol": "vless",

"settings": {
"vnext": [
{
// 服务端 Xray 的公网 IP 或域名
"address": "xray.example.com",

// 服务端 VLESS + REALITY 入站监听端口
"port": 443,

"users": [
{
// 客户端与服务端必须使用相同的 UUID
"id": "替换为服务端配置的 UUID",

// 启用 XTLS Vision 流控,服务端用户配置必须保持一致
"flow": "xtls-rprx-vision",

// VLESS 固定填写 none,外层安全由 REALITY 提供
"encryption": "none"
}
]
}
]
},

"streamSettings": {
// 使用 TCP 承载 VLESS 流量
"network": "tcp",

// 使用 REALITY 保护并伪装外层连接
"security": "reality",

"realitySettings": {
// 必须是服务端 realitySettings.serverNames 允许的域名之一
// 通常与服务端 REALITY 的 target 保持对应
"serverName": "www.apple.com",

// 模拟常见浏览器的 TLS 指纹
"fingerprint": "chrome",

// 填写服务端 REALITY 私钥对应的公钥
"publicKey": "替换为服务端 REALITY 公钥",

// 必须与服务端 shortIds 中的某一项完全一致
"shortId": "0123456789abcdef"
}
}
}
],

"routing": {
"rules": [
{
"type": "field",

// 匹配上方 tag 为 wg 的本地 UDP 入站
"inboundTag": [
"wg"
],

// 将匹配到的 WireGuard 流量交给 VLESS 出站
"outboundTag": "server"
}
]
}
}

完成 Xray 配置后,还需要修改部分 WireGuard 配置:

1
2
3
4
5
6
[Interface]
# 为 Xray、VLESS 和 TCP 的额外封装预留空间
MTU = 1300

[Peer]
Endpoint = 127.0.0.1:51821

这里的 51821 必须与 Xray 入站的 port 一致。WireGuard 会把原本发往远端的 UDP 数据交给本机 Xray,再由 Xray 通过 VLESS 链路送到服务端的 127.0.0.1:51820

3.3 工具命令

1
2
3
4
5
# 生成 VLESS UUID
xray uuid

# 生成 REALITY X25519 密钥对
xray x25519

Xray 只是一个内核工具,有测试指出 sing-box 对 UDP 的转发效率更高,有兴趣的可以自行尝试。

评论