Administrator
Administrator
发布于 2026-10-29 / 0 阅读
0
0

Ping 通却打不开网站:沿 DNS、TCP、TLS、HTTP 分层排查

适合读者:能登录 Linux 服务器,但遇到“网站打不开”时还缺少固定排查顺序的初级运维人员。本文围绕普通 HTTPS over TCP 请求展开;示例中的 example.test 域名和 192.0.2.0/24 地址用于文档演示,实际排查需要替换。

网站访问链路:解析、连接、TLS、HTTP、应用响应

1. Ping 通了,为什么网页仍然打不开

Ping 成功,说明某条路径上的 ICMP 请求得到了回应。浏览器访问 HTTPS,还要完成域名解析、目标端口连接、TLS 握手、HTTP 请求和应用处理。任何一环出问题,都可能显示“打不开”。

同样,Ping 被禁也不等于网站不可用。要围绕出问题的业务请求收集证据,而不是用一种探测结果替代整个访问链路。

先记录四件事:访问的完整 URL、发生时间、客户端所在网络、浏览器或程序的原始错误。这些信息能避免排查过程中悄悄换了域名、端口或请求路径。

2. 用 curl 看清请求停在哪一步

先对真实 URL 做一次带时间限制的请求:

curl -v --connect-timeout 3 --max-time 10 \
  https://app.example.test/healthz

-v 会显示连接、TLS 和 HTTP 细节;--connect-timeout 限制连接阶段,--max-time 限制整个操作。连接阶段也可能包含 DNS 和 TLS,因此“连接超时”还需要结合详细输出判断。参数含义见 curl 官方手册。

分享输出前检查其中是否有 Authorization、Cookie 或内部地址。排障记录保留必要字段即可。

可以重点找这些线索:

输出线索 当前定位 优先检查
Could not resolve host 名称解析失败 拼写、系统解析配置、DNS 或代理主机
Connection refused 连接被拒绝 目标地址、端口、监听或显式拒绝策略
Connection timed out 某阶段未在期限内完成 详细输出最后停在哪、网络路径和服务响应
certificate verify failed 等证书错误 TLS 校验失败 域名、有效期、证书链、信任和系统时间
已收到 HTTP 状态码 请求已到达某个 HTTP 响应方 状态码、正文、响应头和对应日志

“Connection refused”经常来自端口无人监听,但也可能是中间设备主动拒绝,不能直接断言服务进程一定停止。

3. 第一层:域名是否解析到预期地址

在出问题的客户端执行:

getent ahosts app.example.test

getent 使用系统名称服务配置,因此结果可能受 /etc/hosts、DNS 等共同影响。安装了 dig 时,还可以单独观察 DNS 响应:

dig app.example.test A
dig app.example.test AAAA

比较地址是否符合当前架构:访问 CDN 时可能得到边缘节点地址,内网域名在公网解析失败也可能是预期行为。不要仅因为解析结果不是源站 IP,就判定 DNS 出错。

若只在部分客户端失败,分别比较内外网解析、IPv4 和 IPv6 路径:

curl -4 -v --max-time 10 https://app.example.test/healthz
curl -6 -v --max-time 10 https://app.example.test/healthz

IPv6 请求失败还可能只是本机没有可用 IPv6。需要把地址记录和实际连接能力一起看。

4. 第二层:业务端口和监听地址是否正确

在目标 Linux 服务器上查看 TCP 监听:

sudo ss -lntp
ip -br address
ip route

监听 127.0.0.1:8080 的程序只接受对应网络命名空间内的本机连接。它可能被设计为由 Nginx 反向代理访问,并不一定要对所有地址监听。

排查时画清楚实际路径,例如“客户端 → 负载均衡 443 → Nginx 443 → 应用 8080”。外部请求失败时,应分别验证每一跳的目标地址和端口。

如果 Nginx 在容器里,容器内的 127.0.0.1 指向该容器,和宿主机的回环地址不是一处。探测必须在能代表真实请求来源的环境里执行。

5. 第三层:TLS 校验为什么失败

