SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 更新于 2026-10-02

不同提供商的两台 VPS 如何通过 WireGuard 互联

跨提供商 VPS 不共享私有网络。本文用 WireGuard 构建加密覆盖网络,说明地址冲突、MTU、延迟与两端出口流量计费的实际影响。

不同提供商的 2 台 VPS 能否作为一个系统运行

可以。要连接不同提供商的 2 台 VPS,需要自行构建私有网络:通常使用 WireGuard,在公网之上运行加密覆盖网络。任何一家提供商都不会替您完成这项工作,因为每家提供商的私有网络都止于自己的网络边界。您需要为该连接承担无法通过配置消除的延迟,以及两端分别计量的出口流量。数据包进入隧道后还会变小,这可能以完全不像网络故障的方式引发问题。

通常真正需要先回答的问题是由谁管理这些机器。这就是 托管 VPS 与非托管 VPS 的问题,与本页讨论的是不同的问题。本页关注互操作性:东京的一台服务器和另一个国家的一台服务器能否共用一个私有地址范围、通过名称发现彼此、接受对方的流量,并拒绝其他所有来源的流量。

对于在日本的用户,一种常见架构是:东京或大阪的一台 VPS 为国内用户提供服务,另一台更便宜的海外 VPS 运行批处理、备份或构建任务。这种拆分通常运行良好。但将同一个请求路径拆分到这 2 台服务器之间通常不可行,下面将解释原因。

提供商的专用网络为何止于其自身边界

提供商的专用网络是其自有数据中心内部的虚拟局域网(local area network)。第二个网络接口上的 10.x.x.x 地址只能由该提供商的交换机路由,其他网络无法路由它。这是 RFC 1918 私有地址,而私有地址不会在公共互联网中路由:发送到 10.0.0.5 并发往互联网的数据包,会被提供商外部看到它的第一个路由器丢弃。因此,任一控制面板中都没有可以连接这两个账户的设置。在同一提供商内部,情况不同;如果两台机器属于同一账户,应使用同一提供商两台服务器之间的免费专用网络。

跨提供商通信意味着流量会经过您无法控制的中转网络和互联网交换点。您以明文发送的任何内容都可能在那里被读取。覆盖网络不是可选的加固措施,而是这条连接本身。

选择不会冲突的地址

在生成密钥之前完成此操作。在两台服务器上运行:

ip -4 addr show
ip route show
ip -4 addr show docker0 2>/dev/null

记录已在使用的所有网段。两个服务商分配重叠的 RFC 1918 网段很常见,而且 Docker 默认会为 docker0 使用 172.17.0.0/16。然后选择一个在两份列表中都不存在的 overlay 网段,例如 10.83.7.0/24。避免使用 192.168.0.0/24 和 192.168.1.0/24,因为将笔记本电脑加入同一个 overlay 后,这些网段会立即与家用路由器冲突。

网段重叠不会产生错误。它会返回错误结果,因为内核会选择匹配范围最具体的路由。如果 overlay 使用 10.0.0.0/24,而服务商已通过第二个接口路由 10.0.0.0/16,那么发往对端的报文会经由服务商网络离开,并在没有任何日志记录的情况下丢失。

为每台机器在该网段中分配一个固定地址并记录下来。本指南使用 10.83.7.1 作为东京服务器的地址,使用 10.83.7.2 作为海外服务器的地址。

在两台主机上构建隧道:WireGuard

WireGuard 没有客户端和服务器之分。两台机器运行相同的软件,各自持有一对密钥,并将对方列为对等端。在每台主机上运行:

sudo apt update && sudo apt install -y wireguard
sudo install -d -m 700 /etc/wireguard
sudo sh -c 'umask 077; wg genkey > /etc/wireguard/host.key'
sudo sh -c 'wg pubkey < /etc/wireguard/host.key > /etc/wireguard/host.pub'
sudo chmod 600 /etc/wireguard/host.key
sudo cat /etc/wireguard/host.pub

在 Tokyo 主机上写入 /etc/wireguard/wg0.conf。该主机在此处的公网地址是 203.0.113.10:

[Interface]
Address = 10.83.7.1/24
ListenPort = 51820
PrivateKey = <contents of host.key on the Tokyo box>

[Peer]
PublicKey = <contents of host.pub on the overseas box>
AllowedIPs = 10.83.7.2/32
Endpoint = 198.51.100.20:51820
PersistentKeepalive = 25

在海外主机上写入相同文件。该主机在此处的公网地址是 198.51.100.20:

