news 2026/10/10 12:36:48

Linux IP访问控制实战:iptables与firewalld规则详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux IP访问控制实战:iptables与firewalld规则详解

半夜收到监控告警,某台公网服务器的SSH端口被一个IP连续爆破,几百条失败日志刷下来,一看就是扫描器在撞库。这种时候多数人的第一反应是iptables -A INPUT -s <IP> -j DROP,先把来源拉黑再说。做运维这几年,类似操作我执行过几十次,但真正让我印象深刻的,反而是那些“拉黑自己”“重启后规则失效”“规则顺序写错导致白名单也进不来”的翻车瞬间。

Linux下禁止或允许指定IP的访问,本质上就是回答一个问题:谁能碰你的服务器、谁不能碰。工具层面不止iptables一个,还有firewalld富规则、hosts.allow/hosts.deny、应用层配置等。这篇文章我从实际运维视角,把这几条路线的选型逻辑、核心命令、典型坑位一次讲透,适合刚开始接手服务器的新人,也适合想系统梳理防火墙用法的老手。

1. 先分场景再选工具:IP访问控制的第一个决策点

很多人一上来就抄命令,结果越改越乱。我建议动手前先花两分钟想清楚:当前需求属于哪一类?

1.1 三类最常见需求:临时封禁、白名单控制、按服务限源

第一种是临时封禁。典型场景是某个IP正在扫描、爆破、刷接口,你需要立刻把它挡在外面。这类需求的特点是“快”,最好一条规则5秒生效,同时规则要容易删除,因为攻击结束后,这些规则会导致误伤或有安全隐患。

第二种是长期白名单。典型场景是SSH只允许公司固定出口IP访问,或者管理后台只允许网管段访问。这类需求的特点是“稳”,规则必须持久化,重启不能丢,而且要有清晰的维护入口。如果今天封一个IP、明天放一个IP,全靠临时命令堆,早晚会出问题。

第三种是按服务限源。典型场景是Nginx后台只允许内网IP,MySQL只允许应用服务器连接,监控系统只能从监控机拉取数据。这类需求的特点是“精细”,需要同时匹配来源地址和端口、甚至路径,光是主机防火墙不一定够。

1.2 四条技术路线怎么选:iptables、firewalld、TCP Wrapper、应用层

在Linux下做IP访问控制,常见的有四条路线,我把它们的定位和优缺点整理成了表格:

方案工作层级适用系统优点主要局限
iptables内核netfilter几乎所有Linux通用、稳定、规则直接语法偏底层,需手动持久化
firewalld用户态管理框架RHEL/CentOS/Rocky/Fedora支持zone和富规则,管理友好和手动iptables混用会冲突
TCP Wrapper应用层libwrap传统Unix/Linux配置极简单,按服务控制现代发行版很多已默认不支持
应用层配置服务自身所有系统可结合用户、路径精细控制每服务单独配置,无全局视角

选型的核心原则是:看你的系统默认带什么工具,看需求属于哪一类,选最顺手的那一个就行,不必追求“全能”。我自己的习惯是:RHEL系优先用firewalld,Debian系优先用iptables,特殊服务再叠一层应用层限制,而不是盲目在每台机器上都搞一套iptables脚本。

2. iptables的规则链与实操命令:最通用的封禁方案

iptables在Linux世界里就像老黄牛,稳定可靠,但脾气要摸透。它最大的坑不在于“命令难记”,而在于“规则顺序”和“默认策略”这两个底层逻辑。

2.1 链和匹配顺序先搞懂,不然规则写了也白写

iptables中有三条默认链和“访问”直接相关:INPUT(进入本机的包)、OUTPUT(本机发出的包)、FORWARD(被本机转发的包)。标题里的“禁止或允许指定IP访问”,90%的情况都在INPUT链上做文章;但如果你的Linux是路由器或负载均衡器,真正起作用的是FORWARD链,这点很多新手会搞混。

更重要的是匹配顺序:iptables从上到下逐条匹配,命中一条就停止,后面的规则不再执行。

