CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Linux 服务器入门/课时/防火墙与端口
RawBlame
课时目录12 节

Linux 服务器入门

  1. 01Linux 是什么
  2. 02Shell 与 Bash
  3. 03文件系统与权限
  4. 04常用命令
  5. 05编辑器与配置
  6. 06进程与服务
  7. 07用户与 sudo
  8. 08包管理
  9. 09SSH 与密钥
  10. 10防火墙与端口
  11. 11部署 CodeRoadMap
  12. 12综合练习

防火墙与端口

ufw/firewalld、开放 80/443/8080。

25 分钟

防火墙与端口

这一课你将能做到

  1. 用 ss -tlnp 读懂监听状态,区分「对外监听 0.0.0.0」与「仅本机 127.0.0.1」,并找出是谁在监听哪个端口
  2. 用 ufw(Ubuntu)完成标准开门:放行 22/80/443、其余默认拒绝;会认 firewalld(RHEL)的等价命令
  3. 理解「双层门」:云安全组与系统防火墙的关系,并把 CodeRoadMap 配成「只暴露 80/443,Java/MySQL 绑 127.0.0.1」的标准拓扑

为什么要学

「服务器装了 MySQL,第二天就被人扫走勒索」——不是黑客厉害,是 3306 对全网敞开。同理,Spring Boot 直接监听 0.0.0.0:8080 且安全组放行,等于绕过 Nginx 把整个应用裸奔到公网:没有 HTTPS、没有限流、没有缓存、攻击面全开。

本课解决两件事:看清现状(ss:谁在监听、监听在哪个地址)和收紧入口(防火墙只开必需端口 + 应用只绑内网/回环)。这是 CodeRoadMap 上线前的最后一道工序,也是生产安全的第一课。

先建立图像

端口与监听:一扇扇门

IP + 端口 = 服务的门牌号。监听(LISTEN)= 门开着等人敲。

0.0.0.0:8080    ← 门开在「所有网卡」上:本机、内网、公网都能敲  ⚠️
127.0.0.1:3306  ← 门开在「回环」上:只有这台机器自己能敲  ✅
:::22           ← IPv6 的所有地址监听(配合 IPv4 则全网可连 SSH)

ss 输出解剖(看懂它 = 看懂全课)

ss -tlnp
# State  Recv-Q  Local Address:Port   Peer Address:Process
# LISTEN 0      511   0.0.0.0:80           0.0.0.0:*  users:(("nginx",pid=123,fd=6))
# LISTEN 0      4096  127.0.0.1:3306       0.0.0.0:*  users:(("mysqld",pid=456,fd=30))
# LISTEN 0      511         [::]:22        [::]:*     users:(("sshd",pid=789,fd=3))
#         │           │                  │          └ 谁在听(进程名+PID)→ 最有价值的列
#         │           │                  └ 远端 *(等任意来源连接)
#         │           └ 本地监听地址:端口 ← 判断 0.0.0.0 还是 127.0.0.1 的地方
#         └ t=TCP l=监听 n=数字端口 p=进程

CodeRoadMap 的标准端口拓扑(本课的目标态)

公网 → 安全组(只放 22/80/443) → ufw(同样只放 22/80/443)
        ├─ Nginx  0.0.0.0:80/443     ← 唯一的门面
        ├─ SSH    :22                ← 你的管理通道
        ├─ Node   127.0.0.1:3000     ← 内部服务,外人不许见
        ├─ JAR    127.0.0.1:8080     ← 同上
        └─ MySQL  127.0.0.1:3306     ← 绝不上公网

原则:对公网只开「门面」和「管理」,业务进程全部绑 127.0.0.1。即使防火墙配错,应用层还有一层兜底。

跟着做

步骤 1:摸清当前监听现状

ss -tlnp                      # 全部 TCP 监听 + 进程(本课第一命令)
ss -tlnp | grep -E ':(80|443|3000|8080|3306)\s'   # 只看本站关心的端口
ss -tnp                       # 已建立的连接(t=tcp n=数字 p=进程)
ss -s                         # 汇总:连接总数,粗看健康度
sudo ss -tlnp                 # 不加 sudo 看不到别的用户进程的 p 列,习惯加

验收问题(现在就能答):你的机器上哪些端口对全网开放(0.0.0.0/::)?哪些只在本机(127.0.0.1)?每个端口是谁?

