起因

Web 服务在本机已经跑起来、curl 127.0.0.1 也通,可外网就是打不开——十有八九是防火墙把 80/443 拦了。CentOS 7 这一层默认由 firewalld 把守,它和老的 iptables 命令体系完全不同,照搬 CentOS 6 的教程(service iptables save 之类)只会一头雾水。

需求

  • 开放 80、443 端口给外网访问
  • 规则重启后不丢,同时能查询、能撤销

技术实现原理

firewalld 与 zone

firewalld 是 CentOS 7 的默认防火墙前端,底层还是内核的 netfilter。它引入的核心概念是 zone(区域):规则按“网络环境的信任程度”分组,每块网卡归入一个 zone,默认是 public(公共区,默认几乎全关)。--zone=public 的意思就是“这条规则对 public 区里的网卡生效”——VPS 上一般只有一块网卡,跟着默认写 public 即可。

–permanent 的双配置设计(本篇命令的关键)

firewalld 同时维护两套规则:

  • 运行时(runtime):不加 –permanent 改的是它,立即生效,但重启后回到配置文件里的样子;
  • 永久(persistent):加 –permanent 改的是它,写进磁盘、重启后加载,但当下不生效

这就是新手最常见的疑惑根源:加了 –permanent “怎么没反应”?因为它压根没碰运行时规则。所以完整的一次变更是两步:先 --add-port ... --permanent 写入永久配置,再 --reload 把永久配置整体加载进运行时。不加 –permanent 的规则适合临时试验,重启自动消失。

一查看系统防火墙状态

1
firewall-cmd --state

如果返回 running 代表防火墙启动正常;返回 not running 就先用文末“四基本操作”里的 systemctl start 把服务拉起来,防火墙没跑,规则自然一条都不生效。

二开启端口外网访问

添加端口

返回 success 代表成功

–permanent 永久生效,没有此参数重启后失效;但加了它之后规则只写进了永久配置、当前运行时还没生效,必须配合下面的“重新载入”加载一次——这正是上面说的双配置设计。

1
2
firewall-cmd --zone=public --add-port=80/tcp --permanent
firewall-cmd --zone=public --add-port=443/tcp --permanent

开放多个端口

1
firewall-cmd --zone=public --add-port=80-85/tcp --permanent

重新载入

返回 success 代表成功

1
firewall-cmd --reload

查看

返回 yes 代表开启成功

1
firewall-cmd --zone=public --query-port=80/tcp

三关闭端口

删除端口

返回 success 代表成功

1
firewall-cmd --zone=public --remove-port=80/tcp --permanent

重新载入

返回 success 代表成功

1
firewall-cmd --reload

四基本操作

这一节是两层命令的分工:systemctl 管 firewalld 这个服务本身(起不起、开机起不起),firewall-cmd 管防火墙里的规则。规则加不进去时,先确认服务在跑(一的那条 –state)。

启动服务:

1
systemctl start firewalld.service

关闭服务:

1
systemctl stop firewalld.service

重启服务:

1
systemctl restart firewalld.service

显示服务的状态:

1
systemctl status firewalld.service

开机自动启动:

1
systemctl enable firewalld.service

禁用开机自动启动:

1
systemctl disable firewalld.service

查看版本:

1
firewall-cmd --version

查看帮助:

1
firewall-cmd --help

显示状态:

1
firewall-cmd --state

查看所有打开的端口:

1
firewall-cmd --zone=public --list-ports

更新防火墙规则:

1
firewall-cmd --reload

查看区域信息:

1
firewall-cmd --get-active-zones

查看指定接口所属区域:

1
firewall-cmd --get-zone-of-interface=eth0

拒绝所有包:

1
firewall-cmd --panic-on

取消拒绝状态:

1
firewall-cmd --panic-off

查看是否拒绝:

1
firewall-cmd --query-panic

踩坑记录与注意事项

  • 加了 –permanent 却“没生效”:不是失败,是还没加载——永久配置要 –reload 才进运行时(根因见上文的“双配置设计”)。反过来,没加 –permanent 的规则重启就丢,别拿它当正式配置;
  • 云服务器还有第二道门:阿里云/腾讯云等 VPS 在系统之外还有“安全组”,firewalld 全开还是不通时,去控制台看安全组有没有放行 80/443——很多“防火墙明明开了”的疑惑其实卡在这一层;
  • 端口开了 ≠ 服务在听:用 ss -tlnp | grep :80 确认有进程监听在 0.0.0.0:80 而不是 127.0.0.1:80,后者只有本机能访问;
  • query-port 返回 yes/no 不是 success:查询类命令的返回值是判断结果,别当成操作成败;
  • –panic-on 是紧急开关:一键断掉所有网络包,只在怀疑被入侵时用,用完记得 –panic-off;
  • 版本要对上:firewalld 是 CentOS 7 / RHEL 7 以后的体系,CentOS 6 及更早用 iptables 命令,两套不通用。