[Interface]
Address = 10.83.7.2/24
ListenPort = 51820
PrivateKey = <contents of host.key on the overseas box>

[Peer]
PublicKey = <contents of host.pub on the Tokyo box>
AllowedIPs = 10.83.7.1/32
Endpoint = 203.0.113.10:51820
PersistentKeepalive = 25

在两台主机上运行 sudo chmod 600 /etc/wireguard/wg0.conf。AllowedIPs 定义了完整的访问模型:它决定出站数据包发送给哪个对等端,也决定入站时接受该对等端发来的哪些源地址。Cryptokey 路由,即 WireGuard 将公钥绑定到一组地址的机制值得在添加第三台机器前阅读一次。如果是一台主机为多个客户端提供服务,而不是两台主机对等互联,请参阅完整的 WireGuard 服务器指南。

即使两端都有公网地址,也并非严格需要 PersistentKeepalive = 25。但建议设置它。许多云服务商会在实例前配置有状态防火墙,其 UDP 状态项在静默一两分钟后过期。因此,空闲后发送的第一个数据包可能被丢弃,导致链路恢复响应缓慢。

启动并检查:

sudo systemctl enable --now wg-quick@wg0
sudo wg show
ping -c 3 10.83.7.2

wg show 应显示几秒前的 latest handshake,并且两个方向的传输计数器都应为非零值。对等端没有握手记录,表示数据包未到达。请在云服务商自有的网络防火墙中放行 UDP 51820。该防火墙在大多数控制面板中与 ufw 分开配置。然后在接收端运行 sudo tcpdump -ni any udp port 51820,确认是否有任何数据包到达。

仅限制隧道,不限制公网接口

该链路的作用是让服务不再监听公网地址。将每个服务绑定到其 overlay 地址。对于 PostgreSQL,该配置位于 postgresql.conf 的 listen_addresses = '10.83.7.1' 中。对于大多数其他守护进程,该配置位于 bind 或 address 行中。

然后仅在隧道接口上开放端口:

sudo ufw allow from 198.51.100.20 to any port 51820 proto udp
sudo ufw allow in on wg0 to any port 5432 proto tcp
sudo ufw enable

第一条规则是该链路唯一需要的公网暴露,并且仅限于一个地址。来自互联网的数据包永远不会匹配第二条规则,因为数据包只有在 WireGuard 解密后,并根据该对等端的 AllowedIPs 检查其源地址后,才会出现在 wg0 上。如果你不熟悉这些规则,请参阅 VPS 的 ufw 防火墙基础,了解默认策略和规则顺序。

绑定到 overlay 会直接导致一个问题。如果服务在 wg0 存在之前启动,机器上还没有该地址,因此绑定会失败。PostgreSQL 会明确显示:

could not bind IPv4 address "10.83.7.1": Cannot assign requested address

最简单的修复方法是允许绑定到尚不存在的地址:

echo 'net.ipv4.ip_nonlocal_bind = 1' | sudo tee /etc/sysctl.d/99-overlay.conf
sudo sysctl --system

另一种修复方法是让单元在隧道之后启动,并配置 sudo systemctl edit postgresql 和 After=wg-quick@wg0.service 行。sysctl 方法更简单,而且即使接口重启、服务继续运行,也能保持有效;排序修复无法做到这一点。

跨区域延迟对应用的影响

往返时间(RTT)是延迟的下限。在当前 CPU 上,每个数据包的加密开销远低于 1 毫秒,因此隧道本身通常不是可感知延迟的来源。距离才是。光在光纤中的传播速度约为每秒 200,000 km,而实际链路并非直线,因此 RTT 取决于地理位置,也取决于两个服务商之间实际采用的路由。

ChartTypical published round-trip times from Tokyo, and what 200 sequential queries cost
The data behind this chart
[
  {
    "label": "Tokyo to Osaka",
    "rtt_ms": 8,
    "seconds_for_200_queries": 1.6
  },
  {
    "label": "Tokyo to Singapore",
    "rtt_ms": 70,
    "seconds_for_200_queries": 14
  },
  {
    "label": "Tokyo to US West",
    "rtt_ms": 100,
    "seconds_for_200_queries": 20
  },
  {
    "label": "Tokyo to Frankfurt",
    "rtt_ms": 235,
    "seconds_for_200_queries": 47
  }
]

这些是网络连接良好路径的典型公开数据,不是对您两台服务器的测量结果。在根据某个数值进行设计前,请先测量实际链路。

