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

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

1. 项目概述:为什么我们需要关注Linux防火墙

在任何一个稍微有点规模的网络环境里,无论是公司的服务器机房,还是你自己家里跑着服务的树莓派,防火墙都是那个默默无闻但又至关重要的“门卫”。它决定了哪些数据包可以进来,哪些可以出去,哪些需要被无情地丢弃。对于Linux系统来说,这个“门卫”的角色尤为重要,因为Linux作为服务器操作系统的绝对主力,其安全性直接关系到服务的稳定和数据的安全。

很多人一听到“防火墙配置”就觉得头大,觉得这是网络工程师或者安全专家的专属领域。其实不然,基础的防火墙配置是每一个Linux系统管理员,甚至是每一个开发者都应该掌握的技能。你不需要成为安全专家,但你需要知道如何为你的Web服务器打开80端口,如何为数据库服务限制访问来源,或者如何在调试时临时关闭防火墙而不至于让系统门户大开。这就像你会开车不一定要会修车,但至少得知道怎么开雨刷和打转向灯。

我见过太多因为防火墙配置不当导致的问题:服务部署好了却无法从外部访问,排查半天才发现是防火墙没放行端口;或者更糟糕的,服务器被不明扫描和攻击,因为默认的防火墙策略过于宽松。因此,今天我们就来彻底拆解一下Linux防火墙的基础配置方法。我们不求面面俱到成为防火墙大师,但求通过这篇内容,你能独立完成日常工作中90%的防火墙配置需求,并且理解每一步操作背后的逻辑,做到心里有数,遇事不慌。

2. 核心概念与工具选型:iptables vs. firewalld

在动手配置之前,我们必须先搞清楚Linux世界里两套主流的防火墙管理机制:iptablesfirewalld。它们不是非此即彼的关系,而是不同层次、不同时代的工具。理解它们的区别和联系,是避免后续配置混乱的关键。

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 --zone=public --list-services # 如果输出中没有'ssh',则添加它(永久生效) sudo firewall-cmd --zone=public --add-service=ssh --permanent # 重新加载防火墙配置,使永久规则立即生效(不会中断现有连接) sudo firewall-cmd --reload # 再次检查,确认ssh已在列表中 sudo firewall-cmd --zone=public --list-services

场景二:放行Web服务(HTTP和HTTPS)

我们的服务器要运行网站。

# 同时添加http和https服务 sudo firewall-cmd --zone=public --add-service=http --add-service=https --permanent # 重新加载配置 sudo firewall-cmd --reload # 检查结果 sudo firewall-cmd --zone=public --list-services # 应该能看到 ssh, http, https 等服务

场景三:放行自定义端口(例如,一个运行在3000端口的Node.js应用)

不是所有应用都有预定义的服务,这时需要直接操作端口。

# 添加TCP 3000端口(临时生效,重启firewalld或reload后失效) sudo firewall-cmd --zone=public --add-port=3000/tcp # 添加TCP 3000端口(永久生效) sudo firewall-cmd --zone=public --add-port=3000/tcp --permanent sudo firewall-cmd --reload # 查看public区域放行的所有端口 sudo firewall-cmd --zone=public --list-ports

场景四:移除规则

如果你移除了某个服务,或者改错了端口,需要删除规则。

# 移除https服务(永久) sudo firewall-cmd --zone=public --remove-service=https --permanent # 移除3000/tcp端口(永久) sudo firewall-cmd --zone=public --remove-port=3000/tcp --permanent sudo firewall-cmd --reload

3.4 高级配置:IP地址限制与端口转发

限制SSH访问来源IP(提升安全性)

默认情况下,放行服务意味着对所有IP开放。对于SSH这种敏感服务,最好限制只能从特定IP(如你的办公网络IP)访问。

