Linux服务器 上 firewalld 端口转发不生效的解决方案
问题描述
在 AWS EC2 服务器上使用 firewalld 配置端口转发时,遇到了一个令人困惑的问题:
- 需求:将本机 5001 端口的流量转发到另一台服务器 1.2.3.4 的 5001 端口
- 现象:从外部 telnet 到 EC2 的 5001 端口失败,但直接 telnet 目标服务器 1.2.3.4:5001 是通的
- 配置:firewalld 的规则看起来完全正确,端口也已开放,masquerade 也已启用
排查过程
1. 检查 firewalld 配置
首先检查 firewalld 的配置,发现一切看起来都很正常:
$ sudo firewall-cmd --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: eth0
sources:
services: dhcpv6-client mdns ssh
ports: 80/tcp 443/tcp 22/tcp 55555/tcp 5001/tcp
protocols:
forward: yes
masquerade: yes # ✅ masquerade 已启用
forward-ports:
port=5001:proto=tcp:toport=5001:toaddr=1.2.3.4 # ✅ 转发规则存在
source-ports:
icmp-blocks:
rich rules:
配置看起来完美:
- ✅ 5001 端口已开放
- ✅ masquerade 已启用
- ✅ 端口转发规则已配置
2. 发现关键问题
但是当检查实际的 iptables NAT 规则时,发现了问题所在:
$ sudo iptables -t nat -L -n -v
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
NAT 表是完全空的! 这说明 firewalld 的规则根本没有被应用到 iptables 中。
3. 根本原因分析
在较新的 Linux 系统(如 Amazon Linux 2023、RHEL 9、Rocky Linux 9 等)中,firewalld 默认使用 nftables 作为后端,而不是传统的 iptables。
虽然 nftables 是新一代的包过滤框架,但在某些场景下(特别是涉及 NAT 和端口转发时)可能存在兼容性问题,导致规则无法正确生效。
解决方案
核心:切换 firewalld 后端为 iptables
1. 修改 firewalld 配置文件
# 编辑配置文件
sudo vi /etc/firewalld/firewalld.conf
# 找到 FirewallBackend 这一行,修改为:
FirewallBackend=iptables
或者使用命令直接修改:
# 方法一:sed 替换
sudo sed -i 's/^FirewallBackend=.*/FirewallBackend=iptables/' /etc/firewalld/firewalld.conf
# 方法二:如果该配置项不存在,直接添加
echo "FirewallBackend=iptables" | sudo tee -a /etc/firewalld/firewalld.conf
2. 重启 firewalld 服务
sudo systemctl restart firewalld
3. 验证规则是否生效
重启后再次检查 iptables NAT 表:
sudo iptables -t nat -L -n -v
现在应该能看到完整的 NAT 规则了:
Chain PRE_public_allow (1 references)
pkts bytes target prot opt in out source destination
1 60 DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:5001 to:1.2.3.4:5001
Chain POST_public_allow (1 references)
pkts bytes target prot opt in out source destination
14 888 MASQUERADE all -- * !lo 0.0.0.0/0 0.0.0.0/0
完整配置步骤
如果你从头开始配置,以下是完整的步骤:
1. 切换 firewalld 后端(关键步骤)
# 修改配置
sudo sed -i 's/^FirewallBackend=.*/FirewallBackend=iptables/' /etc/firewalld/firewalld.conf
# 如果配置项不存在,添加它
sudo grep -q "FirewallBackend" /etc/firewalld/firewalld.conf || echo "FirewallBackend=iptables" | sudo tee -a /etc/firewalld/firewalld.conf
# 重启 firewalld
sudo systemctl restart firewalld
2. 配置端口转发
# 启用 masquerade(NAT 地址伪装)
sudo firewall-cmd --permanent --add-masquerade
# 添加端口转发规则
sudo firewall-cmd --permanent --add-forward-port=port=5001:proto=tcp:toaddr=1.2.3.4:toport=5001
# 开放端口(允许外部访问)
sudo firewall-cmd --permanent --add-port=5001/tcp
# 重载配置
sudo firewall-cmd --reload
3. 启用 IP 转发
# 检查当前状态
cat /proc/sys/net/ipv4/ip_forward
# 如果返回 0,需要启用
sudo sysctl -w net.ipv4.ip_forward=1
# 永久生效
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
4. 配置 AWS 安全组
别忘了在 AWS 控制台配置安全组:
-
源服务器(13.229.229.33)安全组:
- 入站规则:允许 TCP 5001 端口(来源:0.0.0.0/0 或特定 IP)
-
目标服务器(1.2.3.4)安全组:
- 入站规则:允许 TCP 5001 端口(来源:13.229.229.33/32 或 0.0.0.0/0)
5. 验证配置
# 查看 firewalld 规则
sudo firewall-cmd --list-all
# 查看 iptables NAT 规则
sudo iptables -t nat -L -n -v
# 查看 IP 转发状态
cat /proc/sys/net/ipv4/ip_forward
# 测试端口转发
telnet 你的服务器IP 5001
常见错误提示及含义
在测试过程中,你可能会遇到不同的错误提示,它们代表不同的问题:
| 错误提示 | 含义 | 可能原因 |
|---|---|---|
Connection timed out |
请求被丢弃,无响应 | 防火墙阻止、安全组未配置、服务未监听 |
Connection refused |
端口可达但拒绝连接 | 端口未开放、服务未运行 |
No route to host |
网络不可达 | 目标服务器防火墙拒绝、路由问题 |
为什么 nftables 会有问题?
nftables 是 Linux 的新一代包过滤框架,相比 iptables 有很多优势:
- 更好的性能
- 更简洁的语法
- 更灵活的规则处理
但是,在某些情况下,nftables 可能存在以下问题:
- 兼容性问题:某些内核版本或系统配置下,nftables 的 NAT 功能可能不稳定
- 工具链问题:部分旧的网络工具或脚本只支持 iptables
- 调试困难:nftables 的规则检查和调试不如 iptables 直观
因此,对于需要稳定的端口转发功能的场景,使用 iptables 后端是更保险的选择。
总结
在 AWS EC2 上配置 firewalld 端口转发时,如果规则看起来正确但不生效,关键是检查并切换 firewalld 的后端为 iptables:
# 核心命令
sudo sed -i 's/^FirewallBackend=.*/FirewallBackend=iptables/' /etc/firewalld/firewalld.conf
sudo systemctl restart firewalld
然后通过 iptables -t nat -L -n -v 验证规则是否真正生效。
这个问题在较新的 Linux 发行版上比较常见,希望这篇文章能帮助遇到类似问题的朋友快速解决!
文章评论