目录
WireGuard 安装与双机隧道组网(公网机 ↔ 内网机)
本文记录在两台 Linux 之间用 WireGuard 打通一条加密隧道的最简做法:一台有公网 IP(公网机),一台只有内网、藏在 NAT 后面(内网机)。目标是让内网机主动连上公网机之后,两端互访,并顺带把内网机身后网段的服务也暴露出来。照着做基本能一次通。
一、背景与准备
WireGuard 是内核态的轻量 VPN,配置比 OpenVPN 简单太多,一个 .conf 就搞定。本文场景:
- 公网机:有公网 IP(下文记
<公网IP>),比如一台云服务器,负责"守门",监听 UDP 51820。 - 内网机:没有公网 IP,在公司或家里内网,藏在路由器 NAT 后面,主动去连公网机。
连接方向只能是内网机 → 公网机(因为内网机没有公网地址可被回连),所以内网机的配置里要写 Endpoint = <公网IP>:51820 加上 PersistentKeepalive,让 NAT 映射一直保活,公网机才能"反打"回来。
需要准备的:
- 两台机都是 Linux(Ubuntu/Debian 或 CentOS/RHEL 系都行,本文都覆盖)。
- 内核 ≥ 5.6 自带 wireguard 模块;老内核(如 CentOS 7)要走 DKMS 装
wireguard-dkms。 - 公网机的防火墙要放行 UDP 51820(云厂商安全组也要放)。
- 规划一个隧道内网段,本文用
10.0.0.0/24:公网机10.0.0.1,内网机10.0.0.2。
改 IP、配网络这些前置,可参考同系列的静态 IP 配置和 SSH 公钥登录文档。
二、方案选型:WireGuard 还是 frp / Tailscale
动手装之前,先想清楚用哪种——WireGuard 不是内网穿透的唯一解。下面这张对比表,是结合 IMA 知识库「Linux运维」里《内网穿透方案对比:frp、WireGuard、Tailscale 实测体验》(作者:马哥Linux运维)的实测经验整理的,帮你少走弯路。
| 维度 | WireGuard | frp | Tailscale |
|---|---|---|---|
| 转发原理 | 内核态 VPN,节点间 P2P 直连(不经第三方) | 流量经过你自己的中转服务器 | 基于 WireGuard,自动组网 + 中继兜底 |
| 是否需要公网 IP | 至少一端要(本文就是公网机这端) | 需要一台中转服务器有公网 IP | 不需要(官方中继,或自建 Headscale) |
| 性能 | 极高,内核态 + 直连 | 受中转带宽瓶颈,有额外延迟 | 能直连时同 WireGuard,否则走中继 |
| 部署难度 | 中:写一份 wg0.conf | 中:服务端 + 客户端都要配 | 极低:装客户端、登录账号即可 |
| 维护成本 | 低,纯配置文件 | 中,要长期维护中转机 | 低(官方托管控制面,或自建 Headscale) |
| 典型用途 | 多台服务器组私有网络 | 把本地服务暴露到公网 | 不想折腾、个人/小团队互联 |
那篇实测环境是:客户端在 NAT 后、服务端在阿里云华南(广州)节点,对"家庭宽带 + 云服务器"的组合也成立。
三个方案的取舍(经验之谈)
- WireGuard:适合"机器和机器之间组一张私有网"。加密隧道、直连、性能炸裂。但它有三个现实痛点:① 需要固定公网 IP(动态公网 IP 得配 DDNS,本文排错表也提到了);② NAT 穿透能力弱——只有一端有公网地址时只能那端被动等连,所以本文场景里内网机必须主动连 +
PersistentKeepalive,两端都在对称型 NAT 后可能直接连不上;③ 加新设备要重配所有节点:每加一个 Peer,所有节点的wg0.conf都得补一段[Peer]再重载,规模一大就烦。 - frp:完全可控、不依赖第三方、数据经你自己的中转服务器。缺点是流量都压在中转机上,有带宽瓶颈和延迟;中转服务器也得你自己养。
- Tailscale:最省心,5 分钟能用起来,免费版对个人和小团队够用。它底层也是 WireGuard,只是帮你把"找 IP、打洞、中继"这些脏活干了。代价是要信它的控制面(或自己搭 Headscale 摆脱依赖)。
怎么选(库文作者的场景建议,我认同)
- 只想把家里/公司的 Web、SSH、RDP 暴露到公网 → Tailscale 免费版最省心。
- 文件传输、数据库连接、机器间 SSH 这类"互联"需求 → WireGuard + Tailscale 混合,或纯 WireGuard。
- 想要全场景、且完全自建掌控 → Headscale 自建 + WireGuard。
本文选 WireGuard,是因为它最能讲清"隧道到底怎么搭",而且不依赖任何第三方服务,适合当作基础来学。如果你只是想快速连上,Tailscale 可能更合适——按需取用即可。
三、两端安装
Ubuntu / Debian
bashsudo apt update
sudo apt install -y wireguard # 含 wireguard-tools
sudo modprobe wireguard && echo "模块已加载" # 验证内核支持
CentOS / RHEL 8+ / Rocky / Alma
bashsudo dnf install -y epel-release
sudo dnf install -y wireguard-tools
# 内核 ≥ 5.6 自带模块;更老的内核需额外装 kmod-wireguard(来自 elrepo)
sudo modprobe wireguard && echo "模块已加载"
CentOS 7(内核老,走 DKMS)
bashsudo yum install -y epel-release
sudo yum install -y wireguard-dkms wireguard-tools
sudo modprobe wireguard && echo "模块已加载"
确认 wg 命令可用:wg --version。
四、生成密钥对
每台机各自生成私钥/公钥,私钥只留在本机,公钥发给对端。
bashcd /etc/wireguard
umask 077 # 密钥文件权限收紧
wg genkey | tee privatekey | wg pubkey > publickey # 一次性生成私钥和对应公钥
/etc/wireguard/privatekey:本机私钥,填到自己配置的[Interface]里。/etc/wireguard/publickey:本机公钥,发给对端填到它的[Peer]里。
两端各生成一次。记一下:公网机公钥 <公网机公钥>,内网机公钥 <内网机公钥>。
五、配置公网机(守门方)
/etc/wireguard/wg0.conf:
ini[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <公网机私钥>
# 如果要把内网机身后的网段也转发出来,放开下面两行(eth0 换成公网机出口网卡)
# PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer]
PublicKey = <内网机公钥>
AllowedIPs = 10.0.0.2/32
AllowedIPs = 10.0.0.2/32 表示只有这个隧道地址的流量走公网机的 wg0。
如果还想让公网机能访问内网机后面的整个内网(比如 192.168.1.0/24),把那行改成 AllowedIPs = 10.0.0.2/32, 192.168.1.0/24,同时放开上面的 PostUp/PostDown 做 NAT 转发,并在内网机侧把对应网段也写进它的 Peer AllowedIPs。
六、配置内网机(主动连接方)
/etc/wireguard/wg0.conf:
ini[Interface]
Address = 10.0.0.2/24
PrivateKey = <内网机私钥>
[Peer]
PublicKey = <公网机公钥>
Endpoint = <公网IP>:51820 # 公网机地址,内网机主动连这里
AllowedIPs = 10.0.0.0/24 # 只走隧道访问对端网段;要全局代理改成 0.0.0.0/0
PersistentKeepalive = 25 # NAT 保活,关键!否则公网机无法主动回连
PersistentKeepalive = 25 是 NAT 场景的命脉:内网机每 25 秒发个保活包,让路由器端口映射不超时,公网机才能随时找到它。
七、放行防火墙
公网机要放行 UDP 51820:
bash# Debian/Ubuntu(ufw)
sudo ufw allow 51820/udp
# CentOS/RHEL(firewalld)
sudo firewall-cmd --add-port=51820/udp --permanent
sudo firewall-cmd --reload
云服务器还要在安全组里放 UDP 51820,这是最常见被漏掉的一步。
八、启动与开机自启
两端都执行:
bashsudo wg-quick up wg0 # 拉起隧道
sudo systemctl enable wg-quick@wg0 # 开机自启
sudo wg show # 看接口状态和握手情况
九、验证连通
内网机 ping 公网机隧道地址:
bashping 10.0.0.1
公网机 ping 内网机:
bashping 10.0.0.2
wg show 里 latest handshake 有最近时间戳、且 transfer 有数据,就说明隧道通了。从没握手过,基本就是防火墙 / Endpoint / 密钥三选一错了。
十、让内网服务可被公网访问(可选)
典型需求:内网机上有个 192.168.1.100:8080 的服务,想从外面通过公网机访问。
- 公网机
wg0.conf放开第五节注释的 PostUp/PostDown 两行,并sysctl -w net.ipv4.ip_forward=1(持久化写进/etc/sysctl.d/99-wireguard.conf)。 - 公网机加端口转发,把公网流量引到隧道:
bash
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 -j DNAT --to-destination 10.0.0.2:8080 - 内网机
[Peer]的AllowedIPs保持10.0.0.0/24即可(服务流量从公网机经 wg0 进隧道)。
十一、排错速查
| 现象 | 原因 | 处理 |
|---|---|---|
wg show 一直无 handshake | 防火墙/安全组没放 UDP 51820 | 公网机 ufw/firewalld 放行,云安全组也放 |
| 内网机连不上 | Endpoint 写错或公网 IP 变了 | 核对 <公网IP>:51820;动态公网 IP 要上 DDNS |
| 能握手但 ping 不通 | AllowedIPs 写错 / 没开转发 | 确认两端网段;网关场景开 net.ipv4.ip_forward |
| 公网机无法主动访问内网机 | 缺 PersistentKeepalive | 内网机 Peer 加 PersistentKeepalive = 25 |
RTNETLINK answers: Operation not permitted | 没 root / 模块没加载 | 用 sudo 执行,确认 modprobe wireguard 成功 |
| MTU 导致部分网站打不开 | 默认 MTU 偏大 | [Interface] 加 MTU = 1380 |
十二、小结与参考资料
WireGuard 把"两台 Linux 打通加密隧道"压到了一个配置文件。记住三个关键点:内网机写 Endpoint + PersistentKeepalive(因为只能它主动连)、公网机防火墙和安全组放 UDP 51820、要转发就开 ip_forward 和 NAT。选型上,纯互联、想完全自建就选 WireGuard;只想快速把服务暴露公网、不想折腾,Tailscale 更省力——第二篇「方案选型」一节有完整的对比和取舍。
参考资料:
- WireGuard 官方文档:https://www.wireguard.com/
man wg/man wg-quick- 马哥Linux运维《内网穿透方案对比:frp、WireGuard、Tailscale 实测体验》(IMA 知识库「Linux运维」)
ai协作,人工编辑