举个例子,INPUT链现有这样三条规则:

  1. ACCEPT tcp -- 203.0.113.5 tcp dpt:22
  2. DROP all -- 192.0.2.10
  3. ACCEPT all -- 203.0.113.5

来自203.0.113.5的SSH流量会命中第1条直接放行,根本走不到第3条;来自192.0.2.10的流量会在第2条被丢弃。如果反过来,把第2条DROP插到第1条之前,那么203.0.113.5的SSH也会被先挡掉。所以白名单ACCEPT规则必须放在DROP规则之前,这就是“顺序决定生死”的含义。

如果所有规则都不匹配,包才会落到链的默认策略(-P)。默认策略是ACCEPT就是黑名单模式,默认策略是DROP就是白名单模式,两种模式的操作逻辑完全相反。

2.2 禁止/允许指定IP的核心命令与增删改查

以下命令就是日常最常用的一套,我整理成了速查表:

操作命令
查看规则iptables -L INPUT -n --line-numbers
禁止指定IP全部访问iptables -A INPUT -s 192.0.2.10 -j DROP
允许指定IP全部访问iptables -A INPUT -s 192.0.2.10 -j ACCEPT
禁止指定IP访问22端口iptables -A INPUT -s 192.0.2.10 -p tcp --dport 22 -j DROP
允许指定网段访问iptables -A INPUT -s 192.168.10.0/24 -j ACCEPT
按编号删除规则iptables -D INPUT 3
按具体命令删除规则iptables -D INPUT -s 192.0.2.10 -j DROP
插入规则到最前面iptables -I INPUT 1 -s 192.0.2.10 -j DROP

几个细节解释一下:

  • -s是源IP,也就是“谁发起的请求”;-d是目标IP,一般本机场景不需要写。
  • -p tcp --dport 22是把协议和端口也限制上。如果不写端口,就是对该IP的所有入站流量生效。
  • -A是追加到链尾,-I是插入到链首。想在已有DROP规则之前插入一条白名单ACCEPT,用-I INPUT 1指定插入到第1条。

提示:远程操作服务器时,优先用-I插入到前面的方式放行自己的IP,再追加封禁规则,能降低把自己关在门外的概率。

2.3 DROP和REJECT怎么选

这是iptables里争议最多的问题之一。DROP是直接把包丢掉,不做任何回应;REJECT是丢弃包的同时返回一个拒绝信号。两者的表现差异如下:

动作客户端表现排错难度适用场景
DROP连接一直卡住直到超时像网络不通,较难判断SSH防爆破、隐藏端口、对付扫描器
REJECT立刻提示Connection refused能明确知道被拒绝内网访问限制、希望客户端快速失败

我个人的建议:公网的SSH端口做来源限制,用DROP。原因很简单,扫描器探测到一个超时无响应的端口,大概率认为是不可达端口,会降低继续扫描的兴致;而且DROP不会产生多余的响应包,对服务器本身也清净。内网服务建议REJECT,比如公司OA只允许办公网访问,当同事在咖啡厅连不上时,REJECT能让他立刻意识到“这是网络限制”,而不是“服务坏了”或者“网线没插好”。

2.4 白名单模式:把默认策略改成拒绝的正确顺序

白名单模式的意思是:默认拒绝所有,只放行明确允许的IP和服务。这是安全要求较高的服务器的常见配置,但也是最容易当场把自己踢出去的配置。

正确的操作顺序很重要,先看这段:

# 1. 先放行回环接口 iptables -A INPUT -i lo -j ACCEPT # 2. 放行已建立的连接和关联连接,这个必须放行 iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # 3. 放行白名单IP到SSH iptables -A INPUT -s 203.0.113.5 -p tcp --dport 22 -j ACCEPT # 4. 最后才把默认策略改成DROP iptables -P INPUT DROP

很多人直接跳到第4步执行iptables -P INPUT DROP,结果SSH立刻断掉。原因是TCP是双向的:你发出去的数据包走OUTPUT链没问题,但服务器返回给你的数据包要重新走INPUT链,没有第2步的ESTABLISHED放行,这些回包会被默认策略丢掉,连接自然就断了。

我当时第一次配白名单模式就遇到过这个情况,后来养成了习惯:只要涉及默认策略变更,先确认当前SSH连接状态已经被放行,再动-P。

