Linux防火墙配置实战:从iptables到firewalld的完整指南

Linux防火墙配置实战:从iptables到firewalld的完整指南
1. 项目概述为什么我们需要关注Linux防火墙在任何一个稍微有点规模的网络环境里无论是公司的服务器机房还是你自己家里跑着服务的树莓派防火墙都是那个默默无闻但又至关重要的“门卫”。它决定了哪些数据包可以进来哪些可以出去哪些需要被无情地丢弃。对于Linux系统来说这个“门卫”的角色尤为重要因为Linux作为服务器操作系统的绝对主力其安全性直接关系到服务的稳定和数据的安全。很多人一听到“防火墙配置”就觉得头大觉得这是网络工程师或者安全专家的专属领域。其实不然基础的防火墙配置是每一个Linux系统管理员甚至是每一个开发者都应该掌握的技能。你不需要成为安全专家但你需要知道如何为你的Web服务器打开80端口如何为数据库服务限制访问来源或者如何在调试时临时关闭防火墙而不至于让系统门户大开。这就像你会开车不一定要会修车但至少得知道怎么开雨刷和打转向灯。我见过太多因为防火墙配置不当导致的问题服务部署好了却无法从外部访问排查半天才发现是防火墙没放行端口或者更糟糕的服务器被不明扫描和攻击因为默认的防火墙策略过于宽松。因此今天我们就来彻底拆解一下Linux防火墙的基础配置方法。我们不求面面俱到成为防火墙大师但求通过这篇内容你能独立完成日常工作中90%的防火墙配置需求并且理解每一步操作背后的逻辑做到心里有数遇事不慌。2. 核心概念与工具选型iptables vs. firewalld在动手配置之前我们必须先搞清楚Linux世界里两套主流的防火墙管理机制iptables和firewalld。它们不是非此即彼的关系而是不同层次、不同时代的工具。理解它们的区别和联系是避免后续配置混乱的关键。2.1 iptables经典但底层的规则集iptables是Linux内核中Netfilter框架的用户空间命令行工具。你可以把它理解为直接操作防火墙规则集的“汇编语言”。它非常强大、直接但同时也比较原始和复杂。工作原理iptables通过定义一系列的“表”Tables如filter, nat, mangle和“链”Chains如INPUT, OUTPUT, FORWARD并在链上设置具体的匹配规则Rules和目标动作Targets如ACCEPT, DROP, REJECT来工作。数据包会按照预定义的路径流经这些链并与链上的规则逐一匹配一旦匹配成功就执行相应的动作。特点直接有效规则直接生效无需额外的守护进程。配置持久化麻烦通过命令行添加的规则默认是临时的重启后会丢失。需要手动保存到特定文件如/etc/sysconfig/iptables或使用iptables-save/iptables-restore才能持久化。语法相对复杂规则链和匹配条件需要一定学习成本。2.2 firewalld现代且友好的动态管理器firewalld是Red Hat系列发行版如RHEL, CentOS, Fedora在RHEL7/CentOS 7之后引入的防火墙管理工具。它并不是替代iptables而是运行在iptables之上的一个动态防火墙管理器可以理解为操作防火墙的“高级语言”或“图形化界面生成器”。工作原理firewalld引入了“区域”Zone和“服务”Service的概念。Zone是一套预定义的规则集比如“public”区域只允许SSH和DHCP“home”区域则允许更多服务你可以将网络接口分配到不同的Zone。Service则是预定义好的端口和协议组合如“http”服务对应tcp 80端口。firewalld会根据你的配置在后台自动生成并应用对应的iptables规则。特点配置动态化无需重启服务或重新加载所有规则修改配置如添加一个端口可以立即、动态地生效不影响现有连接。配置持久化简单所有配置修改默认就是永久的。抽象层次高使用Zone和Service的概念更符合人类对网络环境的认知降低了配置复杂度。提供多种管理方式命令行工具firewall-cmd图形化工具firewall-config甚至还有D-Bus接口。2.3 如何选择与共存对于新手和大多数日常管理场景强烈推荐使用 firewalld。它的学习曲线平缓不易出错且功能足够强大。尤其是CentOS/RHEL 7和Fedora用户系统默认安装并启用的就是firewalld。如果你需要极其精细、复杂的控制或者你管理的是一些老旧的、仍在使用SysVinit系统的服务器如CentOS 6那么直接使用 iptables 是更直接的选择。重要提示一个系统上通常只应运行一套防火墙管理工具。同时启用iptables和firewalld可能会导致规则冲突和不可预知的行为。通常firewalld服务firewalld.service会与iptables服务iptables.service冲突启动一个前需要停止并禁用另一个。接下来的内容我们将以firewalld作为主要讲解对象因为它是当前的主流和未来趋势。同时我们也会在关键部分指出其背后对应的iptables原理帮助你加深理解。对于仍在使用iptables的环境我们也会给出对应的基础操作命令作为参考。3. firewalld 基础配置实战假设我们正在配置一台新安装的CentOS 8服务器它需要提供Web服务HTTP/HTTPS和SSH远程管理。我们的目标是配置防火墙仅允许必要的流量通过。3.1 安装、启动与状态检查首先确认firewalld是否已安装并运行。# 1. 检查firewalld是否安装 sudo systemctl status firewalld # 如果未安装极少见可以使用包管理器安装 # CentOS/RHEL/Fedora: sudo yum install firewalld -y # 或 sudo dnf install firewalld -y (新版本) # 2. 启动firewalld并设置开机自启 sudo systemctl start firewalld sudo systemctl enable firewalld # 3. 检查防火墙状态和默认区域 sudo firewall-cmd --state sudo firewall-cmd --get-default-zone sudo firewall-cmd --get-active-zones运行sudo firewall-cmd --state如果返回running说明防火墙正在运行。--get-default-zone通常返回public这是新安装系统的默认区域。--get-active-zones会显示哪些网络接口被分配到了哪个区域。注意在云服务器如AWS EC2, 阿里云ECS上主机商可能在底层还有一层安全组Security Group防火墙。你需要同时在安全组和操作系统防火墙中放行端口流量才能到达你的服务器。很多新手只配了其一导致无法访问。3.2 理解核心概念区域Zone与服务Service这是firewalld配置的核心务必理解。区域Zone一套预定义的信任级别和规则集合。你可以把不同的网络接口如eth0, ens33绑定到不同的区域。drop丢弃任何传入连接都被无响应地丢弃只允许传出连接。block阻塞任何传入连接都被拒绝并返回一个错误只允许传出连接。public公共默认区域。在你不信任的网络中使用只允许选定的传入连接。external外部用于启用了伪装masquerading的外部网络通常用于路由器。仅允许选定的传入连接。internal内部用于内部网络你基本信任网络中的其他计算机。允许更多的服务。dmz隔离区用于位于DMZ的计算机仅允许选定的传入连接。work工作用于工作区你信任网络中的大多数计算机。允许更多的服务。home家庭用于家庭网络你信任网络中的大多数计算机。允许更多的服务。trusted信任接受所有网络连接。最不安全。服务Service一个预定义的规则包含端口号、协议、可能的模块和目的地。例如http服务包含了tcp协议的80端口。使用服务名比直接记端口号更方便、更易管理。查看所有预定义服务sudo firewall-cmd --get-services你会看到一个很长的列表包括ssh,http,https,smtp,mysql等。3.3 常用配置操作放行服务与端口现在我们要为服务器配置规则。假设网络接口ens192已被分配在默认的public区域。场景一放行SSH服务确保远程管理不断SSH是管理服务器的生命线必须首先确保其畅通。通常ssh服务在安装后默认就是放行的但检查一下总没错。# 查看public区域当前放行了哪些服务 sudo firewall-cmd --zonepublic --list-services # 如果输出中没有ssh则添加它永久生效 sudo firewall-cmd --zonepublic --add-servicessh --permanent # 重新加载防火墙配置使永久规则立即生效不会中断现有连接 sudo firewall-cmd --reload # 再次检查确认ssh已在列表中 sudo firewall-cmd --zonepublic --list-services场景二放行Web服务HTTP和HTTPS我们的服务器要运行网站。# 同时添加http和https服务 sudo firewall-cmd --zonepublic --add-servicehttp --add-servicehttps --permanent # 重新加载配置 sudo firewall-cmd --reload # 检查结果 sudo firewall-cmd --zonepublic --list-services # 应该能看到 ssh, http, https 等服务场景三放行自定义端口例如一个运行在3000端口的Node.js应用不是所有应用都有预定义的服务这时需要直接操作端口。# 添加TCP 3000端口临时生效重启firewalld或reload后失效 sudo firewall-cmd --zonepublic --add-port3000/tcp # 添加TCP 3000端口永久生效 sudo firewall-cmd --zonepublic --add-port3000/tcp --permanent sudo firewall-cmd --reload # 查看public区域放行的所有端口 sudo firewall-cmd --zonepublic --list-ports场景四移除规则如果你移除了某个服务或者改错了端口需要删除规则。# 移除https服务永久 sudo firewall-cmd --zonepublic --remove-servicehttps --permanent # 移除3000/tcp端口永久 sudo firewall-cmd --zonepublic --remove-port3000/tcp --permanent sudo firewall-cmd --reload3.4 高级配置IP地址限制与端口转发限制SSH访问来源IP提升安全性默认情况下放行服务意味着对所有IP开放。对于SSH这种敏感服务最好限制只能从特定IP如你的办公网络IP访问。# 首先移除全局的ssh服务规则如果你之前添加过 sudo firewall-cmd --zonepublic --remove-servicessh --permanent # 然后添加一条富规则rich rule只允许来自192.168.1.100的SSH连接 sudo firewall-cmd --zonepublic --add-rich-rulerule familyipv4 source address192.168.1.100 service namessh accept --permanent # 如果你想允许一个网段比如192.168.1.0/24 sudo firewall-cmd --zonepublic --add-rich-rulerule familyipv4 source address192.168.1.0/24 service namessh accept --permanent sudo firewall-cmd --reload富规则非常强大可以基于源/目标IP、端口、协议、时间等进行复杂匹配。配置端口转发例如将外部80端口转发到内部8080端口有时应用运行在非标准端口但你又希望用户能用标准端口访问。# 启用伪装masquerading这是NAT转发的必要条件 sudo firewall-cmd --zonepublic --add-masquerade --permanent # 设置端口转发将到达本机public区域80端口的TCP流量转发到同一台机器localhost的8080端口 sudo firewall-cmd --zonepublic --add-forward-portport80:prototcp:toport8080 --permanent # 或者转发到另一台内网机器的8080端口 sudo firewall-cmd --zonepublic --add-forward-portport80:prototcp:toaddr192.168.1.200:toport8080 --permanent sudo firewall-cmd --reload3.5 配置的持久化与备份firewalld的配置默认就是持久的所有带--permanent标志的命令修改的都是永久配置存储在/etc/firewalld/目录下的XML文件中。--reload命令就是将永久配置加载为运行时配置。永久配置目录/etc/firewalld/运行时配置firewall-cmd命令不加--permanent时操作的是运行时配置重启firewalld服务后会丢失并被永久配置覆盖。备份直接备份/etc/firewalld/整个目录即可。查看完整配置sudo firewall-cmd --list-all-zones可以查看所有区域的详细配置。实操心得我个人的习惯是任何修改都先不加--permanent测试。例如sudo firewall-cmd --zonepublic --add-port9999/tcp。测试通过后再用相同的命令加上--permanent选项做永久设置最后--reload。这样可以避免一条错误的永久规则导致自己被锁在服务器外面特别是操作SSH规则时。测试完毕后记得sudo firewall-cmd --zonepublic --remove-port9999/tcp清理临时规则。4. iptables 基础操作速查尽管firewalld是主流但了解iptables的基础操作仍有必要特别是在维护老系统或进行深度排查时。4.1 基本命令与规则查看# 查看filter表默认表的所有链规则 sudo iptables -L -n -v # -L: 列出规则 # -n: 以数字形式显示IP和端口不解析主机名和服务名更快更清晰 # -v: 显示详细信息如数据包和字节计数 # 查看NAT表规则 sudo iptables -t nat -L -n -v # 以更清晰的格式查看规则显示行号便于删除 sudo iptables -L -n -v --line-numbers4.2 添加与删除规则假设我们要实现和firewalld类似的功能允许SSH22端口、HTTP80端口、HTTPS443端口。# 1. 设置默认策略谨慎操作建议先配置好允许规则再设置DROP sudo iptables -P INPUT ACCEPT # 先将INPUT链默认策略设为ACCEPT避免被锁 sudo iptables -P FORWARD ACCEPT sudo iptables -P OUTPUT ACCEPT # 2. 清空所有现有规则 sudo iptables -F # 3. 允许本地回环(lo)接口的通信 sudo iptables -A INPUT -i lo -j ACCEPT sudo iptables -A OUTPUT -o lo -j ACCEPT # 4. 允许已建立的连接和相关的连接保证对外发起的连接能收到回包 sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # 5. 允许SSH (22端口) sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT # 6. 允许HTTP (80端口) 和 HTTPS (443端口) sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT # 7. 允许PING (ICMP协议) sudo iptables -A INPUT -p icmp -j ACCEPT # 8. 设置INPUT链的默认策略为DROP拒绝所有未明确允许的入站连接 sudo iptables -P INPUT DROP # 9. 保存规则不同发行版方法不同 # CentOS 6/RHEL 6: sudo service iptables save # 规则会保存到 /etc/sysconfig/iptables # Ubuntu/Debian 通常需要安装 iptables-persistent sudo apt-get install iptables-persistent sudo netfilter-persistent save删除规则# 先查看规则行号 sudo iptables -L INPUT -n -v --line-numbers # 假设要删除INPUT链上第3条规则 sudo iptables -D INPUT 34.3 iptables规则持久化陷阱这是iptables新手最容易踩的坑。通过命令行添加的规则只存在于内存中系统重启后会丢失。你必须手动保存。CentOS 6 / RHEL 6使用service iptables save命令它会将当前规则写入/etc/sysconfig/iptables。Ubuntu / Debian需要安装iptables-persistent包。安装过程中会询问是否保存当前规则。之后可以使用netfilter-persistent save来保存。通用方法使用iptables-save命令导出规则然后写入一个文件并在系统启动时用iptables-restore加载。sudo iptables-save /etc/iptables.rules然后编辑/etc/rc.local文件确保它有执行权限在exit 0之前添加iptables-restore /etc/iptables.rules踩坑记录我曾经在Ubuntu服务器上配置了一下午的iptables规则重启后所有规则消失服务全部无法访问。原因是忘了安装iptables-persistent。从此以后在非CentOS 6系统上配置iptables我的第一件事就是查清楚这个系统如何持久化规则。5. 防火墙配置的排错与日常维护配置防火墙后服务无法访问是最常见的问题。下面是一个系统性的排查流程。5.1 问题排查四步法第一步检查防火墙服务状态# firewalld sudo systemctl status firewalld # iptables (作为服务在某些系统上) sudo systemctl status iptables第二步确认规则是否已正确添加并生效# firewalld sudo firewall-cmd --zonepublic --list-all # 检查services和ports里是否有你的服务或端口 # iptables sudo iptables -L -n -v # 仔细查看INPUT链确认你的端口规则是否存在并且顺序在DROP或REJECT规则之前第三步在服务器本地测试端口连通性规则生效不代表服务本身没问题。先在服务器本机测试。# 使用netstat或ss查看端口监听状态 sudo ss -tlnp | grep :80 # 或 sudo netstat -tlnp | grep :80 # 输出应显示有进程正在监听0.0.0.0:80或[::]:80 # 使用telnet或curl在本地连接 curl http://localhost telnet localhost 80如果本地都不通那问题出在Web服务如Nginx/Apache本身而不是防火墙。第四步从外部网络测试确保测试客户端不在防火墙的限制IP范围内如果设置了的话。使用telnet、nc(netcat) 或在线端口检测工具。# 从另一台Linux机器测试 telnet 你的服务器IP 80 nc -zv 你的服务器IP 805.2 常见问题速查表问题现象可能原因排查命令/解决方案SSH连接突然断开无法重连误操作防火墙封锁了SSH端口或IP。1. 如果还有控制台云服务器提供商的控制台VNC从控制台登录。2. 检查防火墙规则sudo firewall-cmd --list-all或sudo iptables -L -n。3.紧急恢复通过控制台执行sudo firewall-cmd --runtime-to-permanent(firewalld) 或sudo iptables -P INPUT ACCEPT(iptables)。服务本地可访问外部无法访问1. 防火墙未放行端口。2. 服务监听在127.0.0.1而不是0.0.0.0。3. 云服务商安全组未配置。1. 检查防火墙规则。2. 检查服务配置如Nginx的listen指令。3. 登录云控制台检查安全组/网络ACL规则。添加了firewalld规则但未生效1. 忘记使用--permanent且未--reload。2. 网络接口未绑定到正确的zone。1.sudo firewall-cmd --reload。2.sudo firewall-cmd --get-active-zones查看接口zone分配。用sudo firewall-cmd --zonepublic --change-interfaceens192 --permanent修改。iptables规则重启后丢失未正确持久化规则。根据发行版使用service iptables save或安装配置iptables-persistent。端口能telnet但服务无响应防火墙可能允许了连接建立但后续数据包被拦截状态检测问题。确保iptables规则中包含了-m state --state ESTABLISHED,RELATED -j ACCEPT。在firewalld中这是默认行为。5.3 日常维护建议变更前备份在修改任何防火墙规则前尤其是iptables先备份现有规则。# firewalld sudo cp -r /etc/firewalld/ /etc/firewalld.backup.$(date %Y%m%d) # iptables sudo iptables-save ~/iptables.backup.$(date %Y%m%d)使用版本控制对于复杂的firewalld配置尤其是自定义的zone和service XML文件可以考虑将其纳入Git管理。注释与文档对于iptables可以在规则中使用-m comment --comment Allow web traffic来添加注释。对于firewalld良好的文件命名和目录结构就是文档。最小权限原则只开放必要的端口和服务。对于管理端口如SSH尽量使用非标准端口或结合IP白名单。定期审计规则使用sudo firewall-cmd --list-all-zones或sudo iptables-save导出规则定期审查是否有过期或不需要的规则。防火墙配置是一个“做减法”的艺术。初始状态应该是“全部拒绝”然后一条条地添加“允许”的规则。始终保持对当前生效规则的清晰认知是保证网络安全和服务可用的基石。从今天起别再害怕命令行里的那些防火墙命令了它们是你服务器最忠诚的守护者。