核心是关闭public区域对外暴露,将ssh/mysql等服务移至internal或trusted区域,并用rich rule精确控制来源ip;先理清zone信任等级(public最严、trusted最松),再绑定网卡与区域,最后重载生效。

新手配置 Firewalld 限制系统服务外网访问,核心就两点:关掉默认的 public 区域对外暴露,把需要保护的服务(比如 SSH、MySQL、Redis)从 public 移到内部可信区域(如 internal 或 trusted),再配合 rich rule 精确控制来源 IP 或端口。别直接删规则,先搞清 zone 和 service 的关系。
先搞懂 Firewalld 的区域(zone)逻辑
Firewalld 不是靠“一条条端口放行”来工作的,而是按“区域”管理网络信任等级。默认安装后,网卡通常绑定在 public 区域——它默认只允许 ssh、dhcpv6-client 这类基础服务,但很多用户误以为“没开的服务就安全”,其实只要服务监听在 0.0.0.0(所有地址),且 public zone 允许该服务,外网就能连上。
- public:面向不可信网络,仅开放明确声明的服务,适合外网接口
- internal:面向内网或可信网络,可自定义放行更多服务(如数据库、API)
- trusted:完全信任,所有流量放行(慎用,仅限隔离网段)
查看当前活动区域和网卡绑定:
firewall-cmd --get-active-zones
确认某张网卡(如 eth0)属于哪个 zone:
firewall-cmd --get-zone-of-interface=eth0
把敏感服务从 public 移出,改用 internal 区域
例如你的 MySQL 默认监听 3306,又绑在 public zone,只要没禁用 mysql service,外网就可能连接。正确做法是:
- 停用 public zone 中的 mysql 服务:
firewall-cmd --permanent --remove-service=mysql --zone=public - 将 MySQL 所在服务器的内网网卡(如 eth1)绑定到 internal 区域:
firewall-cmd --permanent --change-interface=eth1 --zone=internal - 在 internal zone 中启用 mysql:
firewall-cmd --permanent --add-service=mysql --zone=internal - 重载生效:
firewall-cmd --reload
这样 MySQL 只响应来自 internal zone 网络(比如 192.168.10.0/24)的请求,外网即使扫到 3306 也连不上。
用 rich rule 做更细粒度的访问控制
如果必须让某个服务(如 SSH)有限度地对外开放,不要直接 --add-service=ssh 到 public,而是用 rich rule 锁定来源 IP:
- 只允许办公 IP(如 203.0.113.45)通过 TCP 22 连 SSH:
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.45" port port="22" protocol="tcp" accept' - 拒绝整个 C 段访问 6379(Redis):
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.0.2.0/24" port port="6379" protocol="tcp" reject' - rich rule 优先级高于普通 service 规则,且支持日志记录(加
log prefix="redis-block"可排查)
验证与日常维护要点
配置完别跳过验证。重点检查三项:
- 用 firewall-cmd --list-all-zones 查每个 zone 开放了哪些服务、端口、rich rule
- 从外网机器执行 telnet your-server-ip 22 或 nc -zv your-server-ip 3306 实测连通性
- 确认服务本身监听地址:运行 ss -tlnp | grep :3306,若显示
0.0.0.0:3306是正常;若显示127.0.0.1:3306,那 firewalld 再怎么配也没用——得先改服务配置(如 MySQL 的bind-address = 0.0.0.0)
每次修改务必加 --permanent,否则重启 firewalld 或系统后失效。临时调试可用不带 --permanent 的命令,但上线前一定要补上并 reload。











