拿到的 CentOS 7 服务器,部署完项目,端口在服务器本机明明通着,外部就是访问不了。排查了半天,结果发现是防火墙规则压根没放行。这个场景我猜很多运维和开发朋友都经历过,尤其是第一次接触 CentOS 7 的时候,总是绕不开“防火墙”和“服务器端口”这对组合。
这篇文章我不想只丢给你几条命令,而是把 CentOS 7 上防火墙运行的底层机制、安装过程、项目端口开放的各种姿势,以及“端口放行了却依然不通”这类高发问题的完整排查链路一次性讲清楚。无论你是刚接手服务器的新手,还是已经踩过几个坑的进阶用户,照着这篇文章的思路走一遍,应该能省下不少排查时间。
1. CentOS 7 防火墙机制拆解:firewalld 是怎么拦端口的
1.1 搞清楚 firewalld 和 iptables 的关系
排查端口问题前,先把底层机制想明白。CentOS 6 及更早版本,系统自带的是 iptables 服务,规则直接写在 /etc/sysconfig/iptables 里,改完需要重启 iptables 服务才能生效。到了 CentOS 7,默认的管理工具换成了 firewalld,它本身并不是一个全新的包过滤引擎,底层依然走内核的 netfilter 框架,只是用一套更友好的配置方式,把规则加工成 iptables 规则并加载进内核。
可以这样理解:netfilter 是真正干活的检查员,firewalld 是站在门口的经理,负责接收你“放行 8080 端口”的指令,转化成检查员能执行的标准名单。
所以有一个很常见的误区:你执行 iptables -L 看一眼,发现规则链里空空的,就判断“防火墙没拦”,然后跑去查代码、查网络,折腾一圈无果,最后发现真正的拦截逻辑在 firewalld 的规则层。反过来,你用 firewall-cmd --list-all 看到的规则,也不等于 iptables -L 里全部的内容,因为 firewalld 会把规则拆成多个自定义链,比如 IN_public_allow,只有顺着链往下看才看得到全貌。排查的时候,两者要结合起来看。
1.2 zone 区域:一套规则对应一种信任级别
firewalld 引入了“区域”这个概念,这也是很多人刚接触时不理解的地方。你可以把区域理解成一套针对不同网络环境的策略模板,每张网卡会被划分到某个区域下。默认区域是 public,它的特点非常鲜明:出站流量全部放行,入站流量默认拒绝,只有你显式放行的端口或服务才允许进入。
也就是说,当你的项目监听 8080 端口,而你没有在 public 区域里放行 8080,那么外部客户端发送到服务器的数据包,在内核 netfilter 层就被直接丢弃了。服务器本机访问 127.0.0.1:8080,流量走的是回环接口,不经过同一套入站过滤规则,所以本机能连通、外部连不上的现象就出现了。这是整个 CentOS 7 防火墙机制里最基础也最需要理解的一点。
除了 public,常用的还有 trusted(放行所有流量)、internal(内部网络使用)、dmz(隔离区)、drop(丢弃所有入站流量)等。不过对大多数云服务器场景来说,我们只需要和 public 打交道就够了。
1.3 服务、端口和协议:别把三个概念混在一起
firewalld 放行有“服务”和“端口”两种表达方式,它们的底层本质是一样的。按端口放行时,你要指定协议和端口号,比如 8080/tcp;按服务放行时,你用的是一个服务名,比如 http,firewalld 会自动把它翻译成对应的一组端口和协议。
这套服务名映射关系定义在 /usr/lib/firewalld/services/ 目录下的 XML 文件里。你可以打开 http.xml 看一下,里面就写明了端口 80 和协议 tcp。这么设计的好处是语义化,你不需要去记 80 是什么端口、443 是什么端口,直接说服务名就行。但项目里常见的一些自定义端口,比如 8080、8443、9090,系统并没有内置对应的服务名,所以直接使用 --add-port 更实际。
1.4 运行时规则和永久规则:一次性记住这个“坑”
这是 firewalld 设计里最容易踩坑的地方。规则分两套:运行时规则和永久规则。
- 不加
--permanent参数时,修改只在当前运行中的规则集里生效,不会写入配置文件。执行firewall-cmd --reload或者系统重启,规则就没了。 - 加了
--permanent参数时,规则会写入/etc/firewalld/zones/下的 XML 配置里,但不会立刻加载到当前运行环境。必须执行 reload 或重启 firewalld。
那些“明明加了端口规则,重启服务器后又连不上”的情况,绝大多数就是只加了临时规则,或者只加了永久规则但忘了 reload。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备:在最小化 CentOS 7 上把 firewalld 装好并跑起来
2.1 先确认你的服务器当前状态
很多云厂商提供的基础镜像,尤其是最小化安装镜像,出于精简考虑不一定自带了 firewalld。所以第一步不是急着配规则,而是确认服务状态。
执行 systemctl status firewalld,有几种可能的结果:
- 返回
active (running),说明防火墙已启动,可以直接进行下一步。 - 返回
inactive (dead),说明服务装了但没启动。 - 返回
Unit firewalld.service not found,说明系统里根本没装 firewalld。
还有一种情况容易被忽略:服务器上同时安装了 iptables-services,并且 iptables 服务在运行。这种“新旧两套防火墙并存”的局面在接手历史遗留服务器时特别常见,后面专门讲怎么处理。
2.2 安装、启动并设置开机自启
如果在 CentOS 7 上确认没有安装 firewalld,直接通过 yum 安装:
bash复制yum install -y firewalld
安装完成后,启动服务并设置开机自启:
bash复制systemctl start firewalld
systemctl enable firewalld
enable 这一步相当重要。不少人在测试环境手动 systemctl start firewalld 之后没有 enable,服务器一重启,防火墙规则全部失效,项目端口直接暴露到公网,隐患很大。务必把 enable 养成习惯。
启动完用两条命令确认一下:
bash复制systemctl status firewalld
firewall-cmd --state
firewall-cmd --state 返回 running 才代表服务正常。
2.3 查看默认区域的初始规则
刚启动的 firewalld 会带一些默认规则,比如在 public 区域中放行 ssh 服务。用下面的命令查看:
bash复制firewall-cmd --get-default-zone
firewall-cmd --list-all
--list-all 输出里会显示当前默认区域、挂载在这个区域下的网卡接口、已放行的服务列表和端口列表。建议在改动之前先做一次记录,这样之后能清楚地知道自己加了什么、从哪里开始变的。
3. 实战开放端口:从单端口到多服务场景
3.1 最基础的端口放行流程
假设你有一个 Java 项目,监听 8080 端口,希望对外网开放。完整操作是这样:
bash复制firewall-cmd --zone=public --add-port=8080/tcp
firewall-cmd --zone=public --add-port=8080/tcp --permanent
firewall-cmd --reload
第一行让规则立即生效,第二行将规则写入永久配置,第三行重新加载,让永久配置生效。执行后验证:
bash复制firewall-cmd --zone=public --list-ports
正常会看到 8080/tcp。
这里要特别提醒:协议不能写错。项目是 TCP 服务,你写成 8080/udp,等于没放行。反过来,DNS、DHCP 这类基于 UDP 的服务,只放行 TCP 同样不行。写命令前明确项目到底用的是 TCP 还是 UDP,然后再操作。
3.2 按服务名放行:http、https 更语义化
有些场景下不需要记端口,直接用系统提供的服务名更
