🌐 第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 都要,漏掉 UDP 21116 会连不上。

验证防火墙实际效果

配置完要验证,别只看配置文件:

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。