DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

Caddy 配置重载就断开 WebSocket,检查 stream_close_delay

WebSocket 正常建立,却在管理API更新配置时断开;核对重载时间与 stream_close_delay 的保留窗口。

WebSocket 已经建立并正常交换消息,但每次通过 Caddy 管理 API 更新配置,旧连接就同时断开。把断开时间与 admin.api 收到配置更新、旧配置卸载的日志放在一起看:这可能是旧 reverse_proxy 处理器关闭流连接,与连接空闲超时不是同一条路径。

Caddy 默认会在配置重载时关闭 WebSocket,避免旧请求长期持有旧配置。更新一个 map 也可能触发配置重新加载;普通 HTTP 请求的平滑重载行为,不能直接推导为所有长连接永久保留。本文针对已建立连接随配置重载断开的情况,不处理握手还没成功就返回 400、403 的问题。

先确认发生的是配置重载

比较配置更新、客户端关闭事件和上游日志的时间。进程崩溃、容器重启或应用主动关闭,也可能让大量连接一起断开;管理端打印“停止旧服务”不一定表示操作系统进程重新启动。

如果没有更新配置,只在连接达到某个寿命后断开,应检查 stream_timeout 及其他层的关闭规则。该选项控制流连接的最长存活时间,默认没有这一超时;它不是“重载后保留旧连接多久”,也不能把一个固定断开现象直接归为重载。

客户端还没进入正常消息交换阶段时,先检查认证、路由和协议升级。仅增加保留时间,不会修复初始握手失败。

给实际 reverse_proxy 设置有上限的保留时间

stream_close_delay 可以推迟旧处理器关闭流连接的时间。下面是 Caddyfile 片段,以同一网络环境中已确认可用的回环上游为例:

reverse_proxy 127.0.0.1:3000 {
    stream_close_delay 5m
}

将指令合入真正处理这条 WebSocket 路径的现有 reverse_proxy,保留原有请求头、认证和上游配置。5m 是供评估的保留窗口示例,不是每个应用都应采用的固定值;容器中的回环地址还要按实际网络环境调整。

对于直接维护 JSON 配置的部署,对应字段是 stream_close_delay。不要一边 PATCH JSON,一边修改一份运行时并未读取的 Caddyfile;先确认当前配置入口和管理流程,再用它支持的方式更新并检查。

这项设置应在后续重载之前生效。已经断开的 WebSocket 仍需客户端重新连接,它不会恢复原连接,也不会把旧连接迁到新上游。保留窗口结束或连接自然结束后,旧流不会继续无限维持。

长窗口会保留旧配置和连接资源

设置成数小时并不等于长期没有内存影响。频繁重载时,多个旧配置可能仍有活跃流,连接、内存和应用资源都需要实际观察。应按客户端重连能力、允许的旧连接时长和服务资源确定窗口,而不是为追求“不断线”一律延长。

还要确认旧连接继续使用旧路由、授权状态和应用会话是否符合业务要求。新请求会使用新配置,已有连接却不能靠这项设置自动获得新的路由或权限规则;业务需要立即撤销会话时,应有明确的应用关闭方式。

如果映射数据每分钟都在变化,评估服务发现、动态上游或稳定的内部查询服务是否更适合承接它,避免把每次数据更新都变成完整配置重载。仍需保留客户端的有界重连和会话恢复机制,不能假定代理配置能保证消息不丢失。

修改前保存原配置。在受控环境中先建立连接,再通过原管理方式作一次必要的配置更新,确认现有连接在预期窗口内继续交换消息,新连接使用正确路由,并检查窗口结束、客户端主动离开及资源回收。配置校验成功只说明可以加载,不能代替这些行为检查。

需要撤回时恢复原保留规则并按原流程加载,同时安排客户端重连。撤回本身仍是配置变化,也可能关闭已有连接;不能承诺恢复配置就没有任何连接影响。