场景:当容器或主机访问
xx.xx.xx.xx:5668 / 9100时,自动改写为yy.yy.yy.yy.yy:26880 / 26881。
主机上执行(PREROUTING)
# 新建一个名为 nat 的 IPv4 表;若系统已存在同名表会报错,可用 `nft list tables` 先检查
sudo nft add table ip nat
# 在 ip nat 表下创建基础链 prerouting;用于 NAT,挂载在 prerouting hook(路由前处理进入本机的包),priority -100 是常见优先级
sudo nft add chain ip nat prerouting '{ type nat hook prerouting priority -100; }'
# 规则:当目标 IP=xx.xx.xx.xx 且 TCP 端口=5668 时,做 DNAT,把目标改写为 yy.yy.yy.yy.yy:26880
sudo nft add rule ip nat prerouting ip daddr xx.xx.xx.xx tcp dport 5668 dnat to yy.yy.yy.yy.yy:26880
# 规则:当目标 IP=xx.xx.xx.xx 且 TCP 端口=9100 时,做 DNAT,把目标改写为 yy.yy.yy.yy.yy:26881
sudo nft add rule ip nat prerouting ip daddr xx.xx.xx.xx tcp dport 9100 dnat to yy.yy.yy.yy.yy:26881
# 查看当前 prerouting 链规则,确认是否写入成功(会显示 handle 编号,可用于回滚删除)
sudo nft list chain ip nat prerouting
(可选)容器内做出站透明代理(OUTPUT)
# 仅在容器内部执行;容器需要具备 CAP_NET_ADMIN
sudo nft add table ip nat
# 在 ip nat 表下创建 output 链;用于 NAT,挂载在 output hook(处理容器自己发出的包),priority -100 常见
sudo nft add chain ip nat output '{ type nat hook output priority -100; }'
# 规则:容器内发向 xx.xx.xx.xx:5668 的连接,DNAT 到 yy.yy.yy.yy.yy:26880
sudo nft add rule ip nat output ip daddr xx.xx.xx.xx tcp dport 5668 dnat to yy.yy.yy.yy.yy:26880
# 规则:容器内发向 xx.xx.xx.xx:9100 的连接,DNAT 到 yy.yy.yy.yy.yy:26881
sudo nft add rule ip nat output ip daddr xx.xx.xx.xx tcp dport 9100 dnat to yy.yy.yy.yy.yy:26881
# 查看当前 output 链规则,确认是否写入成功
sudo nft list chain ip nat output
PREROUTING vs OUTPUT 对比表
| 场景 | 使用链 | 生效时机 | 适用对象 | 典型用途 |
|---|---|---|---|---|
| 主机 / 宿主机执行 | prerouting | 路由前处理进入主机的数据包 | 外部请求、容器出网经过主机转发的流量 | 拦截发往特定 IP:PORT 的连接并转发到代理 |
| 容器内执行 | output | 容器自己发出的数据包刚产生时 | 容器内进程主动发起的连接 | 在容器内部“透明代理”出站连接 |
PREROUTING是“从外面拦截”,不跨命名空间、不要容器权限、不依赖容器DNS;OUTPUT是“从里面改写”,容易踩权限/命名空间/DNS的坑,更容易出问题。