2026-08-21 12:58 之后,me.asaqe.org、asaqe.org、blog.asaqe.site 同时 502。Cloudflare 报 error code: 502,本机 curl 127.0.0.1:2368 拿到的是 nginx 的 502 HTML。看起来像博客宕机,其实 Ghost 进程一直在跑。
这篇文章记录一次完整的误判路径:先怀疑容器挂了,再发现是边缘代理把容器名解析死在了旧 IP 上。
症状
- 外网三个域名都是 Cloudflare 502
- 源站
ghost-edge(nginx:1.27,映射0.0.0.0:2368)日志:connect() failed (111: Connection refused) while connecting to upstream ... http://172.23.0.27:2368/ - Ghost 容器状态
Up,直连当前 IP172.23.0.12:2368返回 301/200 - MySQL
mysqladmin ping正常,磁盘和内存都不是瓶颈
502 从 Ghost 重建那一秒开始,连续打了大约 37 小时,直到把 ghost-edge 重启。
时间线
- 07-30
ghost-edge启动。nginx 在加载配置时把ghost解析成172.23.0.27,并缓存这个结果。 - 08-21 12:58 Ghost 容器被重建(镜像
ghost:latest,启动后版本 6.59.0),新地址172.23.0.12。旧地址立即拒绝连接。 - 08-21 12:58:33 边缘日志出现第一笔
Connection refused。同一时刻 Ghost 自己去拉 ActivityPub,也撞上这层 502。 - 08-23 01:50 重启
ghost-edge,解析回到172.23.0.12,首页、文章、/ghost/恢复 200。
根因
nginx 的 proxy_pass http://ghost:2368; 如果主机名写死、不用变量,只会在 启动 / 加载配置 时向 Docker 内置 DNS 127.0.0.11 问一次。之后容器重建、IP 变更,nginx 不会再问。
Docker 里这是旧问题,个人博客这种「一个长期活着的反代 + 一个会升级的应用容器」特别容易中招。容器健康检查全绿,对外却是 502,就是这种错位。
修复
应急:
docker restart ghost-edge防再发:让 proxy_pass 走变量,并显式使用 Docker DNS。
resolver 127.0.0.11 valid=10s ipv6=off;
location / {
set $ghost_upstream ghost:2368;
proxy_pass http://$ghost_upstream;
}变量形式会在请求时重新解析。valid=10s 把缓存压到十秒量级,够用,也不会每请求都打 DNS。
同一台机器上的 Nginx Proxy Manager 也有一处写死的 proxy_pass http://new-api:3000;,已改成和它自己 proxy.conf 一样的 $forward_scheme://$server:$port$request_uri。当时 new-api 的 IP 碰巧没变,所以 API 没倒;不改的话,下次 new-api 重建就会把 /v1/ 打挂。
顺手清掉的同类故障
排查博客时把整机 Docker 扫了一遍,另外几处也不是「应用逻辑坏了」,而是运行时状态漂了:
- pgAdmin:数据目录属主
1000,容器用户5050,启动时chmod 0600失败,restart: always空转约 18 万次。处理:chown -R 5050:5050后重启。 - 若干 compose 应用(stream-vault、syncthing、qwen2api、tavily、AutoTeam、Kiro-Go):项目网络被删,旧容器还挂着
*_default,状态是Created/Exited。处理:按现有 compose 重建,接到1panel-network。 - MySQL compose:挂载了主机
/etc/timezone,而这台机器上它是目录不是文件。当前容器能跑,下次 1Panel 重建会起不来。处理:去掉该挂载。
这些和 Ghost 502 是同一类问题:进程在,拓扑不在。
验收
curl -sS -o /dev/null -w '%{http_code}\n' -H 'Host: me.asaqe.org' -H 'X-Forwarded-Proto: https' http://127.0.0.1:2368/
curl -sS -o /dev/null -w '%{http_code}\n' https://me.asaqe.org/
curl -sS -o /dev/null -w '%{http_code}\n' https://me.asaqe.org/ghost/三条都应 200。边缘日志里不应再出现 172.23.0.27。
回滚
如果动态解析有问题,把 proxy_pass 改回 http://ghost:2368 并重启 ghost-edge,行为回到「启动时解析一次」。那是旧行为,能恢复站点,但不能抵抗下一次 Ghost 重建。
以后升级 Ghost 的检查单
- 重建应用容器之后,立刻
curl边缘端口,不要只看docker ps。 - 反代如果用容器名当上游,必须是变量 + Docker DNS,或和被代理容器一起重启。
- 1Panel / Watchtower 自动拉
:latest时,默认假设「边缘还记得人」。这个假设不成立。
个人 AI 和自建博客一样:模型或 CMS 没挂,不等于链路可交付。可靠性出在解析、权限、网络这些不性感的层。