VPS 中转搭建:nftables DNAT 与 GOST 端口转发

VPS 中转搭建:nftables DNAT 与 GOST 端口转发

Jason Chen
2026年10月14日· 8 分钟阅读

VPS 中转是在已有代理服务器前面加一跳:客户端先连中转 VPS,中转再把 TCP 和 UDP 数据原样交给落地服务器,过程中不做任何解密。你可以在内核里用 nftables DNAT 加源地址转换实现,也可以在用户态用 GOST 转发;两种做法都只能用在你拥有或已获授权的服务器之间。

关键要点

  • 中转只改变入口地址,不改变出口:网站看到的仍是落地服务器。
  • nftables DNAT 需要开启 IP 转发,并配一条对应的 SNAT 或 masquerade 规则,否则回包会走错路径。
  • GOST 在应用层转发,不需要内核转发,但长时间的 UDP 会话需要 keepAlive。
  • 两种方式都会让落地服务器看到中转的地址,而不是每个客户端的地址。
  • 客户端的 TLS、REALITY 或密钥设置保持不变,只改服务器地址和端口。

本文依据文末官方来源整理,未完成完整端到端实测。命令以两台服务器均为 Ubuntu 24.04 LTS、使用发行版自带的 nftables 和 GOST v3.3.0 为前提,描述的是文档中的行为,而不是实测结果。先用自建归属与恢复清单确认每台服务器由谁管理。

VPS 中转什么时候有用,什么时候没用?

当客户端访问某个机房比另一个更稳定,或者你想更换公开入口地址而不重建代理本身时,中转就有用处。它不是第二层加密,也不会对落地服务器隐藏流量;那种需求更接近多跳链路,每一跳运行各自的协议。

转发端口也意味着公开这个端口。开放任何端口之前,先了解入站端口转发会如何暴露服务,并决定允许哪些来源地址。如果落地服务器本身已经很慢或负载过高,中转也救不了:先按自建服务器变慢的排查方法测清楚。如果维护两台服务器、两套防火墙和两套升级计划超出了你的实际需要,加这一跳之前先把这份工作量与托管 VPN 对比一下。

只使用你自己管理的服务器,确保控制台访问不依赖被转发的端口,SSH 主机密钥经过带外核验。不要使用来源不明的一键中转脚本:它们经常整体替换防火墙规则,事后也查不到改了什么。

nftables DNAT 还是 GOST:该选哪种中转方式?

问题nftables DNAT 端口转发GOST 端口转发
运行位置Linux 内核 netfilter,带连接跟踪中转上的一个用户态进程
是否需要 ip_forward需要不需要
落地看到的来源SNAT 或 masquerade 之后的中转地址中转地址,因为 GOST 自己发起新连接
UDP 处理每个流一条 conntrack 记录UDP 监听器,带 keepAlive 与 ttl 选项
附加能力计数器、匹配条件,无需额外守护进程多个目标、选择策略、可选的转发链
主要故障点缺少 SNAT,或被 forward 策略丢弃进程停止,或 UDP 通道过早关闭

nftables 的有状态 NAT 在一个流的首个数据包上建立绑定,之后的数据包复用这个绑定。[1] GOST 的 TCP 与 UDP 转发服务在中转上接受连接,再向每个目标节点发起新连接;它也能用 -F 让流量经过转发链中的一跳,但下一台服务器上需要对应的服务。[2] 本文两种方式都只做直接转发,每个端口只选一种。

步骤 1:记录落地服务器信息并规划端口

示例中,中转的公网网卡是 eth0,地址 198.51.100.10;落地服务器是 203.0.113.30,上面已有代理在 TCP 和 UDP 443 上监听。把这些值全部换成你的实际值,并在加中转之前确认直连落地服务正常。

在中转上选好没被占用的端口:这里 nftables 用 8443,GOST 用 8444,方便对比两种方式。用 sudo ss -lntup 检查。用 sudo nft list ruleset > ~/relay-ruleset-before.nft 保存中转当前的规则,并记下正在使用的防火墙管理工具,例如 UFW 或 Docker。

如果落地服务器的防火墙只放行已知的客户端地址,为中转地址放行 TCP 和 UDP 443。中转启用后,落地服务器会把 198.51.100.10 当作所有中转客户端的对端,按客户端地址做的限制和日志将无法区分用户。

步骤 2:开启转发并添加 nftables DNAT 与 SNAT

内核转发默认关闭(net.ipv4.ip_forward 为 0)。[3] 创建 /etc/sysctl.d/90-relay-forward.conf,内容为 net.ipv4.ip_forward = 1,然后运行 sudo sysctl --system,再用 sysctl net.ipv4.ip_forward 确认。内核文档提到,修改这个值会把各网卡的配置参数重置为默认值,所以之后要复查你自定义过的网卡设置。[3]

