ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Linux防火墙firewalld开放端口详解:从zone到firewall-cmd实践

Linux防火墙firewalld开放端口详解:从zone到firewall-cmd实践 先问一句你上服务器部署应用时是不是也习惯性先执行systemctl stop firewalld把防火墙关了如果是我建议你先停一下手。关防火墙确实能解决端口不通的问题但代价是把你整个服务器暴露在公网里不当冤大头。更工程化的做法是搞清楚 firewalld 的工作方式然后针对性地开放被拦住的端口。这篇就按实际运维的思路把 Linux 下 firewalld 防火墙开放端口的那些事捋一遍。1. 为什么先要理解 firewalld 而不是直接关掉它很多人把 firewalld 当成多余的工具总觉得它对新手不友好、管理规则太绕。实际上把视角切换成一个网络守门人就好理解了系统上有哪些服务、哪些端口需要对外网合法提供服务这个规则集合就是防火墙要维护的核心。firewalld 相比老的 iptables最大改进是引入了动态管理——改规则不用重启防火墙服务对正在跑的线上业务影响极低。firewalld 和 iptables 的关系也常常把人搞晕。firewalld 属于上层管理工具它不是替代 iptables而是把 iptables 的规则封装成更容易理解的 zone 和服务概念底层的包过滤仍然走的是内核的 netfilter 框架而firewall-cmd命令最终也是去读写 netfilter 的规则集。理解了这一层你在看iptables -L -n出现和 firewalld 规则对应的条目时就不会懵了。另一个值得留意的点是firewalld 并不是 CentOS / RHEL 系列专属Rocky Linux、AlmaLinux 乃至 openEuler 这些新一代的国产或社区发行版也默认集成了它。学会这套操作换发行版也不用重新学。所以我建议每个接触 Linux 的运维都不要跳过 firewalld 去直接操作底层 iptables 规则除非你是在做防火墙应用开发否则firewall-cmd基本能覆盖全部日常需求。2. 先把 zone 区域概念搞明白端口开放才不会张冠李戴firewalld 最容易被忽略、却也是最重要的逻辑是 zone区域。可以把它理解为多个不同信任等级的规则集合系统里每个网络接口可以绑定到其中一个 zone而每个 zone 里允许哪些端口是独立维护的。这意味着你在 internal 区域开放了 8080但你的服务器网卡实际绑定的是 public 区域8080 依然不通命令也没报错——这种配置明明对了但就是连不上的情况根源十有八九在 zone 上。默认安装完系统会自动生成一套预置区域常用的几个区域名称默认信任等级适用场景public低外部不可信网络默认只允许 SSH 等极少数服务home / work中相对可信的办公或家庭网络internal中高公司内网dmz中非军事区一般放对外提供服务的机器trusted最高接受所有连接一般不用drop / block最低默认丢弃或拒绝禁止连接要查当前系统各区域默认放行的端口用firewall-cmd --zonepublic --list-all会输出类似这样的结果public (active) target: default icmp-block-inversion: no interfaces: eth0 sources: services: ssh dhcpv6-client ports: protocols: forward: yes masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:注意看interfaces这行eth0 绑定的就是 public 区域所以你开放的端口必须加到 public 上才有效。查看当前默认的 zone 也很有用firewall-cmd --get-default-zone如果系统里有多个网卡比如内网卡和公网卡建议把内网卡放到 internal、公网卡放到 public形成内松外紧的隔离效果。这比单纯改默认区域更贴合生产环境。3. 开放单个端口的完整操作与验证手段下面进入正题也是使用频率最高的操作——开放 TCP/UDP 端口。以一个常见的场景为例你在 CentOS 上部署了一个 Web 服务端口是 8080现在外网访问不了需要把 8080 放出来。3.1 命令最简方式与永久生效一次完整的开放操作包含两条命令firewall-cmd --zonepublic --add-port8080/tcp --permanent firewall-cmd --reload这里解释几个容易踩的坑--permanent表示把规则写入防火墙的持久化配置文件不加这个参数,规则只对当前运行时生效重启或 reload 后会消失。加完--permanent后必须执行firewall-cmd --reload让它立刻生效。有人会问为什么我加了 permanent 再执行一次 reload运行时状态里反而看不到刚才的端口因为 reload 的本质是用持久化配置重新加载你之前没加 permanent 的运行态临时规则会被清零所以要注意统一管理。协议类型tcp不能省略。端口在 Linux 里是有协议类型的TCP 和 UDP 属于不同的协议族规则互不通用。比如 DNS 服务对外提供的是 UDP 53 和 TCP 53需要分别开放像 HTTP 这种纯 TCP 服务只加 tcp 就够了。如果实在不确定用了哪种协议可以两条都加firewall-cmd --zonepublic --add-port8080/tcp --permanent firewall-cmd --zonepublic --add-port8080/udp --permanent firewall-cmd --reload3.2 查看是否生效的正确姿势很多人开放完端口喜欢立刻用netstat -lntp去查发现端口在监听就开始怀疑是不是命令没生效。实际上 netstat 只能告诉你进程是否监听某端口它判断不了防火墙是否拦截入站连接。正确的验证方式是firewall-cmd --zonepublic --query-port8080/tcp返回yes说明规则确实加进去了。然后再从另一台机器去telnet或nc测连通性这一步才能真正验证防火墙是否放行成功nc -vz 服务器IP 8080另一个容易忽视的是端口加进防火墙不代表外网一定通还需要确认监听地址是0.0.0.0而不是127.0.0.1。这是应用层配置问题防火墙经常替应用背锅。用ss -lntp | grep 8080看一下监听地址如果只有 127.0.0.1需要改服务监听配置。3.3 移除端口与批量管理开放端口的管理不只是加规则日常还会遇到撤掉某个端口的情况。移除命令形式很接近firewall-cmd --zonepublic --remove-port8080/tcp --permanent firewall-cmd --reload批量开放一段连续的端口也常见比如一些游戏服务器或 RTP 流媒体服务用的是一段范围firewall-cmd --zonepublic --add-port10000-20000/tcp --permanent firewall-cmd --reload批量移除同理把add-port换成remove-port即可。如果你经常要操作一长串端口可以写进 Shell 脚本循环执行每条命令后建议加串联这样中途报错能及时发现。4. 按服务放行比按端口放行更省心直接在--add-port里指定端口号是完全可控的做法可是当服务多了以后你会发现端口号记不住、容易写错。firewalld 其实内置了一套服务名称映射比如http等价于 80/tcphttps等价于 443/tcpssh等价于 22/tcp。4.1 服务管理的命令族firewall-cmd --zonepublic --add-servicehttp --permanent firewall-cmd --zonepublic --add-servicehttps --permanent firewall-cmd --reload查看系统里所有预置的服务定义firewall-cmd --get-services会输出一长串服务名常见的如mysql、postgresql、smtp、ftp等都已经定义好了不需要自己记端口号。用服务名的好处是如果某天服务改了端口只需要改服务定义文件不用去每个 zone 的规则里逐个改端口。但前提是系统里已有这个服务的定义如果没有还是要回到端口模式自己加。4.2 自定义服务的实现方式有时候系统自带的定义不满足需求比如你用的是自定义端口。firewalld 允许你在/etc/firewalld/services/下创建一个 XML 文件定义自己的服务名称。下面创建一个名为myweb的服务?xml version1.0 encodingutf-8? service shortmyweb/short descriptionCustom web service/description port protocoltcp port8080/ port protocoltcp port8081/ /service然后重启 firewalld 让配置生效systemctl restart firewalld这种方式的优势在管理面上一个服务可以包含多个端口加到一个 zone 时只需要一条命令。你在做批量部署时这种可复用的服务定义能省不少事。5. 端口转发和伪装 IP防火墙的高级玩法除了开放端口firewalld 还承担着流量转发的工作。比如你有多台内网服务器想让外网访问 8081 端口时自动转发到内网另一台机器的 80 端口这个场景不需要改路由靠 firewalld 就能完成。5.1 先把 IP 伪装打开端口转发的前提是开启 IP 伪装masquerade它会通过动态修改数据包源地址来实现 NAPT。开启方式firewall-cmd --zonepublic --add-masquerade --permanent firewall-cmd --reload5.2 配置端口转发规则把本机的 8081 端口的 TCP 流量转发到 192.168.1.100 的 80 端口firewall-cmd --zonepublic --add-forward-portport8081:prototcp:toport80:toaddr192.168.1.100 --permanent firewall-cmd --reload这条命令里每一段都有特定含义别省略任何一个冒号后的参数port8081是本机对外监听的端口prototcp是协议类型toport80是目标端口的最终落点toaddr192.168.1.100是数据包要转给的内网主机的 IP。如果只转发端口不转发到其他 IP也就是同一台机器上的不同端口做映射可以去掉toaddrfirewall-cmd --zonepublic --add-forward-portport8081:prototcp:toport8080 --permanent firewall-cmd --reload这种配置在一些内网渗透测试工具、临时调试反向代理时很有用但生产环境更建议用 nginx 处理反向代理毕竟它比内核端口转发多了 TLS 终止、负载均衡、日志审计这些能力。6. 图形界面与配置文件另外两条可行的路径命令行主流不代表它是唯一选择对于服务器上习惯用 Web 管理面板的人firewall-config 这个图形化工具其实很顺手。它随 firewalld 一起分发但默认不一定安装了需要手动装yum install firewall-config在桌面环境里启动后图形界面把 zone、服务、端口都可视化了。想开放一个端口选中对应的 zone切到 Ports 标签页点击 Add填上协议和端口号就行。这种方式的优势是所见即所得适合不太记命令的运维新手或者需要远程演示的场景。不过图形界面默认连接的也是 firewalld 服务所以要注意 Apply 之后同样需要 Runtime 和 Permanent 的切换逻辑。另一条路径是直接改配置 XML。firewalld 的持久化规则都落在/etc/firewalld/zones/目录下以 XML 形式保存。直接编辑文件比命令行的颗粒度更细适合批量修改。以 public zone 为例vim /etc/firewalld/zones/public.xml把需要放行的端口加进去?xml version1.0 encodingutf-8? zone shortPublic/short descriptionFor use in public areas. You do not trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted./description service namessh/ service namedhcpv6-client/ port port8080 protocoltcp/ /zone改完重启 firewalldsystemctl restart firewalld这种文件方式的坑是手写容易出现格式错误导致 firewalld 启动失败。所以每次改完都建议用firewall-cmd --check-config检查一下 XML 合法性然后再 restart。7. 踩坑记录开放端口后仍然不通的排查链路到这里很多基础问题都能解决了但真实环境永远比教程复杂。开放端口后依然连不上是我被问得最多的一类问题。下面整理一条完整的排查链路按这个顺序走基本能定位 80% 的问题。7.1 第一步检查 ping 通不通判断基础网络先用 ping 测一下服务器 IP如果 ping 不通说明问题很可能不在端口层面而是整个主机网络都不可达。这种情况先查服务器的 IP 配置、网关路由、安全组规则云服务器还要额外看云平台的安全组有没有放行 ICMP。7.2 第二步看防火墙规则到底有没有加上规则已加但状态没生效是最常见的乌龙。先执行firewall-cmd --state确认 firewalld 在运行。然后检查刚才加的端口firewall-cmd --zonepublic --list-ports如果列表里是空的回看 3.1 节讲的检查是否加了--permanent是否执行了--reload。可能你采用的是--add-port加运行时规则又马上执行了--reload结果规则被冲掉这个坑踩的人极多。7.3 第三步确认监听地址区分服务配置与防火墙问题端口规则没问题后看服务端监听ss -lntp | grep 8080重点是看 Local Address 列的 IP 是0.0.0.0、::还是某个具体的内网 IP。如果服务只监听了回环地址那外网怎么都连不上这是服务配置的问题跟防火墙没关系。解决方法是改应用的绑定地址让服务监听在所有接口上。7.4 第四步确认 SELinux 没有二次拦截在开启了 SELinux 的系统上即使防火墙放行了端口SELinux 也可能按策略拦截进程的网络访问。检查方法getenforce如果输出Enforcing再看看有没有相关拒绝日志ausearch -m AVC -ts recent | grep 8080如果是 SELinux 拦截临时放行可以直接用setsebool -P httpd_can_network_connect 1更严谨的做法是给对应的服务端口打上合规的 SELinux 端口标签。这部分容易被新手漏掉实际出错概率还蛮高的。7.5 第五步检查云平台安全组和上层设备的 ACL现在不少服务器跑在云上实例本身的 firewalld 只是最后一道防线。云平台的控制台里还有安全组规则它是在虚拟机外部生效的。很多人在 Linux 里把 8080 端口加完了却忘了在安全组里放行。这种问题在命令行层面永远查不出结果需要你登录云控制台核对安全组配置。同理机房内部如果还有硬件防火墙或交换机 ACL 拦截也要一起检查。8. 几条务实建议把防火墙规则管理做得更稳操作层面讲完最后聊点习惯问题。这些东西不是命令能替代的但实战中直接影响你的安全姿态和排障效率。第一线上服务器不要轻易用systemctl stop firewalld来图省事透传所有端口这种方案等于把门打开却不设防。万一被扫到高危端口后患无穷。换成按需放行指定端口配置工作量小安全性却高一个量级。第二规则变更记得加注释。firewalld 原生命令并不支持给规则加备注朴素的解法是在/etc/firewalld/zones/下改 XML 时利用 XML 的注释节点!-- 这里写注释 --把这一条端口是给什么服务用的、谁申请的这些信息记录下来。临时规则也可以通过脚本文件维护在脚本开头写清楚用途。第三定期清点开放端口。一个服务下线了端口却还敞开着是最容易被忽略的安全隐患。建议每季度用firewall-cmd --list-all-zones把当前所有 zone 的规则拉出来做一次复核把不用了的端口全部清理掉。第四把端口开放操作做成脚本模板跟配置管理工具结合。举个例子用 Ansible 管理多台服务器时可以把开放 8080/tcp、443/tcp的 task 固化到 playbook 里实现批量、幂等操作。底层命令还是上面那些但通过配置文件管理规则的可审计性比手动执行命令好得多。实测下来firewalld 的稳定性和规则可靠性都不错踩坑大多是在理解 zone 模型、runtime 与 permanent 的差异、以及和上层防火墙配合这几块。把这几个关键点掌握住Linux 下的防火墙管理基本就不会再让人挠头了。
返回列表