Linux防火墙配置详解:iptables与firewalld实战及避坑指南

📅 发布时间:2026/10/11 14:21:09
Linux防火墙配置详解:iptables与firewalld实战及避坑指南
说句实话Linux防火墙的配置看起来是个老话题但每年依旧能拦下一大批人。不是因为它有多难而是大部分人第一次上手就被“表、链、规则”这些术语搞懵了或者刚配置完发现规则没生效重启一下机器规则又全没了。这篇文章我就把自己在实际操作里碰过壁、后来又琢磨明白的东西重新梳理一遍从原理到命令从iptables到firewalld尽量讲得接地气一点让你看完能直接上手配规则而不是只知道复制粘贴。这篇文章适合刚接触Linux服务器管理的同学也适合那些已经配过几条规则但一直“知其然不知其所以然”的朋友。我会把核心概念、常用命令、常见坑一次说清楚涉及的命令我都会标注场景方便你直接照着用。1. 选iptables还是firewalld先弄明白两者的关系很多人会问Linux防火墙到底用iptables还是firewalld其实这个问法本身就有点问题。iptables和firewalld不是同一个层面的东西firewalld只是一个管理工具它底层真正干活的时候调用的还是iptables相关的内核机制只是在规则表达和交互方式上替你做了不少封装和转换。1.1 先搞懂netfilter和iptables的关系Linux内核里的网络报文过滤框架叫netfilter它定义了一系列钩子点数据包在协议栈中走到这些位置的时候就会停下来被检查。而iptables这个用户态工具就负责往钩子点上的规则表里添加、删除、修改规则。规则的载体本质上是内核里的一张表表里挂着若干链链上按照顺序排列着一堆规则。你用iptables命令加一条规则内核里的netfilter就会立刻感知并且从这一刻起所有经过该链的数据包都要按顺序跟这条规则做匹配。这就是为什么iptables刚配完就能立刻生效不用重启服务也不需要重新加载配置文件这一点和很多改完配置需要重载的应用差别很大。1.2 firewalld的定位和优势firewalld是很多发行版默认预装的防火墙管理方案它引入了区域zone的概念。所谓区域本质上就是一组预先定义的信任级别。比如说内网网卡信任级别高一点可以少拦截点东西外网网卡信任级别低那就多拦一点。你把网卡绑定到某个区域再往区域里添加服务或端口规则firewalld会自动把它们翻译成底层规则。它的优势是动态管理配置完不需要重启服务修改即时生效而且在做永久配置的时候会自动帮你把规则拆成“当前运行时”和“持久化配置”两套状态。这一点看起来不起眼实际运维的时候特别重要因为iptables如果不手动保存重启机器规则就全丢了而firewalld有这个机制兜底能省不少心。不过firewalld不是所有场景都合适比如你要做复杂的策略路由、精细到某个特定网段的NAT转换firewalld能配但表达起来很绕。这种场景我通常还是会回到iptables或者直接用nftables规则写在脚本里一眼能看清楚整个链路。维度iptablesfirewalld底层机制直接操作netfilter间接调用netfilter配置方式命令行逐条操作区域和服务管理实时生效立即生效立即生效持久化需手动保存自动维护可分别配置运行时与永久灵活度高适合复杂规则中规中矩适合常规场景适用人群习惯命令行、折腾过运维的人新手友好习惯了直接开服务我不建议你把两者对立起来更常见的做法是日常管理用firewalld遇到复杂转发需求再用iptables补充。只要别搞得规则交叉混乱两者共存没问题。下面的内容我会分两条线讲你可以按自己的环境选择看哪部分。2. iptables基础配置实操如果说firewalld是自动挡iptables就是手动挡。手动挡一旦熟练你能精准控制数据包的去向而且诊断问题的时候特别直白。先把底层的表和链弄明白这个是很重要的基础。2.1 一张图拆解表、链、规则的关系数据包在Linux内核中经过的路径是固定的一个数据包如果发往本机会经过PREROUTING、INPUT这样的链路如果是本机发出的数据包走OUTPUT链如果需要转发走FORWARD链。我们平时配防火墙规则主要集中在filter表的INPUT链和OUTPUT链上做NAT时才涉及nat表的PREROUTING、POSTROUTING链。你可以把整个流程想象成进一栋大楼POSTROUTING是楼外围的检查口PREROUTING是进楼前的门禁INPUT是你进房间前的最后一道门OUTPUT是出门的通道FORWARD则是从这栋楼的A区走到B区的走廊。每条链上有若干保安规则按顺序站在那儿数据包过来就一个个匹配。filter表和nat表是最常用的两张表另外还有mangle表用于修改数据包头部字段raw表用于跳过状态跟踪平时不太会直接碰。对于基础配置你只需要记住filter管过滤nat管地址转换然后在这两张表的对应链里添加规则即可。注意iptables规则的顺序非常重要。规则是从上往下逐条匹配的一旦命中就会执行相应的动作ACCEPT或DROP后面的规则就不再看了。所以添加规则的时候要先把严格匹配的规则放在前面宽泛的规则放后面否则会出现“明明加了放行规则但请求还是被拦”的怪现象。2.2 查看当前规则的几种姿势配置之前先看现状这是基本功。直接用iptables -L能看到当前所有规则但默认情况下它不解析IP为域名显示效果比较朴素。我更推荐加几个参数再看iptables -L -n -v --line-numbers这里简单拆解一下-n不解析域名显示纯IP地址速度快也不至于被DNS干扰-v显示更详细的信息包括每个接口收到的包量pkts和字节数bytes--line-numbers给每条规则加上序号调试和修改的时候能定位到具体哪一行。第一次执行这条命令你会发现服务器上默认只有几条INPUT和FORWARD链的规则很多发行版初始策略都是ACCEPT等于防火墙没有拦截任何东西。看清楚这个初始状态后续加规则心里就有底了。2.3 一条条规则手把手配置假设我的服务器IP是192.168.1.100我想实现的效果是任何人都能访问80和443端口但是SSH端口只允许内网192.168.1.0/24网段访问其他一切进来的陌生人流量都丢弃。这个场景非常典型配置起来也不复杂。先把默认策略设成DROP注意这里说的是INPUT链的默认策略代表所有不匹配任何放行规则的包都被丢弃。iptables -P INPUT DROP然后放行回环接口和已建立连接。回环接口就是lo它是本机通信的专用通道如果把它拦了很多程序会表现异常。已建立连接的状态是ESTABLISHED、RELATED这种状态必须放行否则TCP连接起来之后回包全部被拦这会导致你网页半天打不开。iptables -A INPUT -i lo -j ACCEPT iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT接着开放HTTP和HTTPS端口iptables -A INPUT -p tcp --dport 80 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -j ACCEPTSSH端口只对内网开放iptables -A INPUT -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT到这里INPUT链上的放行规则就配完了默认策略已经是DROP所以其他不在规则里的流量都会被丢弃。注意一下顺序放行规则一定加在默认策略之前这是常识但经常会有人把规则追加到默认策略之后导致规则永远不会匹配到。把规则配置完只是第一步真正的问题在重启之后。iptables规则默认只保存在内存里机器重启就没了所以你必须保存。保存命令很简单iptables-save /etc/sysconfig/iptables不同的发行版路径可能不同有的在/etc/iptables/rules.v4有的是/etc/sysconfig/iptables你可以根据自己的系统调整。恢复的时候用iptables-restore 配置文件即可。2.4 删除和插入规则的几个细节配置过程中如果发现规则写错了需要删除或者插入新规则。删除特定规则除了按内容匹配最常见的是用行号删除这个操作之所以常用是因为内容匹配删除容易误删相同的规则。iptables -D INPUT -p tcp --dport 80 -j ACCEPT这种方式是直接把规则内容写一遍再挂一个-D参数适合你已经知道确切规则内容的情况。如果你记不清具体内容也可以先看行号再删iptables -L INPUT -n --line-numbers iptables -D INPUT 3这会把INPUT链上的第3条规则删掉。要特别提醒的是删除规则后用iptables -L确认一下别删错行把重要规则弄没了。插入规则用-I参数默认插到第1行。比如我想把一条拒绝某个恶意IP的新规则放在最前面因为它要优先于所有放行规则被匹配iptables -I INPUT -s 10.0.0.88 -j DROP这里最核心的思想是DROP规则必须放在ACCEPT规则前面否则你前面的ACCEPT已经把包放走了这个DROP根本轮不到。类似这种“优先级”问题是新手最容易踩的坑。3. firewalld基础配置实操相对于iptables的“裸操作”firewalld更像是一个带管理后台的防火墙服务。它引入了zone、service、rich rule这些概念配置方式更接近“声明式”我只需要说“这个端口放行那个来源拒绝”它负责翻译成底层规则。下面我逐步讲清楚。3.1 zone区域怎么用才不容易乱firewalld的默认区域有好几个包括public、internal、trusted、drop等每个区域代表不同的信任级别。打开系统上看一下firewall-cmd --get-default-zone firewall-cmd --get-active-zones第一条命令查看当前默认区域第二条查看当前哪些网卡绑定在哪些区域上。安装好的Linux系统一般默认zone是public这意味着所有流量按public区域的规则来执行。配置思路是这样的先把网卡划分到合适的区域然后在区域里开放服务。比如公司内网服务器把内网网卡划到internal外网网卡划到public这样就实现了“内网服务宽进严出、外网服务严格受限”的效果。区域划分好后配置代码会变得非常清爽网络情况一目了然。把网卡划分到区域用如下命令firewall-cmd --permanent --zoneinternal --change-interfaceeth1--permanent表示写入永久配置不加的话只对当前运行状态临时生效。改完记得重载一下firewall-cmd --reload重载是firewalld日常管理最重要的一个动作改完永久配置必须重载才能让配置真正加载进运行时。3.2 放行服务与端口的常用命令比起iptables逐条写端口firewalld放行服务就简单多了。它内置了很多常见服务定义比如ssh、http、https你直接放行服务名即可firewall-cmd --permanent --zonepublic --add-servicehttp firewall-cmd --permanent --zonepublic --add-servicehttps有些服务不在内置列表里那就需要直接用端口号firewall-cmd --permanent --zonepublic --add-port8080/tcp这里的/tcp一定不要省略因为同一个端口号的TCP和UDP协议是分开管理的你只放行了TCPUDP的流量照样会被拦。比如DNS服务同时使用TCP和UDP的53端口你就得把两条都加上。如果嫌两条麻烦也可以写成53/tcp和53/udp各一条。查看当前放行列表firewall-cmd --zonepublic --list-all这个命令会输出该zone下所有开放的端口、服务、富规则等信息。我做配置复核时必跑这个命令确认有没有漏放或者多放。删除服务或端口把--add改成--remove即可。这里要特别说明删除是即时的可别在业务高峰期戴着“永久配置”的心理去操作一旦删除当前连接立即受影响。3.3 用rich rule处理来源白名单内置的服务和端口功能只能做“放行与否”的简单控制如果要做精细化限制比如“只允许某个IP访问8080端口”就需要写富规则rich rule。富规则的表达能力比普通端口规则强很多一个典型例子firewall-cmd --permanent --zonepublic --add-rich-rulerule familyipv4 source address114.114.114.114 port port8080 protocoltcp accept这条规则的意思是只允许来源为114.114.114.114的IP访问本机的8080 TCP端口。如果你希望拒绝某个IP段访问某一批端口可以定义protocol先为tcp然后在port后面跟上port range属性firewall-cmd --permanent --zonepublic --add-rich-rulerule familyipv4 source address192.168.2.0/24 port port8000-8100 protocoltcp reject这里用reject而不是drop区别在于reject会明确告诉对方“你的请求被拒绝”而drop则是直接把包丢弃对方会一直等到超时。在排查问题时reject的反馈更明显想要隐蔽服务时drop更合适。3.4 firewalld的端口转发和伪装除了放行和拦截转发也是防火墙的一个重要工作。比如把外网访问本机的8080端口转发到内网另一台机器192.168.1.50的80端口可以用命令行直接加转发规则firewall-cmd --permanent --zonepublic --add-forward-portport8080:prototcp:toport80:toaddr192.168.1.50转发涉及地址和端口改写需要先开启伪装masquerade否则寻址会失败firewall-cmd --permanent --zonepublic --add-masquerade伪装的功能相当于把内网主机的源地址改写为防火墙的外网地址这样数据包回来的时候才能原路返回。做转发时如果发现内网服务器收不到包绝大部分情况就是因为这个masquerade没开。但注意masquerade在多个网络区域共用时会带来一定的安全性影响如果你不确定自己需要它建议严格控制使用范围。4. 实战场景演练配置命令单独看都很简单真正考验人的是把这些命令组合起来在真实网络场景中完成一套完整需求。这一节我挑四个常见场景从易到难模拟真实操作过程。4.1 场景一Web服务只暴露80和443假设我在一台CentOS服务器上跑着Nginx只提供网页服务。第一步确认防火墙在运行systemctl status firewalld然后把默认区域设为public并只放行HTTP和HTTPSfirewall-cmd --set-default-zonepublic firewall-cmd --permanent --zonepublic --remove-servicessh firewall-cmd --permanent --zonepublic --add-servicehttp firewall-cmd --permanent --zonepublic --add-servicehttps firewall-cmd --reload这里用--remove-servicessh是因为默认区域的public里很可能已经放了ssh为了最小化攻击面顺手把它去掉。如果你还需要远程管理服务器别急着删可以改完再放到internal区域或者临时放行一个管理IP地址。生产环境里如果需要远程管理我一般会为管理IP单独配置一个trusted区域方便又安全firewall-cmd --permanent --zonetrusted --add-source203.0.113.0/24这样内网管理地址走trusted区外网地址走public区互不干扰。最后再用curl验证一下curl -I http://127.0.0.1如果在服务器本机请求正常外网请求被拒就说明防火墙策略已经生效。4.2 场景二内网SSH白名单限制前面提到删除ssh服务时不要一刀切。这个场景里我们就把SSH做严格限制只有公司办公网192.168.10.0/24才能访问22端口其他一律拒绝。用firewalld的富规则能一次到位firewall-cmd --permanent --zonepublic --remove-servicessh firewall-cmd --permanent --zonepublic --add-rich-rulerule familyipv4 source address192.168.10.0/24 port port22 protocoltcp accept firewall-cmd --reload配置完成后最好做一次验证。在192.168.10.0/24网段找一台机器ssh连接试试没问题再用一个外网IP尝试连接应该卡住拒绝。如果外网还连着仔细检查public区域里是不是还残留着--add-servicessh没删干净的话会被规则先匹配到。提示给运维留条后路。如果你人在办公室外突然把生产服务器的SSH端口拦死了后果非常麻烦。做这类白名单限制的时候先开一个临时放行自己的IP确认完全无误后再清理临时规则。这个习惯能救你命。4.3 场景三iptables做区隔转发在有些场景里你可能不想用firewalld的forward规则特别是需要同时改源地址和目的地址的时候。假设我的机器是一台双网卡网关eth0接外网eth1接内网内网机器要访问外网需要做源地址转换。iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE这条规则的意思是所有来自192.168.1.0/24网段、从eth0出去的包把源地址改成eth0的IP。这样内网机器就能以网关的公网IP访问外部了。做这个操作前需要先开启内核转发功能否则规则配好了也不生效sysctl -w net.ipv4.ip_forward1 echo net.ipv4.ip_forward1 /etc/sysctl.conf开启转发后还要确保filter表FORWARD链的默认策略是ACCEPT或者你明确添加了放行规则。我遇过不少同事在网关机器上做了NAT但内网依然上不了网查到最后往往就是内核转发没打开或者FORWARD链策略为DROP把转发包拦死了。4.4 场景四日志查看确认规则是否命中配置完规则怎么确认数据包到底是“匹配了哪一条规则”然后被放行或丢弃的查看计数器是一种简单可行的判断方式。用iptables看计数器iptables -L -n -v观察pkts列的数字如果你看到某条规则统计包数一直在涨说明数据包匹配到了它。同样firewalld查看计数器也不难nft list ruleset这个命令会把firewalld实际翻译出来的规则全部展示出来其中包含每个规则的计数器。如果某个规则的计数器在快速增长就说明当前流量正被它处理。这种方法在排查“连不上、不知道为什么”的问题时非常实用。另外如果确认数据包被DROP了可以临时LOG记录一下来源和去向再判断具体的拦截路径。iptables加日志规则的姿势iptables -A INPUT -j LOG --log-prefix IPTABLES-DROP: --log-level 4然后去/var/log/messages或者journalctl里看日志。加上日志规则要小心不要长期挂在生产环境它会产生大量日志撑爆磁盘我一般排查完就立刻删掉这条规则。5. 常见问题与排查技巧配置防火墙的时候大部分人遇到问题就上网搜搜到命令复制过来还是不对。我把这些年踩过的坑集中整理成几个典型问题配上排查思路你们对号入座。5.1 规则顺序导致莫名失效这是iptables最常见的坑。比如我先加了一条INPUT默认DROP然后又用-A追加了一条放行80端口的规则。因为默认策略在链的末尾放行规则如果追加在默认策略之后链上先匹配到默认策略就把包DROP了放行规则根本执行不到。规则顺序不对配置逻辑再正确也没用。正确做法是给所有放行规则加在链的前面用-I参数插到最前面或者先写好全部放行规则最后再设置默认策略。firewalld虽然帮我们做了规则排序但用富规则时仍要注意同一zone内规则之间的优先级。富规则之间存在顺序关系多条规则互相冲突时后面匹配的优先级反而更高这跟iptables是反着来的写的时候注意理清先后顺序。5.2 重启后规则消失iptables规则不保存的情况下重启机器就恢复成空规则默认策略也会变成ACCEPT。很多人配置完也不保存等到服务器重启才发现所有规则都没了。这个问题的本质是iptables规则只存在内存里你需要在配置完成后执行iptables-save /etc/sysconfig/iptables或者安装iptables-services服务让它在开机时自动加载systemctl enable iptables-servicesfirewalld相对省心它的永久配置会自动保存。但有个坑大家容易忽略只执行了firewall-cmd --add-port没有加--permanent也没有reload重启后配置消失。原因就在于不加--permanent只对运行时生效。5.3 iptables和Docker的网络冲突装了Docker的机器如果同时使用iptables做规则管理很容易出现容器网络不通或者规则互相覆盖的情况。Docker本身会往iptables里写入大量规则尤其是在FORWARD链上。由于Docker的规则优先级通常很高你手工添加的DROP规则可能把容器的流量也拦掉了表现为容器访问外网失败。遇到这种情况排查方式比较简单查看Docker相关的链iptables -L FORWARD -n -v iptables -L DOCKER -n -v看到DOCKER链的存在说明Docker在管理转发规则。如果你业务不是特别复杂建议docker使用自己的bridge网络不要轻易改动FORWARD链的默认策略实在要改避开DOCKER链涉及的流量。还有一个替代方案是用Docker自带的network策略来做隔离尽量少跟系统防火墙规则混着来。5.4 firewalld服务已启动但规则不生效有一种情况很迷惑firewalld明明在运行规则也显示已添加但外部访问还是通的或者还是不通。先别急着怀疑规则先确认iptables里面是否有残留的其他规则。firewalld底层转换成nftables或iptables规则如果你之前手动配过iptables规则或者之前跑过别的防火墙脚本这些残留规则可能和firewalld规则并存、互相干扰。建议的顺序是先清空历史规则再启firewalld再按需添加规则。具体操作可以先把iptables规则保存备份然后清空iptables -F iptables -t nat -F iptables -X清理完之后再通过firewalld重新配置。firewalld规则不生效的另一个常见原因是没有把网卡绑定到正确zone。你明明开放了internal区域的端口但网卡默认在public区域规则当然不会作用到该网卡上。所以配置前先查active-zones确认网卡和区域匹配。5.5 端口是通了但业务还是访问不了这种问题最让人头疼。防火墙已经放行了端口但业务访问还是失败很多人又回去折腾防火墙规则其实问题根本不在防火墙。几个典型案例服务本身没绑定在0.0.0.0上比如Nginx只监听了127.0.0.1外部请求根本到不了内部服务依赖的端口没同时放行比如网页需要访问数据库端口数据库端口被防火墙拦了云平台安全组、物理网络ACL也在做限制本机防火墙放行了但前置的网络层没放行。排查的方法是层层递进先在本机用ss -lntp确认监听地址再用traceroute或telnet从外部测试端口如果端口通但业务报错再看服务和后端依赖。很多时候防火墙是个“背锅侠”真正的问题不在它身上。写在最后做Linux防火墙配置我个人的体会是它不是一个“配完就完事”的动作而是一个持续演进的策略集合。每次变更端口、上线新服务、切换网络结构都应该顺手复查一遍防火墙规则把不再使用的放行项删掉把新增的必要端口加进去。很多服务器被入侵不是防火墙没开而是规则太宽松、太久没人清理导致攻击面越积越大。另外分享一个我自己习惯的做法所有防火墙规则变更都单独记录成一条变更日志注明时间、操作人、目的、影响范围哪怕是“放行一个端口”这样的小改动也记录下来。时间长了你会感谢自己当初这个习惯因为排查问题的时候你翻一下记录就能知道最近谁动过防火墙而不是靠猜或者看历史命令。如果你是在云服务器上操作别忘了同时检查云平台的安全组规则。很多情况下本机防火墙配置没问题但访问不通是因为云平台安全组没放行本机和云平台两层都要兼顾。希望这篇文章里的命令和踩坑经验能帮你少走弯路把防火墙这把锁真正用好。