【OPS.0x04】使用 Wireguard 进行异地组网
本文最后更新于:2025年10月27日 凌晨
龙哥就是龙!惹啊!
0x00. 一切开始之前
最近手上的各种服务器不知道为啥多了起来( 主要是闲置的各种老笔记本啥的笔者都放家里改造成服务器了,毕竟笔记本通常功耗都很低,再加上趁回国瞎买了各种迷你小主机,虽然说都没有发挥什么实际作用 ),但大都没有公网 IP,又都处在不同的局域网里,笔者的肉身连带自己的笔记本也没有办法同时处在这些不同的网络当中,因此笔者迫切需要一个可用且优雅的异地组网方案,从而让笔者能够无论身处何处都能随时访问不同局域网中的任意一台服务器, 当然现在看来这些服务器大部分情况下的用途似乎就是让笔者闲暇时刻运行 neofetch/fastfetch 和 btop 玩玩
局域网(Local Area Network)也就是我们常说的内网,此类网络通常共用一个连接到互联网(公网)的路由器,共用同一公网 IP,利用网络地址转换(Network Address Translation)技术为内网中的设备与公网服务器建立连接(简而言之就是公网 IP:端口 到内网 IP:端口 整了个映射),因此要与内网中的设备进行通信,我们实质上要实现 内网穿透 ,也叫 NAT 穿透 (NAT traversal)

这个需求的实现其实很简单,我们只需要把不同 LAN 当中的设备组到同一个虚拟网络当中就行—— Virtual Private Network 就是专业干这个的,我们可以使用 VPN 技术在设备间建立点对点的加密信道,从而将不同局域网当中的服务器连接起来,而若要为都处于内网的机器进行打洞,则通常需要有一台位于公网的服务器为他们进行中继:
但说实话,
非科班出身的绝大部分国人在提到VPN这个词时第一时间总会想到另外的东西,怎么回事呢?

现有的比较成熟的无需用户自行在公网架设服务器的异地组网服务有 tailscale、zerotier 等,但由于其在中国大陆内通常没有相应的中继服务器,从而导致在国内想要通过此类服务进行连接则往往带有一定的延迟(反正笔者是忍受不了),例如 tailscale 的速度就慢得难以忍受:

如何解决这个问题?不难想到我们可以在公网 VPS 上自行搭建 tailscale 的 DERP 节点,或是自建 zerotier 的 Moon 节点,但既然都要自建节点了, 那么我们为什么不直接自建 VPN 呢 —— 诸如 IPSec、OpenVPN 等老牌 VPN 方案可谓是应有尽有
但相比于这些传统方案,笔者更愿意选择被 Linus 青睐甚至已经合并入 Linux kernel mainline 的 WireGuard —— 这是一个高性能的基于 UDP 的现代 VPN 协议,或许也是目前已知的最好的 VPN 解决方案

因此本篇博客主要讲述如何利用公网服务器搭建 WireGuard VPN 网络
0x01. 公网服务器基本配置
公网服务器选购
如果你仅在国内进行网络互联,那么直接腾讯云阿里云之类的学生机买起就好了,性能上绝对是够够的
但如果你需要考虑跨国间的国际互联的话,要降低网络延迟,你大概率需要购买那些针对国内线路有优化的 VPS,而需要注意的点便是 物理距离上的近并不代表网络距离上的近 ( 例如总会有人直接无脑购买香港或者新加坡的 VPS 然后发现回国流量要往美国绕一圈而捶胸顿足后悔不已 ),简而言之是因为互联网顶层是由各个自治系统(Autonomous System)连接而成的,而 AS 间如果没有建立直连关系则网络流量往往需要绕道去走建立了直连关系的那些 AS, 因此有的时候你用 traceroute 去观测网络路径会发现一个反常现象就是 “明明物理上距离非常近,网络流量却需要绕道别的地方再绕回来” ,核心原因就在于对应的 AS 间没有建立直连 ,因此在购买前最好先看看该 VPS 所属的 AS 与你所在的 AS 间是否相对距离足够近(以回国流量为例就是看是否和三大运营商的骨干网上的任一 AS 建立了连接关系,只要有一个建立了连接关系那么在网络流量走对应运营商时便能快速访问)
网上各种具体 VPS 厂商的测评也很多,这里笔者就不展开了:)
安装与配置 WireGuard
首先我们在公网服务器上安装 WireGuard,笔者这里是 Ubuntu 24.04:
1 | |
完成安装之后我们会获得一个内核模块,以及相应的用户态 CLI 程序 wg :