步骤 2:ufw 标准四连(Ubuntu)

# 先放行 SSH 再 enable —— 顺序错了等于把自己锁在门外!
sudo ufw allow OpenSSH        # 或 sudo ufw allow 22/tcp
sudo ufw allow 80/tcp         # HTTP
sudo ufw allow 443/tcp        # HTTPS
sudo ufw enable               # 激活(此时问你 Command may disrupt... 输 y)
sudo ufw status verbose       # 验收:default deny (incoming),22/80/443 ALLOW

日常增删:

sudo ufw allow from 203.0.113.10 to any port 22 proto tcp   # SSH 只给公司出口 IP
sudo ufw deny 3306/tcp        # 明确拒绝数据库端口(双保险)
sudo ufw status numbered      # 带编号规则表
sudo ufw delete 3             # 删第 3 号规则(按编号表来)
sudo ufw insert 1 allow 443/tcp   # 插到最前(规则有顺序,命中即止)
sudo ufw disable              # 全关(排障时临时用,用完记得 enable)

步骤 3:firewalld 对照(RHEL/Rocky/CentOS 会认)

# Rocky/Alma 上的等价操作:
sudo firewall-cmd --state
sudo firewall-cmd --permanent --add-service=ssh      # ≈ ufw allow OpenSSH
sudo firewall-cmd --permanent --add-service=http     # 80
sudo firewall-cmd --permanent --add-service=https    # 443
sudo firewall-cmd --permanent --remove-service=mysql # 拒 3306
sudo firewall-cmd --reload                           # ≈ ufw enable 的生效动作
sudo firewall-cmd --list-all                         # ≈ ufw status verbose
动作Ubuntu ufwRHEL firewalld
看状态/规则ufw status verbosefirewall-cmd --list-all
放行端口ufw allow 443/tcpfirewall-cmd --permanent --add-port=443/tcp
拒绝端口ufw deny 3306/tcp--remove-port / 默认拒绝
生效规则即时生效--permanent 后必须 --reload

两套底层都是内核的 netfilter(iptables/nftables),ufw/firewalld 只是「好用的外壳」。

步骤 4:双层门——云安全组与系统防火墙

互联网 → [云安全组] → [系统防火墙 ufw/firewalld] → [应用监听地址]
  第一道:云控制台配置,实例外拦截         第二道:OS 内拦截

排障口诀:连接不通先问两遍——安全组放了吗(云控制台)?ufw 放了吗(status)?应用绑的是 0.0.0.0 吗(ss -tlnp)?三关都过才通。

动手验证「双层」的存在:在云控制台安全组临时放行 8080,但不放 ufw——curl 公网IP:8080 依然不通,因为第二道门没开;反之亦然。两层是「与」的关系。

步骤 5:把 Java/前端绑到 127.0.0.1(应用层收口)

防火墙之外,应用监听地址是最后一道兜底。Spring Boot:

# /www/wwwroot/coderoadmap/application-prod.yml 里:
#   server:
#     address: 127.0.0.1     ← 关键行,只听回环
#     port: 8080
sudo systemctl restart coderoadmap-backend
sudo ss -tlnp | grep 8080      # 期望:127.0.0.1:8080(不再是 0.0.0.0 或 *:8080)

Node(Next.js):

# package.json 的 start 脚本加 -H 0.0.0.0 反而错——本机只有 Nginx 反代访问它,绑回环即可:
#   "start": "next start -H 127.0.0.1 -p 3000"
pm2 restart platform 2>/dev/null || sudo systemctl restart platform
sudo ss -tlnp | grep 3000      # 期望:127.0.0.1:3000

MySQL:

sudo grep -n "bind-address" /etc/mysql/mysql.conf.d/mysqld.cnf
# Ubuntu 默认已是 127.0.0.1;若是 0.0.0.0 改回并重启:
# sudo systemctl restart mysql

步骤 6:端到端验收(上线前检查单)

# ① 门面要通:
curl -I http://你的服务器IP        # 期望 200/301(Nginx 应答)
# ② 内部端口公网不可达(关键!):
curl -m 3 http://你的服务器IP:8080  # 期望:连接超时/拒绝 —— 不通才对
curl -m 3 http://你的服务器IP:3306  # 同上
# ③ 本机回环可达(Nginx 反代的依赖):
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8080/actuator/health
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:3000/
# ④ 规则表终审:
sudo ufw status verbose

