技术工作里有个高频对话:
「网站打不开了,是不是网络挂了?」 「我这边 ping 通的啊。」 「我 telnet 端口也不通…」 「……」
每次这种对话,背后都是一套排查链路:DNS → 路由 → 防火墙 → 监听 → 应用。任意一环出问题表现都可能是「访问不到」,但用的命令、看的指标完全不同。
这一篇按真实排查流程串一遍 IP / 端口 / 防火墙,从 ping 不通讲到 iptables / nftables 一份完整 ruleset。新人学完能独立处理 80% 的"网络不通"场景。
一、心智模型:访问链路的 5 个关卡
浏览器 / 客户端 │ ├─ ① DNS 解析:域名 → IP │ 工具:dig / nslookup / cat /etc/resolv.conf │ ├─ ② 三层联通:本机 → 目标 IP │ 工具:ping / traceroute / mtr │ ├─ ③ 四层联通:本机 → 目标 IP:端口 │ 工具:telnet / nc / curl │ ├─ ④ 服务端防火墙:包能不能进到应用 │ 工具:iptables-save / nft list ruleset / ufw status │ ├─ ⑤ 应用监听:端口是不是真的在听 │ 工具:ss -lntp / netstat -lntp │ └─ ⑥ 应用本身:能不能正确处理请求 工具:tail -f 应用日志
新人最常犯的错:跳过前面几关直接怀疑应用挂了。正确顺序是从 ① 往下排,每一关都验证一下,省得回头又怀疑。
二、IP 与子网:CIDR 一句话讲明白
IP 地址 192.168.1.10/24 里的 /24 是什么?
- 32 位 IPv4 中,前 24 位是网络位、后 8 位是主机位
/24 等价于子网掩码 255.255.255.0,能容纳 2^8 - 2 = 254 台主机(首尾两个保留)
常见 CIDR 速查:
必背的特殊地址段
127.0.0.0/8 回环(127.0.0.1 是 localhost)10.0.0.0/8 私网 A 段(云上 VPC 常用)172.16.0.0/12 私网 B 段(Docker 默认 bridge 在 172.17.x)192.168.0.0/16 私网 C 段(家庭路由 / 小办公网)169.254.0.0/16 链路本地(DHCP 失败时自分配,云上元数据 169.254.169.254)0.0.0.0/0 "任意 IP",防火墙规则里常出现
新人易混点:
0.0.0.0:作为源 IP 表示"未指定";作为监听 表示"所有接口";作为防火墙规则 表示"任意源"127.0.0.1 vs 0.0.0.0:监听 127.0.0.1 只接受本机访问,监听 0.0.0.0 接受所有网卡访问。应用配错经常导致"本机能访问、外部访问不到"
三、看本机网络:ip 命令族
ifconfig / route / arp 这些老命令在多数现代发行版已经不预装了,统一用 ip 命令:
# 看所有网卡 + IPip addrip a # 简写# 1: lo: <LOOPBACK,UP,LOWER_UP> ...# inet 127.0.0.1/8 scope host lo# 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> ...# inet 10.0.0.5/24 brd 10.0.0.255 scope global eth0# 看路由表ip routeip r# default via 10.0.0.1 dev eth0 proto dhcp# 10.0.0.0/24 dev eth0 proto kernel scope link src 10.0.0.5# 看 ARP 缓存ip neighip n# 10.0.0.1 dev eth0 lladdr 00:50:56:01:23:45 REACHABLE# 临时给网卡加 IP(重启失效)sudo ip addr add 10.0.0.99/24 dev eth0# 加路由sudo ip route add 192.168.10.0/24 via 10.0.0.254
新旧命令对照表:
| |
|---|
ifconfig | ip addr |
route -n | ip route |
arp -a | ip neigh |
netstat -lntp | ss -lntp |
netstat -rn | ip route |
新机器上永远用 ip / ss,老命令在 Alpine / 最新 Ubuntu 上可能根本没装。
四、端口:TCP / UDP 与监听
端口分类
0-1023 Well-known,特权端口(**绑定需要 root**) 80 http / 443 https / 22 ssh / 53 dns / 25 smtp1024-49151 Registered,注册端口 3306 mysql / 6379 redis / 5432 postgres / 8080 http-alt49152-65535 Dynamic,动态端口(客户端连接时内核自动分配)
新人常见误区:
- “我把应用配在 80 端口跑不起来” → 不是 root 用户绑不上 1024 以下端口(解决:用 systemd 的
AmbientCapabilities=CAP_NET_BIND_SERVICE,或者用 8080+ 用户端口) - “客户端口号一直是 49152+” → 内核
ip_local_port_range 控制,可调 1024-65535
TCP 和 UDP 一句话区别
- TCP:有连接、有顺序、有重传、慢但可靠 —— HTTP / SSH / 数据库
- UDP:无连接、不保证顺序、不重传、快 —— DNS 查询 / 视频流 / QUIC(HTTP/3)
看本机监听了什么
ss -lntp# Netid State Local Address:Port Peer Address:Port Process# tcp LISTEN 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1234,fd=6))# tcp LISTEN 127.0.0.1:5432 0.0.0.0:* users:(("postgres",pid=5678,fd=4))# tcp LISTEN 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=999,fd=3))# 参数含义# -l listening 只看监听# -n 不解析为服务名(数字显示)# -t TCP# -u UDP(看 UDP 加这个)# -p 显示进程# 看活跃的 TCP 连接ss -tnp# 看连接数ss -tan state established | wc -lss -tan state time-wait | wc -l
新人最最最高频问题:「我的 mysql 远程连不上」→ 多半是 bind-address = 127.0.0.1,只监听本机回环。ss -lntp | grep mysql 一眼看出来。
五、防火墙现状:四个工具一张表
这是 Linux 防火墙世界让新人最头大的地方——同一件事有四套工具:
| | | | |
|---|
iptables | | | | |
nftables | Ubuntu 22+ / CentOS 8+ 默认 | | | /etc/nftables.conf |
firewalld | | | | |
ufw | | 最低 | | |
新人应该用哪个:
- Ubuntu / Debian →
ufw(最省心) - CentOS / RHEL / Rocky →
firewalld - 需要精细控制或自动化 →
nft(写 ruleset 文件) - 不要再裸写 iptables 规则
六、ufw 实战(Ubuntu 新人首选)
# 看状态sudo ufw status verbose# Status: inactive (表示还没启用)# 默认策略sudo ufw default deny incoming # 默认拒绝入流量sudo ufw default allow outgoing # 默认允许出流量# 放行常用服务(用名字,自动从 /etc/services 查端口)sudo ufw allow ssh # 等价 allow 22/tcpsudo ufw allow http # 80/tcpsudo ufw allow https # 443/tcp# 按端口sudo ufw allow 8080/tcpsudo ufw allow 53 # tcp + udp 都开(DNS 用)# 限定源 IP(只允许办公网访问 SSH)sudo ufw allow from 10.0.0.0/24 to any port 22# 启用sudo ufw enable# 第一次启用会警告:要确认 SSH 规则已放行,不然敲完 enable 会立刻被踢出去# 删规则sudo ufw status numbered# [ 1] 22/tcp ALLOW IN Anywhere# [ 2] 80/tcp ALLOW IN Anywheresudo ufw delete 2
ufw 新人铁律:
- 启用前一定先
allow ssh - 改默认策略到 deny incoming,不要无脑 allow
七、firewalld 实战(CentOS 系新人首选)
firewalld 引入了**区域(zone)**概念,常见有 public / internal / trusted 等。
# 看状态sudo systemctl status firewalldsudo firewall-cmd --state# running# 看当前区域sudo firewall-cmd --get-default-zone# public# 看 public 区域开了什么sudo firewall-cmd --zone=public --list-all# services: ssh dhcpv6-client# ports:# ...# 放行服务sudo firewall-cmd --permanent --add-service=httpsudo firewall-cmd --permanent --add-service=https# 放行端口sudo firewall-cmd --permanent --add-port=8080/tcp# 限定源 IPsudo firewall-cmd --permanent --zone=trusted --add-source=10.0.0.0/24sudo firewall-cmd --permanent --zone=trusted --add-service=ssh# 重载生效(**必须 reload,否则只在运行时生效,重启就丢**)sudo firewall-cmd --reload# 删sudo firewall-cmd --permanent --remove-service=httpsudo firewall-cmd --reload
--permanent 和 reload 是配对的:不加 permanent 是临时改,重启丢;加了 permanent 不 reload 又不立刻生效。养成 --permanent ... ; --reload 一气呵成的习惯。
八、nftables 实战:一份完整 ruleset 样板
nft 是新一代防火墙,Ubuntu 22+ / Debian 11+ / CentOS 8+ 默认走它(即使你 iptables -L 也是 nft 在后面跑兼容层)。
直接写一份完整 ruleset,能用于一台典型 Web 服务器:
sudotee /etc/nftables.conf <<'EOF'#!/usr/sbin/nft -fflush rulesettable inet filter {# 入站 chain input {type filter hook input priority 0; policy drop;# 1. 已建立 / 相关连接放行 ct state established,related accept# 2. 本机回环必须放行 iif lo accept# 3. ICMP(ping)放行 ip protocol icmp accept ip6 nexthdr icmpv6 accept# 4. SSH 放行(建议限源 IP 段,二选一,不要同时启用) tcp dport 22 ip saddr 10.0.0.0/24 accept # 推荐:只允许内网网段# tcp dport 22 accept # 备选:公网全开放(仅在堡垒机/单机调试场景)# 5. HTTP / HTTPS 放行 tcp dport { 80, 443 } accept# 6. 其他全部 drop(已由 policy drop 兜底)# 默认 drop,所以不需要显式写 }# 出站(一般全放) chain output {type filter hook output priority 0; policy accept; }# 转发(如果不是路由器一般全 drop) chain forward {type filter hook forward priority 0; policy drop; }}EOF# 校验语法sudo nft -c -f /etc/nftables.conf# 启用sudo systemctl enable --now nftables# 看当前规则sudo nft list ruleset
几个关键设计:
ct state established,related accept 必须放第一条——否则出去的请求收不到回包(响应包不算 new 状态会被 drop)iif lo accept 必须有——很多本机服务(Postgres / Redis)只听 127.0.0.1,回环必须通policy droptcp dport { 80, 443 }
九、典型排查:ping 通但 telnet 不通
最经典的网络排查 case:
# Step 1:ping 通了ping -c 3 192.168.1.10# 3 packets transmitted, 3 received, 0% packet loss# → 三层 IP 联通没问题# Step 2:telnet 端口不通telnet 192.168.1.10 80# Trying 192.168.1.10...# telnet: Unable to connect to remote host: Connection refused
两种可能:
Connection refused → 包到了主机,但没人监听 / 防火墙明确 rejectConnection timed out → 包根本没到主机(中间链路阻断 / 防火墙 drop)
refused vs timed out 是关键信号:
- refused = 目标主机内核回了 RST → 要么应用没起,要么防火墙 reject
- timeout = 没收到任何回包 → 多半在中间链路(云安全组 / 网络 ACL / drop 防火墙)
继续排:
# 上 192.168.1.10 看ssh 192.168.1.10ss -lntp | grep ':80'# 如果没输出 → 应用根本没监听# 如果有 LISTEN 127.0.0.1:80 → 监听了但只听本地# 看防火墙sudo ufw status # Ubuntusudo firewall-cmd --list-all # CentOSsudo nft list ruleset # nftables# 看应用日志sudo journalctl -u nginx --since "10 min ago"
十、典型排查:ping 慢但 curl 快(反之亦然)
ping baidu.com # 50mscurl -o /dev/null -s -w "%{time_total}\n" https://baidu.com # 5s
可能原因:
- DNS 解析慢:
time curl baidu.com,再单独 time dig baidu.com 对比;DNS 解析占大头时换 8.8.8.8 / 114.114.114.114 - TLS 握手慢:
curl -w "@curl-format.txt" ... 拿到各阶段耗时 - TCP 三次握手慢
- 应用响应慢
完整 curl 计时格式:
cat > /tmp/curl-format.txt <<'EOF' DNS: %{time_namelookup}s Connect: %{time_connect}s TLS: %{time_appconnect}s First Byte: %{time_starttransfer}s Total: %{time_total}sEOFcurl -w "@/tmp/curl-format.txt" -o /dev/null -s https://example.com
新人最易忽略的现象:ping 走 ICMP,curl 走 TCP。云上 ICMP 可能被默认 drop,ping 不通不等于服务不通,反过来 ping 通也不代表服务能用。
十一、云上的「安全组」:两层防火墙必须协同
云服务器跟物理机最大区别:外面还有一层云平台的"安全组"。
┌─────────────┐互联网 ──→ ① 云安全组 ──→ ② OS 防火墙 ──→ ③ 应用监听 │ 两层都通才行
云防火墙在 OS 之前生效,OS 上 ufw allow 了,云安全组没放行,外面照样进不来。
典型踩坑:
- 阿里云 / AWS 默认安全组只放 22,新开的 80 / 443 全靠后台 → 「nginx 启动了、ufw 也开了、外网就是访问不到」
- 临时调试在 OS 上
ufw allow xxx 后又疑惑没生效 → 去云控制台看安全组
新人记一句:云上「访问不到」永远先看安全组,再看 OS 防火墙。
十二、排查工具速查表
| | |
|---|
| ip a | ip a show eth0 |
| ip r | ip r |
| ss -lntp | ss -lntp |
| ss -tnp | ss -tan state established |
| ping | ping -c 3 host |
| nc -zv | nc -zv host 80 |
| mtr | mtr -r -c 30 host |
| curl -v | curl -v https://host |
| dig | dig +short host |
| tcpdump | tcpdump -i eth0 port 80 -nn |
写在最后
- 网络排查永远走五关:DNS → 三层联通 → 四层联通 → 防火墙 → 监听 → 应用
- 新机器统一用
ip / ss,ifconfig / netstat 已经被边缘化 - 0.0.0.0 vs 127.0.0.1 监听差别巨大:本机能访问但外面访问不到,多半是只听了 127.0.0.1
- ufw 启用前先 allow ssh
- firewalld 改完要
--reload - 不要再写裸 iptables,新机器用 nft / firewalld / ufw
- Connection refused vs Connection timed out 含义完全不同——前者多半是服务问题,后者多半是网络/防火墙问题
- 云服务器永远先看安全组