# MaiBot WebUI TLS/SSL 配置指南 本文档基于当前仓库实现整理,目标是让 WebUI 通过 HTTPS 提供访问能力,并保持登录、Cookie、WebSocket 和 Let's Encrypt 续期正常工作。 ## 1. 先说结论 MaiBot 当前最合适的 TLS/SSL 方案是让反向代理终止 HTTPS,然后把请求转发到 WebUI 的 HTTP 服务。 推荐顺序如下: 1. Caddy 反向代理 + Let's Encrypt 自动签发与续期 2. 宝塔面板反向代理 + Let's Encrypt 3. 1Panel 反向代理 + Let's Encrypt 4. 不建议直接让 WebUI 自己监听 HTTPS,当前仓库没有现成的 WebUI 原生 TLS 配置入口 ## 2. 当前项目的部署特征 当前仓库里,WebUI 的前后端是同源部署思路: 1. 后端是独立的 FastAPI WebUI 服务,默认监听 127.0.0.1:8001 2. 前端构建产物由这个 FastAPI 服务直接托管 3. 浏览器生产模式下默认按同源访问 API 4. 页面如果通过 HTTPS 打开,前端会自动把 WebSocket 协议切到 WSS 这意味着最稳妥的方式是: 1. MaiBot WebUI 继续在本机或容器内网跑 HTTP 2. 让 Caddy、宝塔 Nginx 或 1Panel OpenResty 对外暴露 443 3. 由代理把所有请求和 WebSocket 都转发到 WebUI ## 3. 配置前的准备工作 正式启用 HTTPS 之前,先确认下面几项: 1. 已准备一个已经解析到服务器公网 IP 的域名,例如 maibot.example.com 2. 80 和 443 端口可以从公网访问 3. 服务器没有其他程序占用 80 和 443 4. WebUI 可以在本机正常打开,例如 http://127.0.0.1:8001 如果采用 Docker Compose 部署,还要确认: 1. 容器已经能正常启动 2. 根目录的 docker-compose.yml 当前可以正常运行 3. HTTPS 入口将统一由反向代理接管 ## 4. WebUI 自身配置 无论采用 Caddy、宝塔还是 1Panel,都建议先把 WebUI 配成生产模式。 修改 config/bot_config.toml 里的 webui 配置段,建议值如下: ```toml [webui] enabled = true mode = "production" anti_crawler_mode = "loose" allowed_ips = "127.0.0.1" trusted_proxies = "127.0.0.1" trust_xff = true secure_cookie = true enable_paragraph_content = false ``` 各项的意义: 1. mode = "production" 让 WebUI 按生产环境运行,并倾向启用更严格的安全行为。 2. secure_cookie = true 让登录 Cookie 仅在 HTTPS 下传输。 3. trust_xff = true 允许从反向代理传入的 X-Forwarded-For 获取真实来源 IP。 4. trusted_proxies = "127.0.0.1" 表示只有来自本机反向代理的 X-Forwarded-For 才被信任。 注意: 1. 如果使用 Docker 内部的反向代理,trusted_proxies 不应固定写 127.0.0.1,而应填写反向代理容器到 MaiBot 的实际来源地址或所在网段。 2. 如果尚未切换到 HTTPS,不要提前开启 secure_cookie = true,否则可能出现登录 Cookie 不生效或握手异常的问题。 ## 5. 直接部署方式如何配置 TLS/SSL 这里的“直接部署”指的是: 1. MaiBot 直接跑在宿主机上 2. WebUI 监听本机 127.0.0.1:8001 3. 宿主机安装 Caddy 4. 由 Caddy 负责申请证书和 HTTPS 反代 ### 5.1 推荐的网络结构 ```text 浏览器 -> https://maibot.example.com -> Caddy :443 -> 127.0.0.1:8001 -> MaiBot WebUI ``` ### 5.2 宿主机直装 Caddy 以 Debian 或 Ubuntu 为例,参考步骤如下: ```bash sudo apt update sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list sudo apt update sudo apt install -y caddy ``` macOS Homebrew 参考: ```bash brew install caddy ``` ### 5.3 Caddyfile 示例 仓库已提供两份可复制的示例文件,请按部署方式选择: 1. 非 Docker 宿主机部署:dashboard/docs/Caddyfile.host.example 2. Docker Compose 部署:dashboard/docs/Caddyfile.docker.example 宿主机直连部署可使用以下最简配置: ```caddyfile maibot.example.com { reverse_proxy 127.0.0.1:8001 } ``` 如需显式添加安全头,可以使用增强版: ```caddyfile maibot.example.com { encode zstd gzip header { Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" X-Content-Type-Options "nosniff" X-Frame-Options "SAMEORIGIN" Referrer-Policy "strict-origin-when-cross-origin" } reverse_proxy 127.0.0.1:8001 } ``` 非 Docker 直接部署建议直接从 dashboard/docs/Caddyfile.host.example 开始修改域名并投入使用。 ### 5.4 HSTS 是否启用 可以启用,而且当前推荐由反向代理统一下发 HSTS 响应头,而不是让 WebUI 自己在 FastAPI 层单独处理。 当前仓库提供的两份 Caddy 示例都已经带了 HSTS: 1. dashboard/docs/Caddyfile.host.example 2. dashboard/docs/Caddyfile.docker.example 示例配置中的这一行就是 HSTS: ```caddyfile Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" ``` 这行配置的含义如下: 1. max-age=31536000 浏览器在 1 年内记住该站点只能使用 HTTPS。 2. includeSubDomains 所有子域名也必须强制使用 HTTPS。 3. preload 表示该域名计划提交到浏览器内置的 HSTS preload 列表。 HSTS 建议按下面的节奏启用: 1. 初次上线 HTTPS 时,可以先使用不带 preload 的版本。 2. 确认主域名和所有相关子域名都长期稳定支持 HTTPS 后,再考虑是否加入 preload。 3. 如果无法确认所有子域名都支持 HTTPS,不要轻易保留 includeSubDomains。 更稳妥的起步版本如下: ```caddyfile Strict-Transport-Security "max-age=31536000" ``` 如果所有子域名都已经稳定支持 HTTPS,可以使用: ```caddyfile Strict-Transport-Security "max-age=31536000; includeSubDomains" ``` 只有在满足下面条件时,才建议使用 preload: 1. 主域名始终可通过 HTTPS 访问。 2. 所有子域名都始终可通过 HTTPS 访问。 3. 已明确理解 preload 是长期约束,而不是临时开关。 HSTS 的风险点主要有这些: 1. 一旦浏览器记住该域名只能用 HTTPS,后续临时切回 HTTP 会直接失败。 2. 如果开启 includeSubDomains,而某个子域名并没有部署 HTTPS,该子域名会被浏览器直接拦截。 3. 如果开启 preload 并提交到浏览器列表,撤销成本会比较高,生效和移除都不是即时的。 因此,本文档里的 Caddy 示例更适合作为“完整增强版示例”参考。首次部署时,建议先按实际域名情况,将 HSTS 调整成更合适的版本后再正式上线。 ### 5.5 启动与验证 ```bash sudo caddy validate --config /etc/caddy/Caddyfile sudo systemctl restart caddy sudo systemctl status caddy ``` 检查项: 1. 浏览器访问 https://maibot.example.com 能正常打开登录页 2. 登录后 Cookie 正常写入 3. 日志页和聊天页的 WebSocket 可以正常连接 4. 证书是 Let's Encrypt 或所选颁发机构签发的有效证书 ### 5.6 直接部署方式的 Let's Encrypt 申请与续期 Caddy 默认会自动处理证书签发和续期,前提如下: 1. 域名已正确解析到服务器 2. 80 和 443 可从公网访问 3. 没有 CDN、WAF 或安全组拦截 ACME 验证请求 Caddy 的自动续期通常无需手工干预,只需确保: 1. 保持 Caddy 常驻运行 2. 不要阻断 80 和 443 3. 定期关注 Caddy 日志是否存在 ACME 失败记录 常用检查命令: ```bash sudo journalctl -u caddy -n 200 --no-pager sudo journalctl -u caddy -f ``` 如果续期失败,优先检查: 1. 域名是否仍然解析到当前服务器 2. 80 和 443 是否被防火墙、面板或云安全组拦截 3. 是否存在另一个程序抢占了 80 或 443 ## 6. 宝塔面板如何配置 SSL 宝塔适合已经习惯图形化管理 Nginx 站点的部署方式。思路仍然是:由宝塔的站点反向代理到 MaiBot WebUI。 ### 6.1 推荐网络结构 ```text 浏览器 -> 宝塔站点 HTTPS -> 宝塔 Nginx/OpenResty 反向代理 -> 127.0.0.1:8001 -> MaiBot WebUI ``` ### 6.2 宝塔站点创建步骤 1. 登录宝塔面板。 2. 进入网站。 3. 添加站点。 4. 域名填写实际使用的 WebUI 域名,例如 maibot.example.com。 5. PHP 版本可以选纯静态或关闭运行环境,重点是站点存在即可。 ### 6.3 反向代理配置步骤 1. 进入对应站点。 2. 打开反向代理。 3. 新增反向代理。 4. 目标 URL 填写 http://127.0.0.1:8001。 5. 发送域名通常保持目标域或原域名即可。 如果使用的是宝塔站点配置文件,也可以手动补这一段: ```nginx location / { proxy_pass http://127.0.0.1:8001; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; } ``` 如果宝塔环境没有现成的 connection_upgrade 变量,可以改成: ```nginx proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; ``` ### 6.4 宝塔中申请 Let's Encrypt 证书 1. 进入站点设置。 2. 打开 SSL。 3. 选择 Let's Encrypt。 4. 勾选对应域名。 5. 申请证书。 6. 开启强制 HTTPS。 ### 6.5 宝塔中续期证书 宝塔一般会自动续期,但仍然需要检查: 1. 面板计划任务是否正常运行 2. 80 端口是否在验证时可达 3. 域名解析是否未被改动 建议定期查看: 1. 宝塔站点 SSL 到期时间 2. 宝塔计划任务执行日志 3. 站点错误日志和 Nginx 错误日志 ### 6.6 宝塔模式下 WebUI 配置建议 建议保持: ```toml [webui] mode = "production" secure_cookie = true trust_xff = true trusted_proxies = "127.0.0.1" ``` 如果宝塔和 MaiBot 不在同一台机器上,trusted_proxies 需要换成宝塔所在服务器到 MaiBot 的来源地址。 ## 7. 1Panel 如何配置 SSL 1Panel 的逻辑和宝塔类似,本质上也是由面板管理的网关或站点反向代理到 MaiBot WebUI。 ### 7.1 推荐网络结构 ```text 浏览器 -> 1Panel 网站/反向代理 HTTPS -> OpenResty/Nginx 反向代理 -> 127.0.0.1:8001 或 core:8001 -> MaiBot WebUI ``` ### 7.2 1Panel 配置步骤 1. 登录 1Panel。 2. 打开网站或反向代理管理。 3. 新建网站,域名填 maibot.example.com。 4. 添加反向代理规则,目标地址指向 http://127.0.0.1:8001。 5. 开启 WebSocket 支持。 6. 保存并重载站点配置。 如果是在 Docker 环境里通过 1Panel 管理容器,目标地址也可以填写容器服务名,例如 http://core:8001,但前提是 1Panel 管理的网关容器与 MaiBot 在同一个 Docker 网络内。 ### 7.3 在 1Panel 申请 Let's Encrypt 证书 1. 打开证书管理。 2. 选择 Let's Encrypt。 3. 绑定域名。 4. 选择 HTTP-01 或面板默认验证方式。 5. 完成签发后,把证书绑定到对应网站。 6. 启用 HTTPS。 ### 7.4 1Panel 中续期证书 1Panel 通常会自动续期,但需要确认: 1. 自动续期开关处于启用状态 2. 面板的任务调度正常 3. 80 和 443 端口验证时不被拦截 4. 域名始终指向正确服务器 ### 7.5 1Panel 模式下的反代头 请确认面板生成的配置会向后端传递: 1. Host 2. X-Real-IP 3. X-Forwarded-For 4. X-Forwarded-Proto 5. Upgrade 6. Connection 缺少 X-Forwarded-Proto 时,WebUI 可能误判为 HTTP,进而影响 secure cookie 与登录行为。 ## 8. Docker Compose 下如何配置 TLS/SSL 根目录 docker-compose.yml 已补充默认注释的 Caddy 示例块,用于容器化部署时启用 HTTPS。 Docker 模式下请使用:dashboard/docs/Caddyfile.docker.example 非 Docker 宿主机模式下请使用:dashboard/docs/Caddyfile.host.example 详细步骤请看另一份专项文档:dashboard/docs/webui-tls-ssl-compose.md 这里只先给结论: 1. 启用 Caddy 反向代理时,不应再把 core 的 8001 直接映射到公网 2. 应由 Caddy 容器暴露 80 和 443 3. Caddy 通过容器网络访问 core:8001 ## 9. 常见问题 ### 9.1 开了 HTTPS 后无法登录 优先检查: 1. webui.secure_cookie 是否在 HTTPS 环境下开启 2. 代理是否正确传递 X-Forwarded-Proto 3. 浏览器访问的是否确实是 https:// 域名而不是 http:// IP 4. Cookie 是否被浏览器策略、扩展或跨站配置拦截 ### 9.2 页面能打开,但日志页或聊天页 WebSocket 失败 优先检查: 1. 代理是否支持 WebSocket Upgrade 2. 是否使用了 HTTPS 页面去连接 ws:// 明文地址 3. Caddy、Nginx、宝塔、1Panel 是否有单独的 WebSocket 开关或升级头配置 ### 9.3 Let's Encrypt 申请失败 优先检查: 1. 域名解析是否正确 2. 80 端口是否可访问 3. 是否开启了 CDN 代理但没有正确放通验证流量 4. 面板或防火墙是否拦截 ACME 请求 ### 9.4 是否能直接用 IP 申请 Let's Encrypt 不能。Let's Encrypt 只为域名签发公开可信证书,不为裸 IP 签发。 ### 9.5 内网环境如何测试 HTTPS 可以使用 Caddy 的 tls internal 进行测试,但客户端必须手工信任内部 CA 根证书。正式对外服务仍建议使用有效公网域名和 Let's Encrypt。 ## 10. 推荐实践 普通 Linux 服务器部署的推荐顺序如下: 1. 宿主机直装 Caddy 2. WebUI 绑定 127.0.0.1:8001 3. 域名指向服务器 4. 用 Caddy 反代并自动管理 Let's Encrypt 如果已经使用面板管理服务器,则: 1. 宝塔用户直接用宝塔反向代理和 Let's Encrypt 2. 1Panel 用户直接用 1Panel 网站或网关反代和证书管理 如果采用 Docker Compose 部署,则: 1. 使用根目录 compose 中提供的默认注释 Caddy 示例块 2. 注释掉 core 服务里直接暴露 WebUI 的端口映射 3. 由 Caddy 统一对外暴露 80 和 443