Skip to content

第 2 讲|服务器上公网

本机执行 curl http://127.0.0.1:8080 能正常返回,但换一台机器或换一个网络环境,同一个服务就连不上——这是第一次部署服务时几乎所有人都会遇到的场景。

根本原因是:服务在机器内部跑起来,与外部用户能访问到它,中间还隔着公网 IP、入口转发、端口监听、防火墙、安全组这一组关卡。任何一层断了,外部都无法访问。本讲依次讲清楚这些关卡,以及云上和机房环境的差异。

服务从本机可访问到公网可访问,中间要经过多层关卡

一、IP 地址类型:内网与公网

服务器通常有两种 IP 地址:内网地址公网地址。两者在网络可达范围、用途、计费方式上完全不同。

内网 IP 的固定网段

由 RFC 1918 规定,以下三个网段是私有 IP,只能在局域网/机房/云 VPC 内部使用,无法在公网路由:

网段范围可用地址数
10.0.0.0/810.0.0.0 ~ 10.255.255.255约 1677 万
172.16.0.0/12172.16.0.0 ~ 172.31.255.255约 105 万
192.168.0.0/16192.168.0.0 ~ 192.168.255.255约 6.5 万

看到 IP 是这三个网段开头的,基本可以判定是内网地址——同一 VPC/机房内的机器互通,但外部公网无法直接访问。

公网 IP

不属于上述三个私有网段的地址,统称为公网 IP——全世界唯一,理论上从任何能上网的位置都能访问。云服务器一般同时分配两种 IP:

  • 内网 IP — 用于同 VPC 内机器之间互通(应用连数据库、应用调用内部 API),无流量费、低延迟
  • 公网 IP — 用于接受外部用户的请求

生产环境的高频规范:应用服务器与数据库之间的通信必须走内网 IP,绝对不要走公网 IP。原因:

  • 延迟:内网通常 < 1ms,公网几十到几百毫秒
  • 流量费:云厂商对公网流量收费,内网免费
  • 安全:数据库走公网就意味着暴露公网接口,极大增加被攻击的可能

内网地址不能被公网直接路由,应用连数据库应走内网

云上公网 IP 的实现:EIP 与 NAT 映射

云上的公网 IP 不一定真正绑定在虚拟机的网卡上。两种常见实现:

实现方式特征典型云厂商
EIP(Elastic IP)公网 IP 是独立资源,可以挂载/卸载到 ECS 上AWS EIP、阿里云 EIP
直接绑定公网 IP 由云平台在出口做 NAT 映射,机器内 ip addr 只看到内网地址部分国内云厂商的"公网带宽"模式

第二种情况会让初学者困惑——ip addr 看不到公网 IP,但外部确实能通过公网 IP 访问。这是云平台在网关层做的 SNAT/DNAT 映射,对虚拟机内部透明。

验证一台云主机的公网 IP 实际工作方式:

bash
# 从外网角度看
curl -s https://api.ipify.org   # 这个公网 IP 是云平台映射后的

# 从机器内部看
ip addr                          # 可能只看到内网 IP

EIP 和公网带宽常由云网关层映射到虚拟机内网地址

二、机房环境与云上的概念对照

机房自建与云上部署在物理层面差异很大,但在抽象上是对应的:

机房组件云上对应资源职责
物理服务器ECS / CVM / 虚拟机实例计算资源
公网出口线路EIP / 弹性公网 IP公网入口
防火墙策略安全组 / 网络 ACL包过滤
内网网段 / VLANVPC / 子网网络隔离
入口负载均衡设备SLB / ALB / CLB流量分发
F5、A10 等专用硬件LB 服务高性能负载均衡

理解这种对应关系的好处:机房经验可以直接迁移到云上,云上学到的设计模式也能应用到机房。任何一层的故障定位思路都是通用的。

公网请求的标准路径

外部请求进入服务的标准链路:

公网用户

公网 IP (EIP)

安全组规则 (云防火墙)

VPC / 子网

负载均衡 SLB (可选)

ECS 虚拟机

主机防火墙 (iptables / firewalld)

服务进程 (监听端口)

每一层都可能成为访问失败的卡点,排查时基本就是顺着这条链路逐层确认。

三、NAT:SNAT 与 DNAT

NAT(Network Address Translation,网络地址转换)是支撑"内网与公网互通"的核心机制。两种典型用法:

SNAT:让内网机器主动访问公网

许多内网服务器虽然没有公网 IP,但 yum installdocker pullcurl https://api.github.com 这些访问外网的操作都能成功——背后是 SNAT(Source NAT,源地址转换)在工作。

机制:内网机器的请求出去时,被网关(或专门的 NAT 服务器)把源地址从内网 IP 替换成网关的公网 IP,这样目标服务器才能正确回包。回包到达网关后,网关查询转换表,反向把目标地址改回内网 IP,转交给真正发起请求的机器。整个过程对内网机器透明。

DNAT:让公网用户访问内网服务

外部用户访问没有公网 IP 的内网服务,用的是 DNAT(Destination NAT,目的地址转换)。

机制:公网 IP 的某个端口被映射到内网某台机器的端口上。例如负载均衡器拿到访问公网 80 端口的请求,转给内网 10.0.1.10:8080。这是端口转发(port forwarding)、负载均衡、Kubernetes Service 等机制的基础。

SNAT 与 DNAT 的记忆方法

