Ubuntu 18.04 UFW防火墙配置实战:从默认裸奔到生产级防护
1. 为什么 Ubuntu 18.04 用户必须亲手配置 UFW,而不是跳过这一步
你刚在一台全新的 Ubuntu 18.04 服务器上跑通了 Nginx,网页能打开;又顺手装了 Samba,局域网内同事的 Windows 电脑也能访问共享文件夹;甚至把 MySQL 的 3306 端口也开放给了内网开发机——一切看起来都很“丝滑”。直到某天凌晨三点,你被监控告警短信惊醒:服务器 CPU 持续 98%、SSH 登录缓慢、/var/log/auth.log 里密密麻麻全是来自巴西、罗马尼亚、越南 IP 的暴力破解记录,失败尝试每秒超过 12 次。你紧急登录后发现,一个叫admin的弱密码账户已被成功爆破,攻击者已上传挖矿脚本并开始消耗你的 CPU 资源。
这不是虚构场景。我在 2019 年运维一批部署在阿里云华东 1 区的 Ubuntu 18.04 虚拟机时,连续三台在开通公网 IP 后 72 小时内被攻陷,原因高度一致:系统默认未启用任何防火墙策略,所有端口对外“裸奔”。而 Ubuntu 官方从 16.04 开始就将 UFW(Uncomplicated Firewall)作为默认推荐的防火墙管理工具,它不是可有可无的“锦上添花”,而是 Ubuntu 18.04 生产环境的第一道生存防线。UFW 本质是 iptables 的高级封装层,它把原本需要记忆十几条复杂 iptables 命令、理解 chain 和 table 概念的底层操作,压缩成sudo ufw allow 22这样一句人类可读的指令。但问题在于,很多人误以为“装了系统就有防火墙”,或者只执行了sudo ufw enable就以为万事大吉——这恰恰是最危险的认知。UFW 默认策略是deny all incoming, allow all outgoing, deny all routed,这意味着:你主动发起的请求(比如 curl 外部 API、apt update)完全不受限;但所有外部主动连接你的请求(SSH、HTTP、Samba)默认全部被拒绝。所以,如果你没手动allow对应端口,你的服务根本无法被访问。反过来,如果你allow得太宽泛(比如sudo ufw allow from 192.168.1.0/24却忘了限制端口),或者错误地allow了22/tcp而没加limit,就等于给攻击者递上了万能钥匙。我见过最典型的翻车案例,是运维同学为图省事,在测试环境执行了sudo ufw allow 0.0.0.0/0(允许所有 IP 访问所有端口),结果该命令被误复制到生产服务器,导致 Redis 6379 端口暴露,3 小时内被勒索软件加密全部数据。因此,配置 UFW 不是“会不会”的技术问题,而是“敢不敢”为系统安全负起第一责任的操作纪律。它要求你清晰回答三个问题:我的服务需要哪些端口?这些端口只对谁开放?如果有人恶意扫描或暴力尝试,系统该如何响应?接下来的所有操作,都围绕这三个问题展开,没有一句废话,没有一个步骤是多余的。
2. UFW 的真实工作原理:它不是魔法,而是 iptables 的“翻译官”
很多初学者把 UFW 当成一个独立的防火墙程序,这是根本性误解。UFW 本身不处理任何网络包,它只是一个 Python 编写的策略编译器和管理前端。它的核心价值在于:把人类友好的规则(如allow OpenSSH)翻译成 iptables 能执行的底层指令,并确保这些指令按正确顺序写入/etc/ufw/before.rules、/etc/ufw/after.rules和/lib/ufw/user.rules等配置文件,最终由内核的 netfilter 框架执行。理解这一点至关重要,因为它直接决定了你排查问题的路径。当你执行sudo ufw status verbose时,看到的“Status: active”和下方的规则列表,其实是 UFW 读取自身配置文件后,反向解析出的“人话版”摘要;而真正生效的,是它写入的那些 raw iptables 规则。我曾遇到一个棘手问题:客户服务器上sudo ufw status显示OpenSSH规则状态为ALLOW,但外部 SSH 连接始终超时。常规思路会去检查 UFW 规则,但这次我直接执行了sudo iptables -L INPUT --line-numbers,发现 INPUT 链的第 1 条规则是-j ufw-before-logging-input,而第 5 条才是-j ufw-user-input,但在这两条之间,有一条手工添加的-p tcp --dport 22 -j DROP规则(来自之前一位同事的临时调试)。由于 iptables 规则严格按顺序匹配,这条 DROP 规则在 UFW 的 ALLOW 规则之前就被触发,导致所有 SSH 请求在到达 UFW 处理逻辑前就被丢弃。这个案例说明:UFW 是 iptables 的“翻译官”,但不是“独裁者”。它无法覆盖或删除你手动添加的 iptables 规则。因此,UFW 的工作流程必须被拆解为四个明确阶段:
2.1 阶段一:规则定义(用户输入)
你执行的每一条ufw命令,如sudo ufw allow 80/tcp或sudo ufw deny from 203.0.113.5 to any port 22,都会被 UFW 解析为结构化数据,存入/lib/ufw/user.rules(用户自定义规则)或/etc/ufw/user6.rules(IPv6 规则)。这些文件是纯文本,你可以用cat /lib/ufw/user.rules直接查看其内容。你会发现,allow 80/tcp最终被转译为类似*filter\n:ufw-user-input - [0:0]\n-A ufw-user-input -p tcp --dport 80 -j ACCEPT\nCOMMIT的语句。这里的关键是-A(Append),意味着规则被追加到链末尾,而非插入到特定位置。
2.2 阶段二:规则编译(UFW 内部处理)
当执行sudo ufw enable时,UFW 并不会立即调用 iptables 命令。它首先读取所有配置文件(/etc/ufw/ufw.conf定义全局策略,/etc/ufw/before.rules定义前置规则如 ICMP、loopback,/lib/ufw/user.rules是你的主规则),然后按照预设的优先级顺序(before → user → after)将它们合并、去重、排序,生成一个完整的、可执行的 iptables 脚本。这个脚本被写入/var/lib/ufw/user.rules(注意路径与/lib/ufw/user.rules不同),它是 UFW 实际提交给内核的“最终答卷”。
2.3 阶段三:内核加载(iptables 执行)
UFW 调用系统命令iptables-restore < /var/lib/ufw/user.rules,将编译好的规则批量载入内核。此时,iptables -L INPUT输出的内容,才真正反映了 UFW 的策略效果。这也是为什么ufw status和iptables -L有时会不一致——前者显示的是 UFW “认为”自己应该做的,后者显示的是内核“实际”在执行的。
2.4 阶段四:运行时拦截(netfilter 工作)
当一个网络包抵达服务器网卡,Linux 内核的 netfilter 框架会按预设的 hook 点(如 PREROUTING、INPUT、FORWARD)依次处理。对于进入本机的包,它首先进入 INPUT 链。INPUT 链中的每条规则按顺序匹配:如果包的目的端口是 22,且来源 IP 在白名单中,则ACCEPT;否则继续下一条;如果遍历完所有规则都没匹配,则执行默认策略(DENY)。UFW 的limit功能(如sudo ufw limit 22/tcp)正是在此阶段生效:它利用 iptables 的hashlimit模块,在内存中维护一个计数器,对同一 IP 在指定时间窗口内的连接请求数进行统计,一旦超限,后续请求自动被REJECT。这比简单DROP更友好,因为REJECT会向客户端返回 TCP RST 包,让对方立刻知道连接被拒,而不是无响应等待超时,这对防止慢速攻击(slowloris)非常关键。
提示:UFW 的
limit并非万能。它只能限制“新连接”(即 TCP SYN 包),对已建立的连接(ESTABLISHED)无效。因此,它防不住应用层的暴力破解(如 SSH 密码穷举),只能缓解扫描行为。真正的防护需要结合 fail2ban 这类应用层监控工具。
3. 从零开始的完整配置流程:每一步都对应一个真实风险点
配置 UFW 不是执行几条命令就结束的流水线,而是一个需要持续验证、动态调整的风险控制闭环。下面是我基于 Ubuntu 18.04 生产环境总结出的七步法,每一步都直指一个常见翻车点,所有命令均经过实测验证。
3.1 第一步:确认系统状态与基础清理(避免“带病上岗”)
在动任何防火墙规则前,必须确保系统处于一个干净、可知的状态。很多人跳过这步,直接enable,结果发现 SSH 断连,只能重启服务器进救援模式。执行以下命令:
# 检查当前 UFW 状态(通常为 inactive) sudo ufw status verbose # 查看所有已加载的 iptables 规则,重点找是否有冲突的手动规则 sudo iptables -L INPUT --line-numbers | head -20 # 检查是否已有其他防火墙服务在运行(如 firewalld),它们会与 UFW 冲突 sudo systemctl list-units | grep -E "(firewalld|iptables)" # 如果发现 firewalld 正在运行,必须先禁用它,否则 UFW 无法正常工作 sudo systemctl stop firewalld sudo systemctl disable firewalld这一步的核心是“清场”。Ubuntu 18.04 默认不启动 firewalld,但如果你是从 CentOS 迁移过来的镜像,或使用了某些一键脚本,firewalld 可能残留。它和 UFW 都试图管理 iptables,结果就是规则互相覆盖,行为不可预测。我曾帮一个客户恢复服务,根源就是firewalld在后台静默运行,ufw enable后ufw status显示一切正常,但iptables -L却空空如也——因为 firewalld 把 UFW 写入的规则全清掉了。
3.2 第二步:设置默认策略(划定安全基线)
UFW 的默认策略是安全的起点,但必须显式确认和加固。执行:
# 设置默认入站策略为 DENY(这是最关键的一步!) sudo ufw default deny incoming # 设置默认出站策略为 ALLOW(保证服务器能正常更新、发邮件等) sudo ufw default allow outgoing # 设置默认转发策略为 DENY(除非你明确需要做路由器或 NAT) sudo ufw default deny routed这里有个极易被忽略的细节:ufw default deny incoming并不会立即生效,它只是修改/etc/ufw/ufw.conf中的DEFAULT_INPUT_POLICY="DROP"。真正的生效,是在你执行ufw enable之后。但设置这一步的意义在于,它为你后续添加的每一条allow规则,都设定了一个“安全默认值”。想象一下,如果你的服务只需要 22 和 80 端口,那么即使你忘记deny其他端口,UFW 的默认DENY也会替你兜底。这就像给房子装了防盗门(默认 DENY),再给快递员配一把专用钥匙(allow 22),而不是把所有窗户都敞开(默认 ALLOW)。
3.3 第三步:精准开放必要服务端口(拒绝“端口全开”)
这是最体现专业度的环节。绝不能allow 0.0.0.0/0,也不能allow 22就完事。必须遵循“最小权限原则”。以最常见的三个服务为例:
# 【SSH】仅允许特定 IP 段访问,并启用连接频率限制(防暴力破解) sudo ufw limit from 192.168.1.0/24 to any port 22 proto tcp # 【Web 服务】如果只提供 HTTP,只开 80;如果启用了 HTTPS,则必须同时开 443 sudo ufw allow 80/tcp sudo ufw allow 443/tcp # 【Samba】这是标题中提到的高频需求,但 `sudo ufw allow samba` 命令不存在! # 正确做法是:Samba 使用多个端口,必须逐一开放 sudo ufw allow from 192.168.1.0/24 to any port 137 proto udp # NetBIOS name service sudo ufw allow from 192.168.1.0/24 to any port 138 proto udp # NetBIOS datagram service sudo ufw allow from 192.168.1.0/24 to any port 139 proto tcp # NetBIOS session service sudo ufw allow from 192.168.1.0/24 to any port 445 proto tcp # SMB over TCP/IP注意:sudo ufw allow samba command not found这个热搜词,正源于此。UFW 没有内置的samba服务别名,它只认识端口号和协议。很多教程直接写ufw allow samba,导致新手执行报错,还以为是命令语法错了。实际上,这是对 Samba 协议栈理解不足的表现。Samba 的 137/138(UDP)用于名称解析和广播,139/445(TCP)用于文件共享会话。如果只开 445,旧版 Windows(如 XP)可能无法发现共享;如果只开 139,新版 Windows(Win10+)可能连接失败。因此,生产环境必须四端口全开,并严格限制来源 IP。
3.4 第四步:启用并验证(用真实连接测试,而非仅看状态)
执行sudo ufw enable后,UFW 会提示Command may disrupt existing ssh connections. Proceed with operation (y|n)?。此时务必选择y,但不要立即关闭当前 SSH 会话。保持这个会话活跃,然后在另一台机器上,用完全独立的网络环境(如手机热点)尝试连接:
# 在另一台机器上测试 SSH(替换为你的服务器 IP) ssh -p 22 user@your-server-ip # 测试 Web 服务 curl -I http://your-server-ip # 测试 Samba 发现(Linux 客户端) smbclient -L //your-server-ip -U% # 关键验证:尝试连接一个未开放的端口(如 3306),应超时或被拒绝 nc -zv your-server-ip 3306如果 SSH 连接失败,不要慌。立刻回到原会话,执行sudo ufw disable临时关闭防火墙,然后检查sudo ufw status numbered,看规则编号是否正确,再用sudo iptables -L INPUT确认底层规则。永远不要在没有备用连接通道的情况下启用防火墙。我曾因网络波动导致备用连接中断,ufw enable后 SSH 断开,只能联系云服务商后台 VNC 进入,耗时 40 分钟才恢复。
3.5 第五步:日志与监控(让安全可见,而非“黑盒”)
UFW 默认不开启详细日志,这等于关掉了安全系统的“眼睛”。必须激活:
# 启用日志功能(日志级别设为 low,避免磁盘被撑爆) sudo ufw logging on sudo ufw logging low # 日志文件位置 # /var/log/ufw.log (主日志) # /var/log/ufw.log.1 (轮转日志) # 实时监控新日志(在另一个 SSH 会话中执行) sudo tail -f /var/log/ufw.log开启后,当你从外部尝试连接 22 端口,日志中会出现类似IN=eth0 OUT= MAC=... SRC=203.0.113.5 DST=192.0.2.10 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=54321 DF PROTO=TCP SPT=54321 DPT=22 WINDOW=29200 RES=0x00 SYN URGP=0的记录。其中SRC是攻击者 IP,DPT是目标端口,SYN表示连接请求。通过分析这些日志,你能清晰看到谁在扫描你、扫哪些端口、频率多高。这才是安全防护的起点——看见威胁,才能应对。
3.6 第六步:定期审计与规则更新(安全是持续过程)
防火墙规则不是“一次配置,永久有效”。随着业务变化,规则必须动态更新。我建立了一个简单的月度审计清单:
| 审计项 | 检查方法 | 风险示例 |
|---|---|---|
| 冗余规则 | sudo ufw status numbered,检查是否有重复或已失效的allow规则 | 为测试临时添加的allow 8080忘记删除,成为潜在入口 |
| 过期 IP 白名单 | 检查from 192.168.1.0/24类规则,确认该网段是否仍需访问 | 前任员工的办公网络已变更,旧 IP 段成为安全隐患 |
| 服务端口变更 | 核对当前运行的服务端口(sudo ss -tuln)与 UFW 允许的端口是否一致 | 应用升级后监听 8443,但 UFW 只开了 443,导致服务不可用 |
| 日志增长趋势 | sudo du -sh /var/log/ufw.log*,监控日志体积 | 日志突然暴增,可能预示大规模扫描或 DDoS 攻击 |
执行审计时,删除规则用sudo ufw delete [编号](如sudo ufw delete 3),比sudo ufw delete allow 22更精准,避免误删其他 22 端口规则。
3.7 第七步:故障应急方案(当一切都不工作时)
再完美的配置也可能出意外。必须准备“逃生舱”:
# 方案一:临时禁用(最快,但最不安全) sudo ufw disable # 方案二:重置为初始状态(清除所有自定义规则,保留默认策略) sudo ufw reset # 方案三:从备份恢复(最稳妥,前提是你有备份) # 备份规则:sudo cp /lib/ufw/user.rules /root/ufw-user.rules.backup # 恢复规则:sudo cp /root/ufw-user.rules.backup /lib/ufw/user.rules && sudo ufw reload # 方案四:通过云平台控制台(终极保障) # 如果以上都失败,登录你的云服务商(如 AWS EC2、阿里云 ECS)控制台, # 在“安全组”或“网络 ACL”层面,临时放行 22 端口,获得访问权后再修复 UFW。我坚持一个原则:任何防火墙配置变更,必须在变更前,用sudo ufw show added或sudo ufw status numbered截图保存当前状态。这张截图就是你的“后悔药”。
4. 高频问题深度排错:从command not found到连接超时的完整链路
网络搜索热词sudo ufw allow samba command not found和linux防火墙firewall实战案例,揭示了用户在实操中最常卡壳的几个点。下面我以真实排错笔记的形式,还原从问题现象到根因定位的全过程。
4.1 问题一:sudo ufw allow samba报错 “command not found”
现象描述:
在终端输入sudo ufw allow samba,系统返回sudo: ufw: command not found或ufw: command not found。
排查链路:
第一步:确认 UFW 是否已安装
Ubuntu 18.04 默认预装 UFW,但极少数精简版镜像(如某些 Docker 基础镜像)可能未包含。执行which ufw或dpkg -l | grep ufw。如果无输出,说明未安装。
解决方案:sudo apt update && sudo apt install ufw -y。第二步:确认命令拼写与语法
ufw allow samba是错误的。UFW 不识别samba这个服务名。它只接受端口号、协议或/etc/services中定义的标准服务名(如ssh,http,https)。samba不在/etc/services中。
解决方案:改用端口号,如sudo ufw allow 445/tcp。第三步:检查 PATH 环境变量
极少数情况下,ufw二进制文件在/usr/sbin/ufw,而当前用户的PATH未包含/usr/sbin。执行echo $PATH,看是否含/usr/sbin。
解决方案:临时添加export PATH="/usr/sbin:$PATH",或直接用绝对路径/usr/sbin/ufw allow 445/tcp。
注意:
ufw命令必须用sudo,因为它需要 root 权限修改系统防火墙。单独ufw status可以不加sudo(只读),但allow、deny、enable等写操作必须sudo。
4.2 问题二:UFW 已启用,但 SSH 连接超时(Connection timed out)
现象描述:sudo ufw status显示Status: active且22/tcp规则存在,但从外部ssh user@ip时,提示ssh: connect to host ip port 22: Connection timed out。
排查链路:
这是一个经典的“多层过滤”问题,必须逐层穿透:
| 排查层级 | 检查命令 | 预期结果 | 异常含义 |
|---|---|---|---|
| L1:本地网络连通性 | ping your-server-ip | 64 bytes from ... | 服务器宕机或网络不通 |
| L2:服务器 SSH 服务状态 | sudo systemctl status ssh | active (running) | SSH 服务未启动或崩溃 |
| L3:UFW 规则是否生效 | sudo ufw status numbered | 22/tcp ALLOW IN存在 | 规则未添加或被删除 |
| L4:底层 iptables 是否加载 | sudo iptables -L INPUT --line-numbers | grep 22 | 显示ACCEPT规则 | UFW 规则未成功写入 iptables |
| L5:云平台安全组 | 登录云控制台,查看安全组入方向规则 | 包含TCP:22且源 IP 正确 | 云平台防火墙拦截(最常见原因!) |
根因定位:
在 90% 的案例中,问题出在 L5——云平台安全组。UFW 是操作系统层面的防火墙,而云服务商(AWS、阿里云、腾讯云)在虚拟机外还有一层网络防火墙(安全组)。如果安全组没开 22 端口,UFW 再怎么配置都无济于事,因为数据包根本到不了你的服务器网卡。我处理过的此类工单,平均每个要花 15 分钟说服客户去控制台检查安全组,因为他们坚信“ufw status 显示 active 就一定没问题”。
终极验证:
在服务器本地,用curl -v telnet://localhost:22测试。如果能连上,证明 SSH 服务和 UFW 本地规则都 OK;如果连不上,问题在 SSH 服务本身。
4.3 问题三:Samba 共享在 Linux 客户端可见,但在 Windows 上找不到
现象描述:
在 Ubuntu 服务器上配置好 Samba,并用sudo ufw allow开放了 137-139,445 端口,Linux 客户端用smbclient -L //server能列出共享,但 Windows 资源管理器中却看不到该服务器。
根因分析:
Windows 的网络发现(Network Discovery)依赖 NetBIOS 名称服务(NBNS),它使用 UDP 137 端口进行广播和查询。UFW 默认deny incoming,虽然你allow了 137/udp,但UDP 广播包的来源 IP 是0.0.0.0,而你的规则是from 192.168.1.0/24。UFW 无法匹配0.0.0.0到子网,导致广播包被默认DENY策略拦截。
解决方案:
必须添加一条专门针对广播的规则:
# 允许来自任意地址的 UDP 137 广播(仅限局域网,公网无需此规则) sudo ufw allow proto udp from any to any port 137同时,确保 Samba 配置文件/etc/samba/smb.conf中的interfaces和bind interfaces only设置正确,避免绑定到错误网卡。
提示:这个问题凸显了防火墙配置的“上下文敏感性”。同样的规则,在不同网络拓扑(纯内网 vs 混合云)下,效果可能截然不同。没有放之四海而皆准的“最佳实践”,只有贴合你具体环境的“最适实践”。
5. 超越基础:UFW 的进阶技巧与生产环境加固
当基础配置已稳定运行,下一步是让 UFW 成为更智能、更主动的安全卫士。这些技巧并非“炫技”,而是我在处理高危客户环境时沉淀下来的实战经验。
5.1 技巧一:基于应用层的动态端口限制(解决ufw limit的局限性)
UFW 的limit只能限制新连接速率,对已建立连接内的恶意行为(如 HTTP Flood)无能为力。但我们可以利用 UFW 的before.rules文件,在 iptables 的最前端插入更精细的规则。例如,防止针对 Web 服务的慢速攻击(slowloris):
# 编辑 before.rules,在 *filter 和 :ufw-before-input 的定义之间,插入以下内容 sudo nano /etc/ufw/before.rules # 在文件末尾的 COMMIT 之前,添加: # Limit new HTTP connections per IP -A ufw-before-input -p tcp --dport 80 -m state --state NEW -m hashlimit --hashlimit-above 50/sec --hashlimit-burst 100 --hashlimit-mode srcip --hashlimit-name http -j DROP -A ufw-before-input -p tcp --dport 443 -m state --state NEW -m hashlimit --hashlimit-above 50/sec --hashlimit-burst 100 --hashlimit-mode srcip --hashlimit-name https -j DROP这段规则的意思是:对每个源 IP,每秒最多允许 50 个新的 HTTP/HTTPS 连接请求;如果瞬间超过 100 个(burst),后续请求直接DROP。hashlimit模块比limit更强大,它能基于源 IP 维护独立计数器,避免一个恶意 IP 影响其他正常用户。修改后,必须执行sudo ufw reload使新规则生效。
5.2 技巧二:IP 地址黑名单的自动化管理(告别手动deny)
手动sudo ufw deny from x.x.x.x效率低下,且无法持久化。更好的方式是结合fail2ban。Fail2ban 是一个守护进程,它实时监控/var/log/auth.log,一旦发现某个 IP 在 10 分钟内失败登录超过 5 次,就自动调用ufw命令将其加入黑名单。配置步骤如下:
# 安装 fail2ban sudo apt install fail2ban -y # 创建 jail.local 配置文件 sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local sudo nano /etc/fail2ban/jail.local # 在 [sshd] 段落中,取消注释并修改: [sshd] enabled = true filter = sshd logpath = /var/log/auth.log maxretry = 5 bantime = 3600 # 关键:指定 action 为 ufw action = ufw[actiontype=ban]重启服务:sudo systemctl restart fail2ban。此后,所有被 fail2ban 封禁的 IP,会自动出现在sudo ufw status numbered的列表中,且带有DENY标签。这实现了从“被动防御”到“主动封禁”的跃迁。
5.3 技巧三:规则版本控制与团队协作(避免“配置地狱”)
在团队环境中,多人修改 UFW 规则极易导致混乱。我的做法是将 UFW 配置纳入 Git 版本控制:
# 创建配置仓库 mkdir ~/ufw-config && cd ~/ufw-config git init # 将所有关键配置文件软链接到仓库 ln -sf /etc/ufw/ufw.conf . ln -sf /etc/ufw/before.rules . ln -sf /etc/ufw/after.rules . ln -sf /lib/ufw/user.rules . # 提交初始版本 git add . && git commit -m "Initial UFW config for prod server"每次修改规则前,先git pull获取最新配置;修改后,git add . && git commit -m "Allow port 8080 for new app";最后git push。这样,每一次变更都有迹可循,回滚只需git checkout HEAD~1并sudo ufw reload。这不仅是技术实践,更是工程规范。
5.4 技巧四:性能监控与瓶颈识别(UFW 会影响服务器性能吗?)
这是个普遍担忧。答案是:在绝大多数场景下,UFW(即 iptables)的性能开销可以忽略不计。Linux 内核对 netfilter 的优化极为成熟,单核处理数万 PPS(包每秒)毫无压力。但有两个例外:
- 规则数量爆炸:如果你添加了上千条
ufw allow from x.x.x.x规则,iptables 的线性匹配会变慢。此时应改用ipset,将 IP 列表预编译为哈希表。 - 日志级别过高:
ufw logging high会为每个被拒绝的包写日志,磁盘 I/O 成为瓶颈。
监控方法:
# 查看 UFW 相关的 iptables 规则数量 sudo iptables -L INPUT | wc -l # 监控日志写入速率(每秒多少行) sudo tail -f /var/log/ufw.log | pv -lr > /dev/null # 检查 CPU 在 netfilter 上的占用(需安装 sysstat) sudo sar -n ALL 1 10 | grep -A5 "ip"在我的生产集群中,单台服务器承载 200+ 条 UFW 规则,CPU 在 netfilter 上的占用常年低于 0.1%,远低于 Nginx 或数据库的开销。
6. 个人经验总结:那些文档里不会写的“血泪教训”
最后,分享几个我在 Ubuntu 18.04 上配置 UFW 时,用真金白银(和无数个深夜)换来的体会。它们没有技术术语,但句句都是踩坑后的顿悟。
第一个教训:永远不要在ufw enable后立刻关闭 SSH 会话。我曾因一个ufw allow 22拼写成ufw allow 222,导致自己被锁在服务器外。后来我养成了一个铁律:ufw enable后,保持原会话至少 5 分钟,并在另一台设备上完成所有服务的连通性测试。这 5 分钟,是留给“万一”的缓冲带。
第二个教训:ufw status是个“谎言制造者”。它只显示 UFW 自己管理的规则,对iptables -I INPUT -j DROP这样的手动规则视而不见。有一次,客户服务器的网站打不开,ufw status显示一切正常,我花了 2 小时排查,最后发现是前任运维在before.rules里加了一条DROP规则,但忘了注释。从此,我的标准动作是:ufw status之后,必跟iptables -L INPUT,双保险。
第三个教训:Samba 的端口开放,是一场与 Windows 版本的博弈。Win7 及更早版本重度依赖 137-139,Win10+ 则主推 445。如果你的用户群体混杂,就必须四端口全开。但全开意味着更大的攻击面。我的妥协方案是:在ufw allow规则中,对 137-139 使用proto udp,对 139/445 使用proto tcp,并严格限定from子网。UDP 端口无法被 TCP 连接利用,这本身就是一层隔离。
第