Dozzle 反向代理与 Base Path 完整配置指南:子路径挂载、SSE 流式日志与 WebSocket 代理实战
【免费下载链接】dozzleRealtime log viewer for containers. Supports Docker, Swarm and K8s.项目地址: https://gitcode.com/GitHub_Trending/do/dozzle
Dozzle 是一个面向容器的实时日志查看器,支持 Docker、Swarm 与 Kubernetes。在生产环境中,Dozzle 几乎总是被部署在 Nginx、Traefik、Caddy 等反向代理之后,用于终止 TLS、集中鉴权,或与同主机上的其他服务共享域名。本文基于 docs/guide/changing-base.md 展开,完整讲解如何通过--base标志或DOZZLE_BASE环境变量将 Dozzle 挂载到子路径,以及让 SSE 日志流与 WebSocket 终端正常工作所需的反向代理配置。读完本文,你将掌握 Dozzle 在三种主流代理下的标准部署姿势,并能快速定位"白屏、日志断流、Shell 秒断"等经典故障。
修改 Base Path:把 Dozzle 挂载到子路径
Dozzle 默认挂载在根路径/。当需要与其他服务共享一个域名时(例如https://example.com/foobar/下的 Dozzle),可以通过命令行标志或环境变量改变其挂载路径:
- 命令行标志:
--base - 环境变量:
DOZZLE_BASE
两者在源码中是同一配置项。在 internal/support/cli/args.go 中定义:
Base string `arg:"env:DOZZLE_BASE" default:"/" help:"sets the base for http router."`默认值为/,通过arg:"env:DOZZLE_BASE"将环境变量与标志绑定,因此两种方式等价。
Docker CLI 方式
docker run --volume=/var/run/docker.sock:/var/run/docker.sock -p 8080:8080 amir20/dozzle --base /foobarDocker Compose 方式
services: dozzle: image: amir20/dozzle:latest volumes: - /var/run/docker.sock:/var/run/docker.sock ports: - 8080:8080 environment: DOZZLE_BASE: /foobar配置完成后,Dozzle 将在http://localhost:8080/foobar/提供服务,并表现出两个关键行为:
所有静态资源被重写为
/foobar/{file.path}。前端运行时通过withBase()统一拼接前缀,见 assets/stores/config.ts:export const withBase = (path: string) => `${config.base}${path}`;自动重定向:访问
/foobar(不带尾斜杠)会被 301 重定向到/foobar/。这个逻辑实现在 internal/web/routes.go:if base != "/" { r.Get(base, func(w http.ResponseWriter, req *http.Request) { http.Redirect(w, req, base+"/", http.StatusMovedPermanently) }) }
Base Path 在服务端的完整落地
从源码结构看,base贯穿了 Dozzle 的整个 HTTP 路由层,而不仅仅是前端资源前缀:
- 路由挂载:
createRouter将整个应用(含/api路由、健康检查、PWA manifest、Service Worker)统一挂载在r.Route(base, ...)之下,见 internal/web/routes.go。这意味着所有 API 请求路径都带上前缀。 - 前端配置注入:服务端在渲染
index.html时把base写入模板配置,见 internal/web/index.go,前端据此拼接资源与请求路径。 - PWA Manifest 感知:
manifest.webmanifest的start_url与scope都会带上 base 前缀,确保以子路径部署时 PWA 安装和启动行为正确,见 internal/web/manifest.go。 - 认证重定向感知:开启鉴权后,未登录访问会被重定向到
{base}/login?redirectUrl=...,登录页同样基于 base 生成跳转地址,见 internal/web/index.go 与 assets/pages/login.vue。
因此,修改 base 后,前后端所有路径都会同步变化,前提是代理必须把带前缀的完整路径原样转发给 Dozzle(详见下文"常见坑")。
反向代理的三大硬性要求
Dozzle 的实时能力依赖两种长连接协议:
- Server-Sent Events(SSE):用于流式推送容器日志、主机日志与事件流。
- WebSocket:用于容器 Shell(attach / exec 终端)。
反代要正常工作,必须满足以下三点:
1. 禁用响应缓冲(Disable response buffering)
SSE 是"事件到达即推送"的模型,任何缓冲都会导致日志成批到达、延迟到达,甚至永远不到达。Dozzle 会在响应头中发送X-Accel-Buffering: no,该头在 SSE 流的构造处设置,见 internal/support/web/sse.go:
w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-transform") w.Header().Add("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") w.Header().Set("X-Accel-Buffering", "no")X-Accel-Buffering是 Nginx 约定的头,能够自动关闭 Nginx 对该响应的缓冲;但部分代理会忽略该头,此时必须在代理侧显式关闭缓冲。另外注意 SSE 写入端还设置了Content-Encoding: gzip(当客户端接受 gzip 时)并逐事件 Flush,见 internal/support/web/sse.go,说明"按事件即时冲刷"是 Dozzle 的原生行为,代理不应打断它。
2. 转发 WebSocket 升级头(Forward WebSocket upgrade headers)
容器 Shell 依赖 WebSocket。代理必须原样转发Upgrade与Connection头,否则升级握手失败,终端会立即断开。Dozzle 的 attach / exec 端点注册在 internal/web/routes.go:
if h.config.EnableShell { r.Get("/hosts/{host}/containers/{id}/attach", h.attach) r.Get("/hosts/{host}/containers/{id}/exec", h.exec) }注意:Shell 功能默认关闭,需要
--enable-shell(或DOZZLE_ENABLE_SHELL=true)才会注册这些 WebSocket 路由。
3. 不要压缩text/event-stream
压缩中间件通常会缓冲整个响应后再压缩,从而破坏 SSE 的实时性。如果代理启用了压缩中间件,必须将text/event-stream排除在压缩范围之外。
Nginx 配置
以下配置将 Dozzle 挂载在/foobar/子路径下:
location ^~ /foobar/ { proxy_pass http://dozzle:8080; chunked_transfer_encoding off; proxy_buffering off; proxy_cache off; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }关键指令说明:
proxy_buffering off:显式关闭缓冲(双保险:即使忽略X-Accel-Buffering也能保证 SSE 即时推送)。proxy_cache off:禁止缓存流式响应,避免日志被缓存污染。chunked_transfer_encoding off:配合流式输出,避免 SSE 被 chunked 编码二次打包。proxy_http_version 1.1+Upgrade/Connection头:WebSocket 升级的必要条件,缺一不可。
如果 Dozzle 挂载在根路径,去掉^~ /foobar/前缀即可。关于 Nginx 缓冲问题的更多细节,可参考 FAQ 条目 Disabling buffering in nginx,那里给出了按/api路径精细化关闭缓冲的另一种写法。
Traefik 配置
Traefik 会自动处理 WebSocket 升级,因此无需手动配置 Upgrade 头;但默认的compress中间件会破坏 SSE。必须通过excludedContentTypes排除text/event-stream:
http: middlewares: middlewares-compress: compress: excludedContentTypes: - text/event-stream背景:不排除时,症状是"通过 Traefik 域名访问时部分容器日志不再显示,而直接访问
localhost:8080却正常"。此现象在 FAQ 中有明确记录(常见于 dozzle、homepage、glances、filebrowser 等容器),见 docs/guide/faq.md。
随后在 Dozzle 服务上添加典型的路由 labels:
services: dozzle: image: amir20/dozzle:latest labels: - traefik.enable=true - traefik.http.routers.dozzle.rule=Host(`dozzle.example.com`) - traefik.http.routers.dozzle.entrypoints=websecure - traefik.http.routers.dozzle.tls.certresolver=letsencrypt - traefik.http.services.dozzle.loadbalancer.server.port=8080若需要同时启用压缩,可将压缩中间件挂到 router 上(traefik.http.routers.dozzle.middlewares=middlewares-compress),并确保使用上述排除了text/event-stream的版本。
Caddy 配置
Caddy 的配置最为简洁,核心是flush_interval -1:
dozzle.example.com { reverse_proxy dozzle:8080 { flush_interval -1 } }flush_interval -1表示禁用响应缓冲,让 Caddy 对流式端点立即冲刷数据。Caddy 对 WebSocket 升级同样原生支持,无需额外配置。
常见坑(Common Pitfalls)
坑 1:使用--base后白屏或静态资源 404
根因:代理在转发前剥离了路径前缀。例如 Nginx 只把/foobar/之后的部分传给 Dozzle,导致 Dozzle 收到/assets/xxx.js而非/foobar/assets/xxx.js,资源请求全部落空。
解法:确保代理将**完整路径(含前缀)**透传给 Dozzle。Nginx 的proxy_pass http://dozzle:8080;(不带 URI 部分)会保留原始 URI;若写成proxy_pass http://dozzle:8080/;(带尾斜杠)则会替换掉 location 前缀,正是触发此坑的典型写法。
坑 2:日志几秒后停止
根因:代理的连接超时设置太短。SSE 是长时间挂起的连接,短超时会让代理在日志流持续期间主动断开。
解法:将代理的读写超时调大到至少数分钟。例如 Nginx 增加:
proxy_read_timeout 3600s; proxy_send_timeout 3600s;坑 3:Shell 立即断开
根因:Upgrade与Connection头未被转发,WebSocket 升级握手失败。
解法:核对代理配置中是否包含这两条头(Nginx 见上文配置;Traefik 与 Caddy 自动处理,一般无需关心)。
小结与验证清单
将 Dozzle 置于反向代理之后,只需记住三件事:base 决定挂载路径,SSE 拒绝缓冲与压缩,WebSocket 需要升级头。部署完成后可按下述清单自检:
- 访问
http://localhost:8080/foobar/,页面正常渲染且资源均带/foobar/前缀(F12 网络面板检查)。 - 打开任意容器日志,观察日志是否逐条实时出现(而非成批涌现),确认 SSE 未被缓冲。
- 开启 Shell 并连接终端(需先配置
--enable-shell),确认不会秒断。 - 访问
{base}/manifest.webmanifest,确认start_url与scope带前缀。
关于 Nginx 缓冲、Traefik 压缩等问题的深入排查记录,可继续阅读 docs/guide/faq.md;若需在开启认证(simple / OIDC / forward-proxy)的场景下组合 base 路径,可参考 docs/guide/authentication.md,登录重定向逻辑同样已按 base 前缀正确处理(见 internal/web/index.go)。
【免费下载链接】dozzleRealtime log viewer for containers. Supports Docker, Swarm and K8s.项目地址: https://gitcode.com/GitHub_Trending/do/dozzle
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考