接下来使用 wg 生成一份私钥与对应的公钥,存放在 /etc/wireguard 目录下:
1 | |
接下来创建 WireGuard 配置文件,这里我们放在 /etc/wireguard/wg0.conf ,写入如下内容:
1 | |
这里的 PostUp 与 PreDown 参数分别为接口启动时与关闭时执行的命令,存在如下四个执行节点:
PreUp:在网络接口创建前执行PostUp:在网络接口创建后执行PreDown:在网络接口删除前执行PostDown: 在网络接口删除后执行
现在我们解析具体命令,其中 wg0 为我们后面要创建的虚拟网卡名,该命令主要是使用 iptables 进行流量转发,在启动 WireGuard 时添加转发规则,在停用时删除转发规则:
iptables -A FORWARD -i wg0 -j ACCEPT:(默认 filter 表)在 FORWARD 链添加规则——允许从wg0接口转发入流量iptables -A FORWARD -o wg0 -j ACCEPT:(默认 filter 表)在 FORWARD 链添加规则——允许转发流量出到wg0接口iptables -t nat -A POSTROUTING -o 你的能访问公网的网卡名 -j MASQUERADE:使用 NAT 表,在 POSTROUTING 链添加规则——对发出的数据做地址伪装使其看起来像从本地网卡发出的数据包,MASQUERADE即意味着修改出站的包的源地址为该网卡的 ip
如果你不记得 iptables 四表五链,可以简单回忆一下:
为什么不用 nftables?因为👴懒得两个都写了,反正背后都是 netfilter
对于可以访问公网的网卡的名称,可以简单通过如下命令进行获取:
1 | |
接下来使用如下命令启动该接口,其会创建一个虚拟网卡 wg0 :
1 | |