2.5 规则持久化:RHEL和Debian两种体系的差异

iptables命令改完,重启后规则默认会丢。持久化方式因发行版而异。

RHEL系(CentOS、Rocky、AlmaLinux)如果要用纯iptables管理,建议先停掉firewalld,避免双框架冲突:

systemctl disable --now firewalld yum install -y iptables-services systemctl enable iptables systemctl start iptables iptables-save > /etc/sysconfig/iptables

Debian/Ubuntu比较省心,装一个iptables-persistent就行:

apt install -y iptables-persistent netfilter-persistent save netfilter-persistent reload

每次修改规则后记得重新save。多数人遗忘的就是这一步,导致小心翼翼的规则配完后,一重启全没了。

3. firewalld富规则与区域:现代发行版的IP控制正解

如果是RHEL系的较新系统,我建议直接用firewalld,不要绕道去手工管理iptables。

3.1 firewalld和手动iptables不是一回事

firewalld是一个用户态防火墙管理框架,它自己的规则最终也是通过内核netfilter生效,但它提供了更上层的抽象:zone、service、rich rule。它的动态特性体现在,修改规则后不需要像iptables那样手动保存,firewall-cmd reload时会重新加载自己的规则集,并且持久化到/etc/firewalld/zones/下的XML文件里。

这里有个运维新手经常踩的坑:firewalld在跑,你又手动用iptables -A加规则,当时是生效的,但等到firewalld reload或者服务器重启,iptables手动加的规则会被清掉。两套工具并存,等于给自己埋雷。

3.2 区域(Zone)是策略分流的骨架

firewalld把网络接口划分到不同zone,每个zone有各自的放行规则。默认zone通常是public,特点是“大门紧闭,只放行显式允许的服务”。你可以把内网网卡划到internal,外网网卡划到public,这样策略自然分流。

常用查看命令:

# 查看默认zone firewall-cmd --get-default-zone # 查看默认zone的完整信息 firewall-cmd --list-all # 查看指定zone firewall-cmd --zone=trusted --list-all

在做“禁止或允许指定IP”时,我们通常不直接改zone里的服务放行,而是用**富规则(rich rule)**做更精确的表达。

3.3 富规则:指定IP与端口组合的精确控制

富规则是firewalld里最接近iptables表达力的功能,而且语法比iptables更可读。几个高频场景我直接给代码:

# 禁止指定IP访问本机所有端口 firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.0.2.10" drop' # 允许指定IP访问SSH服务 firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.5" service name="ssh" accept' # 允许指定IP访问8080端口的TCP流量 firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.5" port port="8080" protocol="tcp" accept'

这里最关键的是--permanent。加了它,规则写入持久化配置,但不会立刻生效,需要firewall-cmd --reload才能加载;不加它,规则立即生效,但重启后丢失。

查询和删除也很直观:

# 查看当前所有富规则 firewall-cmd --list-rich-rules # 删除时把完整规则原样写在--remove-rich-rule里 firewall-cmd --permanent --remove-rich-rule='rule family="ipv4" source address="192.0.2.10" drop' firewall-cmd --reload

注意:删除富规则时,规则内容必须和添加时完全一致,包括引号、空格、顺序。建议用--list-rich-rules的输出直接复制,避免肉眼比对误差。

3.4 临时与永久规则的配合技巧

运维过程中经常出现一种需求:同事出差,临时需要从某个IP访问服务器,明天就结束。如果图省事直接加永久规则,事后很容易忘了删。

我的做法是:临时放行一律不加--permanent,让它立即生效且重启自动消失。真正需要长期存在的规则,才加--permanent并reload。

这样还有一个额外好处:每次firewall-cmd --list-all时,临时规则和永久规则一目了然,审计时有据可查,不会出现“规则为什么在这里”的困惑。

4. hosts.allow/hosts.deny与TCP Wrapper:老办法还剩多少用

这条路现在越来越冷门,但老系统上还能见到,值得讲清楚边界。

4.1 原理与匹配优先级

