资讯动态

Dozzle 前置代理认证(Forward Proxy)完全指南:接入 Authelia、Cloudflare Zero Trust 与 oauth2-proxy/Pocket ID

发布时间:2026/9/15 17:39:55 来源:尧图企业网站定制
Dozzle 前置代理认证Forward Proxy完全指南接入 Authelia、Cloudflare Zero Trust 与 oauth2-proxy/Pocket ID【免费下载链接】dozzleRealtime log viewer for containers. Supports Docker, Swarm and K8s.项目地址: https://gitcode.com/GitHub_Trending/do/dozzle导读Dozzle 除了自带的用户名密码登录外还支持一种把身份验证完全交给前置代理的认证模式设置--auth-provider forward-proxy后Dozzle 不再自己校验口令而是信任反向代理如 Traefik、Caddy、Cloudflare Tunnel透传的身份请求头根据请求头中携带的用户名、邮箱、过滤器与角色信息动态构建会话。本文将从源码层面剖析这一模式的认证链路与五个可自定义的请求头并完整演示如何将其接入 Authelia、Cloudflare Zero Trust 与 Pocket ID经由 oauth2-proxy三种主流身份认证方案让你在复用已有 SSO 基础设施的前提下为 Dozzle 的每个登录用户精细控制容器可见范围与操作权限。一、模式原理Dozzle 如何信任代理请求头把--auth-provider设为forward-proxy后Dozzle 不再提供自己的登录页面而是把每个 HTTP 请求中的认证信息当作既成事实直接采信。其核心逻辑位于 internal/auth/proxy.go 的AuthMiddleware当请求头中存在headerUser默认Remote-User时中间件解析Remote-Filter头得到该用户的容器过滤器解析Remote-Roles头得到该用户的角色位掩码然后用newUser(...)构造一个User对象并通过WithUser写入请求上下文后续所有 API 路由通过UserFromContext取出该用户配合 internal/auth/users.go 中的RequireAuthentication拦截未认证请求无用户上下文时直接返回 401若请求头中没有用户信息请求会以匿名身份继续传递由路由层决定是否拒绝。从 internal/web/routes.go 可以看到forward-proxy是 Dozzle 认证提供者枚举none/simple/forward-proxy/oidc中的一等公民且在此模式下不会注册/token、/auth/login等会话签发路由——因为会话已经完全由代理侧管理。值得一提的实现细节是 proxy.go 中的hashEmail它会先对邮箱做去空格与转小写处理再取 MD5 用于拼装 Gravatar 头像地址这也解释了文档中邮箱用于查找用户 Gravatar 头像的机制。前提条件此模式默认要求代理先完成认证并清理来自客户端的同名伪造头见下文各方案的trustForwardHeader/expose等配置否则任何人都可以伪造Remote-User冒充他人。二、快速启用两种部署形态2.1 Docker CLI 方式$ docker run -v /var/run/docker.sock:/var/run/docker.sock -v /path/to/dozzle/data:/data -p 8080:8080 amir20/dozzle --auth-provider forward-proxy2.2 Docker Compose 方式services: dozzle: image: amir20/dozzle:latest volumes: - /var/run/docker.sock:/var/run/docker.sock - /path/to/dozzle/data:/data ports: - 8080:8080 environment: DOZZLE_AUTH_PROVIDER: forward-proxy2.3 必须挂载/data卷的原因前置代理模式下用户的个人设置同样会写入磁盘主题、固定列、常用过滤器等偏好。若没有挂载持久化卷容器每次重建都会导致所有用户设置丢失。这与simple模式下/data承载users.yml的职责不同——forward-proxy 下/data纯粹用于持久化用户偏好。三、Dozzle 期望的请求头完整参考在默认配置下Dozzle 期望代理在通过认证后注入以下五个请求头请求头用途示例Remote-User用户名johndoeRemote-Email用户邮箱同时用于查找 Gravatar 头像johndoeexample.comRemote-Name显示名称John DoeRemote-Filter允许该用户使用的容器过滤器列表逗号分隔labelcom.example.appRemote-Roles允许该用户拥有的角色列表逗号分隔shell,actions这五个请求头的名称并非写死全部可以通过环境变量或 CLI 参数重新映射定义见 internal/support/cli/args.go这正是下文适配 Authelia、Cloudflare、oauth2-proxy 三种不同请求头命名约定的关键CLI 参数环境变量默认值--auth-header-userDOZZLE_AUTH_HEADER_USERRemote-User--auth-header-emailDOZZLE_AUTH_HEADER_EMAILRemote-Email--auth-header-nameDOZZLE_AUTH_HEADER_NAMERemote-Name--auth-header-filterDOZZLE_AUTH_HEADER_FILTERRemote-Filter--auth-header-rolesDOZZLE_AUTH_HEADER_ROLESRemote-Roles从 proxy.go 的源码可以确认若Remote-Filter头无法被 container.ParseContainerFilter 解析中间件会直接返回 400而Remote-Roles头为空或缺失时该用户默认获得全部角色userRoles : All——这一默认全量授权的语义在配置时必须格外留意见第六节。3.1 配置登出 URL前置代理模式下Dozzle 的登出按钮需要把用户送回代理的登出端点可用DOZZLE_AUTH_LOGOUT_URL配置DOZZLE_AUTH_LOGOUT_URL: http://oauth2.example.ru/oauth2/sign_out四、配合 Authelia 使用 DozzleTraefik forward-authAuthelia 是开源的身份验证与授权服务器与门户提供完整的身份与访问管理能力。搭建 Authelia 本身超出了本文范围但下面的配置可直接作为 Dozzle 接入 Authelia 的完整示例点击展开➡️ 点击展开 Authelia 示例docker-compose.ymlnetworks: net: driver: bridge services: authelia: image: authelia/authelia container_name: authelia volumes: - ./authelia:/config networks: - net labels: - traefik.enabletrue - traefik.http.routers.authelia.ruleHost(authelia.example.com) - traefik.http.routers.authelia.entrypointshttps - traefik.http.routers.authelia.tlstrue - traefik.http.routers.authelia.tls.optionsdefault - traefik.http.middlewares.authelia.forwardAuth.addresshttp://authelia:9091/api/authz/forward-auth - traefik.http.middlewares.authelia.forwardAuth.trustForwardHeadertrue - traefik.http.middlewares.authelia.forwardAuth.authResponseHeadersRemote-User,Remote-Groups,Remote-Name,Remote-Email expose: - 9091 restart: unless-stopped traefik: image: traefik:v3.5 container_name: traefik volumes: - ./traefik:/etc/traefik - /var/run/docker.sock:/var/run/docker.sock networks: - net labels: - traefik.enabletrue - traefik.http.routers.api.ruleHost(traefik.example.com) - traefik.http.routers.api.entrypointshttps - traefik.http.routers.api.serviceapiinternal - traefik.http.routers.api.tlstrue - traefik.http.routers.api.tls.optionsdefault - traefik.http.routers.api.middlewaresautheliadocker ports: - 80:80 - 443:443 command: - --api - --providers.dockertrue - --providers.docker.exposedByDefaultfalse - --providers.file.filename/etc/traefik/certificates.yml - --entrypoints.httptrue - --entrypoints.http.address:80 - --entrypoints.http.http.redirections.entrypoint.tohttps - --entrypoints.http.http.redirections.entrypoint.schemehttps - --entrypoints.httpstrue - --entrypoints.https.address:443 - --logtrue - --log.levelDEBUG dozzle: image: amir20/dozzle:latest networks: - net environment: DOZZLE_AUTH_PROVIDER: forward-proxy volumes: - /var/run/docker.sock:/var/run/docker.sock - dozzle:/data labels: - traefik.enabletrue - traefik.http.routers.dozzle.ruleHost(dozzle.example.com) - traefik.http.routers.dozzle.entrypointshttps - traefik.http.routers.dozzle.tlstrue - traefik.http.routers.dozzle.tls.optionsdefault - traefik.http.routers.dozzle.middlewaresautheliadocker expose: - 8080 restart: unless-stopped volumes: dozzle:Authelia configuration.yml############################################################### # Authelia configuration # ############################################################### server: address: tcp://0.0.0.0:9091 log: level: info totp: issuer: authelia.com identity_validation: reset_password: jwt_secret: a_very_important_secret authentication_backend: file: path: /config/users_database.yml access_control: default_policy: deny rules: - domain: traefik.example.com policy: one_factor - domain: dozzle.example.com policy: one_factor session: secret: unsecure_session_secret cookies: - domain: example.com # 应与你受保护的根域名一致 authelia_url: https://authelia.example.com default_redirection_url: https://public.example.com regulation: max_retries: 3 find_time: 120 ban_time: 300 storage: encryption_key: you_must_generate_a_random_string_of_more_than_twenty_chars_and_configure_this local: path: /config/db.sqlite3 notifier: filesystem: filename: /config/notification.txt4.1 关键点解读必须使用有效的 SSL 密钥因为 Authelia 只支持 SSLTraefik 通过forwardAuth中间件把请求转发给 Authelia 的/api/authz/forward-auth做认证并通过authResponseHeaders把 Authelia 返回的Remote-User、Remote-Groups、Remote-Name、Remote-Email透传给 DozzletrustForwardHeadertrue表示 Traefik 信任 Authelia 返回头——注意这是 Traefik 到 Authelia 之间的信任关系生产环境务必确保 Dozzle 容器不被公网直接访问否则客户端可伪造请求头绕过认证。4.2 将 Authelia 用户组映射为 Dozzle 角色Authelia 在Remote-Groups中发送用户的组信息而Dozzle 默认不读取这个头。要把 Authelia 的用户组映射到 Dozzle 的角色请在 Dozzle 服务上设置DOZZLE_AUTH_HEADER_ROLES: Remote-Groups并按角色名称来命名用户组。dozzle_前缀的别名就是为此准备的名为dozzle_shell的组会授予shell角色其他组名会被忽略。不做这个映射的话每个通过验证的用户都会拿到全部角色。为什么需要dozzle_前缀别名看 internal/auth/roles.go 的ParseRole实现角色解析器会把输入按逗号/竖线或 JSON 数组切分逐项匹配shell、actions、download、notifications、cloud、all、none及其dozzle_前缀变体未知的名称会被打日志后忽略invalid role。这意味着如果你把 Authelia 的普通业务用户组如developers原样传入它既不会生效也不会报错——只有显式命名为dozzle_xxx的组才具有明确语义从而让用户组名与角色名解耦避免把业务组全部误当作角色解析。五、配合 Cloudflare Zero Trust 使用 DozzleCloudflare Zero Trust 是一项为自托管软件提供认证访问的服务。Dozzle 通过把认证头映射到 Cloudflare 注入的Cf-Access-Authenticated-User-Email来实现对接services: dozzle: image: amir20/dozzle:latest environment: DOZZLE_AUTH_PROVIDER: forward-proxy DOZZLE_AUTH_HEADER_USER: Cf-Access-Authenticated-User-Email DOZZLE_AUTH_HEADER_EMAIL: Cf-Access-Authenticated-User-Email DOZZLE_AUTH_HEADER_NAME: Cf-Access-Authenticated-User-Email volumes: - /var/run/docker.sock:/var/run/docker.sock - dozzle:/data expose: - 8080 restart: unless-stopped volumes: dozzle:5.1 安全要点务必用expose而不是portsexpose让 8080 端口不暴露在主机上唯一的入口就是 Cloudflare 隧道。如果用ports发布出去主机上的任何人都能自己设置Cf-Access-Authenticated-User-Email从而完全绕过 Cloudflare 的身份校验——这是该方案中最容易踩的坑。5.2 配置 Cloudflare 侧应用启动 Dozzle 容器后按照 Cloudflare Zero Trust 控制台的自托管应用向导配置 Application把dozzle.example.com加入 Access 策略并确保在 Access 设置中勾选传递Cf-Access-Authenticated-User-Email等身份头默认开启。六、配合 Pocket ID 使用 Dozzleoauth2-proxy 方案[!TIP] Dozzle 现在原生支持 OpenID Connect你可以直接把--auth-oidc-issuer指向 Pocket ID完全不需要 oauth2-proxy参见使用 GitHub 与 OIDC 登录。下面这套方案仍然保留供已经在跑 oauth2-proxy、或者希望代理保护的不只是 Dozzle 的场景参考。你需要先起一个容器通过反向代理传递 OpenID Connect 验证信息。下面是使用 oauth2-proxy 的完整示例点击展开➡️ 点击展开 oauth2-proxy 示例1. 在 Pocket ID 中为 Dozzle 新建一个 OIDC 客户端名称Dozzle回调 URLhttps://dozzle.example.com/oauth2/callbackPKCEEnabled复制Client ID和Client Secret的值备用。2. 在现有的 Dozzle compose 中加入以下内容environment: DOZZLE_AUTH_PROVIDER: forward-proxy DOZZLE_AUTH_HEADER_USER: X-Forwarded-User DOZZLE_AUTH_HEADER_EMAIL: X-Forwarded-Email DOZZLE_AUTH_HEADER_NAME: X-Forwarded-Preferred-Username注释掉 Dozzle 的端口因为流量会改为经过新的验证容器转发这种做法一般不需要改动反向代理的配置# ports: # - 8080:80803. 在现有的 Dozzle compose 中新增一个 oauth2-proxy 服务services: # ... oauth2-proxy: image: quay.io/oauth2-proxy/oauth2-proxy:latest restart: unless-stopped container_name: dozzle-oidc command: --config /oauth2-proxy.cfg volumes: - ./oauth2-proxy.cfg:/oauth2-proxy.cfg ports: - 8080:41804. 在 compose 文件所在目录创建oauth2-proxy.cfgclient_id xxx # 来自 Pocket ID client_secret xxx # 来自 Pocket ID cookie_secret xxx # 用 openssl rand -base64 32 | tr -- / -_ 生成 upstreams http://dozzle:8080 # 上游指向 Dozzle 容器的内部端口 code_challenge_method S256 # PKCE 挑战方式plain 或 S256 cookie_expire 0 # 秒0 表示会话级 cookie_name __Host-oauth2-proxy # 或 __Secure-oauth2-proxy安全性稍低 cookie_secure true # 使用 secure 的 HTTPS cookie email_domains [*] # 允许任意邮箱域名登录 http_address 0.0.0.0:4180 # oauth2-proxy 监听的端口 oidc_issuer_url https://id.example.com # 你的 Pocket 基础 URL provider_display_name Pocket ID # OIDC 登录时显示的名称 provider oidc # 使用 OpenID Connect reverse_proxy true # 反向代理流量 scope openid email profile groups # 透传这些 OIDC scope按注释填好各项变量。5. 最后重启你的 Docker compose 服务栈。现在反向代理应该会通过 oauth2-proxy 让你登录 Dozzle。如有问题请查看日志排查。6.1 方案的请求头流与端口变化该方案的请求头名与默认值不同oauth2-proxy 注入的是X-Forwarded-User、X-Forwarded-Email、X-Forwarded-Preferred-Username因此必须用DOZZLE_AUTH_HEADER_USER等三个环境变量完成重映射。同时 Dozzle 的8080端口被注释掉后所有入站流量先到达 oauth2-proxy 的4180认证成功后再把X-Forwarded-*头写入转发给 Dozzle 容器的内部8080请求。七、请求头映射的角色与过滤器语义源码级解析为了让前置代理模式与simple模式保持一致的角色体验Dozzle 复用了同一套角色解析器。结合 internal/auth/roles.go 与简单模式身份验证文档Remote-Roles支持以下取值逗号或竖线分隔也可用 JSON 数组名称不区分大小写角色同时接受授予的权限shelldozzle_shell连接容器并打开 exec 会话。实例还需要开启--enable-shell。actionsdozzle_actions启动、停止和重启容器。实例还需要开启--enable-actions。downloaddozzle_download把容器日志下载为文件。notificationsdozzle_notifications创建和编辑通知规则与通知目标。clouddozzle_cloud关联、解除关联并配置 Dozzle Cloud。alldozzle_all以上所有角色。Remote-Roles头缺失时的默认值。nonedozzle_none没有任何角色。日志仍可查看受用户过滤器约束。会覆盖其他所有设置。任何角色都可以加^前缀表示排除排除规则最后生效、顺序无关紧要如all,^shell表示除shell外的所有角色none是唯一不能被取反的角色。对应地Remote-Filter头接受 Docker 标签过滤语法如labelcom.example.app其解析同样由 internal/container/container_store.go 中的ParseContainerFilter完成与全局--filter参数同源可参照过滤器文档使用。八、三种方案的选型对比与安全红线方案代理层认证头来源是否需要额外容器角色映射AutheliaTraefik forwardAuthRemote-User等 Remote-Groups否Authelia 本体自建需设DOZZLE_AUTH_HEADER_ROLES: Remote-Groups并命名dozzle_前缀组Cloudflare Zero TrustCloudflare TunnelCf-Access-Authenticated-User-Email否默认全角色需在 Cloudflare 侧按邮箱/组做应用策略Pocket ID oauth2-proxyoauth2-proxy 容器X-Forwarded-User等是默认全角色可配合 OIDC 的 groups scope 自定义映射无论选择哪种方案有三条安全红线必须遵守绝不能让 Dozzle 的 8080 端口直连公网或宿主网络一旦绕过代理直接访问 Dozzle任何攻击者都能自行伪造认证头Cloudflare 方案中exposevsports的差异即是为此代理必须清理客户端传入的认证头确保Remote-User、Cf-Access-*、X-Forwarded-*等头只能由认证层写入不能由浏览器直接携带注意默认全角色语义从 proxy.go 的实现可知Remote-Roles头缺失时用户默认持有All权限。若你的身份提供方不注入该头所有登录用户都拥有全部操作能力建议至少通过DOZZLE_AUTH_HEADER_ROLES映射一个真实的角色头并用dozzle_前缀组精确控制授权。九、小结前置代理认证让 Dozzle 的访问控制与既有企业身份体系无缝融合Dozzle 只负责消费代理注入的五个请求头用户名、邮箱、显示名、过滤器、角色并据此完成用户上下文构建、Gravatar 头像解析、容器可见范围过滤与操作权限判定。通过DOZZLE_AUTH_HEADER_*系列环境变量定义于 internal/support/cli/args.go你可以让任意符合规范的身份提供方Authelia、Cloudflare Zero Trust、oauth2-proxy/Pocket ID 等接入 Dozzle而dozzle_前缀角色别名则让 IdP 的用户组与 Dozzle 的细粒度权限模型直接打通。接入后记得挂载/data持久化用户偏好、保持 8080 端口仅在内网可达、并确认Remote-Roles有真实的角色来源即可在享受统一 SSO 的同时守住容器安全的底线。【免费下载链接】dozzleRealtime log viewer for containers. Supports Docker, Swarm and K8s.项目地址: https://gitcode.com/GitHub_Trending/do/dozzle创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价