Firewalld 端口转发教程:包含 IPv4/IPv6 双栈端口转发

在日常运维或配置服务器(如阿里云、腾讯云等厂商的 VPS)时,我们经常需要将本机的某个端口流量代理到外部的另一台服务器上。firewalld 作为 Linux 内核层面的防火墙工具,不仅可以轻松管理放行、关闭端口,还能极其高效地实现端口转发(端口映射)。
为了让大家更直观地理解,以下是 Firewalld 端口转发的底层逻辑图:
本教程将基于 Debian/Ubuntu 全面讲解如何使用 firewall-cmd 命令配置 IPv4 和 IPv6 的端口转发。
1. 开启内核 IP 转发
无论是做 NAT 还是端口转发,开启系统的 IP 转发功能是第一步。
临时转发:
sudo sysctl -w net.ipv4.ip_forward=1让配置永久生效:
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p2. 安装并启动 firewalld
在部分 Mini 版镜像(如 Debian/Ubuntu 最小安装版)中,系统默认是不带 firewalld 的。我们需要手动安装并确保它正在运行:
sudo apt update -y
sudo apt install firewalld -y
# 启动并设置开机自启
sudo systemctl enable --now firewalld3. 添加 firewalld 端口转发规则
假设我们需要将本机 10001 端口的流量,映射转发至目标机器 158.178.231.249:30553。你可以分别添加 TCP 和 UDP 的转发规则:
# 添加端口转发规则:本机 60001 → 158.178.231.249:30553
# 添加 TCP 端口转发规则
sudo firewall-cmd --permanent --add-forward-port=port=10001:proto=tcp:toaddr=158.178.231.249:toport=30553
# 添加 UDP 端口转发规则
sudo firewall-cmd --permanent --add-forward-port=port=10001:proto=udp:toaddr=158.178.231.249:toport=305534. 启用伪装(masquerading)
⚠️ 重点: firewalld 端口转发必须开启 NAT 伪装!这一步决定了你的数据包能否成功被转发出去。如果你发现端口转发不生效,多半是因为漏掉了这一步。
sudo firewall-cmd --permanent --add-masquerade5. 开放本机入站端口(放行端口)
在第 3 步中,我们将本机的 10001 端口作为入口,这意味着外部必须要能访问本机的 10001 端口。因此,我们需要在防火墙中将其放行:
# 放行 TCP 10001 端口
sudo firewall-cmd --permanent --add-port=10001/tcp
# 放行 UDP 10001 端口
sudo firewall-cmd --permanent --add-port=10001/udp6. 重载生效与查看开放端口
每次修改 --permanent(永久生效)的规则后,都需要重新加载 firewalld。
sudo firewall-cmd --reload验证与查看端口状态:
# 查看当前 firewalld 放行的端口与所有规则
sudo firewall-cmd --list-all
# 深入查看底层的 NAT 转发规则
sudo iptables -t nat -L -n -v7. 删除 firewalld 端口与转发规则
当我们不再需要这项服务,或者需要更换 IP 时,可以通过以下命令安全地清理规则:
# 关闭/删除 10001 端口放行
sudo firewall-cmd --permanent --remove-port=10001/tcp
sudo firewall-cmd --permanent --remove-port=10001/udp
# 删除 TCP 转发规则
sudo firewall-cmd --permanent --remove-forward-port=port=10001:proto=tcp:toaddr=158.178.231.249:toport=30553
# 删除 UDP 转发规则
sudo firewall-cmd --permanent --remove-forward-port=port=10001:proto=udp:toaddr=158.178.231.249:toport=30553
# 重新加载生效
sudo firewall-cmd --reload8. 进阶:IPv6 下的 firewalld 端口转发
以上是标准的 IPv4 转发流程。
随着 IPv6 的普及,很多场景也需要用到 IPv6 转发。
注意:IPv6 的规则配置必须使用 firewalld 的富文本规则(rich-rule),否则默认作为 IPv4 处理。
8.1 开启 IPv6 内核转发
sudo sysctl -w net.ipv6.conf.all.forwarding = 1
echo "net.ipv6.conf.all.forwarding = 1" | sudo tee /etc/sysctl.conf
sudo sysctl --system8.2 开启 IPv6 伪装(Masquerade)
指定 family="ipv6" 开启伪装:
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv6" masquerade'8.3 添加 IPv6 转发规则与放行
这里以将本机 60000 流量转发至 [2603:c024:450f:3066:e654:bdf2:7bf8:3a5c]:33333 为例:
# 转发 TCP 流量
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv6" forward-port port="60000" protocol="tcp" to-port="33333" to-addr="2603:c024:450f:3066:e654:bdf2:7bf8:3a5c"'
# 转发 UDP 流量
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv6" forward-port port="60000" protocol="udp" to-port="33333" to-addr="2603:c024:450f:3066:e654:bdf2:7bf8:3a5c"'
# 重载生效
sudo firewall-cmd --reload8.4 删除 IPv6 转发规则
如需删除,只需将 --add-rich-rule 替换为 --remove-rich-rule 即可:
sudo firewall-cmd --permanent --remove-rich-rule='rule family="ipv6" forward-port port="60000" protocol="tcp" to-port="33333" to-addr="2603:c024:450f:3066:e654:bdf2:7bf8:3a5c"'
sudo firewall-cmd --permanent --remove-rich-rule='rule family="ipv6" masquerade'
sudo firewall-cmd --reload9. 总结与进阶方案
以上就是 firewalld 端口转发的所有常见命令,基本上就能满足绝大多数日常运维需求。firewalld 依靠内核层面转发,性能优秀,而且非常适合应对国内 审查较为严格 的云厂商环境,但 firewalld 也有其局限性。
假设一种场景:我有一台 VPS A(IPv4 + IPv6 双栈)和 VPS B(仅支持 IPv6 入站),但是我本地的网络环境只有 IPv4,无法直接连接 VPS B。这时候仅仅使用防火墙转发配置起来会极其繁琐。
面对这种复杂的跨栈中转需求,强烈推荐阅读我的另一篇进阶教程:👉 Realm 端口转发教程:优雅解决复杂的跨网段与双栈中转。
10. FAQ:firewalld 端口转发不生效常见排查指南
如果你配置完发现无法联通,不要慌,绝大多数情况可以通过以下 4 个问题逐一排查解决:
Q1:我已经添加了转发规则,为什么依然无法连通?
A: 请首先检查 Linux 内核底层的 IP 转发功能是否开启。如果系统本身不允许转发,firewalld 的规则再正确也没用。
- 排查方法:输入
sysctl net.ipv4.ip_forward。 - 解决:如果输出结果不是
1,请回头参考本文的第 1 步开启内核转发。
Q2:规则没问题,内核也开启了,但数据包还是发不出去怎么办?
A: 极有可能是漏掉了开启 IP 伪装(Masquerade)。端口转发本质上依赖 NAT 机制,未开启伪装会导致数据包无法正确修改源地址而出站。
- 排查方法:输入
firewall-cmd --list-all,查看信息中masquerade:后面是否为yes。 - 解决:如果显示为
no,请执行本文的第 4 步开启伪装功能。
Q3:firewalld 里已经放行了入口端口,为什么外网还是访问不到?
A: 如果你的服务器托管在阿里云、腾讯云、AWS 等云厂商,这里有一层容易被忽略的“外部防火墙”。除了在系统内部配置 firewalld 外,你必须登录云服务商的网页控制台。
- 解决:在实例的 安全组(Security Group) 或网络防火墙规则中,手动添加放行对应的入口端口(例如本教程中的
10001端口)。
Q4:如何确认是不是目标服务器本身挂了?
A: 有时候问题根本不在你的转发机器上,而是目标节点的服务没跑起来,或者目标机器封锁了你的 IP。
- 排查方法:在配置转发的这台当前机器上,直接测试目标节点端口是否可达:
curl -v telnet://{转发目标 IP}:{转发目标端口} - 解决:如果提示 Connection timed out 或 Connection refused,说明目标服务器本身有问题,你需要先去排查目标节点。