国内链路的 8 ms 延迟对用户来说通常不可感知。东京到美国西部的 100 ms 延迟则不同,东京到法兰克福的 235 ms 延迟又属于另一类问题。延迟会累积,这一点最容易让人意外。一个 Web 请求如果依次执行 200 次数据库查询,这对基于对象关系映射器构建的应用很常见,那么每次查询都要支付 1 个 RTT。在查询实际处理任何字节前,国内链路就会耗时 1.6 秒,法兰克福链路则会耗时 47 秒。

吞吐量受同样的根本因素影响。TCP 流一次只能在传输中保留一个尚未确认的数据窗口,因此吞吐上限等于窗口大小除以 RTT。Linux 会自动将窗口增大到 net.ipv4.tcp_rmem 中的最大值,但在长距离链路上,任何丢包都会缩小窗口,而且恢复速度很慢。使用一个 rsync 流复制大型备份,会比将同一复制任务拆分到 8 个并行流中慢得多。

如何准确测量您自己的链路

运行 ping -c 100 10.83.7.2,并读取 min/avg/max/mdev 汇总行,而不是只看某个样本。较高的 mdev 表示链路不稳定,这对应用的影响可能比平均值较高更严重。然后在一台服务器上运行 iperf3 -s,在另一台服务器上运行 iperf3 -c 10.83.7.2 -t 30,测试单个流;接着运行 iperf3 -c 10.83.7.2 -t 30 -P 8,测试 8 个流。如果 8 个流明显快于 1 个流,限制因素就是窗口大小和丢包,而不是带宽。最后,测量实际任务的耗时。通过隧道在 psql 中使用 \timing 为 1 次查询计时,比任何合成测试都更有参考价值。

两端都会产生出站流量费用

几乎所有服务商都会统计出站流量并免收入站流量费用。隧道会双向传输流量,因此 Tokyo 服务器发送的字节数由 Tokyo 服务商计费,海外服务器发送的字节数由海外服务商计费。截至 September 2026,这仍是常见安排,但请分别查看两边的账户,因为不同主机的包含额度和超额费率可能相差一个数量级。

有两点容易被忽略。备份和复制流量会在发送端全额计费,因此每晚从 Tokyo 拉取 50 GB 的数据库转储时,每晚消耗的是 Tokyo 的 50 GB 流量额度,而不是海外服务器的额度。WireGuard 的每个数据包开销也属于计费流量。对于完整的 1500 字节数据包,开销约为 4%,通常不明显。对于发送 100 字节有效载荷的高频通信协议,每个数据包在线路上占用 160 字节,因此开销相当于有效载荷的 60%。

后续设计很简单。将数据按计划批量传输,而不是按请求逐个传输,并在数据离开前先压缩。将高频通信部分保留在链路的一侧。

MTU 和分片会导致大数据传输失败,小数据传输不会

MTU(最大传输单元)是接口能够发送的最大数据包大小。WireGuard 会在数据包外部封装 IP 头、UDP 头、自身的消息头和身份验证标签。

ChartWireGuard overhead and the tunnel MTU that fits
The data behind this chart
[
  {
    "label": "1500 byte path, IPv4 outer",
    "overhead_bytes": 60,
    "tunnel_mtu": 1440
  },
  {
    "label": "1500 byte path, IPv6 outer",
    "overhead_bytes": 80,
    "tunnel_mtu": 1420
  },
  {
    "label": "1492 byte path, IPv4 outer",
    "overhead_bytes": 60,
    "tunnel_mtu": 1432
  },
  {
    "label": "1400 byte path, IPv4 outer",
    "overhead_bytes": 60,
    "tunnel_mtu": 1340
  }
]

使用 IPv4 时,额外开销为 60 字节,因此标准的 1500 字节路径在隧道内可用 1440 字节。使用 IPv6 时,额外开销为 80 字节。wg-quick 默认将接口设置为 1420,因为它始终减去较大的数值。这种设置更安全,但不是最优。如果两个服务商之间的某一跳支持的大小小于 1500 字节,所需值还要更小:1400 字节的路径在隧道内只能留下 1340 字节。

这种症状很典型,但每次都会让人困惑。ping 可以正常工作。SSH 能够连接,输入操作也感觉正常。然后 apt update 停滞,大型 HTTPS 响应在收到响应头后卡住,或者文件复制在传输几千字节后冻结。小数据包可以通过,大数据包则无法通过。内核本应通过 ICMP(互联网控制消息协议)的“需要分片”消息获知限制,但许多网络会丢弃 ICMP,因此发送方无法获知限制,并会持续重传一个永远无法到达的数据包。