最后,我们可以为 wg0 接口配置自启动:
1 | |
配置防火墙
为了让 iptables 规则正常工作,我们还需要修改防火墙以允许 IPV4 流量转发,首先编辑 /etc/sysctl.conf 文件,添加如下配置:
1 | |
也可以在 WireGuard 配置文件中的
[Interface]添加如下配置来动态开关:
1
2PostUp = sysctl -w net.ipv4.ip_forward=1
PostDown = sysctl -w net.ipv4.ip_forward=0
然后重新载入配置:
1 | |
最后开启 wireguard 监听端口上的 UDP 连接:
1 | |
如果你使用阿里云这样比较专业的云服务器提供商,你可能还需要在相应的控制台页面添加规则:
0x02. 客户端基本配置
Linux 客户端配置
基础配置
首先还是按惯例在本地安装 WireGuard,这里笔者的系统是 openSUSE Tumbleweed :
1 | |
然后按惯例生成公钥与私钥:
1 | |
接下来修改 服务端 配置文件, 添加 客户端配置如下:
每新增一个客户端就添加一份
[Peer]配置
1 | |
然后重启 服务端 WireGuard :
1 | |
然后在 客户端 创建配置文件 /etc/wireguard/wg0.conf ,写入如下内容:
1 | |
如果你不止想要组网,还想要让 WireGuard 服务端代理客户端的全部流量,只需要配置客户端的
AllowedIPs = 0.0.0.0/0即可
最后按惯例启动客户端的 WireGuard 即可:
1 | |
如果有需要,可以配置自启动:
1 | |
配置 DDNS
作为中继的公网服务器的 IP 在某些需求下不一定是恒定的,虽然说域名通常是可以不变的,但有的时候域名对应的 IP 可能会发生改变,而 WireGuard 不会重复进行解析,仅会使用第一次的结果,从而可能造成组网失败 :(
对于 Linux,WireGuard 官方已经提供了 一份自动重新解析 DNS 的脚本 ,我们只需要设置一个定时执行任务即可,例如使用 crontab :
在 Ubuntu 下,该脚本似乎会默认在
/usr/share/doc/wireguard-tools/examples/reresolve-dns/reresolve-dns.sh安装一份
1 | |
Windows 客户端配置
不用 Windows 👋
首先从官网下载对应架构的安装包并安装,选择新建空隧道:

其会自动生成一份私钥和公钥,我们只需要再按照前面的方式填写配置文件即可:

之后在服务端也添加相应配置并重启 WireGuard 即可
0x03. 动态调整服务器的客户端记录
我们不难发现如果每次添加一个新的客户端或删除一个旧的客户端都要在修改完 wg.conf 文件之后重启 WireGuard 似乎有点太愚蠢了(虽然设计上是偏向于预先配置好网络拓扑 所以说优雅在哪 ),因此本节讲述如何在保持服务端的 WireGuard 持续运行的情况下调整服务器上的客户端记录
动态增加新的客户端
我们可以使用如下命令动态添加新的客户端配置:
1 | |
不过该配置不会被持久化到文件中,而仅保存在内存中,这意味着下次重新启动就消失了,因此我们需要额外的配置来将其持久化
持久化当前配置
我们已知如下命令可以显示当前配置:
1 | |
因此我们可以在关闭 WireGuard 时将当前配置持久化到文件当中,编写脚本 /etc/wireguard/wg0.down.sh 如下(别忘了 chmod +x 添加权限):
以及把之前的 iptables 也搬到这个脚本里,方便管理
1 | |
之后我们在启动 WireGuard 时将该配置加载进来,编写脚本 /etc/wireguard/wg0.up.sh 如下:
以及把之前的 iptables 也搬到这个脚本里,方便管理
1 | |
然后修改 /etc/wireguard/wg0.conf 如下:
1 | |
0x04. 基于高级加密信道的 WireGuard 连接
注:这会让速度大幅下降➕延迟大幅提高(毕竟多了好几层传输和加解密的工作),因此除非 Wireguard 直连无法完成配置,否则 如果只是出于纯组网目的的话笔者其实不太推荐搭建这样的架构
众所周知随着国际网络局势不断变化,前面忘了中间忘了后面也忘了,总而言之就是 WireGuard 直接组网因为各种直接或间接的因素而存在一定的小问题导致无法连接成功,例如笔者 肉身所在的澳洲某大学的防火墙 就过滤掉了 WireGuard 流量(也有可能是 UDP 都过滤了,总而言之 这导致笔者不能用基于 wireguard 协议的 tailscale 连接学校服务器 就很难受 ),因此需要为我们的 WireGuard 隧道套一些防护
使用 Xray-core 反代 WireGuard Over Vless
好🐂🍄长的标题
前面忘了中间忘了后面忘了,总而言之基于 UDP 的 WireGuard 协议容易被各种预期外的物理因素识别与阻断,因此我们不难想到的是我们可以再套几层协议以提高其连接稳定性,在 如何在澳洲校园网玩原神 这一篇博客中笔者简要叙述了使用代理方案将来自澳洲的流量转发回离中国大陆较近的区域,在这里我们同样可以利用类似的架构转发 Wireguard 流量完成组网:

注:似乎 WireGuard 在这个架构当中是多余的,也可以直接用 Xray 组网?
公网服务器配置
首先配置 WireGuard,和前面的流程基本一样,这里不再赘叙
接下来配置一个 NGINX 用作伪装,这样别人直接访问你的域名时看到的就是一个普通的网站而没有 WireGuard 特征,首先是安装与启用 NGINX,这里以 Debian 为例:
1 | |
接下来在 /etc/nginx/conf.d 目录下创建一个新的配置文件 自己想名字.conf ,写入如下内容:
1 | |
然后重启 NGINX:
1 | |
最后配置 XRAY Vless + Reality 代理,这里直接上 Docker:
需要注意,出于安全起见,你 不应当完全直接照搬笔者的这个模板,而应当手动更改为当前的最新版本的 Xray 的下载链接
1 | |
配置文件 config.json 这么写:
1 | |
构建运行,这里直接让容器使用本地网络:
1 | |
注:如果你的 xray 上还有其他的一些代理规则,则可以配置通过 SNI 或 user.email 进行分流,以下是一个代理与 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{
"log" : {
"loglevel" : "warning",
"error" : "/var/log/xray/error.log",
"access" : "/var/log/xray/access.log"
},
"inbounds" : [
{
"listen" : "0.0.0.0",
"port" : 443,
"protocol" : "vless",
"tag" : "xray-proxy",
"settings" : {
"clients" : [
{
"id" : "用xray uuid生成一个id",
"email" : "用作分流的自定义邮箱地址1",
"flow" : "xtls-rprx-vision"
},
{
"id" : "用xray uuid生成一个id",
"email" : "用作分流的自定义邮箱地址2",
"flow" : "xtls-rprx-vision"
}
],
"decryption" : "none"
},
"streamSettings" : {
"network" : "tcp",
"security" : "reality",
"realitySettings" : {
"dest" : "nginx本地监听端口",
"xver" : 1,
"serverNames" : [
"你的域名"
],
"privateKey" : "使用xray x25519生成的私钥",
"shortIds" : [
""
]
}
},
"sniffing" : {
"enabled" : true,
"destOverride" : [
"http",
"tls",
"quic"
]
}
}
],
"routing" : {
"domainStrategy" : "AsIs",
"rules" : [
{
"type" : "field",
"user" : [
"用作分流的自定义邮箱地址1"
],
"outboundTag" : "internet-next"
},
{
"type" : "field",
"user" : [
"用作分流的自定义邮箱地址2"
],
"outboundTag" : "wireguard"
}
]
},
"outbounds" : [
{
"protocol" : "freedom",
"tag" : "internet-next"
},
{
"protocol" : "freedom",
"tag" : "wireguard",
"sendThrough" : "0.0.0.0",
"settings" : {
"redirect" : "127.0.0.1:59810"
}
},
{
"protocol" : "blackhole",
"tag" : "block"
}
]
}
内网客户端配置
首先配置 WireGuard,和前面基本一致,其他不再赘叙,不过配置文件修改如下:
1 | |
接下来配置 xray,这里直接上 Docker:
1 | |
配置文件 config.json 这么写:
1 | |
构建运行,这里直接让容器使用本地网络:
1 | |
成功连接,延迟其实相对增加的不是特别多:

如果你的客户端同时要用 wireguard 和网络代理,笔者的建议是分两个不同的 docker 容器,服务端是因为要从同一个端口(
443)进才不得不把两份配置放在一个 xray 里,客户端则完全没有这个问题,直接不同的容器用不同的端口即可
0x05. 可能遇到的问题
客户端能握手但无法连接其他终端,wg show 显示 allowed ips: (none)
在多设备连接到同一网络时可能出现,客户端无法连接到包括服务端在内的其他终端, 但是可能会有一个奇异现象是仅有一个客户端能正常连接 :

出现这种情况的原因可能是因为 IP 冲突 ,大概原因是客户端之间的 IP 相互 overlap 了,从而只有其中一个能够正常工作
最简单的解决方案是 把客户端的子网掩码 设为 /32 ,下面是一个示例配置文件:
1 | |
对应的服务端配置:
1 | |
配置 WireGuard 后无法解析域名,但可以通过 IP 进行访问
可能是 DNS 解析出现问题,在客户端配置文件当中你可能会 习惯性 额外配置如下:
1 | |
这会覆盖原有 DNS 配置,但 DNS 服务器未必是可达的( 原因懂的都懂 ),最简单的解决方案是删除 DNS 配置或是更改成其他的可用的 DNS 服务器(例如 114.114.114.114 )