「② 不通 + ③ 通」同时成立,才叫配置正确。

讲清楚要点

  1. 监听地址是比防火墙更内层的防线:0.0.0.0:8080 即使被防火墙挡住,也只是「门锁着窗没关」的运气;127.0.0.1:8080 是窗根本不存在。生产三件套:绑回环 + 防火墙默认拒 + 安全组白名单。
  2. 默认拒绝是防火墙的正确姿势:ufw enable 后默认 incoming deny,只 allow 白名单。「默认允许,见一个堵一个」永远堵不完(Redis 未授权、新开的调试端口都在赌你没堵)。
  3. 规则有顺序,命中即止:ufw 里 insert 进前面的规则先生效。典型的「先 deny 再 allow」逻辑(先拒绝网段、再放行某 IP)必须用编号确认顺序。
  4. SSH 规则必须先于 enable:ufw enable 的瞬间按现有规则接管流量,没放 22 你就把自己锁外面了。云控制台 VNC 是最后的救援通道,但别指望它。
  5. 安全组 ≠ 系统防火墙:两者独立生效、取交集。迁移服务器/换镜像时最容易漏的就是只配了一层。排障时按「外层到内层」顺序过。
  6. 对外暴露的每个端口都要有「存在理由」:443 因为要 HTTPS、22 因为要管理(最好限源 IP)、80 通常只为跳转 443。除此之外出现任何 0.0.0.0 监听,都该问一句「谁开的?为什么?能不能绑回环?」

你可能会懵的地方

  • 127.0.0.1 和 0.0.0.0 到底是「谁的地址」? 它们是服务器自己的监听绑定地址,不是客户端的。0.0.0.0=「监听本机所有网卡」(接受任何来源);127.0.0.1=「只监听回环接口」(物理上只有本机进程能连)。浏览器里访问自己的公网 IP 能通不代表绑对了——从外部机器 curl 才算数。
  • ufw enable 之后 SSH 断了怎么办? 立即走云控制台 VNC/救援登录,sudo ufw disable 或补 ufw allow 22/tcp。预防:enable 前先 allow OpenSSH;改动防火墙时保持一条已连接的 SSH 会话不退出(本课与 SSH 课的双重保命规则)。
  • 3306 绑了 127.0.0.1,远程开发机想连数据库怎么办? 三条路按优先级:① SSH 隧道(ssh -L 13306:127.0.0.1:3306 prod,本机连 localhost:13306)——最安全;② 专用堡垒/跳板机;③ 实在要直连:云安全组+ufw 限源 IP + MySQL 专用账户限 host,三者齐备且经评审。永远不要 0.0.0.0 + 弱密码。
  • TIME_WAIT 一大堆是故障吗? 不是。TIME_WAIT 是主动关闭方等待迟到的包,60 秒后消失,高并发短连接下量大属正常。要优化的是「让连接复用」(应用层连接池、Nginx upstream keepalive),而不是去「杀」TIME_WAIT。
  • iptables 还要学吗? ufw/firewalld 的底层。除非做容器网络(Docker 的端口映射就是 iptables 规则)或需要复杂转发,日常服务器管理用外壳即可。知道 sudo iptables -L -n 能看到底层规则、Docker 会绕过 ufw 直接插规则(暴露容器端口时安全组要单独确认)就够本阶段用。

错法对照

错法问题正解
ufw enable 前没放 SSH全机失联先 allow OpenSSH 再 enable;改规则时留已连会话
「临时测试」放行 3306/6379/8080 到公网忘了收回去 = 数据库裸奔临时规则用完即删:ufw status numbered 定期审
Java 监听 0.0.0.0 依赖安全组兜底换机器/改安全组就裸奔,Nginx 被绕过server.address=127.0.0.1 应用层先收口
只配安全组不配 ufw(或反之)迁移/重装后防线归零双层都配,验收用公网 curl 实测
防火墙问题第一反应 disable 排障全网敞开,且忘 enable逐条 status 定位;临时 disable 用完立刻回滚
用 telnet 判断端口「通不通」就下结论通只代表 TCP 层,不代表服务健康curl 带路径验业务(actuator/health),分层判断

