网站打不开?先别改代码——安全组与网络排查入门
一、先建立一个正确的排查顺序
一个请求从你的浏览器到服务器上的进程,要穿过三道关卡。任何一道没过,你都看不到页面。
你的浏览器
│
├─ ① 安全组 ────────── 云平台层,在服务器外面
│ 没放行 → 连接超时
│
├─ ② 系统防火墙 ────── 操作系统层,在服务器里面
│ 没放行 → 连接被拒绝
│
└─ ③ 服务监听地址 ──── 进程层,网卡绑在哪
只听 127.0.0.1 → 外部连不上
三层必须按顺序查,从外到内。 反过来查会浪费大量时间——你会反复改 Nginx 配置,而问题其实在安全组。
判断该从哪层入手,最有效的方法是看失败的具体表现:
| 浏览器表现 | 大概率卡在 |
|---|---|
| 转了十几秒,最后「无法访问此网站」/ 连接超时 | ① 安全组 |
| 立刻显示「连接被拒绝」 | ② 防火墙,或 ③ 服务没启动 |
服务器上 curl 127.0.0.1:80 正常,外部不行 |
① 或 ② |
服务器上 curl 127.0.0.1:80 正常,但 curl 内网IP:80 不行 |
③ 监听地址 |
这张表能省掉大部分瞎试。「超时」和「拒绝」是两种完全不同的信号:超时说明包被静默丢弃(安全组),拒绝说明包到了机器但被明确回绝(防火墙或没有进程监听)。
二、第一层:安全组
2.1 它是什么
安全组是云平台的虚拟防火墙,作用于实例的网卡,在操作系统之前生效。也就是说,即使你把服务器里的 firewalld 全关了,安全组不放行,外部一样进不来。
这是新手最容易忽略的一层,因为它是「云上的东西」,不在你登录后的那个系统里。
规则按方向分两类:
- 入方向:别人访问你。默认是拒绝的。
- 出方向:你访问别人。默认是允许的。
新建的云服务器,入方向通常是空的——意思是任何外部访问都不允许。所以刚装好的服务,除非你主动加规则,否则一定访问不了。
2.2 怎么加一条规则
两种入口,效果一样:
- 从实例进:ECS 控制台 → 点进实例 → 「安全组」标签页 → 配置规则
- 从 VPC 进:虚拟私有云控制台 → 访问控制 → 安全组 → 选中实例所属的安全组 → 入方向规则 → 添加规则
添加时要填四个字段:
| 字段 | 填什么 | 说明 |
|---|---|---|
| 优先级 | 1~100,数字越小越优先 | 没特殊要求就填 1 |
| 协议端口 | TCP + 80(或直接写 80) |
也可以写范围 8000-8010 |
| 源地址 | 0.0.0.0/0 |
表示允许所有 IPv4 来源 |
| 描述 | 自己看的备注,如「网站 HTTP」 | 以后回来看得懂 |
填完保存,规则立即生效,不需要重启服务器。
0.0.0.0/0 的含义是「任何来源」。对公开网站这是必要的,但要清楚它意味着整个互联网都能扫到这个端口。如果只是自己临时用,更安全的做法是填自己的公网 IP 加 /32,例如 1.2.3.4/32。
2.3 三个最容易错的地方
第一,ping 不通不等于服务器挂了。
ping 走的是 ICMP 协议,不是 TCP。安全组里如果没有 ICMP 规则,ping 一定不通,但网站在 80 端口上照样能访问。想验证网络通不通,别用 ping,直接测目标端口:
telnet 你的公网IP 80
# 或者
curl -I http://你的公网IP
第二,出方向规则不要随手删。
有人为了「安全」把出方向也设成拒绝,结果服务器连不上外网——apt install 装不了包、curl 拉不到东西、NTP 对不了时间,然后开始怀疑网络故障。出方向保持默认允许即可。
第三,注意 80 和 443 要分别放行。
只加了 443,用 http:// 访问依然不通。反过来只加 80,https:// 也不通。两个都要加。
2.4 快速验证是不是安全组的问题
用换端口法:把服务临时改到 8080 端口,安全组放行 8080,然后访问 http://IP:8080。
- 8080 能通、80 不通 → 说明 80 被挡了(安全组没放行,或者域名未备案被拦截)
- 两个都不通 → 说明问题不在端口,继续往下查防火墙和服务
这个方法的好处是不用改任何配置就能定位问题层次。
三、第二层:系统防火墙
安全组放行之后,包进到了机器里,接下来遇到的是操作系统自己的防火墙。
先看它到底开没开:
# CentOS / openEuler / 华为云 EulerOS
systemctl status firewalld
# Ubuntu / Debian
ufw status
firewalld 的临时与永久
这是最容易踩的坑。firewalld 有「运行时」和「永久」两套配置:
# 临时放行(立即生效,但 reload 或重启后消失)
firewall-cmd --add-port=80/tcp
# 永久放行(写进配置,需要 reload 才生效)
firewall-cmd --add-port=80/tcp --permanent
firewall-cmd --reload
# 查看当前生效的规则
firewall-cmd --list-all
只加 --permanent 不 reload,规则不会生效;只加临时规则不 --permanent,重启就丢。 两个坑都极其常见,表现都是「明明加了规则,还是不通」。
正确的做法永远是:--permanent + --reload 一起用。
ufw 的区别
ufw 简单一些,allow 就是永久的:
ufw status
ufw allow 80/tcp
ufw allow 443/tcp
改完立即生效,不用 reload。
一个务实的建议
如果你在排查阶段,可以临时关掉防火墙做验证,确认问题层次后再打开并精确放行:
systemctl stop firewalld # 临时停止,重启后会恢复
但不要长期关着。关防火墙相当于把第二层防线整个撤掉,只剩安全组一层。
四、第三层:服务本身
安全组通了、防火墙放行了,还是访问不了,那就剩最后一个可能:服务没有监听在对外网卡上。
4.1 127.0.0.1 和 0.0.0.0 的区别
这是新手最常撞的墙,而且它的表现很有欺骗性——在服务器上 curl localhost 完全正常,所以你不会怀疑服务。
# 只允许本机访问:外部永远连不上
listen 127.0.0.1:80;
# 监听所有网卡:外部可以访问
listen 80;
# 等价于 listen 0.0.0.0:80;
同样的坑在其他语言里也有:
| 语言/框架 | 默认监听 | 要改成 |
|---|---|---|
| Flask | app.run() → 127.0.0.1 |
app.run(host='0.0.0.0') |
| Django | runserver → 127.0.0.1 |
runserver 0.0.0.0:8000 |
| Node/Express | app.listen(3000) → 所有网卡 |
一般无需改 |
| Spring Boot | 默认所有网卡 | 一般无需改 |
判断方法就是看它到底听在哪。
4.2 一条命令看监听地址
ss -lntp | grep ':80'
输出大概是:
LISTEN 0 511 127.0.0.1:80 0.0.0.0:* users:(("nginx",pid=1234,fd=6))
重点看 Local Address 那一列:
127.0.0.1:80→ 只有本机能连,外部一定失败0.0.0.0:80→ 所有网卡都听,正常192.168.x.x:80→ 只听内网网卡,公网访问不了
如果这里没有输出,说明根本没有进程在监听这个端口,回到上一步确认服务是否真的启动了。
4.3 服务启动了却立刻退出
systemctl status 显示 active (running) 但几秒后变 failed,或者 activating 卡住,要看日志:
journalctl -u nginx -n 50 --no-pager
常见原因:端口被占用(Address already in use)、配置文件语法错误、证书文件路径不对导致启动失败。
查端口被谁占了:
ss -lntp | grep ':80'
# 或者
lsof -i :80
五、两个容易漏掉的前提
三层都排查过了还是不通,先别怀疑自己——有两件事在「三层」之外,但同样常见。
5.1 服务器根本没绑公网 IP
创建云服务器时如果没有勾选「分配弹性公网 IP」,这台机器就只有内网地址。你在控制台看到的那串 192.168.x.x 是内网 IP,在家里、在公司都访问不到——它只在同一个 VPC 内部有效。
判断方法很直接:打开实例列表,看「弹性公网 IP」这一列。空的就是没绑。
没绑也能补:在实例详情里绑定一个 EIP,或者在 VPC 控制台申请一个弹性公网 IP 再绑定到实例。绑完立刻可用,不用重启。
这里有个容易混淆的点:内网 IP 和公网 IP 是两套地址,服务只需要监听 0.0.0.0 就能同时接受两边访问,不需要为公网单独配置。
5.2 域名没备案,请求到不了服务器
如果你是用域名访问(而不是 IP),并且服务器在中国大陆,那么域名必须完成备案。没备案的域名,请求会在到达你的服务器之前就被拦掉。
这个现象特别好认:用 IP 访问正常,换成域名就超时。 因为 IP 直连不受备案约束,域名会。
遇到这种情况,不用再查安全组和防火墙了——问题在网络链路上游,跟你服务器里的任何配置都无关。备案的完整流程在另一篇里单独讲。
六、一张排查表
把上面三层压缩成一张表,下次遇到直接照着走:
| 现象 | 最可能的原因 | 一条命令验证 |
|---|---|---|
| 浏览器转圈后超时 | 安全组没放行 | telnet IP 端口 看是否超时 |
| 立刻「连接被拒绝」 | 防火墙拦了,或服务没起 | ss -lntp | grep :端口 |
| 本机 curl 通,外部不通 | 监听地址是 127.0.0.1 | ss -lntp | grep :端口 |
| 内网 IP 通,公网 IP 不通 | 没绑弹性公网 IP | 控制台看 EIP 列是否为空 |
| 加域名超时,用 IP 正常 | 域名未备案被拦 | 换 IP 访问看是否恢复 |
| 加了规则还是不通 | firewalld 少了 --reload |
firewall-cmd --list-all |
| ping 不通但网站能开 | 安全组没放 ICMP | 属正常现象,不用管 |
| 昨天能开今天不能 | 安全组被改 / 服务挂了 | systemctl status + 安全组规则 |
七、小结
排查这类问题,靠的不是经验,是顺序。
从外到内三层:安全组 → 系统防火墙 → 服务监听地址。每层都有明确的判断方法,而且失败表现本身就在告诉你卡在哪一层——超时是安全组,拒绝是防火墙或缺进程,本机通外部不通是监听地址。
新手最常犯的错,不是不会配,而是顺序反了:一上来就怀疑代码、反复改配置、重装服务,把时间花在根本没出问题的地方。
下次再遇到「打不开」,先别动代码。打开终端,敲那条 ss -lntp | grep :80。
- 点赞
- 收藏
- 关注作者
评论(0)