Appearance
服务器上公网
本机打开 http://127.0.0.1:8080 能跑,换个网络环境或者别人电脑就连不上——这个问题困扰过每一个第一次部署服务的人。原因其实就一句话:程序跑起来不等于外部能访问,中间还隔着公网地址、入口转发、端口监听、防火墙、安全组这一堆关卡,任何一层断了外部都进不来。
一、IP 地址类型
服务器一般有两种 IP:内网的和公网的。内网地址有几个固定网段,10.x.x.x、172.16.x.x、192.168.x.x——只要看到这三个开头,基本就是内网地址,只能在公司网络、机房或者云的 VPC 内部用,出了这个范围连不上。
公网地址就不一样了,全世界唯一、谁都能访问。云服务器一般两种都给:内网 IP 用于同 VPC 内机器互通(比如应用连数据库走内网,快又省钱),公网 IP 用于接外部用户的请求。
这里有个容易绕的细节:有些云厂商(尤其是国内厂商)的公网 IP 不是真的绑在网卡上,而是在云网络里做了一层映射。所以你 ip addr 看到的是内网地址,但外部访问公网 IP 流量能进来——中间这层映射是云平台在出口做的。在阿里云、华为云这种厂商上挺常见,AWS 那种弹性公网 IP(EIP)则是另一种实现,但用户侧看起来都差不多。
二、公网入口组件
如果是机房自建,公网入口通常是这么一条链路:运营商拉过来的光纤 → 防火墙 → 核心交换机 → 负载均衡设备 → 内网服务器。每一段都要配,任何一段断了服务就废了。
云上把这些物理设备都抽象成了控制台资源,概念对照大概是:
| 机房里叫什么 | 云上叫什么 |
|---|---|
| 物理服务器 | ECS、CVM、虚拟机 |
| 公网出口线路 | 弹性公网 IP、EIP |
| 防火墙策略 | 安全组、网络 ACL |
| 内网网段和 VLAN | VPC、子网 |
| 入口负载均衡设备 | SLB、ALB、CLB |
外部请求进来大概的路径是:先到公网 IP → 过安全组规则 → 进 VPC → 到负载均衡或者直接到机器 → 最终到跑服务的进程或容器。每一步都可能成为访问失败的卡点,排查时基本就是顺着这条链路找。
三、NAT
有个反直觉的现象:很多内网服务器明明没有公网 IP,但 yum install、docker pull、curl https://api.github.com 这些访问外网的操作都能成功。原因是出口做了 SNAT——内部机器的请求出去时,被网关把源地址从内网 IP 替换成了一台带公网 IP 的设备的地址,这样外部就能回包,回来之后再做反向替换转给真正发起请求的机器。整个过程对内网机器透明。
反过来,如果外部要访问一个没公网 IP 的内网服务,用的是 DNAT——公网 IP 的某个端口被映射到内网某台机器的端口上。比如负载均衡器拿到公网 80 端口的请求,转给内网 10.0.1.10:8080,这就是 DNAT 的一种典型应用。
记忆方法也简单:SNAT 是 Source(源地址)被替换,所以是"我主动出访"的场景;DNAT 是 Destination(目标地址)被替换,所以是"别人来访问我"的场景。
四、端口与监听
公网 IP 能 ping 通不代表服务能访问——还得看端口这一层。一个请求能从外部打到应用进程,要在四个位置都对得上:
- 应用进程:必须监听在正确的地址和端口上。比如
0.0.0.0:8080表示监听所有网卡的 8080;如果只监听127.0.0.1:8080,那就只有本机能连,外部永远进不来 - 主机防火墙:Linux 上的 iptables、firewalld、ufw 这些,要把对应端口放进来
- 云安全组:云控制台里的安全组规则,必须显式放行来源 IP 段和端口——这条忘了的话,机器里端口监听正常、防火墙也开了,但外部还是连不上,因为流量在云网络那一层就被丢了
- 入口转发:如果前面挂着 Nginx 或者负载均衡,要确认它的转发配置指向了正确的后端地址和端口
127.0.0.1 vs 0.0.0.0 这个坑非常常见。本地 curl 127.0.0.1:8080 能通,部署上去外部访问就不行——十有八九是服务只监听了 127.0.0.1。netstat -tlnp | grep 8080 看一眼,如果显示 127.0.0.1:8080 就是这个问题,改成 0.0.0.0:8080 重启就好。
五、访问链路
把前面的层都串起来,用户从浏览器访问一个域名到最终拿到响应,经过的链路大概是:
排查"用户访问不了"这种问题,根据用户侧看到的现象,基本能定位到链路的哪一段:
| 用户侧现象 | 大概率卡在哪 |
|---|---|
域名报 NXDOMAIN | DNS 记录没配或者过期,问题在域名这一层 |
| 浏览器一直转、最后超时 | 公网 IP 不通、路由问题、安全组没放行、防火墙拦了 |
立即返回连接被拒绝(ERR_CONNECTION_REFUSED) | 端口没监听、服务没起来 |
能连上但返回 404 | 路径没匹配上,问题在 Nginx 路由或者后端接口 |
返回 502 | 入口连不上后端,问题在 Nginx 到应用这一段 |
记住这张表的好处是:用户给你一个截图或者一句描述,你大致就知道该往哪一层查,不用一上来就 ssh 进机器瞎翻日志。这也是为什么前面要把每一层都拆开讲——不是为了背概念,是为了排查的时候能精准定位。