缩写全称替换什么适用场景
SNATSource NAT源地址"内网主动访问外网"
DNATDestination NAT目的地址"外网访问内网服务"

记忆方法:S = Source,主动方向(我出去);D = Destination,被动方向(别人进来)。

SNAT 改源地址,DNAT 改目的地址

四、端口与监听

公网 IP 能 ping 通不代表服务能访问——还需要端口这一层正确配置。从外部请求到达应用进程,需要四个位置都对得上:

1. 应用进程:必须监听在正确的地址和端口上

最常见的坑:服务监听了 127.0.0.1:8080 而非 0.0.0.0:8080

127.0.0.10.0.0.0 的区别:

监听地址含义谁能访问
127.0.0.1:8080仅本机回环仅本机
0.0.0.0:8080所有网卡所有能访问该机器的 IP
192.168.1.10:8080特定网卡 IP仅能访问该 IP 的客户端

排查方式:

bash
ss -lntp | grep 8080
# 或
netstat -tlnp | grep 8080

如果输出显示 127.0.0.1:8080,即使防火墙完全打开,外部仍然无法访问——必须修改服务配置,把监听地址改为 0.0.0.0:8080 或具体的网卡 IP。

2. 主机防火墙

Linux 上的防火墙工具:

  • iptables(传统,主流)
  • firewalld(RHEL 系)
  • ufw(Ubuntu 简化前端)
  • nftables(新一代,替代 iptables)

任意一个工具阻拦了对应端口,外部都进不来。

3. 云安全组

云环境特有的一层——在云平台控制台配置的网络规则,作用于云内网络出入口,优先于主机内部的防火墙

云安全组没放行的端口,流量在云平台层面就被丢弃,根本到不了虚拟机。这种情况下:

  • 机器内的服务监听正常
  • 主机防火墙开放
  • 但外部访问仍然超时

诊断方法是用云控制台 VNC 登录机器从机器内部反向访问——如果机器内能访问、外部不能,基本就是安全组问题。

4. 入口转发

如果架构里有 Nginx、负载均衡器,要确认它们的转发配置指向正确的后端地址和端口。例如:

  • Nginx proxy_pass http://10.0.1.10:8080; — 后端地址写错会 502
  • 负载均衡的 backend 配置 — 健康检查端口和路径必须可访问

从外部请求到应用进程,安全组、防火墙、监听地址和转发端口都要对齐

五、按用户侧现象快速定位

把所有层串起来,根据用户看到的具体错误,可以快速定位故障层:

用户侧现象大概率卡在哪排查重点
域名报 NXDOMAINDNS域名解析记录、本地 DNS 缓存
浏览器一直转,最后超时公网入口或网络层公网 IP 可达性、安全组、防火墙、路由
立即返回 ERR_CONNECTION_REFUSED端口或服务服务进程是否启动、是否监听对外地址
能连上但返回 404路由Nginx 路由配置、后端路由表
返回 502入口到后端Nginx error log、后端实例健康状态
接口慢或返回 504后端处理后端应用日志、数据库慢查询

实际排查的标准命令组合

新部署服务无法外部访问,从外到内依次诊断:

bash
# 1. 从外部访问点(本地电脑或另一台云主机)
curl -v http://公网IP:80               # 看连接是否建立、是哪种错
nc -zv 公网IP 80                       # 单独测端口连通性

# 2. 从云内部访问(如同 VPC 的另一台机器)
curl -v http://内网IP:80               # 排除外网链路问题

# 3. 在目标机器本机访问
curl -v http://127.0.0.1:80            # 排除服务本身问题

# 4. 看服务监听情况
ss -lntp | grep ':80'                  # 是 0.0.0.0 还是 127.0.0.1?

# 5. 看主机防火墙
iptables -L INPUT -n -v                # 计数器看包是否被丢
firewall-cmd --list-all                # firewalld 规则

# 6. 看云控制台
# 安全组规则、网络 ACL、EIP 绑定状态

按这个顺序排查,前一步通了再继续向内:外部不通就先查安全组、内网通就排除外网链路、本机通就查防火墙、本机也不通就查服务本身。一步一步收敛范围,比"凭直觉判断在哪一层"高效得多。

六、生产环境的端口暴露原则

新机器投入使用前,对监听的端口做一次审查——所有不需要暴露的端口都收紧。

bash
# 看本机所有监听
ss -lntup

# 应该只暴露业务需要的端口,例如:
# - 22 (SSH,且只允许跳板机 IP)
# - 80/443 (业务)
# - 服务自身的端口(必要时仅监听内网)

常见错误示例:

服务错误做法正确做法
Redis监听 0.0.0.0:6379 无密码暴露公网监听内网 IP、设密码、安全组只放行应用 IP
MySQL监听 0.0.0.0:3306 直接对公网开放仅内网监听,运维通过堡垒机访问
应用调试端口测试用的 /debug 接口公网可访问生产环境禁用或限制访问来源
Docker daemon2375/tcp 暴露仅本地 socket、TLS 加密 + 客户端证书

公网无认证的 Redis、Elasticsearch、MongoDB、Docker daemon 是最常见的被入侵入口——这类服务被扫描器持续扫描,默认配置就能直接连进去。任何"无认证的服务"都必须严格限制访问来源,绝不能裸暴露到公网。

生产环境只开放必要端口,无认证服务不要裸暴露公网