TCP Wrapper通过libwrap库,让daemon在收到连接时先查两个文件:/etc/hosts.allow和/etc/hosts.deny。匹配逻辑是:先查allow,命中就放行;没命中再查deny,命中就拒绝;都不命中,默认放行。

注意这个“默认放行”和iptables默认DROP是相反的。配置格式也简单:左边是服务名,右边是客户端匹配规则。

# /etc/hosts.allow sshd: 203.0.113.5 sshd: 10.10.0.0/16 # /etc/hosts.deny sshd: 192.0.2.10

如果要做成白名单,常规思路是在allow里写白名单,在deny里写sshd: ALL。但我不建议在deny里写过于宽泛的ALL: ALL,因为一旦allow里有笔误或漏写,所有走libwrap的服务都会拒绝连接,远程管理直接瘫痪。

4.2 先确认服务支持不支持libwrap

这个方法最大的问题是:现代很多发行版的服务已经不再链接libwrap库。判断方法很简单:

ldd /usr/sbin/sshd | grep libwrap

如果有输出,说明sshd支持hosts.allow/deny;如果没有输出,说明你配置了也没用。Rocky Linux 9、Debian 12这些新版本里,我实测过很多默认sshd已经不带libwrap了。

所以我的建议是:这套老方案适合老系统、自编译的旧服务;新装系统别依赖它,直接上firewalld或iptables更实际。

4.3 现代应用层替代方案:sshd_config按来源地址限制

如果你一定要在“应用层”限制SSH来源,现代sshd本身提供的能力更强:

# 在sshd_config里,只允许指定来源IP AllowUsers admin@203.0.113.5 ops@10.0.0.0/8 # 或者用Match块做更精细控制 Match Address 192.0.2.10 DenyUsers all

配置完记得systemctl reload sshd。这种方式的好处是可以结合用户名,比如“只允许admin这个账号从公司出口IP登录”,比单纯按IP控制多了一个维度。它适合作为纵深防御的最后一层,而不是唯一的防线。

5. 远程操作防火墙的翻车现场与救急流程

这一节可能是整个主题里最有价值的部分。远程操作防火墙,最怕的不是命令记不住,而是把自己关在门外。我把自己踩过和被朋友问过的三次典型翻车,连同完整的排查链路都写在这里。

5.1 把自己IP封了:一次操作失误的完整自救

场景很常见:公司出口IP是203.0.113.66,我从跳板机登录服务器,想封一个扫描IP 203.0.113.67,结果命令里写错了IP,把-s 203.0.113.66执行了下去。下一秒,SSH就断掉了。

自救路线有三个层次:

第一,带外管理。如果是云服务器,用云控制台的VNC登录;如果是物理机,用iDRAC/IPMI。登录后执行:

iptables -D INPUT -s 203.0.113.66 -j DROP

第二,求助他人。让机房同事或团队里其他有权限的人帮忙执行同样的删除命令。

第三,预防胜于救急。我现在的习惯是,远程执行任何“封禁类”命令前,先给自己留一条定时恢复的后路:

# 5分钟后自动删除封禁规则,给自己留后悔药 echo "iptables -D INPUT -s 203.0.113.66 -j DROP" | at now + 5 minutes

如果操作没问题,用atq找到任务编号,再用atrm <编号>取消。这个习惯救了我好几次,强烈推荐。

5.2 默认策略改DROP后SSH立刻断:ESTABLISHED状态没放行

我见过不止一个同事执行完iptables -P INPUT DROP后,监控立刻告警“服务器失联”。原因前面说过,TCP连接是双向的,服务器回包也是通过INPUT链进来的,默认DROP把它丢了。

正确的顺序在2.4节已经给过。这里补充一个更安全的“带验证的改法”:

# 先以最快的速度确认自己IP能访问22端口 iptables -I INPUT 1 -s 203.0.113.66 -p tcp --dport 22 -j ACCEPT # 再放行已建立连接 iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # 最后改默认策略 iptables -P INPUT DROP

这样即使后续规则有问题,第一条自己的IP放行仍然兜底。改完测试确认无误后,再决定是否保留这条临时ACCETP。

5.3 firewalld和iptables混用导致规则丢失

