当你有几台分散在不同地方的服务器,又想让它们像在同一个内网里一样互访时,一台 VPN 服务器就是最省事的答案。传统方案里,OpenVPN 配置复杂、性能一般,IPSec 更是让很多人望而却步。WireGuard 的出现改变了这个局面:它的代码量只有几千行,配置短到几十行,性能却常常优于传统方案,如今已经并入 Linux 内核主线。对中小企业 IT 和个人站长来说,它是自建 VPN 组网的首选。
这篇文章从运维角度,完整讲一遍 WireGuard 的部署:它的工作方式和为什么快,服务端和服务端如何生成密钥,服务端的 wg0.conf 怎么写,怎么配置 IP 转发和 NAT 让客户端能访问内网和访问外网,客户端配置怎么生成,怎么用 wg show 和 ping 测试连通性,以及上线前必须想清楚的安全与合规问题。命令区分 RHEL/CentOS/Rocky 与 Debian/Ubuntu 两套。
本文的定位是"自己给自己搭一条加密通道",用于把分散的服务器、办公网络、个人设备连成一个安全的私有网络。所有内容都是防御与运维视角,不涉及任何绕过他人网络边界或隐藏来源的用法。请只在你有权管理的设备和网络范围内搭建、使用。
一、WireGuard 为什么快:原理先讲清楚
WireGuard 快和简单的根源,在于它的设计取舍。它基于 UDP 传输,而不是像 OpenVPN 那样默认走 TCP。UDP 省去了 TCP-over-TCP 的层层重传问题,握手和转发都更轻。它工作在 Linux 内核态(通过内核模块),数据包不用在用户态和内核态之间反复拷贝,转发效率高。它使用固定的加密套件——Curve25519 做密钥交换、ChaCha20 加密、Poly1305 做认证、BLAKE2 做哈希——不给你一堆算法选项去纠结,也就少了配置出错的空间。
它的连接模型也很有特点:不太像传统"客户端连服务器",而更像"一群对等的节点通过公钥互相认识"。每个节点都有一对密钥,知道自己该转发哪些流量给哪个对端。服务端和客户端在配置层面是对称的,区别只在于谁监听固定端口、谁主动发起连接。这种基于公钥的 peer 模型,让加一个新节点只需互相把公钥和地址配上,非常清爽。
密钥这件事在 WireGuard 里是核心。每个 peer 都有私钥(自己保存,绝不外传)和公钥(给对端)。两端互相知道对方的公钥,就能建立加密隧道。理解这一点,后面配置里的 PrivateKey 和 PublicKey 就一目了然了:本机的私钥加上对端的公钥,构成一条通路。
二、安装与服务端准备
安装很简单,但要注意内核支持。现代发行版的内核大多已经自带 WireGuard 模块,老内核可能需要装 DKMS 版本。
# Debian / Ubuntu
sudo apt update
sudo apt install -y wireguard wireguard-tools
# RHEL / CentOS / Rocky / AlmaLinux
sudo dnf install -y wireguard-tools
# 如果内核不支持,可能需要 ELRepo 的 kmod-wireguard(视内核版本而定)
# 验证内核模块能否加载(无报错说明可用)
sudo modprobe wireguard && echo "wireguard 模块可用"
# 查看已加载的 wireguard 模块
lsmod | grep wireguard
服务端还需要确认两件事:一是服务器的公网 IP(客户端要用它来连接),二是有没有可用的 UDP 端口。WireGuard 默认用 UDP 51820,你需要确保云安全组放行了这个 UDP 端口。
# 确认公网 IP(从服务器外部视角看)
curl -s ifconfig.me; echo
# 确认 51820/udp 没有被别的程序占用
sudo ss -lunp | grep 51820
风险提示:放行 UDP 51820 属于暴露一个新的公网端口。虽然 WireGuard 默认只响应携带正确密钥的握手包,不携带密钥的探测包会被静默丢弃(这一点让它比开放端口的服务更"隐形"),但仍应配合防火墙限制来源,或在不需要公网入口时把服务端放在内网。云安全组里请精确放行 51820/udp,不要图省事开放全端口。
三、生成密钥:私钥绝不外传
密钥生成用 wg 命令,一行搞定。私钥要严格保护,权限设为 600 且只有属主可读;公钥可以给对方。
# 进入一个安全目录(建议不放家目录根下,而是专门目录)
sudo mkdir -p /etc/wireguard/keys
cd /etc/wireguard/keys
# 生成服务端密钥对
wg genkey | tee server_private.key | wg pubkey > server_public.key
chmod 600 server_private.key
# 生成一个客户端密钥对(示例,客户端也可以在自己机器上生成)
wg genkey | tee client1_private.key | wg pubkey > client1_public.key
chmod 600 client1_private.key
# 查看生成的公私钥
echo "服务端公钥: $(cat server_public.key)"
echo "客户端1公钥: $(cat client1_public.key)"
wg genkey 输出的是一段 base64 字符串,这就是私钥;把它作为输入送给 wg pubkey,得到的就是对应的公钥。整个过程本地完成,不联网、不回传,这也是 WireGuard 密钥管理简单的一个体现。
有一个容易忽略的细节:tee 会把私钥同时写到文件和标准输出,如果终端有记录历史或日志,可能留下痕迹。更稳妥的写法是先生成到文件,再单独读取。
# 更干净的生成方式:直接写入文件,不回显到终端
umask 077
wg genkey > server_private.key
wg pubkey < server_private.key > server_public.key
umask 077 保证新建文件默认只有属主可读写,避免私钥文件生成时权限过松。
四、服务端 wg0.conf:一个完整的例子
WireGuard 的主配置文件通常放在 /etc/wireguard/wg0.conf,文件名里的 wg0 就是接口名。配置文件在接口启动时读取,所以每次改完都要重启或重载接口。
服务端配置由 [Interface] 段和若干个 [Peer] 段组成。[Interface] 描述自己,每个 [Peer] 描述一个对端。
# /etc/wireguard/wg0.conf (服务端)
[Interface]
# 服务端在隧道内的私有地址,以及隧道的网段
Address = 10.8.0.1/24
# 监听端口
ListenPort = 51820
# 服务端私钥(从文件读取,避免明文写在配置里)
PrivateKey = <服务端私钥内容>
# 启动接口后执行的命令:开启转发并设置 NAT(让客户端能访问公网)
# 这两条会在 wg-quick 拉起接口时自动执行
PostUp = sysctl -w net.ipv4.ip_forward=1
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
# 以下是各个对端(客户端)
[Peer]
# 客户端1的公钥
PublicKey = <客户端1公钥内容>
# 客户端1在隧道内的地址(可以给单个 /32,也可以给一个可分配的网段)
AllowedIPs = 10.8.0.2/32
配置里几个字段的含义必须弄清楚。Address 是这台机器在隧道网络里的地址;ListenPort 是 UDP 监听端口;PostUp/PostDown 是接口起来/关闭时执行的命令,用来开转发和做 NAT(这一步是让客户端"上网"的关键);AllowedIPs 在服务端的 [Peer] 段里,表示"允许这个 peer 使用哪些源地址,也决定把哪些目的地址的流量路由给它"。
AllowedIPs 是 WireGuard 里最需要理解的字段,它在两端含义不同。在服务端的每个 [Peer] 里,它声明"这个客户端在隧道里的地址",通常是一个 /32,避免不同客户端分配到相同地址。在客户端的 [Peer] 里,它决定"哪些流量走隧道":填 0.0.0.0/0 就是所有流量都走 VPN(全流量代理),只填 10.8.0.0/24 就是只有访问隧道内网才走 VPN。这个区别后面客户端配置会再展开。
把私钥从文件读进配置,可以用 shell 拼接,避免手动复制粘贴出错:
# 生成服务端配置,私钥从文件读取
cd /etc/wireguard
sudo tee wg0.conf >/dev/null <
注意 eth0 要换成服务器实际的出口网卡名,用 ip route get 1.1.1.1 或 ip -br addr 确认。写错网卡名,NAT 就不生效,客户端能连上隧道却上不了网。
# 确认出口网卡名
ip -br addr
ip route get 1.1.1.1 # 输出里 "dev" 后面的就是出口网卡
如果系统用的是 nftables(比如新版 Debian 或某些发行版),NAT 要用 nft 的写法:
# nftables 版本的 PostUp/PostDown
PostUp = nft add rule ip nat POSTROUTING oifname "eth0" masquerade
PostDown = nft delete rule ip nat POSTROUTING oifname "eth0" masquerade
另外,持久化转发开关更规范的做法是写进 /etc/sysctl.d/ 而不是每次 sysctl -w:
# 持久开启 IP 转发
echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl --system
五、客户端配置:一份配置走天下
客户端配置和结构对称,但方向相反:客户端不监听固定端口(或用一个随机端口),它的 [Peer] 指向服务端。
# 客户端1的配置(例如 client1.conf)
[Interface]
# 客户端在隧道内的地址,要在服务端的网段里且不与其他客户端重复
Address = 10.8.0.2/24
# 客户端自己的私钥
PrivateKey = <客户端1私钥内容>
[Peer]
# 服务端的公钥
PublicKey = <服务端公钥内容>
# 哪些流量走隧道:全流量填 0.0.0.0/0,只访问内网填 10.8.0.0/24
AllowedIPs = 10.8.0.0/24, 192.168.10.0/24
# 服务端的公网地址和端口
Endpoint = 198.51.100.20:51820
# 每 25 秒发一次保活包,让 NAT 映射不超时(客户端在 NAT 后面时很关键)
PersistentKeepalive = 25
这里的 AllowedIPs 决定隧道的使用范围,是全篇最实用的一个开关。填 10.8.0.0/24, 192.168.10.0/24,表示只有访问隧道网段和服务端那边的内网(192.168.10.0/24)才走 VPN,其余流量照走本地网络——这是"只做内网组网"的模式。填 0.0.0.0/0,表示所有流量都走 VPN,适合需要把出口也放到服务端(比如统一出口 IP)的场景,但这需要服务端配置了 NAT 并可能要额外设置 DNS。
PersistentKeepalive = 25 值得解释一下。客户端通常在防火墙或 NAT 后面,NAT 映射会超时。定期发保活包能维持这个映射,让服务端随时能反向联系客户端。但如果客户端有稳定的公网地址、能主动连服务端,这个值可以省略。
生成客户端配置时,最省事的办法是把上述模板写出来,用脚本填充私钥和公钥,然后用 qrencode 生成二维码,方便手机 WireGuard App 扫码导入。
# 生成客户端配置(示例:只访问内网)
cd /etc/wireguard
sudo tee client1.conf >/dev/null <
客户端配置里包含私钥,属于敏感文件,分发时要注意安全(通过加密渠道发送、用完删除)。手机 App 扫码导入后,建议把服务器上的这份 client1.conf 删掉或妥善保存,不要留在公网可访问的位置。
六、启动、测试与接入更多节点
配置写好之后,用 wg-quick 拉起来。
# 启动 wg0 接口
sudo wg-quick up wg0
# 查看接口状态、每个 peer 的最新握手时间和流量
sudo wg show
# 如果配置有语法问题,wg-quick 会报错,可按提示排查
# 设置开机自启(wg-quick 生成的 systemd 服务名是 wg-quick@接口名)
sudo systemctl enable wg-quick@wg0
# 停止接口
sudo wg-quick down wg0
# 修改配置后重新加载:先 down 再 up,或用 wg syncconf 不中断地同步
sudo wg syncconf wg0 <(sudo wg-quick strip wg0)
wg show 的输出是排查的核心。它能告诉你在隧道里,每个 peer 的 latest handshake(最近一次握手时间)、transfer(收发字节数)、allowed ips。如果某个 peer 从未握手、或者收发字节一直是 0,说明连接没建起来。
连通性测试分两步:先在隧道内部 ping 对端地址,再测试访问对端内网。
# 在客户端上:ping 服务端在隧道内的地址
ping -c 3 10.8.0.1
# 在客户端上:ping 服务端所在内网的某台机器
ping -c 3 192.168.10.20
# 在服务端上:查看某个客户端是否已握手
sudo wg show wg0
# 输出里对应的 peer 应显示 "latest handshake: xx seconds ago" 和增长的 transfer
# 在服务端上:ping 客户端在隧道内的地址(客户端配了 Keepalive 时通常可达)
ping -c 3 10.8.0.2
如果 ping 不通,按这个顺序查:wg show 看有没有握手;没有握手就查 Endpoint 地址和端口对不对、云安全组有没有放行 UDP 51820、服务端防火墙有没有放行;有握手但内网不通,查服务端的 ip_forward 是否开启、PostUp 里的 NAT 网卡名对不对、以及回程路由。
# 服务端排查:确认转发已开启
sysctl net.ipv4.ip_forward # 应为 1
# 确认 NAT 规则存在
sudo iptables -t nat -L POSTROUTING -n -v | grep MASQUERADE
# 确认接口存在且地址正确
ip -br addr show wg0
# 放行 UDP 端口的防火墙规则
# RHEL 系:
sudo firewall-cmd --permanent --add-port=51820/udp && sudo firewall-cmd --reload
# Debian/Ubuntu:
sudo ufw allow 51820/udp
接入更多客户端,就是在服务端 wg0.conf 里追加 [Peer] 段,为每个客户端分配不同的 10.8.0.x 地址,并给每个客户端一份包含对应私钥和对端公钥的配置。
# 在服务端 wg0.conf 追加第二个客户端
[Peer]
PublicKey = <客户端2公钥内容>
AllowedIPs = 10.8.0.3/32
追加后重载配置:
# 追加 peer 后,平滑同步到运行中的接口
sudo wg addconf wg0 <(sudo wg-quick strip wg0)
# 或直接重载接口
sudo wg-quick down wg0 && sudo wg-quick up wg0
风险提示:重载接口会短暂中断所有已有隧道,若你正通过这条 VPN 管理服务器,重载可能让你断开。建议在本地有另一条管理通道(如云控制台)时操作,或使用 wg syncconf / wg addconf 这种不需要 down 接口的方式。
七、安全与合规:几条务实的建议
WireGuard 本身是安全的,但搭好不代表就安全了,配置和管理上有几点要留心。
第一,私钥管理是重中之重。私钥只应存在于它所属的设备上,服务端持有的所有客户端私钥(如果服务端生成的话)要严格保护。建议每个 peer 的密钥在它自己的设备上生成,只把公钥交给服务端,这样服务端即使被入侵,也拿不到客户端的私钥。
第二,每个设备一把独立密钥,不要多设备共用。共用密钥意味着无法区分设备、无法单独吊销,一台设备丢了就得全换。独立密钥的好处是:设备丢失时,只需在服务端删掉对应的 [Peer] 段,该设备立刻失去访问。
第三,限制客户端的可达范围。AllowedIPs 不要随手写 0.0.0.0/0 给所有客户端,除非业务真的需要。走隧道流量越大,VPN 的性能压力和潜在横向移动风险越大。默认只放通需要互访的网段,最小够用。
第四,服务端的转发和 NAT 要配合主机防火墙一起收紧。开了 ip_forward 和 NAT 之后,客户端之间、客户端到内网的流量都经过服务端,应该用防火墙规则限制"哪些客户端能访问哪些内网资源",而不是默认全通。
第五,注意合规。VPN 的使用在不同地区和场景下有各自的合规要求,企业内网组网应遵守所在组织的安全策略,涉及数据跨区域传输时还要考虑数据合规。本文讲的是自己管理自己设备/网络的技术方法,请确保使用场景是合法且你有权限的。
第六,关闭不必要的公网入口。如果这套 VPN 只用于少数几台固定服务器互联,可以考虑把服务端的 UDP 端口限制在特定来源 IP 或走已有的可信网络,减少暴露。
常见问题
Q:客户端连上了(wg show 有握手),但访问不了服务端内网,为什么?
大概率是转发或 NAT 没配好。检查服务端 net.ipv4.ip_forward 是不是 1、PostUp 里的出口网卡名是不是写对了、NAT 规则是否真的添加成功。另一台内网机器的回程路由如果指向别的网关,也需要它知道怎么把回包送回隧道网段。
Q:wg show 里某个客户端一直没有 latest handshake,怎么办?
先确认客户端能否 ping 到服务端的公网 IP(链路通不通)、云安全组和主机防火墙是否放行 UDP 51820、客户端配置里的 Endpoint 地址和端口是否正确、双方公钥是否配对正确。任何一处不对都会导致握手失败。
Q:AllowedIPs 填 0.0.0.0/0 有什么影响?
所有流量都会走 VPN。这需要服务端配置 NAT 才能上网,且如果客户端原来有本地 DNS 或需要直连的资源,可能会被一并导流。只在确实需要"统一出口"时使用,并注意与本地网络的路由冲突。
Q:一个客户端想同时接入两个不同的 WireGuard 网络行不行?
可以,但要注意隧道内网段不能重叠,否则路由会打架。给两个网络分配不同的地址段(比如 10.8.0.0/24 和 10.9.0.0/24)即可。手机 App 一般支持多个隧道但同一时刻只激活一个,桌面端则可同时启用多个接口。
Q:能不能用域名当 Endpoint 动态 IP?
可以,Endpoint 支持域名,客户端会在连接时解析。但要确保域名解析稳定且指向正确的公网地址。对于出口 IP 会漂移的场景,域名+DDNS 是常见做法。
总结
WireGuard 用一套简洁的设计换来了高性能和易配置:基于 UDP、内核态转发、固定加密套件、基于公钥的 peer 模型。它把 VPN 配置从"几十页文档"压缩到了几十行。
部署的核心流程是:安装、生成密钥(私钥严守、公钥分发)、写服务端 [Interface] 和 [Peer]、开启 IP 转发并配置 NAT、写客户端配置、wg-quick up 拉起、用 wg show 和 ping 验证连通。
最需要理解的字段是 AllowedIPs:在服务端它声明客户端的隧道地址,在客户端它决定哪些流量走隧道。搞清这一点,全流量代理和只做内网组网就能自由切换。
排障的顺序很清晰:wg show 看有没有握手,没握手查链路和端口放行,有握手但内网不通查转发与 NAT。绝大多数问题都落在两步之内。
最后,安全靠的是规范管理而不是工具本身:每个设备一把独立密钥、私钥绝不外传、按最小范围放通、转发流量用防火墙限制、使用场景确保合法合规。做到这些,WireGuard 就能成为你服务器组网里最省心的一环。
企业QQ咨询




