为什么你做的网站,只有你自己能打开?

2024-08-05 Linux 运维

明明在自己电脑上能打开,发给别人却打不开——这是每个自建网站的新手都会遇到的灵魂拷问。

别慌,99% 的情况不是你的代码有问题,而是网络层面的几个小开关没打开。下面从最常见到最隐蔽,一步步排查。

1. 你绑定了 127.0.0.1,而不是 0.0.0.0

这是最最常见的坑。

# ❌ 这样写,只有本机才能访问
app.run(host='127.0.0.1', port=5000)

# ✅ 这样写,局域网内所有设备都能访问
app.run(host='0.0.0.0', port=5000)

127.0.0.1 是本地回环地址——相当于一扇门只朝向屋里,外面的人根本找不到。0.0.0.0 则监听所有网络接口,包括局域网 IP。

同理:

# ❌ 只监听 localhost
python -m http.server 8000

# ✅ 监听所有接口
python -m http.server 8000 --bind 0.0.0.0

验证方法

在本机用 localhost 和 局域网 IP 分别访问:

curl http://localhost:8000    # ✅ 应该正常
curl http://192.168.1.100:8000  # ❌ 如果连不上 → 绑定问题

如果能通过 localhost 访问但不能通过局域网 IP 访问,就是你绑定了 127.0.0.1。

2. 防火墙拦住了端口

即使你绑定了 0.0.0.0,系统防火墙可能默认拦截非授信端口。

Linux(iptables / firewalld)

# 查看防火墙状态
sudo systemctl status firewalld

# 放行指定端口(以 8000 为例)
sudo firewall-cmd --add-port=8000/tcp --permanent
sudo firewall-cmd --reload

# 或者临时关闭防火墙测试(注意安全!)
sudo systemctl stop firewalld

Linux(ufw)

sudo ufw allow 8000/tcp
sudo ufw reload

Windows 防火墙

控制面板 → Windows Defender 防火墙 → 高级设置 → 入站规则 → 新建规则 → 端口 → 输入你的端口号 → 允许连接。

验证方法

在本机用 nc 或 telnet 测试端口是否开放:

nc -zv 192.168.1.100 8000

如果本机能连上但外网连不上,说明问题出在更上层(路由器或 ISP)。

3. 路由器没做端口转发

你的服务器在局域网内(比如 IP 192.168.1.100),外部请求无法直接到达局域网内部。需要在路由器上设置 端口转发(Port Forwarding):

  1. 登录路由器管理后台(通常是 192.168.1.1 或 192.168.0.1)
  2. 找到「端口转发」或「虚拟服务器」选项
  3. 添加规则:
    • 外部端口:80(或你用的端口)
    • 内部 IP:你的服务器局域网 IP(如 192.168.1.100)
    • 内部端口:你的服务端口
    • 协议:TCP

⚠️ 运营商可能屏蔽 80/443 等常见端口,可以换成高位端口(如 8080、8443、30000+),配合域名解析使用。

验证方法

在局域网外(比如用手机 4G 断掉 Wi-Fi)访问 你的公网IP:端口。如果打不开,大概率是端口转发没生效。

4. 你没有公网 IP

家庭宽带默认使用 NAT(网络地址转换),多台设备共享一个公网 IP。查询你的公网 IP:

curl ifconfig.me

然后在局域网内访问 公网IP:端口:

  • 如果在局域网内能访问这个公网 IP → 你有公网 IP ✅
  • 如果打不开 → 你的 IP 可能是 CGNAT(运营商级 NAT),即多个用户共享一个公网 IP

确认是否 CGNAT

查看路由器 WAN 口 IP,和 ifconfig.me 获取的 IP 对比:

  • 一致 → 你有独立公网 IP ✅
  • 不一致 → 你处于 CGNAT 下 ❌

解决方案

  • 打电话给运营商要求改为公网 IP(通常可以免费申请,就说家里要装监控)
  • 或者使用 内网穿透(见下文第 6 点)

5. 运营商屏蔽了端口

电信、联通、移动会屏蔽家庭宽带的 80、443、25 等常用端口,防止私自搭建网站。

验证方法

尝试使用高位端口(50000+),如果高位端口可用而 80/443 不可用,就是被运营商屏蔽了。

解决方案:

  • 服务监听高位端口,通过 反向代理(Nginx/Caddy)将域名指向高位端口
  • 或者用 Cloudflare Tunnel(见下文)

6. 终极方案:内网穿透

如果没有公网 IP,或者不想折腾路由器,用内网穿透是最省心的方案。

frp(推荐)

在有公网 IP 的服务器上部署 frp 服务端,内网机器连接上去:

# frpc.ini(内网机器配置)
[common]
server_addr = 你的公网服务器IP
server_port = 7000

[web]
type = tcp
local_ip = 127.0.0.1
local_port = 8000
remote_port = 8000

Cloudflare Tunnel(免费且无需公网 IP)

# 安装 cloudflared
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64

# 登录并创建隧道
cloudflared tunnel login
cloudflared tunnel create my-tunnel

# 配置域名指向本地服务
cloudflared tunnel route dns my-tunnel your-domain.com

# 启动
cloudflared tunnel run my-tunnel

Ngrok(快速测试)

ngrok http 8000

会生成一个 https://xxx.ngrok.io 的临时域名,直接发给别人就能访问。适合快速演示。

7. 另外两个容易忽略的原因

排查到这里还是打不开,回头检查这两个「假故障」:

端口被别的程序占用了。 你以为服务起来了,其实端口被另一个进程占着(服务启动失败,或者跑到了别的端口上)。确认到底谁在监听:

sudo ss -tlnp | grep :8000

如果看到的进程不是你启动的那个,换一个端口,或者把占用端口的程序停掉。

浏览器缓存骗了你。 你看到的「能打开」可能是缓存的旧页面 —— 尤其在改过端口、改过绑定地址之后。用无痕窗口打开,或者干脆用手机流量网络再试一次,就能排除这一项。

8. 排查流程图

网站打不开
  │
  ├─ 本机能访问吗?
  │    ├─ 否 → 服务没启动 / 端口错了 / 绑定 127.0.0.1 ← 回第 1 点
  │    └─ 是
  │          │
  ├─ 同局域网能访问吗?
  │    ├─ 否 → 防火墙拦截 ← 回第 2 点
  │    └─ 是
  │          │
  ├─ 外网能访问吗?
  │    ├─ 否 → 有公网 IP 吗?
  │    │       ├─ 有 → 端口转发没配 / 运营商封端口 ← 回第 3、5 点
  │    │       └─ 无 → CGNAT / 内网穿透 ← 回第 4、6 点
  │    └─ 是 → 🎉 恭喜,网站已经正常对外服务了!

总结

问题 表现 解决
绑定 127.0.0.1 本机能访问,局域网内不能 改为 0.0.0.0
防火墙拦截 本机 telnet 不通端口 放行端口或关闭防火墙
未做端口转发 外网无法访问内网 IP 路由器设置端口转发
没有公网 IP 公网 IP 和路由器 WAN IP 不一致 申请公网 IP 或用内网穿透
运营商封端口 80/443 不通,高位端口可用 换高位端口 + 反向代理
端口被别的程序占用 服务启动失败,或访问到别的程序 sudo ss -tlnp \| grep :<端口> 查占用进程,换端口
浏览器缓存了旧页面 你以为能访问,别人访问不了 无痕窗口 / 换网络(如手机流量)再试

一句话总结:先确保绑定 0.0.0.0,再开防火墙,再做端口转发,没有公网 IP 就用内网穿透。按这个顺序走一遍,99% 的问题都能解决。