这是RHEL系很隐蔽的一个坑。有台CentOS 7服务器,firewalld正常运行,SSH已经放行。某天发现有人扫描SSH,运维图省事直接iptables -A INPUT -s 192.0.2.10 -j DROP,当时确实是生效的。但过了几天,firewall-cmd --reload后,这条规则就消失了,扫描流量重新进来。

原因是firewalld在reload时会把自己的规则集整体下发,同时清理不属于自己管理的规则。手动iptables加的规则不在它的“记忆”里,自然被覆盖。

结论很明确:firewalld运行期间,所有规则变更都通过firewall-cmd完成,不要混用iptables命令。如果确实需要iptables,那就先把firewalld彻底停掉,用前面2.5节的iptables-services方案管理。

5.4 “连不上”是不是防火墙拦截?标准排查链路

当客户端报“连不上服务器”,先别急着怀疑防火墙有问题。我通常按下面这套顺序排查:

第一步,在客户端测试端口状态:

nc -vz 10.0.0.5 22
  • 如果一直卡住最终timeout,大概率是DROP。
  • 如果立即返回Connection refused,可能是服务没启动,也可能是REJECT策略。

第二步,在服务器上抓包确认:

tcpdump -nn -i eth0 host 10.0.0.6 and tcp port 22

如果能看到客户端的SYN包不断重传,但服务器没有回应,基本可以断定被DROP了。

第三步,看iptables计数:

iptables -L INPUT -n -v --line-numbers

观察目标IP对应的DROP规则,计数是否在比赛增长。注意这里要加-v,才能看到匹配次数的累计。

第四步,如果是firewalld环境:

firewall-cmd --list-rich-rules firewall-cmd --list-all

被DROP的流量是静默丢弃,系统里通常不会留日志,所以靠dmesg或journalctl往往看不到线索,别浪费时间。正确的判断路径就是“测试端口 + 抓包 + 看规则计数”。

6. 生产服务器组合配置案例与运维习惯

最后给一个可以“抄作业”的综合案例。假设一台公网Web服务器,使用Rocky Linux 8,跑Nginx提供80/443服务,SSH只允许公司固定出口IP和备用运维网段,同时经常有恶意IP扫描,需要快速封禁且不影响在线业务。

6.1 一个典型公网服务器的访问控制需求

需求拆开来看就是三层:

  • Web服务:面向所有公网用户,必须放行80和443。
  • SSH管理:只允许固定的两个来源,属于白名单。
  • 恶意IP扫描:要能临时拉黑,但封禁规则不能长期堆积,更不能误伤正常用户。

这个需求用firewalld加ipset最合适,纯iptables也能实现,但firewalld的富规则可读性更好,边界更清晰。

6.2 用ipset做动态拉黑:封禁大量IP的正确姿势

当需要封禁的IP数量超过十几条时,iptables逐条加规则不仅乱,匹配效率也会下降。ipset是内核提供的高性能集合工具,配合firewalld的富规则可以做到“一条丢弃规则管一个IP黑名单”。

创建带超时时间的黑名单集合:

ipset create deny_list hash:ip timeout 86400

把ipset应用到firewalld富规则:

firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source ipset="deny_list" drop' firewall-cmd --reload

发现恶意IP后,直接加进集合:

ipset add deny_list 192.0.2.10 # 查看当前拉黑列表 ipset list deny_list

timeout 86400的意思是集合中的条目会在86400秒(24小时)后自动过期,相当于临时封禁一天。这个设计适合应对扫描器、爆破攻击:攻击时段快速止血,又不会因为忘了清理而永久误伤。如果要永久拉黑,创建集合时不加timeout;要立刻清除某个IP,用ipset del deny_list 192.0.2.10。

6.3 变更、验证、回滚与版本管理

生产环境动防火墙,一定要有变更意识。我的标准动作是这样的:

变更前先备份:

cp -r /etc/firewalld /root/backup/firewalld-$(date +%F)

配置完成后验证。除了看规则列表,还要从不同网络位置实测:

# 查看最终规则 firewall-cmd --list-all firewall-cmd --list-rich-rules # 业务侧验证 curl -I http://服务器IP # SSH来源验证 ssh -v 203.0.113.5@服务器IP