# 首先,移除全局的ssh服务规则(如果你之前添加过) sudo firewall-cmd --zone=public --remove-service=ssh --permanent # 然后,添加一条富规则(rich rule),只允许来自192.168.1.100的SSH连接 sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.100" service name="ssh" accept' --permanent # 如果你想允许一个网段,比如192.168.1.0/24 sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" service name="ssh" accept' --permanent sudo firewall-cmd --reload

富规则非常强大,可以基于源/目标IP、端口、协议、时间等进行复杂匹配。

配置端口转发(例如,将外部80端口转发到内部8080端口)

有时应用运行在非标准端口,但你又希望用户能用标准端口访问。

# 启用伪装(masquerading),这是NAT转发的必要条件 sudo firewall-cmd --zone=public --add-masquerade --permanent # 设置端口转发:将到达本机public区域80端口的TCP流量,转发到同一台机器(localhost)的8080端口 sudo firewall-cmd --zone=public --add-forward-port=port=80:proto=tcp:toport=8080 --permanent # 或者,转发到另一台内网机器的8080端口 sudo firewall-cmd --zone=public --add-forward-port=port=80:proto=tcp:toaddr=192.168.1.200:toport=8080 --permanent sudo firewall-cmd --reload

3.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 --zone=public --add-port=9999/tcp。测试通过后,再用相同的命令加上--permanent选项做永久设置,最后--reload。这样可以避免一条错误的永久规则导致自己被锁在服务器外面(特别是操作SSH规则时)。测试完毕后,记得sudo firewall-cmd --zone=public --remove-port=9999/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-numbers

4.2 添加与删除规则

假设我们要实现和firewalld类似的功能:允许SSH(22端口)、HTTP(80端口)、HTTPS(443端口)。

# 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 3

4.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 --zone=public --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范围内(如果设置了的话)。使用telnetnc(netcat) 或在线端口检测工具。

# 从另一台Linux机器测试 telnet <你的服务器IP> 80 nc -zv <你的服务器IP> 80

5.2 常见问题速查表

问题现象可能原因排查命令/解决方案
SSH连接突然断开,无法重连误操作防火墙,封锁了SSH端口或IP。1. 如果还有控制台(云服务器提供商的控制台VNC),从控制台登录。
2. 检查防火墙规则:sudo firewall-cmd --list-allsudo 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 --zone=public --change-interface=ens192 --permanent修改。
iptables规则重启后丢失未正确持久化规则。根据发行版使用service iptables save或安装配置iptables-persistent
端口能telnet但服务无响应防火墙可能允许了连接建立,但后续数据包被拦截(状态检测问题)。确保iptables规则中包含了-m state --state ESTABLISHED,RELATED -j ACCEPT。在firewalld中,这是默认行为。

5.3 日常维护建议

  1. 变更前备份:在修改任何防火墙规则前,尤其是iptables,先备份现有规则。
    # firewalld sudo cp -r /etc/firewalld/ /etc/firewalld.backup.$(date +%Y%m%d) # iptables sudo iptables-save > ~/iptables.backup.$(date +%Y%m%d)
  2. 使用版本控制:对于复杂的firewalld配置(尤其是自定义的zone和service XML文件),可以考虑将其纳入Git管理。
  3. 注释与文档:对于iptables,可以在规则中使用-m comment --comment "Allow web traffic"来添加注释。对于firewalld,良好的文件命名和目录结构就是文档。
  4. 最小权限原则:只开放必要的端口和服务。对于管理端口(如SSH),尽量使用非标准端口或结合IP白名单。
  5. 定期审计规则:使用sudo firewall-cmd --list-all-zonessudo iptables-save导出规则,定期审查是否有过期或不需要的规则。

防火墙配置是一个“做减法”的艺术。初始状态应该是“全部拒绝”,然后一条条地添加“允许”的规则。始终保持对当前生效规则的清晰认知,是保证网络安全和服务可用的基石。从今天起,别再害怕命令行里的那些防火墙命令了,它们是你服务器最忠诚的守护者。