WireGuard 是一条跑在三层的加密隧道,做法是把整个 IP 包封装进 UDP 再发出去。它用一对公钥代替证书体系,用固定的加密套件代替算法协商,目标是让“建一条隧道”接近“配一块网卡”。下面按概念、原理、配置步骤、误区四段展开,只写能在官方文档里对上的内容。
WireGuard 是什么:一条 UDP 上的三层隧道
官方文档的表述是:WireGuard 把 IP 包安全地封装在 UDP 之上,所有数据包都走 UDP。你要做的只是加一块虚拟网卡(习惯叫 wg0),填上本机私钥和对端公钥,之后像普通网卡一样收发数据。
落到系统里,wg0 的地址交给 ip-address(8) 配,路由用 ip-route(8) 增删,防火墙规则照旧写;只有 WireGuard 自己的部分用 wg(8)。地址、路由、过滤共用同一套内核设施,这一点决定了它和 IPsec 那种策略库、密钥库分离的模型完全不是一回事。
加密套件是写死的,没有协商环节:Curve25519 做 ECDH,ChaCha20 配 Poly1305 做 AEAD(采用 RFC 7539 的构造),BLAKE2s 做哈希与带密钥哈希(RFC 7693),SipHash24 算哈希表键,HKDF(RFC 5869)派生密钥。少了算法列表,也就没有降级协商的余地。
密钥分发被明确划在协议之外。官方首页的说法是“密钥分发与推送配置不在范围内”,模型更接近 SSH:双方各自拿到对方公钥就能互通。公钥是 32 字节、Base64 编码的短字符串,邮件、配置管理系统、口令库都可以递送。
CryptoKey Routing:公钥与 AllowedIPs 的绑定
这是整套设计的地基。每块接口一把私钥,加一组 peer;每个 peer 有公钥和一份 AllowedIPs。公钥就是身份,AllowedIPs 是它被允许使用的隧道地址集合。
发送方向,AllowedIPs 当路由表用:包要发出去,先看目的地址落在哪个 peer 的列表里,用那个 peer 的公钥加密,再发到它最近一次的 endpoint。接收方向,它当访问控制表用:解密并校验通过的包,若源地址不在该 peer 的 AllowedIPs 内,直接丢弃。官方把这张表叫 Cryptokey Routing Table。