卡点急救

  1. 公网 curl :80 全部超时:顺序过三关——云安全组 80 放行了吗?ufw status 有 80 allow 吗?ss -tlnp | grep :80 Nginx 在监听且是 0.0.0.0 吗?哪关缺补哪关。
  2. 本机 curl 127.0.0.1:8080 通、公网 8080 不通,但希望它通:先反问自己「真的需要它通吗」——90% 情况正确做法是配 Nginx 反代而不是暴露 8080。确需直连:改 server.address + ufw allow + 安全组,三步一起动。
  3. 「连接被拒绝」和「连接超时」要区分:refused=包到了但没人听(端口没监听/服务没起);timeout=包在路上被丢(安全组/防火墙拦截、IP 错、网络不通)。refused 查服务,timeout 查防火墙——一句话定位大方向。
  4. ufw 规则改乱了想重来:sudo ufw reset 清空全部规则回到默认,然后按「先 SSH → 80/443 → enable」顺序重来(reset 会自动 disable,正好是个干净的起点)。
  5. Docker 容器端口绕过了 ufw:-p 6379:6379 直接插 iptables 规则,ufw 拦不住。容器对外暴露一律走安全组限制源 IP;或让容器只绑 127.0.0.1(-p 127.0.0.1:6379:6379)再由 Nginx 反代。

面试常问

  • 如何查看服务器上哪些端口对外监听? sudo ss -tlnp(现代工具)或老机器 netstat -tlnp。重点看 Local Address:Port 列:0.0.0.0/::=全网可达需审查,127.0.0.1=仅本机安全。p 列给出进程,配合 ps 确认业务归属。公网视角再用外部机器 curl 交叉验证防火墙与安全组。

  • 0.0.0.0 和 127.0.0.1 监听的区别?Spring Boot 怎么只绑本机? 0.0.0.0 监听所有网卡、接受任何来源(含公网);127.0.0.1 只监听回环、仅本机进程可达。Spring Boot:server.address=127.0.0.1(yml)或启动参数 --server.address=127.0.0.1。生产模式:应用绑回环 + Nginx 443 反代。

  • 云安全组和系统防火墙的关系? 两个独立生效的过滤器,流量需依次通过(取交集):安全组在虚拟化层(实例外,云控制台配),防火墙在 OS 内(ufw/firewalld 配)。任一层没放行就不通。正确配置是两层同时收敛到同一份白名单,避免「单层裸奔」。

  • 数据库端口能不能对公网开放?为什么? 默认不能。MySQL/Redis 历史上大量未授权访问与勒索事件(Redis 尤甚)。必须开放时(跨机内网调用):走 VPC 内网、安全组限源 IP、数据库专用账号限 host、启用 TLS/强密码,并配审计。公网直连数据库属于架构 smell——正确方向是内网互通或 API 收口。

  • 一台机器突然 CPU/内存异常,怀疑被入侵,怎么查? 联动本 track 多课:ss -tnp 看异常外连(对外挖矿端口);ps aux 按 CPU 找陌生进程,ls -l /proc/PID/exe 定位文件路径;last、grep Accepted /var/log/auth.log 查异常登录;crontab -l 与 /etc/cron* 查持久化后门。防再犯:密钥登录+禁密码、防火墙默认拒、最小权限(这些正是前面各课的拼图)。

自测三问

  1. ss -tlnp 输出里 127.0.0.1:3306 与 0.0.0.0:8080 分别意味着什么?哪个需要整改?
  2. 服务器迁移后站点打不开,写出按「安全组 → ufw → 应用监听 → 服务状态」排查的命令序列。
  3. 开发机需要连服务器的 MySQL 调试数据,给出最安全的一条路径并写出命令。

小结一句话

防火墙的目标态一句话:公网只开 22/80/443,业务与数据端口全部绑 127.0.0.1,安全组与 ufw 双层同源白名单——ss -tlnp 是你的眼睛,curl 实测是你的验收,默认拒绝是你的信仰。

延伸

  • Ubuntu 官方 — Firewall (ufw)
  • firewalld 官方文档
  • 下一课预告:部署 CodeRoadMap——零件齐了:Shell、权限、systemd、SSH、防火墙。本课把它们组装成一台真正能访问的站点:目录规范 → 上传产物 → 双服务启动 → Nginx 反代 → 全链路验收。
加载本节练习…
← 上一课SSH 与密钥下一课 →部署 CodeRoadMap