手动查找实际限制。以下命令发送 1472 字节的负载,加上 8 字节的 ICMP 头和 20 字节的 IP 头后正好是 1500 字节,并禁止分片:

ping -M do -s 1472 -c 2 198.51.100.20

如果失败,将差值减半并尝试 1372,然后尝试 1272。若限制就在本地接口上,命令会立即给出结果:

ping: local error: message too long, mtu=1500

如果限制位于路径中的更远位置,结果如下所示,消息中的数字就是所需的值:

From 192.0.2.1 icmp_seq=1 Frag needed and DF set (mtu = 1400)

取成功发送的最大负载,加上 28 得到路径 MTU,再减去 60,然后将结果填入两台设备的 [Interface] 部分:

MTU = 1340

使用 sudo systemctl restart wg-quick@wg0 重启,然后在隧道内使用 ping -M do -s 1312 -c 2 10.83.7.2 重复测试。如果通过该链路路由的是整个子网,而不只是两个隧道地址,请在转发路径上添加 TCP MSS(最大分段大小)调整。因为位于两台设备后面的计算机无法自行获知隧道的 MTU。

内部 DNS:让两台主机能够相互发现

不要将 overlay 地址直接填入应用配置。为主机设置名称。只有两台主机时,在每台主机上使用 /etc/hosts 简单可靠,且自身没有额外的故障模式:

10.83.7.1 tokyo.internal tokyo
10.83.7.2 batch.internal batch

使用您拥有的域名后缀,或明确用于内部网络的域名后缀。不要自行编造可能在未来成为真实顶级域的后缀。否则该后缀正式启用后,您的内部名称可能开始解析到他人的服务器。主机数量超过 4 或 5 台后,可在一台主机上运行 dnsmasq,将其绑定到该主机的 overlay 地址,再通过 /etc/systemd/resolved.conf.d/ drop-in 将其他主机指向它。此时,该解析器会成为一项依赖:如果运行解析器的主机关机,其他主机上的名称解析也会停止。因此,请保留 /etc/hosts 条目作为备用。如果您还不熟悉解析器和记录类型,请参阅DNS 的定义以及一次查询实际如何完成解析,其中的说明更简短。

时钟同步,因为这些 VPS 不再共用同一台虚拟机监控程序

同一服务商提供的两台 VPS 通常通过半虚拟化时钟从同一台物理主机读取时间,因此无需额外配置也能保持一致。不同服务商提供的两台 VPS 则没有共同的时间源。它们会分别产生时钟漂移;虚拟机比物理机漂移更明显,因为 vCPU 暂停时会错过定时器中断。

时钟偏差通常表现为看似与时钟无关的问题。运行较慢的 VPS 上,TLS(传输层安全)验证会失败,并显示“证书尚未生效”错误。一台 VPS 签发的 JWT(JSON Web Token)会被另一台拒绝,因为其 nbf 声明的时间仍在未来。两台机器的日志行会以错误顺序交错显示,使故障时间线失真。在两台 VPS 上安装 chrony:

sudo apt install -y chrony
chronyc tracking
chronyc sources -v

chronyc tracking 会输出一行 System time,其中包含当前偏移量。低于 1 毫秒属于正常范围。超过 1 秒就需要立即处理,不能拖延。在日本的 VPS 上,使用附近的时间源可以缩短路径:将 server ntp.nict.jp iburst 添加到 /etc/chrony/chrony.conf,其中 ntp.nict.jp 是由日本国立信息通信研究机构运行的公共服务。出海 VPS 也应使用附近的时间源,原因相同。然后运行 sudo systemctl restart chrony,再次检查 chronyc sources -v,确认存在标记为 ^* 的时间源。

您管理密钥,或依赖协调服务

上面的配置不包含第三方。两个私钥都由您持有,只要两台主机都在线,连接就能工作。代价是维护工作。每增加一台机器,就需要在其他每台机器上编辑一个 [Peer] 块;轮换密钥也必须手动完成,并且需要记得执行。机器数量为两三台时,这不算什么。达到十五台后,就容易出现重复地址和过期对等节点。