所以这份列表写宽了不只是路由问题:某个 peer 拿到 0.0.0.0/0,等于允许它以任意源地址往接口里塞包。服务端给每台客户端写 /32,实际是在声明“这台设备只拥有这一个隧道地址”。
顺带的好处是服务端不必写 Endpoint。它从“能正确解密认证的包来自哪个地址”推出对端位置,往那里回包;对端换 Wi-Fi、切蜂窝网络,隧道跟着走,不用重连。
握手流程:Noise_IK 如何在一来一回里完成认证
握手用 Noise 框架的 IK 模式,构造串为 Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s。IK 的含义是:发起方预先知道响应方的静态公钥(K),并且在首条消息里就带上自己的静态公钥(I)。配置里本来就填了对端公钥,这个前提天然成立。
首条消息含发起方临时公钥、加密后的静态公钥、加密后的 TAI64N 时间戳,以及 mac1、mac2 两个字段;第二条消息含响应方临时公钥和一段零长度明文的 AEAD 密文。两次交换之后,双方由 chaining key 派生出收发各一把的传输密钥,中间值随即清零。协议页把收益归纳为几条:抗密钥泄露伪装、防重放、前向保密、身份隐藏。
四个细节值得记住:
- 不认证就不回应。收到验证不过的包时它保持静默,不为未认证的包分配状态,扫描器拿不到明确回应,端口像是关着的。
- 重放靠时间戳挡。首条消息就带认证,因此可被重放;包内带 TAI64N 时间戳,对端为每个 peer 记录已见时间戳的上限,小于等于该值的包一律丢弃。
- CPU 吃紧时改发 cookie。响应方负载高时不直接做 ECDH,而是回一个 cookie reply;发起方下次带上由该 cookie 算出的 mac2,响应方只验 MAC 就能限速,cookie 两分钟过期。
- 数据包带 64 位计数器。接收端维护约 2000 个历史值的滑动窗口,在 UDP 允许乱序的前提下挡重放,同时保证计数器不回卷。
三步配置:密钥、接口、路由
官方快速上手给的路径很朴素。
- 生成密钥。先设 umask 077,再执行 wg genkey 写私钥,然后用 wg pubkey 从私钥推出公钥,两个文件都是 Base64 文本。私钥权限必须收窄,泄露等于把身份交出去。
- 建接口、配地址。ip link add dev wg0 type wireguard 建出接口(非 Linux 平台改用 wireguard-go wg0),接着用 ip address add 配隧道地址,再 ip link set up。
- 写 peer。wg set wg0 listen-port 51820 private-key 私钥文件 peer 公钥 allowed-ips 网段 endpoint 地址:端口。示例端口 51820 只是习惯值,可以换。
命令重复多了就交给 wg-quick。它读 /etc/wireguard/wg0.conf,把 [Interface] 段里的 Address、DNS、MTU、Table、PreUp 与 PostUp 这些扩展项自己处理掉,其余原样传给 wg(8) 的 setconf。
两个行为要清楚:wg-quick 会按所有 peer 的 AllowedIPs 推断路由并写进系统路由表,遇到默认路由就借助 ip-rule(8) 处理网关覆盖;MTU 不显式指定时,由 endpoint 地址或系统默认路由推算,所以同一条隧道在 IPv4 与 IPv6 出口下的取值可能不同。
| 配置项 | 所在段 | 作用 |
|---|---|---|
| Address | [Interface] | 接口在隧道内的地址,可写多行,IPv4 与 IPv6 混用 |
| PrivateKey | [Interface] | 本接口的身份私钥,泄露等于身份被顶替 |
| ListenPort | [Interface] | 监听的 UDP 端口,服务端需要固定 |
| PublicKey | [Peer] | 对端身份,由对端私钥推出 |
| AllowedIPs | [Peer] | 出站路由表与入站白名单,同一份数据 |
| Endpoint | [Peer] | 对端最近的公网地址,服务端可缺省 |
| PersistentKeepalive | [Peer] | 按秒计的心跳,用于维持 NAT 映射 |
五个常见误区
- 把 AllowedIPs 当成单向的路由配置。它同时是入站白名单。只按出站需要填写,却漏掉对端地址,典型表现是握手成功、ping 不通。
- 以为要配证书或 CA。没有证书链、没有撤销查询,身份就是公钥本身。真要吊销某台设备,只能把 peer 从配置里删掉并更换密钥。
- 手工填满每个 peer 的 Endpoint。服务端通常不需要;反过来,客户端写的域名只在启动时解析一次,对方地址变了不会自动重解析,得靠 reresolve-dns 脚本或重新执行 wg set 来纠正。
- 无脑加 PersistentKeepalive。它默认关闭,只在“位于 NAT 或防火墙之后、又需要被动接收”时才有意义,官方给的经验值是 25 秒;不需要时开着,只是让隧道一直有话可说。
- 期待它包办网络层面的全部问题。官方“已知局限”页写得很直白:不支持 TCP 模式(TCP over TCP 性能很差),不做流量混淆,抗深度包检测要靠上层工具;默认也不抗量子,只能用预共享密钥补一层。
适用人群与上手建议
适合两类人:需要把几台机器、几个机房、家里 NAS 连成一个平面的运维与自托管用户;以及想搞清“加密隧道到底怎么工作”的读者。它不适合需要二层广播域、需要证书链审计,或必须在只放行 TCP 的网络里穿出去的场景。
上手顺序建议这样走:先在一台有公网地址的机器和一台内网机器之间跑通点对点,确认 wg show 里出现 latest handshake;再改成 wg-quick 配置文件并设开机自启;最后才做站点互联。站点互联时两端都要有固定 endpoint,隧道网段取很小的前缀,两侧内网网段不能重叠,并且不要对隧道流量做 NAT,这一点Ubuntu 的站点互联文档讲得比较清楚。它也提醒,/31 虽然被规范允许,遇到路由异常时退回 /30 更省事。
排障优先看三样:wg show 打出的最近握手时间与收发字节数、ip route 里有没有对应路由、防火墙是否放行 UDP 端口。这三项都对得上,问题基本就在上层应用。
顺带一提,如果只是想在局域网里共享一套键鼠,Deskflow 这类工具比搭隧道轻得多;把家里的服务放到公网之前,也先想清楚是走隧道还是直接开端口,比如自托管相册往往一条隧道就够用。
密钥即身份这个思路,和通行密钥的工作方式相通:注册时绑定一次,之后靠密钥认人,不再传递可被复用的口令。理解了这一层,再看 WireGuard 的配置项,就不会把它当成一份需要背诵的语法。
© 版权声明
文章版权归作者所有,转载需注明出处。未声明原创的皆为网络收集,如有侵权请邮箱lishiwenhuagx@sina.com联系下架处理。