回滚也很直接:如果验证发现问题,删除刚才添加的富规则或者把备份的zone文件还原,再reload。但手动还原文件不如“一条条删除刚才添加的规则”来得快,所以我在变更时会把每一条命令都记录在笔记里,方便反悔。

经验再多说两句。第一,防火墙规则文件建议纳入版本管理,团队协作时至少把/etc/firewalld/zones/的变更记录进git,做到“什么时候、谁、加了什么规则”都有迹可循。第二,定期清理一次性放行的临时规则,比如每周跑一遍firewall-cmd --list-rich-rules和ipset list deny_list,把已经过期的、不再需要的规则清掉。否则半年过去,规则越堆越多,最后排查问题时全是在给自己制造噪音。

我在实际生产环境里管理IP访问控制,从来不是“一条命令搞定”的事。它更像一套流程:先判断需求类型,再选对工具,然后按“先放行自己、再放行业务、最后收紧默认”的顺序操作,最后做好持久化和回滚预案。把这套流程走熟了,防火墙操作就不再是凌晨三点让人心跳加速的冒险。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/10 12:36:46

OpenClaw卸载不干净?一份从进程到缓存的完整清理指南

OpenClaw这种跑在大模型边上的自动化助手&#xff0c;装的时候能折腾一整天——git clone、npm install、docker compose up、配Ollama、写API Key&#xff0c;每一步都有坑。等你想卸载的时候才发现&#xff0c;这坑比安装还深。我在Windows和Linux上分别部署过OpenClaw&#…

作者头像 李华
网站建设 2026/10/10 12:36:12

代码性能剖析实战指南:从火焰图到慢接口优化

做后端服务优化这几年&#xff0c;我见过太多人一遇到接口变慢&#xff0c;第一反应就是加缓存、加线程池、拆微服务&#xff0c;折腾一整晚&#xff0c;效果却像在漏水的船上换了一个更大的桶——水流得再多也没用。真正老练的做法其实是反过来的&#xff1a;先用代码性能剖析…

作者头像 李华
网站建设 2026/10/10 12:34:55

TraeAI Skill接入Unity完整指南:一次配置,长期生效

做Unity开发的人应该都有这种体验&#xff1a;项目越做越深&#xff0c;问AI的问题却越来越“重复”。我最近在给一个数字孪生Demo收尾&#xff0c;天天在TraeAI里让它帮我写C#脚本、查URP管线报错、排查粒子特效内存泄漏&#xff0c;但每次开口前都得先把一堆项目背景重新交代…

作者头像 李华
网站建设 2026/10/10 12:34:48

Cocos2d-x 编译实战:版本选择、环境配置与报错排查指南

干了这么多年游戏和工具开发&#xff0c;Cocos2d-x 的编译问题一直是群里问得最多的&#xff0c;没有之一。很多人拿着老项目或者刚拉下来的源码&#xff0c;一顿操作猛如虎&#xff0c;结果卡在环境配置、NDK 版本、符号找不到这些破事上&#xff0c;一折腾就是两三天。这篇东…

作者头像 李华
网站建设 2026/10/10 12:33:04

PyCharm快捷键实战指南:从鼠标操作到键盘流高效编码

先抛个问题&#xff1a;你在PyCharm里写代码的时候&#xff0c;右手是不是经常离开键盘去摸鼠标&#xff1f;我猜答案是肯定的&#xff0c;因为我自己曾经也是这副德性。直到有一次帮人处理一个很简单的Bug&#xff0c;改了三处变量名、调了一个函数参数&#xff0c;全程键盘操…

作者头像 李华
网站建设 2026/10/10 12:32:22

教育文本分析落地指南:从评教意见到课堂改进的技术路径

我最早意识到文本分析对教育有用&#xff0c;是因为一位做教研的朋友半夜发来一句话&#xff1a;“几百条评教意见&#xff0c;每一条我都看了&#xff0c;但看完等于没看。”这句话听起来像抱怨&#xff0c;其实点中了教育场景的核心痛点——学校已经积攒了大量文本数据&#…

作者头像 李华