TLS 问题常见于四个方面:证书里的域名不匹配、证书过期或尚未生效、中间证书链不完整、客户端不信任签发方。系统时间错误也会影响有效期判断。

在客户端检查时间,然后看 curl 的具体证书错误:

date -Is
curl -v --max-time 10 https://app.example.test/healthz

需要测试某个指定服务器 IP,同时保留真实域名时,可以使用:

curl --resolve app.example.test:443:192.0.2.10 \
  --connect-timeout 3 --max-time 10 -v \
  https://app.example.test/healthz

把域名、端口、IP 换成真实值。这样 URL 中的主机名仍用于 TLS 的 SNI、证书名称校验及 HTTP Host,而连接地址由本次命令指定。只修改 Host 请求头不能完整替代这件事。

--resolve 适用于本次直接连接测试;存在显式代理时,应结合代理的解析和连接方式判断。curl 对这些机制的说明见 Everything curl:Name resolve tricks。

使用 -k 会跳过关键的证书校验。即使临时使用它后请求成功,也只能说明校验值得进一步检查,不能把该结果作为证书问题已经修复的证据。

6. 第四层:收到 404 或 502,其实已经多了一条证据

收到 HTTP 响应后,要问“是谁返回了它”,再解释状态:

  • 404:该响应方没有找到相应资源,可能是路径、虚拟主机或路由问题。
  • 401/403:检查身份、权限和访问策略。
  • 502/503/504:常见于代理上游异常、服务不可用或等待超时,但具体含义取决于响应方。

响应头和页面样式能提供线索,最终仍需要结合入口代理和应用日志。不能看到 502 就断言数据库故障。

curl 默认也不会把所有 HTTP 4xx/5xx 自动当作命令失败。脚本如果需要这类响应返回非零退出码,可使用 --fail;需要同时保留错误正文时,较新版本可使用 --fail-with-body。具体行为见 curl HTTP 失败处理说明。

7. 本地实验:亲眼看到“连接成功、业务请求失败”

使用编辑器保存下面的 http-demo.py,在装有 Python 3 的测试环境运行。服务只监听本机回环地址:

from http.server import BaseHTTPRequestHandler, HTTPServer

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        ok = self.path == "/healthz"
        body = b"ok\n" if ok else b"not found\n"
        self.send_response(200 if ok else 404)
        self.send_header("Content-Type", "text/plain; charset=utf-8")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)

HTTPServer(("127.0.0.1", 18081), Handler).serve_forever()

终端 A 启动服务:

python3 http-demo.py

终端 B 分别访问有效路径和不存在的路径:

curl --max-time 5 -i http://127.0.0.1:18081/healthz
curl --max-time 5 -i http://127.0.0.1:18081/missing
printf 'curl_exit=%s\n' "$?"

预期第一个请求是 200,第二个请求是 404,但第二条 curl 命令本身的退出码仍为 0:它成功完成了 HTTP 传输。

再明确要求 curl 将 HTTP 错误视为失败:

curl --fail --max-time 5 http://127.0.0.1:18081/missing
printf 'curl_exit=%s\n' "$?"

预期退出码为 22。退出码要立即读取,中间插入别的命令会覆盖 $?。实验结束后,在终端 A 按 Ctrl+C 停止服务。

8. 修复后如何证明链路恢复

分别在服务器本机和真实客户端复测原始 URL,记录 HTTP 状态、连接到的地址和耗时:

curl -sS --connect-timeout 3 --max-time 10 \
  -o /dev/null \
  -w 'http=%{http_code} remote=%{remote_ip} total=%{time_total}s\n' \
  https://app.example.test/healthz

还要验证实际业务页面、身份认证和必要的接口。健康检查返回 200,只能证明该检查定义覆盖的功能。

有效的排查记录通常能写成一句明确的话:“域名解析正确、TCP 连接成功、TLS 校验通过,请求在入口返回 404;修正虚拟主机路由后,原始 URL 从内外两个位置均返回预期内容。”这样下一次类似故障,就有了可对照的证据。


评论