把下面的规则保存为 /etc/nftables-relay/relay-nat.nft:

table ip relay_nat
delete table ip relay_nat

table ip relay_nat {
    chain prerouting {
        type nat hook prerouting priority -100; policy accept;
        iifname "eth0" tcp dport 8443 counter dnat to 203.0.113.30:443
        iifname "eth0" udp dport 8443 counter dnat to 203.0.113.30:443
    }
    chain postrouting {
        type nat hook postrouting priority 100; policy accept;
        ip daddr 203.0.113.30 tcp dport 443 counter masquerade
        ip daddr 203.0.113.30 udp dport 443 counter masquerade
    }
}

前两行先创建再删除这张表,所以重复加载文件时只会替换 relay_nat,不会碰其它表。不要加 flush ruleset:它会把 UFW、Docker 或服务商代理程序的规则一并清掉。prerouting 链改写目标地址,postrouting 链把源地址改成中转地址,这样落地服务器会回包给中转,再由 conntrack 把回包转换回客户端。[1] 没有这一步 SNAT,落地服务器会直接把回包发给客户端,与客户端原来的连接对不上。

先用 sudo nft -c -f /etc/nftables-relay/relay-nat.nft 检查语法,再用 sudo nft -f 加同一路径加载。

在过滤规则中放行转发流量

NAT 规则不能替代过滤规则。在 nftables 中,一条基础链的 accept 并不是最终结论,同一挂载点上另一条基础链的 drop 仍然生效。[4] 运行 sudo nft list ruleset | grep -B2 -A4 'hook forward'。如果某条 forward 链是 policy drop,就在管理这条链的工具里添加放行。以 UFW 为例,使用 sudo ufw route allow proto tcp to 203.0.113.30 port 443,再加一条 proto udp 的同类规则,而不是另建一张相互冲突的表。

步骤 3:或者用 GOST 转发同一个服务

从 GOST 官方 v3.3.0 发布页下载 Linux 版本,查看发布说明和官方校验和,安装为 /opt/gost/v3.3.0/gost,属主 root,权限 0755。[5] GOST 读取通过 -C 传入的 YAML 或 JSON 文件。[6] 把以下内容保存为 /etc/gost-relay/gost.yml:

services:
- name: relay-tcp
  addr: :8444
  handler:
    type: tcp
  listener:
    type: tcp
  forwarder:
    nodes:
    - name: landing-tcp
      addr: 203.0.113.30:443
- name: relay-udp
  addr: :8444
  handler:
    type: udp
  listener:
    type: udp
    metadata:
      keepAlive: true
      ttl: 30s
  forwarder:
    nodes:
    - name: landing-udp
      addr: 203.0.113.30:443

keepAlive 为 false 时,GOST 的 UDP 监听器在返回响应后立即关闭通道,这适合单次 DNS 查询,却会让需要大量往返数据包的 QUIC 类代理中断。设为 keepAlive: true 后,空闲通道每隔 ttl 检查一次,最多经过两个空闲周期关闭。[2] readBufferSize 默认 4096 字节,更大的 UDP 包会被截断,除非你的协议会发送更大的数据报,否则保持默认。

创建不可登录的账号 gost-relay,再写一个 systemd 单元,以该账号运行 /opt/gost/v3.3.0/gost -C /etc/gost-relay/gost.yml,并设置 Restart=on-failure 和 NoNewPrivileges=true。8444 端口高于 1024,进程不需要额外权限。在中转的入站防火墙中放行 TCP 和 UDP 8444;GOST 流量对中转来说是本机流量,不需要 forward 规则。

步骤 4:让客户端连接中转

复制客户端可用的配置,只把服务器地址改成 198.51.100.10,端口改成 8443(nftables)或 8444(GOST)。TLS 服务器名、REALITY 参数、UUID 和密钥都保持原样。两种方式都不终结 TLS,所以客户端仍然端到端地校验落地服务器的证书或 REALITY 参数。

如果原配置把落地服务器的 IP 地址当作 TLS 名称,经中转后依然可用,因为名称校验针对的是证书,而不是套接字地址。下面的检查全部通过之前,保留直连配置作为备用。

如何验证中转路径与回程流量?

