🌐 第03章 · 防火墙 ufw / iptables
开放/封禁端口、本服务器端口规划
防火墙 ufw / iptables¶
防火墙决定"哪些口放行、哪些口拦截"。ufw 是 Ubuntu 默认的简化封装,背后干活的是 iptables(或它在 Ubuntu 24.04 上的继任者 nftables)。这一章先讲 ufw 怎么用、本机端口怎么规划,再讲 iptables 规则长什么样。
ufw 基本操作¶
ufw 是一个三层命令状态:未启用(inactive)→ 启用(active)→ 增删规则。启用前务必先允许 SSH,否则可能把自己关在门外。
ufw status # 查看当前状态(inactive/active)
ufw status verbose # 查看规则详情
ufw allow 22 # 允许 22 端口(排障/第一次操作时先做这一步!)
ufw allow 80 # 允许 HTTP
ufw allow 443 # 允许 HTTPS
ufw default deny incoming # 默认拒绝所有入站
ufw default allow outgoing # 默认允许所有出站
ufw enable # 真正启用防火墙
警告
ufw enable会立刻生效。如果先执行了enable再配规则,一旦忘了 allow 22,SSH 连接立刻断掉,只能等云商控制台(VNC/救援)或公网入口去救。正确顺序:先allow 22,再default deny incoming,最后enable。
本机端口规划¶
这套服务器上哪些端口该对外、哪些只能回环访问,规划清晰才能安全。下面是一张参考表(端口与真实监听对应):
| 端口 | 服务 | 监听地址 | 是否对外放行 | 说明 |
|---|---|---|---|---|
| 22 | SSH | 0.0.0.0 |
放行 | 远程管理,建议白名单 IP |
| 80 / 443 | nginx | 0.0.0.0 |
放行 | 对外网站 |
| 3000 / 3010 | Node 应用 | * |
按需 | 若可由 nginx 反代,建议不放行公网 |
| 8090 | GitLab 反代 | 0.0.0.0 |
放行 | GitLab 入口 |
| 9090 / 9100 | Prometheus | * |
按需 | 监控面板,强烈建议只放行运维 IP |
| 21115–21119 | RustDesk | * |
放行 | 远程桌面,注意 21116 需 TCP+UDP |
| 3306 | MySQL | 127.0.0.1 |
不放行 | 只允许本机应用连接 |
| 10086 | Xray | 127.0.0.1 |
不放行 | 由 nginx 反代对外,应用层不露 |
| 3081 | dsh | 127.0.0.1 |
不放行 | 内部服务 |
核心原则 对外只暴露必须的端口;数据库、代理、内部服务一律绑回环。绑
127.0.0.1是防火墙之外更硬的一道边界——它让外部连进来都做不到。
按 IP 精确放行¶
ufw 可以更精细:只允许指定来源 IP、指定端口区间。
ufw allow from 1.2.3.4 to any port 22 # 只允许固定 IP 访问 SSH
ufw allow from 192.168.0.0/24 to any port 22 # 只允许某网段访问
ufw allow 9090/tcp # 只放行 TCP 的 9090(默认 TCP)
ufw allow 21116/tcp # RustDesk 21116 同时要 TCP+UDP(看下一行)
ufw allow 21116/udp # RustDesk 21116 的 UDP 部分
ufw delete allow 9090/tcp # 删除一条规则
ufw deny 3389 # 明确拒绝某端口
ufw reload # 修改规则后重载
易错点
ufw allow 9090默认只放行 TCP;要给 UDP 通通行,必须显式写/udp。RustDesk 的21116就是 TCP 和 UDP 都要,漏掉 UDP21116会连不上。
验证防火墙实际效果¶
配置完要验证,别只看配置文件:
ufw status verbose # 确认规则在
ss -tlnp | grep 22 # 确认端口在用
nc -zv 127.0.0.1 3000 # 本机测试
curl https://bangdream.xyz # 应用层验证
iptables 概念与规则结构¶
ufw 只是前端,真正干活的是 iptables(Ubuntu 24.04 底层是 nftables,很多系统 iptables 命令已变成兼容包装)。理解 iptables,才能看懂防火墙的本质。
iptables 以表和链为骨架,核心是 filter 表,里面有三个链:
| 链 | 作用 | 典型规则 |
|---|---|---|
| INPUT | 进入本机的包 | 允许 22、拒绝陌生端口 |
| OUTPUT | 本机发出的包 | 允许出站 |
| FORWARD | 经过本机转发的包 | 路由器场景才用 |
一条规则的语法结构:
iptables -A <链> 在链末尾追加
-p <协议> tcp / udp
--dport <端口>
-s <来源IP> 源地址
-j <动作> ACCEPT / DROP / REJECT
常用操作:
iptables -L -n -v # 列出全部规则(-n 数字,-v 详细)
iptables -A INPUT -p tcp --dport 22 -j ACCEPT # 允许 SSH
iptables -A INPUT -p tcp --dport 3306 -j DROP # 丢 MySQL 入站
iptables -A INPUT -s 1.2.3.4 -j DROP # 丢某 IP 所有入站
iptables -D INPUT -p tcp --dport 22 -j ACCEPT # 删除一条
iptables -F # ⚠️ 清空所有规则(危险!)
警告
iptables -F会清空 filter 表全部规则,默认策略通常是允许,清空后等于"完全裸奔"——所有外网都连得进来。千万别在远程生产上随手执行;若真清空了,ufw状态也会被破坏,需重新ufw disable+ufw enable恢复。
REJECT 与 DROP 的区别¶
| 动作 | 行为 | 主动端感受 | 适用 |
|---|---|---|---|
REJECT |
主动返回拒绝包 | 立刻报 connection refused,快 |
明确不让访问,快速暴露 |
DROP |
直接丢弃,不回应 | 客户端一直等,timeout |
想隐藏端口存在,或对扫描者装"不存在" |
易错点 想快速定位问题用
REJECT,想让端口"看起来不存在"用DROP。但这两种都属于iptables底层动作;日常用ufw更省心,别直接上手iptables写规则,除非能精确控制,否则极容易把自己封死。
易错点¶
- 先 allow SSH 再 enable:顺序颠倒 = 远程失联。
allow 9090不带/tcp默认只放 TCP,要allow 9090/udp才放 UDP。iptables -F清空 = 裸奔,远程慎用。ufw规则与云安全组是两层,都要配齐(见第 8 章),只配一层会误判"为什么还是不通"。- 默认策略 vs 规则:
ufw default deny incoming之后,新端口必须显式 allow 才放行,别以为"我开了服务就自动能访问"。
相关命令¶
ufw、iptables、nftables、ss、nc、curl。配置文件:/etc/ufw/rules(ufw 生成的规则)、/etc/ufw/sysctl.conf。