在CentOS系统中折腾防火墙,最让人头疼的不是编写iptables规则本身,而是机器重启后规则全部丢失,或者误操作导致把自己锁在服务器外面。iptables的规则完全运行在内核内存中,系统一旦重启,所有精心配置的过滤链、NAT映射、流量整形策略都会瞬间蒸发。解决这个问题的核心在于理解两个动作:持久化和备份还原。

CentOS 7/8下使用iptables-save实现即时持久化

很多人以为在CentOS 7或8上用systemctl restart iptables就能保存规则,实际情况是,如果你直接通过iptables命令添加规则,这些规则只存在于当前运行内存。要让规则在重启后依然生效,必须显式执行保存动作。最直接的方法是使用iptables-save工具,它能把当前内核中所有表的所有规则导出为标准输出。

执行以下命令将当前规则保存到系统默认的规则文件:

iptables-save > /etc/sysconfig/iptables

对于IPv6的规则,需要单独处理:

ip6tables-save > /etc/sysconfig/ip6tables

这里有一个容易踩的坑:CentOS 7默认安装时,/etc/sysconfig/iptables这个文件可能不存在,或者是一个空文件。如果直接执行iptables-save重定向,文件会被创建并写入内容。但如果你之前用system-config-firewall或firewalld管理过防火墙,这个文件里可能残留旧配置。建议在保存前先备份原有文件,然后覆盖写入。保存完成后,可以重启iptables服务验证规则是否真的被加载:

systemctl restart iptables
iptables -L -n -v

如果重启服务后发现规则没变,说明持久化成功。这里需要特别注意,CentOS 7开始引入firewalld作为默认防火墙管理工具,iptables服务默认是停止且被屏蔽的。如果你想彻底切回传统的iptables管理方式,必须先停掉firewalld并启用iptables服务:

systemctl stop firewalld
systemctl disable firewalld
systemctl mask firewalld
yum install iptables-services -y
systemctl enable iptables
systemctl start iptables

做完这些操作后,iptables-save保存的规则才会在系统启动时被iptables服务脚本自动加载。这个服务脚本在启动时会读取/etc/sysconfig/iptables文件,用iptables-restore命令恢复规则。

利用iptables-restore进行批量规则恢复与原子化加载

iptables-restore的威力在于它能以原子操作的方式一次性加载整套规则集。与逐条执行iptables命令不同,iptables-restore在加载过程中如果遇到错误,整个恢复操作会失败回滚,不会出现只加载了一半规则的危险状态。这在远程维护服务器时尤其重要,能有效防止因规则文件语法错误导致网络中断。

标准恢复命令如下:

iptables-restore < /etc/sysconfig/iptables

如果你想在恢复前先清空所有现有规则,可以在规则文件开头加上清除指令。一个完整的规则文件结构通常这样写:

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
COMMIT
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT

这种格式的文件直接兼容iptables-restore。文件中的星号加表名表示开始配置某个表,COMMIT表示提交该表的配置。冒号开头的行定义链的默认策略和计数器初始值。这种结构化格式让规则管理变得清晰,你可以把不同功能的规则分表存放,维护时一目了然。

在实际运维中,我习惯把规则文件版本化管理。每次修改规则前,先把当前生效的规则导出并打上时间戳:

iptables-save > /root/iptables-backup/iptables-$(date +%Y%m%d-%H%M%S).rules

这样即使新规则有问题,也能迅速用iptables-restore回滚到上一个稳定版本。

自定义systemd服务实现开机自动恢复自定义规则

有些场景下,你可能不想用系统自带的iptables服务,或者需要从非标准路径加载规则文件。这时可以编写自己的systemd服务单元来实现更灵活的持久化。创建一个文件/etc/systemd/system/iptables-custom.service:

[Unit]
Description=Custom iptables rules loader
After=network.target
Before=network-online.target

[Service]
Type=oneshot
ExecStart=/sbin/iptables-restore /etc/iptables/custom-rules.v4
ExecStart=/sbin/ip6tables-restore /etc/iptables/custom-rules.v6
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

然后启用这个服务:

systemctl daemon-reload
systemctl enable iptables-custom.service
systemctl start iptables-custom.service

这样做的好处是规则文件路径完全由你控制,可以把规则文件放在挂载的独立分区或网络存储上,实现多台服务器共享同一套基础规则模板。不过要注意After和Before的依赖关系,确保规则在网络接口激活后、应用程序依赖网络前加载完成,否则可能出现服务启动时防火墙尚未就绪的安全窗口。

规则备份策略与自动化脚本设计

手动备份规则容易遗忘,把备份操作自动化才是可靠的做法。一个实用的思路是结合cron定时任务和git版本控制。每天凌晨自动导出当前规则,如果规则有变化就提交到本地git仓库,保留完整的变更历史。