检查方法预期现象不符时的处理
通过中转配置向你控制的端点发请求得到预期响应先测直连配置,再查中转的监听和规则
在中转上运行 sudo nft list table ip relay_natDNAT 与 masquerade 规则的计数增加DNAT 无计数:网卡或端口不对;有 DNAT 无 masquerade:检查 ip daddr
在落地服务器上运行 sudo ss -tn state established '( sport = :443 )'对端显示为中转地址显示客户端地址:缺少 SNAT,或流量绕过了中转
通过中转配置运行一个 UDP 业务UDP 计数增加,会话保持GOST 确认 keepAlive: true,nftables 检查 UDP 规则
只停止 gost-relay,再连 8444新连接失败,8443 不受影响8444 被其它进程占用,或客户端用错了配置
直连配置访问落地服务器可用,或在你限制只许中转访问时被拒绝按你的规划调整落地防火墙

通过中转配置打开 IP 地址检测工具。它应显示落地服务器的出口地址,而不是中转地址,因为中转只承载入站这一段。如果以后搭建每一跳都运行各自代理协议的链路,请按 Xray 代理链逐跳验证方法检查,而不是用这张表。

如何持久化、回退与清理?

要在开机时加载 nftables 文件,写一个属主为 root 的小型一次性单元 relay-nat.service:在 network-online.target 之后运行 /usr/sbin/nft -f /etc/nftables-relay/relay-nat.nft,设置 RemainAfterExit=yes,并用 ExecStop=/usr/sbin/nft delete table ip relay_nat。启用它,在维护窗口内重启,再重复计数器和对端检查。sysctl 文件已经让转发持久化。只有保留 GOST 方式时才启用 gost-relay。

回退从客户端开始:切回直连配置,用一次新请求确认。在中转上运行 sudo systemctl disable --now relay-nat gost-relay,删除你添加的 UFW route 或入站规则;如果没有其它用途需要转发,删除 /etc/sysctl.d/90-relay-forward.conf 后运行 sudo sysctl --system。把 sudo nft list ruleset 与保存的副本对比。落地服务器上为中转放行的规则最后再删。

总结

  • 中转只移动入口,落地服务器仍是出口,也不会多出新的解密环节。
  • nftables 需要转发、DNAT、SNAT,以及与你的防火墙工具一致的 forward 放行。
  • GOST 不需要内核转发,但必须让 UDP 通道在长会话中保持打开。
  • 在弃用直连配置之前,核对计数器、落地端对端地址、UDP 与出口地址。

常见问题

VPS 中转会给代理流量额外加密吗?

不会。两种方式都只转发数据包或数据流,不做解密,也不加新的加密层。加密仍然来自客户端与落地服务器之间运行的代理协议本身。

为什么只配 DNAT 时连接会卡住?

因为落地服务器会把回包发给客户端的原始地址,而不是发回中转。加上 SNAT 或 masquerade 后,回包才会经过中转的连接跟踪返回客户端。

同一台中转上能同时用 GOST 和 nftables 吗?

可以,像本文这样用不同端口即可。不要让两种方式指向同一个中转端口,否则 DNAT 规则会先截走数据包,GOST 根本收不到这些连接。

落地服务器还能看到我真实的客户端地址吗?

在这两种配置下看不到。落地服务器看到的都是中转地址,所以它上面按客户端地址做的限制和日志都会失去这部分信息。

GOST 的 UDP 转发适合 QUIC 类代理吗?

可以,前提是 UDP 监听器能让通道保持打开。把 keepAlive 设为 true,并设置合适的 ttl,然后确认长时间会话经过中转后不会中断。

中转能让慢的落地服务器变快吗?

单靠中转不行。它可以改变客户端到达入口的线路,但吞吐量仍然受落地服务器的带宽、处理器负载和网络拥塞限制,需要分别排查。

怎样移除中转又不破坏其它防火墙规则?

只删除 relay_nat 表、GOST 服务和你自己添加的那几条放行规则。不要清空整个规则集,否则其它工具管理的规则也会一起消失。

免责声明: 本文仅供一般信息参考,不构成法律、技术或其他专业建议。我们不保证内容的准确性、完整性或时效性。

来源:

  1. nftables wiki: Performing Network Address Translation (NAT) — https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)
  2. GOST: Port forwarding — https://gost.run/en/tutorials/port-forwarding/
  3. Linux kernel documentation: IP sysctl — https://docs.kernel.org/networking/ip-sysctl.html
  4. nftables wiki: Configuring chains — https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains
  5. GOST release v3.3.0 — https://github.com/go-gost/gost/releases/tag/v3.3.0
  6. GOST: Command line reference — https://gost.run/en/reference/configuration/cmd/

Sources checked 2026 年 10 月 14 日。

延伸阅读:

开启 3 天免费试用

注册即可免费体验全部高级功能。

*仅限新用户;每位用户只能获得一次试用。

VPS 中转搭建:nftables DNAT 与 GOST 端口转发 | AethoVPN