Tailscale 和 NetBird 将这些维护工作转移到协调服务器。两者都使用 WireGuard 作为数据平面,并在此基础上提供密钥分发、地址分配、NAT(网络地址转换)穿透和访问规则。Headscale 是一个开源协调器,可自行托管,供 Tailscale 客户端使用。您的流量仍会直接在两台主机之间传输,协调器也不会持有用于加密流量的密钥;但协调器不可访问时,新的对等节点无法加入,密钥也无法轮换。自行运行 WireGuard 与让协调器运行它之间的取舍主要取决于您预计一年后需要管理多少台机器。如果您希望海外主机访问国内主机后面的整个私有网段,而不是单个地址,那么需要使用通告私有网段的子网路由器;手动配置意味着需要在执行转发的主机上匹配 AllowedIPs 条目和 net.ipv4.ip_forward = 1。

不应在不同服务商之间拆分的工作负载

有些工作负载无法承受跨链路部署,任何调优都无法解决。对于同步数据库副本,如果主库必须等待确认,每次写入都会增加完整的 RTT。应用查询远端数据库时,每次查询都要支付 1 个 RTT;上面的图表已将这一成本折算为秒。通过 100 ms 链路使用 NFS(网络文件系统)等网络文件系统不可用,因为元数据操作包含大量小型往返,用户必须等待所有操作完成。etcd 等集群协调服务在心跳丢失时会开始选举新领导者,而较长或不稳定的链路本身就会导致心跳丢失。

适合拆分的工作负载有一个共同特征:它们是异步的,因此一侧不会等待另一侧。批处理、每夜备份、CI(持续集成)构建运行器、日志传输、媒体转码,以及主动拉取任务的队列工作器,都能容忍较长的链路,因为每个工作项都包含工作器所需的全部内容。这正是“面向用户的东京节点,加上海外更便宜的重型任务节点”这一架构的特点。海外低价节点通常使用 ARM 而不是 x86,因此在购买前应确认批处理工作负载是否能在 ARM 上正常运行,因为依赖的每个容器镜像都必须提供适用于该架构的版本。

将面向用户的服务及其数据库放在链路同一侧。将工作按批次发送到另一侧,并让远端在完成后返回结果。

FAQ

我可以使用提供商的私有网络访问另一家提供商的服务器吗?

不可以。提供商的私有网络只在该提供商自己的数据中心内部路由,其中的 10.x.x.x 地址属于 RFC 1918 私有地址,公网中的路由器不会转发发往该地址的流量。从提供商外部发送到该地址的数据包,会被第一个接收到它的路由器丢弃。要连接两家提供商,您需要自行通过公网建立加密覆盖网络。通常是在两台服务器上运行 WireGuard,并将对方列为 peer。

WireGuard 隧道会在两台 VPS 之间增加多少延迟?

隧道本身几乎不会增加延迟。在当前的 CPU 上,每个数据包的加密和解密开销远低于 1 毫秒。您实际测到的延迟取决于两个数据中心之间的距离,以及两家提供商在两者之间采用的路由。使用 ping -c 100 通过隧道进行检查,并读取平均值和偏差,不要只看单次结果。如果隧道中的 RTT 明显高于两个公网地址之间的 RTT,应检查 CPU 是否饱和或是否存在丢包,而不是查找 WireGuard 设置问题。

为什么通过隧道进行大文件传输时会卡住,但 ping 仍然正常?

因为数据包超过了路径允许的大小,而发送方没有收到通知。WireGuard 在 IPv4 上增加 60 字节,因此 MTU 为 1500 字节的路径在隧道内最多承载 1440 字节。如果两家提供商之间的某一跳支持的大小小于该值,超大的数据包就会被丢弃;而阻止 ICMP 的网络会阻止“需要分片”消息到达发送方,导致发送方无限重传。使用 ping -M do -s 1472 <peer public address> 找到可用的大小,逐步减小该值,直到传输成功,然后在两台服务器的 [Interface] 部分中设置 MTU。

我需要为隧道流量向两家提供商支付出站流量费用吗?

通常需要。每家提供商都会统计其服务器发送的出站流量,并且通常不收取入站流量费用,因此双向流量会在两端各计费一次。WireGuard 每个数据包的额外开销也会计入流量,这在流量由大量小数据包组成,而不是少量大数据包时尤其明显。在规划每晚同步前,请查看两个账户包含的流量额度和超额费率,因为截至 2026 年 9 月,不同主机的费率差异很大。

我应该将应用部署在一家提供商,将数据库部署在另一家提供商吗?

如果用户需要等待结果,则不应该这样部署。每次查询都需要一次往返,因此一个页面发起 200 次查询时,在任何查询开始执行实际工作前就需要 200 次往返;在跨洲链路上,这可能需要数秒。将应用和数据库放在同一侧。让另一侧处理不阻塞用户请求的任务,例如备份、批处理作业、日志传输和构建运行器。