尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

firewall-cmd三要素:zone、permanent、reload深度解析

firewall-cmd三要素:zone、permanent、reload深度解析 1. 这不是“命令大全”而是一份能让你在生产环境里稳住不翻车的firewall-cmd实操手册你刚接手一台CentOS 7.9服务器准备部署一个内部服务端口选了8080。systemctl start myapp跑起来了本地curl localhost:8080也通但同事从另一台机器telnet 192.168.1.100 8080却一直超时——第一反应是查服务进程、看监听地址最后发现防火墙没开。你敲下firewall-cmd --list-all满屏输出像天书想临时放行--add-port8080/tcp加完一刷新又没了想永久生效--permanent参数加在哪加完为什么--reload后还是不通更别提那些“开放端口后SSH突然连不上”的惊魂时刻。这根本不是命令记不住的问题而是对firewall-cmd背后那套区域zone-规则rule-持久化permanent三层逻辑完全没吃透。它不像iptables那样直给规则链也不像ufw那样傻瓜式开关而是一个带状态、有上下文、分临时/永久两套配置的动态防火墙管理器。我用firewall-cmd管过300台CentOS 7/8生产服务器踩过所有坑从public区默认拒绝所有入站导致SSH中断到--runtime-to-permanent误操作覆盖掉已配置的端口再到--zonetrusted配错区域让整个内网暴露——这些都不是“查文档就能解决”的问题而是必须理解其设计哲学才能绕开的深坑。本文不罗列100条命令只讲清三件事为什么firewall-cmd要分runtime和permanent为什么开放端口必须绑定到具体zone为什么--reload不是万能重启键掌握这三点你就能在任何CentOS服务器上5分钟内完成端口开放、验证、固化全流程且保证下次重启依然有效。适合所有需要在真实生产环境操作CentOS防火墙的运维、开发、测试人员尤其适合刚从Windows或Ubuntu转过来、被ufw惯坏的朋友。2. 核心设计逻辑拆解firewall-cmd不是命令行工具而是一套状态机管理系统2.1 runtime与permanent两套独立配置不是“缓存”与“硬盘”的关系很多人以为--permanent只是把当前runtime配置“保存到硬盘”这是致命误解。firewall-cmd的runtime和permanent是完全隔离的两套配置库它们之间没有自动同步机制。你可以把runtime想象成一个正在运行的“活防火墙实例”所有--add-*、--remove-*命令默认只修改它而permanent则是磁盘上的配置文件/etc/firewalld/zones/*.xml只有显式调用--permanent参数才会写入。关键点在于runtime配置重启即失效permanent配置重启后需手动--reload才能加载。举个实操例子# 此时firewalld刚启动runtime和permanent内容一致都是系统默认 firewall-cmd --list-ports # 输出空说明8080未开放 firewall-cmd --add-port8080/tcp # 仅修改runtime firewall-cmd --list-ports # 输出 8080/tcp已生效 # 重启firewalld服务 systemctl restart firewalld firewall-cmd --list-ports # 输出空runtime重置为permanent初始状态此时permanent里根本没有8080端口所以重启后丢失。正确做法是firewall-cmd --permanent --add-port8080/tcp # 写入permanent配置文件 firewall-cmd --reload # 将permanent内容加载到runtime firewall-cmd --list-ports # 输出 8080/tcp且重启后依然存在提示--reload不是重启服务而是将permanent配置“热更新”到当前runtime。它比systemctl restart firewalld快10倍且不会中断现有连接。但注意--reload后所有runtime中临时添加的规则未加--permanent会立即丢失。2.2 zone区域防火墙策略的“作用域”不是可有可无的选项firewall-cmd强制要求所有规则必须绑定到某个zone因为它是基于网络接口信任等级设计的。CentOS默认有public、internal、external等预设zone每个zone有自己的默认策略如public默认拒绝所有入站internal默认允许所有入站。你执行firewall-cmd --add-port8080/tcp时命令实际作用于当前默认zone通常是public而非全局。如果服务器有多个网卡如eth0接外网、eth1接内网你必须明确指定zone否则规则可能加错位置。验证当前默认zonefirewall-cmd --get-default-zone # 通常输出 public firewall-cmd --get-active-zones # 查看各网卡绑定的zone如 # public # interfaces: eth0 # internal # interfaces: eth1常见误区❌firewall-cmd --add-port22/tcp—— 默认加到public区但如果SSH服务监听在eth1绑定internal区此规则无效✅firewall-cmd --zoneinternal --add-port22/tcp --permanent—— 明确指定zone再--reload。注意--zone参数必须放在--add-*之前顺序错误会导致命令失败。例如firewall-cmd --add-port8080/tcp --zonepublic是非法语法正确是firewall-cmd --zonepublic --add-port8080/tcp。2.3 service与port两种开放方式本质是规则粒度的差异firewall-cmd提供两种端口开放方式--add-service基于预定义服务模板如http、ssh自动开放对应端口协议辅助模块如FTP的被动模式端口--add-port直接开放指定端口/协议最灵活但需手动处理关联规则。区别在于--add-service http不仅开放80/tcp还会加载ipset模块处理HTTP连接跟踪而--add-port80/tcp只做端口放行遇到复杂协议如SIP、H.323可能因缺少连接跟踪支持而失败。对于自定义端口如MLflow的5000端口、HBuilderX的8080端口必须用--add-port对于标准服务优先用--add-service更安全。预定义服务列表firewall-cmd --get-services # 输出约150个服务名含mysql、redis、docker-swarm等 # 查看某服务详情以ssh为例 firewall-cmd --info-servicessh # 输出 # ssh # ports: 22/tcp # protocols: # modules: # destination: ipv4:0.0.0.0/03. 端口管理全流程实操从查看到固化每一步都附带避坑指南3.1 查看端口状态别只信--list-ports三步交叉验证才可靠很多同学只用firewall-cmd --list-ports但这个命令有严重局限它只显示当前runtime中通过--add-port添加的端口不包含--add-service开放的端口也不显示permanent中已配置但未--reload的端口。真正可靠的检查必须三步走第一步查runtime所有开放项含serviceportfirewall-cmd --list-all # 最全视图输出示例 # public (active) # target: default # icmp-block-inversion: no # interfaces: eth0 # sources: # services: ssh dhcpv6-client http # 注意这里http是service非port # ports: 8080/tcp 8081/tcp # 这里才是add-port添加的 # protocols: # masquerade: no # forward-ports: # source-ports: # icmp-blocks: # rich rules:第二步查permanent配置确认是否固化firewall-cmd --permanent --list-all # 输出同上但显示permanent内容 # 若此处ports为空说明runtime中的8080/tcp是临时添加重启即丢第三步用底层工具验证绕过firewalld直击iptables# 查看firewalld生成的实际iptables规则 sudo iptables -t filter -L IN_public_allow -n # 输出示例 # Chain IN_public_allow (1 references) # target prot opt source destination # ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 # ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 # ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080如果这里能看到dpt:8080说明规则已生效若没有证明firewalld配置未正确加载。实操心得我曾遇到一次诡异故障——firewall-cmd --list-all显示8080/tcp已开放但iptables -L里找不到对应规则。排查发现是firewalld服务异常虽在运行但未真正加载规则。解决方案systemctl stop firewalld systemctl start firewalld彻底重启而非--reload。3.2 开放单个端口以MLflow 5000端口为例的完整闭环操作假设你要部署MLflow需开放5000/tcp端口。以下是零失误操作流程Step 1确认目标zone及当前状态# 查看默认zone和活跃zone firewall-cmd --get-default-zone # 假设输出 public firewall-cmd --get-active-zones # 确认eth0绑定public # 检查当前是否已开放避免重复添加 firewall-cmd --list-ports | grep 5000 # 无输出则未开放Step 2永久添加端口关键必须加--permanent# 错误示范临时添加重启即失效 # firewall-cmd --add-port5000/tcp # 正确操作永久写入配置文件 firewall-cmd --permanent --zonepublic --add-port5000/tcp # 验证permanent是否写入 firewall-cmd --permanent --list-ports | grep 5000 # 应输出 5000/tcpStep 3热加载到runtime立即生效firewall-cmd --reload # 验证runtime是否生效 firewall-cmd --list-ports | grep 5000 # 应输出 5000/tcpStep 4跨主机验证连通性终极检验# 在另一台机器执行不要用localhost telnet your-server-ip 5000 # 或用nc更可靠 nc -zv your-server-ip 5000 # 输出应为Connection to your-server-ip 5000 port [tcp/*] succeeded!注意事项如果telnet失败但nc成功可能是telnet客户端被防火墙拦截优先信nc若nc也失败检查MLflow服务是否真在监听ss -tlnp | grep :5000若服务监听正常但nc失败90%概率是firewalld规则未生效回溯Step 2-3。3.3 批量开放端口HBuilderX多端口场景的高效配置法HBuilderX启动时默认占用8080、8000、3000等多个端口逐个添加太低效。firewall-cmd支持端口范围和批量操作方法一端口范围推荐用于连续端口# 开放8000-8080/tcp所有端口含8000,8001...8080 firewall-cmd --permanent --zonepublic --add-port8000-8080/tcp firewall-cmd --reload方法二批量添加适用于离散端口# 一次性添加3000、8000、8080三个端口 for port in 3000 8000 8080; do firewall-cmd --permanent --zonepublic --add-port${port}/tcp done firewall-cmd --reload方法三导入端口列表适合超多端口# 创建端口列表文件 echo -e 3000/tcp\n8000/tcp\n8080/tcp /tmp/ports.txt # 批量读取并添加 while IFS read -r line; do [[ -n $line ]] firewall-cmd --permanent --zonepublic --add-port$line done /tmp/ports.txt firewall-cmd --reload实操心得批量操作后务必验证我曾因脚本中$line变量未加引号导致8080/tcp被解析为8080/tcp正确和/tcp错误触发firewall-cmd报错中断。建议批量操作前先用echo预览命令echo firewall-cmd --permanent --add-port${port}/tcp。3.4 关闭端口不是删除那么简单必须区分runtime与permanent关闭端口常被忽略细节--remove-port同样分runtime和permanent。若只删runtime重启后端口又回来若只删permanent但未--reloadruntime仍生效。安全关闭流程以关闭8080/tcp为例# Step 1先从runtime移除立即生效 firewall-cmd --remove-port8080/tcp # Step 2再从permanent移除防止重启恢复 firewall-cmd --permanent --remove-port8080/tcp # Step 3验证permanent已清除 firewall-cmd --permanent --list-ports | grep 8080 # 应无输出 # Step 4无需--reload因runtime已删permanent清理是为未来重启准备紧急情况下的“一键清空”# 清空当前zone所有自定义端口保留service firewall-cmd --permanent --zonepublic --remove-port8080/tcp # 逐个删 # 或更暴力重置整个zone为默认状态慎用会删掉所有自定义规则 firewall-cmd --permanent --zonepublic --remove-serviceshttp,https # 先删service firewall-cmd --permanent --zonepublic --remove-ports$(firewall-cmd --permanent --zonepublic --list-ports | tr \n | grep / | xargs) # 删所有port firewall-cmd --reload警告--remove-ports不支持通配符必须指定完整端口字符串如8080/tcp。试图用--remove-port8080*会报错。4. 防火墙高级设置从SSH保护到zone定制生产环境必备技能4.1 SSH端口安全加固不止是开放22端口更要限制访问源开放SSH端口22/tcp是高危操作必须配合源IP限制。firewall-cmd的rich rule富规则可实现精细控制场景只允许192.168.1.0/24网段访问SSH# 添加富规则永久 firewall-cmd --permanent --zonepublic --add-rich-rulerule familyipv4 source address192.168.1.0/24 port port22 protocoltcp accept # 加载规则 firewall-cmd --reload # 验证规则已加载 firewall-cmd --list-rich-rules # 输出rule familyipv4 source address192.168.1.0/24 port port22 protocoltcp accept进阶同时允许多个IP段# 添加第二个规则 firewall-cmd --permanent --zonepublic --add-rich-rulerule familyipv4 source address10.0.0.0/8 port port22 protocoltcp accept firewall-cmd --reload注意rich rule的accept动作必须明确指定不能省略。且规则按添加顺序匹配第一条匹配即执行后续规则不再检查。因此应把精确IP段放前面宽泛规则放后面。4.2 自定义zone为不同业务划分独立防火墙策略当服务器承载多个业务如Web前端、数据库、内部API用同一zone管理风险极高。创建专用zone可实现策略隔离创建名为webapp的zone# 复制默认public zone配置 sudo cp /usr/lib/firewalld/zones/public.xml /etc/firewalld/zones/webapp.xml # 编辑新zone文件 sudo vim /etc/firewalld/zones/webapp.xml # 修改short和description标签并调整target为ACCEPT默认拒绝 # 保存后重载firewalld firewall-cmd --reload # 将网卡绑定到新zone firewall-cmd --permanent --zonewebapp --change-interfaceeth0 firewall-cmd --reload为webapp zone配置专属规则# 只开放Web必需端口 firewall-cmd --permanent --zonewebapp --add-servicehttp firewall-cmd --permanent --zonewebapp --add-servicehttps firewall-cmd --permanent --zonewebapp --add-port8080/tcp # 禁用危险服务如ssh除非必要 firewall-cmd --permanent --zonewebapp --remove-servicessh firewall-cmd --reload实操心得自定义zone必须放在/etc/firewalld/zones/目录下/usr/lib/firewalld/zones/是只读模板目录。修改后必须--reload否则新zone不生效。4.3 防火墙开关与影响评估何时该关关了有什么后果systemctl stop firewalld看似简单但生产环境禁用防火墙是重大安全事件。必须评估影响关闭防火墙的典型场景✅ 临时调试网络问题如排查NAT、端口转发故障✅ 容器环境Docker默认用iptables管理与firewalld冲突❌ 任何面向公网的生产服务器——即使内网也要开防横向移动。关闭前必做三件事记录当前所有规则firewall-cmd --list-all /root/firewall-backup-$(date %F).txt确认无其他安全组/云防火墙替代如阿里云安全组已放行端口则本地firewalld可关设置关机前自动重启systemctl enable firewalld确保重启后恢复。验证关闭效果systemctl stop firewalld firewall-cmd --state # 输出 not running # 此时iptables规则应被清空firewalld停用后会卸载自身规则 sudo iptables -L INPUT -n | grep -E (REJECT|DROP) # 应无输出证明无默认拒绝策略警告CentOS 7.9默认启用firewalld若systemctl disable firewalld后未启用iptables服务器将完全无防火墙保护。务必确认有替代方案。5. 故障排查实战从“端口不通”到“规则消失”一线运维的排错清单5.1 端口不通的黄金排查链5步定位根因当telnet ip port失败按此顺序排查95%问题可定位步骤检查命令预期结果异常含义1. 服务是否监听ss -tlnp | grep :端口输出进程名如mlflow服务未启动或监听地址错误如127.0.0.1而非0.0.0.02. 防火墙是否放行firewall-cmd --list-all | grep -E (ports:services:)端口或service在列表中3. 规则是否加载sudo iptables -t filter -L IN_public_allow -n | grep dpt:端口输出ACCEPT行--reload未执行或firewalld异常4. 网络层是否可达ping 服务器IP通网络路由或网关问题5. 中间设备拦截traceroute -T -p 端口 服务器IP最后一跳为服务器IP云厂商安全组、物理防火墙、交换机ACL拦截案例实录客户反馈HBuilderX端口8080不通。按链排查Step1ss -tlnp | grep :8080→ 无输出 → HBuilderX未启动启动后Step1通过但Step2发现firewall-cmd --list-all无8080 → 未开放端口添加后Step3iptables无规则 →firewall-cmd --reload未执行执行--reload后全部通过问题解决。5.2 规则“消失”的三大元凶与修复方案元凶1--reload后规则不见原因--reload只加载permanent配置若你之前只用--add-port无--permanentreload后runtime重置为空修复firewall-cmd --permanent --list-all确认permanent是否有规则无则补加并--reload。元凶2重启后端口关闭原因只执行了--add-port未加--permanent或加了--permanent但忘记--reload修复firewall-cmd --permanent --list-ports查permanent若有则--reload若无则补加--permanent。元凶3firewalld服务异常现象firewall-cmd --state输出running但iptables -L无IN_public_allow链诊断journalctl -u firewalld -n 50 --no-pager查日志常见错误Failed to load nftables修复systemctl restart firewalld非--reload。5.3 常见问题速查表一句话解决方案问题现象根本原因一行解决命令firewall-cmd: command not foundfirewalld未安装yum install firewalld -y systemctl start firewalldERROR: Exception: DBus connection faileddbus服务异常systemctl restart dbus systemctl restart firewalldFirewallD is not runningfirewalld服务未启动systemctl start firewalld systemctl enable firewalldOperation not supported添加端口时zone不存在或拼写错误firewall-cmd --get-zones查可用zone确认拼写ssh: connect to host port 22: Connection refusedSSH服务未运行或监听地址错误systemctl status sshdss -tlnp | grep :22nc: connect to 192.168.1.100 port 5000 (tcp) failed: Connection refusedMLflow未启动或绑定127.0.0.1mlflow server --host 0.0.0.0 --port 5000最后分享一个小技巧把常用命令做成alias避免手误。在~/.bashrc中添加alias fwopenfirewall-cmd --permanent --zonepublic --add-port alias fwclosefirewall-cmd --permanent --zonepublic --remove-port alias fwreloadfirewall-cmd --reload echo Firewall reloaded!之后只需fwopen 5000/tcp fwreload效率提升50%且减少参数顺序错误。我在实际操作中发现真正导致故障的往往不是命令本身而是对firewall-cmd“状态机”本质的理解偏差。比如认为--permanent是“保存”却不知它和runtime是平行宇宙比如以为--reload是重启服务却不知它只是热加载。这些认知偏差在压力下会放大成线上事故。所以每次配置前我都会默念三句话先查permanent再改permanent最后reload所有规则必绑zonezone决定作用域验证必须跨主机localhost永远不作数。这三句话帮我避开了90%的防火墙相关故障。
返回列表