开启 3 天免费试用
注册即可免费体验全部高级功能。
*仅限新用户;每位用户只能获得一次试用。


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 为前提,描述的是文档中的行为,而不是实测结果。先用自建归属与恢复清单确认每台服务器由谁管理。
当客户端访问某个机房比另一个更稳定,或者你想更换公开入口地址而不重建代理本身时,中转就有用处。它不是第二层加密,也不会对落地服务器隐藏流量;那种需求更接近多跳链路,每一跳运行各自的协议。
转发端口也意味着公开这个端口。开放任何端口之前,先了解入站端口转发会如何暴露服务,并决定允许哪些来源地址。如果落地服务器本身已经很慢或负载过高,中转也救不了:先按自建服务器变慢的排查方法测清楚。如果维护两台服务器、两套防火墙和两套升级计划超出了你的实际需要,加这一跳之前先把这份工作量与托管 VPN 对比一下。
只使用你自己管理的服务器,确保控制台访问不依赖被转发的端口,SSH 主机密钥经过带外核验。不要使用来源不明的一键中转脚本:它们经常整体替换防火墙规则,事后也查不到改了什么。
| 问题 | 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] 本文两种方式都只做直接转发,每个端口只选一种。
示例中,中转的公网网卡是 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 当作所有中转客户端的对端,按客户端地址做的限制和日志将无法区分用户。
内核转发默认关闭(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 的同类规则,而不是另建一张相互冲突的表。
从 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 规则。
复制客户端可用的配置,只把服务器地址改成 198.51.100.10,端口改成 8443(nftables)或 8444(GOST)。TLS 服务器名、REALITY 参数、UUID 和密钥都保持原样。两种方式都不终结 TLS,所以客户端仍然端到端地校验落地服务器的证书或 REALITY 参数。
如果原配置把落地服务器的 IP 地址当作 TLS 名称,经中转后依然可用,因为名称校验针对的是证书,而不是套接字地址。下面的检查全部通过之前,保留直连配置作为备用。
| 检查方法 | 预期现象 | 不符时的处理 |
|---|---|---|
| 通过中转配置向你控制的端点发请求 | 得到预期响应 | 先测直连配置,再查中转的监听和规则 |
在中转上运行 sudo nft list table ip relay_nat | DNAT 与 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 与保存的副本对比。落地服务器上为中转放行的规则最后再删。
不会。两种方式都只转发数据包或数据流,不做解密,也不加新的加密层。加密仍然来自客户端与落地服务器之间运行的代理协议本身。
因为落地服务器会把回包发给客户端的原始地址,而不是发回中转。加上 SNAT 或 masquerade 后,回包才会经过中转的连接跟踪返回客户端。
可以,像本文这样用不同端口即可。不要让两种方式指向同一个中转端口,否则 DNAT 规则会先截走数据包,GOST 根本收不到这些连接。
在这两种配置下看不到。落地服务器看到的都是中转地址,所以它上面按客户端地址做的限制和日志都会失去这部分信息。
可以,前提是 UDP 监听器能让通道保持打开。把 keepAlive 设为 true,并设置合适的 ttl,然后确认长时间会话经过中转后不会中断。
单靠中转不行。它可以改变客户端到达入口的线路,但吞吐量仍然受落地服务器的带宽、处理器负载和网络拥塞限制,需要分别排查。
只删除 relay_nat 表、GOST 服务和你自己添加的那几条放行规则。不要清空整个规则集,否则其它工具管理的规则也会一起消失。
免责声明: 本文仅供一般信息参考,不构成法律、技术或其他专业建议。我们不保证内容的准确性、完整性或时效性。
来源:
Sources checked 2026 年 10 月 14 日。
延伸阅读:
注册即可免费体验全部高级功能。
*仅限新用户;每位用户只能获得一次试用。