下面是一个可以直接使用的备份脚本/root/scripts/iptables-backup.sh:

#!/bin/bash
BACKUP_DIR="/root/iptables-backup"
mkdir -p $BACKUP_DIR
cd $BACKUP_DIR

# 初始化git仓库(首次运行时)
if [ ! -d ".git" ]; then
    git init
    git config user.email "root@localhost"
    git config user.name "Auto Backup"
fi

# 导出规则
iptables-save > iptables-current.rules
ip6tables-save > ip6tables-current.rules

# 检查是否有变化
if git diff --quiet; then
    # 无变化,不提交
    exit 0
else
    # 有变化,提交并打标签
    git add iptables-current.rules ip6tables-current.rules
    git commit -m "Auto backup $(date +%Y-%m-%d_%H:%M:%S)"
    git tag "backup-$(date +%Y%m%d-%H%M%S)"
fi

把脚本加入crontab,每天凌晨3点执行:

0 3 * * * /bin/bash /root/scripts/iptables-backup.sh

这个方案的独到之处在于,它不仅仅是备份,还通过git记录了每次规则变更的差异。当某天你发现某个端口突然不通,可以用git log查看规则变更历史,用git diff对比两次备份之间的具体改动,快速定位是哪次修改引入的问题。相比简单的按日期保存文件,版本控制让规则管理上升到了可审计的层次。

处理规则持久化中的常见陷阱

第一个陷阱是Docker与iptables的冲突。Docker服务启动时会自动修改iptables规则来实现容器网络通信,如果你在Docker启动前用iptables-restore恢复了自定义规则,Docker随后可能会覆盖或打乱你的规则。解决方法是调整加载顺序,确保Docker服务在你的自定义iptables服务之后启动,或者在Docker的配置中设置iptables: false来禁止Docker操作防火墙(但这会影响容器网络功能,需谨慎)。

第二个陷阱是云主机的安全组与iptables双重过滤。很多云平台在虚拟机外部还有一层安全组过滤,如果你在iptables里配置了严格的入站规则,同时云控制台的安全组也做了限制,排查网络问题时需要两层都检查。建议在iptables规则里对安全组已放行的流量做明确注释,减少排障时的混淆。

第三个陷阱是规则保存时未包含所有需要的表。很多人只关注filter表,忘了nat表和mangle表。如果你配置了端口转发或流量标记,这些规则存在nat表和mangle表里。执行iptables-save时必须不加任何表名限制,它会导出所有表。如果用iptables-save -t nat只导出nat表,恢复时就会丢失filter和mangle的配置。

第四个陷阱是SELinux对规则文件路径的限制。在某些强化配置下,SELinux可能阻止iptables-restore读取非标准路径的规则文件。如果你把规则文件放在自定义目录,需要用chcon或semanage设置正确的文件上下文,或者直接把规则放在/etc/sysconfig/目录下避免权限问题。

构建规则文件模板实现快速部署与还原

当管理多台CentOS服务器时,为每台机器单独编写规则效率低下且容易出错。更好的做法是建立一个基础规则模板,包含所有服务器通用的安全策略,然后为每台机器维护一个差异化的附加规则文件。基础模板可以这样组织:

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
# 允许本地回环
-A INPUT -i lo -j ACCEPT
# 允许已建立的连接
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 允许ping
-A INPUT -p icmp --icmp-type echo-request -j ACCEPT
# SSH端口(默认22,按需修改)
-A INPUT -p tcp --dport 22 -j ACCEPT
# 在此处插入服务器特定规则
COMMIT

部署新服务器时,先用这个基础模板通过iptables-restore加载,然后根据服务器角色添加特定端口。例如Web服务器追加80和443端口,数据库服务器追加3306端口并限制来源IP。这种分层管理的方式让规则维护变得模块化,修改基础策略时只需更新模板文件并在所有机器上重新加载即可。

对于规则还原的场景,建议在服务器上保留最近三次的规则快照。修改规则前执行一次自动快照,如果修改后出现问题,可以快速回滚。这个机制可以集成到日常的配置管理工具如Ansible中,在推送规则变更前自动在目标机器上执行iptables-save备份,变更后检测SSH连接是否正常,如果连接失败则通过带外管理或控制台回滚规则。

iptables规则持久化看似简单,实际上涉及服务管理、文件格式、启动顺序、与容器和云平台的交互等多个层面。把iptables-save和iptables-restore这两个核心工具用透,配合自动备份和版本控制,才能确保防火墙策略在服务器重启、规则误改、系统迁移等各种场景下都可靠地保持预期状态。这套方法在CentOS 6到CentOS 8上都适用,即使未来迁移到基于nftables的新系统,理解这种持久化和备份还原的思路也同样有价值。