遇到线上站点无法访问时,如果在没有排查日志和端口状态的情况下直接重启容器或服务器,不仅会丢失故障现场,遇到磁盘写满或配置文件语法错误时,重启反而会导致服务无法再次启动。
本文按自底向上的网络与系统分层,整理一套从客户端 DNS 解析、TCP 端口探测、TLS 握手核验到容器状态与宿主机磁盘检查的分步排查清单。
网站无法访问时的分层排查顺序
发生访问异常时,可按照下图所示的 L1 → L6 顺序依次执行诊断命令,逐步缩小问题范围:
第 1 层(L1):核对客户端 DNS 解析是否指向正确 IP
在本地电脑终端使用公共递归 DNS(如 223.5.5.5 或 1.1.1.1)查询域名,排除本机 Hosts 配置、DNS 缓存陈旧或域名过期问题:
1 | # 在本地电脑执行:核对 A / AAAA 记录返回的地址是否与 <服务器地址> 一致 |
- 常见现象:返回空值、
SERVFAIL或指向了已停用的旧服务器 IP。 - 处理方式:前往域名 DNS 控制台核对记录值与域名状态,无需登录服务器改动容器。
第 2 层(L2):在客户端测试外部 TCP 握手与 TLS 协商
如果 DNS 解析正确,接下来在本地电脑对 <服务器地址> 的 80 / 443 端口发起带 5 秒超时的连接测试:
1 | # 在本地电脑执行:验证 TCP 三次握手与 HTTP/HTTPS 响应头 |
- 情况 A(返回
Connection timed out):SYN 数据包在传输途中被丢弃,通常是云厂商控制台安全组或宿主机 UFW 防火墙未放行80/tcp、443/tcp。 - 情况 B(返回
Connection refused):数据包已到达服务器网卡,但宿主机内核回复RST(当前没有进程在该端口监听),继续排查第 3 层。 - 情况 C(返回
SSL certificate problem: certificate has expired):TLS 证书过期或容器未重载最新证书,可执行acme.sh --cron并运行docker exec blog-web nginx -s reload。
第 3 层(L3):登录服务器检查宿主机套接字监听(ss -tlnp)
通过 SSH 登录服务器,查看宿主机内核网络栈中 80 与 443 端口的绑定情况:
1 | # 在服务器执行:检查监听地址是 0.0.0.0 还是仅绑定了 127.0.0.1 |
- 常见原因:如果输出显示
127.0.0.1:80而非0.0.0.0:80,说明容器端口映射只绑定了本机回环地址,且外层没有配置宿主机反向代理,导致公网请求被拒绝。
第 4 层(L4):本机回环 HTTP 探测(区分外部网络与容器内部故障)
如果 ss 显示端口正在监听,在服务器本机对 127.0.0.1 发起 HTTP 请求,并带上站点 Host 头:
1 | # 在服务器本机执行:绕过公网与外部安全组,直接测试 Nginx 容器响应 |
- 若本机返回
200 OK而外网超时:问题在云厂商安全组、CDN 回源配置或外部网络路由,容器本身运行正常。 - 若本机返回
403 Forbidden/404 Not Found/500:请求已进入 Nginx 容器,通常是挂载目录权限不足(例如宿主机目录权限为700导致容器内nginxworker 进程无权读取)或/srv/blog/releases/current软链接指向了空目录。
第 5 层(L5):检查 Docker 容器状态、退出码与挂载路径
当第 3 层无监听或第 4 层返回异常时,查看 blog-web 容器的运行状态、退出码与错误日志:
1 | # 查看容器状态、退出码(Exit Code)与最近 50 行错误日志 |
ExitCode=1且日志提示[emerg]:通常是修改default.conf时引入了语法错误,导致容器启动后立即退出。OOMKilled=true(或ExitCode=137):容器或宿主机其他进程耗尽内存被内核终止,继续排查第 6 层。
第 6 层(L6):排查宿主机内核 OOM、磁盘空间与 Inode 占用
容器无法启动或日志停止写入,有时是因为宿主机底层资源耗尽:
1 | # 1. 检查内核是否有 Out of Memory 终止进程记录 |
如果 df -h 显示磁盘使用率达到 100%,不要直接 rm 正在被进程写入的日志文件(进程未关闭句柄时磁盘空间不会释放),而应使用 truncate -s 0 <日志文件路径> 原地清空文件,再运行 sudo logrotate -f /etc/logrotate.d/blog-nginx。
生产环境上线核对表
站点部署上线前,可对照下表逐项核验系统安全、前端构建与容器配置:
| 模块 | 检查项 | 关联文章 | 核验命令或标准 |
|---|---|---|---|
| 架构与目录 | 固定链接与目录结构 | 个人技术博客架构选型 | 宿主目录为 /srv/blog/releases/current,文章路由固定为 /posts/<slug>/ |
| 系统与权限 | 目录属主与 Systemd 托管 | Linux 文件系统与 Systemd | 静态目录权限 755、文件 644,关键守护进程配置 Restart=on-failure |
| SSH 与防火墙 | 密钥登录与端口收敛 | Ubuntu 初始化与 SSH 加固 | PasswordAuthentication no,UFW 仅放行 SSH、80/tcp 与 443 |
| 网络与证书 | DNS、BBR 与 HTTPS 续期 | DNS、TCP BBR 与 ACME 证书 | sysctl net.ipv4.tcp_congestion_control 输出 bbr,TLS 1.3 握手正常 |
| 静态构建 | 草稿隔离与构建校验 | Astro 静态构建与发布流程 | npm run check 无报错通过,草稿文件不进入 public/ |
| 主题与色彩 | 明暗主题与正文字体对比度 | CSS 色彩变量与明暗主题 | 正文对比度满足 WCAG AA(>= 7.2:1),刷新页面无明暗闪烁 |
| 版面与交互 | 响应式双栏与代码块复制 | 长文双栏网格与目录交互 | 桌面端 Sticky 目录高亮正常,窄屏下代码块与表格无横向溢出 |
| 内容与插图 | 敏感信息扫描与 SVG 校验 | 技术写作规范与构建检查 | 仓库无真实公网 IP 或凭据残留,SVG 架构图包含完整 viewBox 与描述 |
| 检索与图谱 | 异步检索防竞态与图谱渲染 | 本地全文检索与知识图谱 | 快速输入检索词无旧结果覆盖,Canvas 图谱支持缩放、拖拽与节点筛选 |
| Docker 基础 | 镜像分层与容器网络隔离 | Docker 镜像、网络与数据卷 | 守护进程配置日志上限,容器运行在自定义 Bridge 网络中 |
| Nginx 网关 | 路由匹配、真实 404 与缓存头 | Nginx 进程模型与路由配置 | 随机不存在路径返回真实 HTTP/2 404,HTML 与静态资源采用分级缓存 |
| 只读容器托管 | Compose 只读挂载与端口绑定 | Docker Compose + Nginx 托管 | 静态产物与配置均以 :ro 只读挂载,容器常驻内存低于 25 MB |
| 自愈与发布 | 容器自愈、日志切分与回滚 | 容器自愈、日志轮转与发布脚本 | logrotate 配合 USR1 信号切分日志,发布脚本支持失败自动回滚 |
| 故障诊断 | 分层排障链路验证 | 本文 | 掌握 dig +trace、curl -w、ss -tlnp、docker inspect 与 dmesg -T |