跳到主要内容

远程访问指南

这篇文档聚焦 CountBot 的实际远程访问流程,包括开放监听、首次远程初始化、登录认证、安全边界和常见排障。

这篇文档解决什么问题

如果你希望:

  • 在局域网内从另一台设备访问 CountBot
  • 将 CountBot 暴露给公网或反向代理
  • 允许“首次初始化”在远程完成
  • 理解 /setup/<随机路径>、认证、WebSocket 和安全边界之间的关系

那么优先阅读本页;认证细节可以再配合 /docs/advanced/auth 查看。

为什么放在这里

这类内容更适合作为“进阶部署指南”的一部分,而不是快速开始:

  • 它和监听地址、反向代理、初始化入口、认证、安全策略强相关
  • 它比单纯的“认证机制”更偏实际运维和排障
  • 它会随着远程初始化能力、日志提示、入口有效期等策略变化而持续演进

因此它最适合放在 advanced 分类,紧挨“部署与运维”和“认证”。

本地访问与远程访问的区别

当前实现里,本地访问和远程访问是两条不同路径:

  • 本地访问:127.0.0.1::1localhost
  • 远程访问:局域网 IP、公网 IP、经过反向代理且带有代理头的访问

设计目标是:

  • 本地使用尽量零摩擦,不影响原有使用方式
  • 远程访问默认受控,避免未授权访问 Web UI、API 和 WebSocket

第一步:先决定监听地址

默认启动时,CountBot 监听:

127.0.0.1:8000

这意味着只有本机能访问。

如果你要开放给局域网或公网,需要显式设置:

HOST=0.0.0.0
PORT=8000
python start_app.py

开放后,启动日志通常会同时打印:

  • Local: http://localhost:8000
  • Network: http://<你的局域网IP>:8000

首次远程初始化怎么做

情况 A:已经初始化过账号密码

这种情况最简单:

  1. 远程访问首页
  2. 系统跳转到登录页
  3. 登录成功后继续使用

情况 B:还没有初始化过账号密码

现在 CountBot 支持“受控的远程首次初始化”,但不是直接开放 /api/auth/setup 给任何人调用。

启动时,如果系统尚未完成认证初始化,会生成一个一次性远程入口:

/setup/<随机八位字母路径>

例如:

/setup/akLRzvlW

正确做法是:

  1. 查看启动日志中的“远程首次初始化入口”提示
  2. 将这段路径拼接到上方 Network 地址后访问
  3. 在该页面完成账号和密码设置
  4. 初始化成功后,该入口立即失效

实际访问形态类似:

http://192.168.2.211:8000/setup/akLRzvlW

随机入口有效期

这个随机初始化入口不是永久有效的,它有独立有效期。

配置项:

REMOTE_SETUP_SECRET_TTL_MINUTES

规则如下:

  • 默认值:30
  • 最小值:10
  • 最大值:120
  • 超过时间后,旧入口自动失效
  • 初始化成功后,无论是否到期,都会立刻失效

例如:

REMOTE_SETUP_SECRET_TTL_MINUTES=45
HOST=0.0.0.0
python start_app.py

如果设置了非法值,系统会自动夹紧到 10-120 分钟范围内。

远程访问的认证边界

远程访问时,当前主要保护以下入口:

  • /api/*
  • /ws/chat

其中公开或半公开的基础状态接口包括:

  • /api/auth/status
  • /api/auth/login
  • /api/auth/setup
  • /api/health
  • /api/system/health

但要注意:

  • /api/auth/setup 并不是对所有远程请求开放
  • 它只接受本地请求,或来自合法隐藏初始化入口的请求
  • /ws/chat 在远程下同样要求通过认证,不能绕过

远程首次初始化背后的安全模型

当前实现不是“任何远程用户都能初始化密码”,而是“拿到一次性随机入口的人,才能在有效期内完成首次初始化”。

这套模型的优点是:

  • 本地原有行为不受影响
  • 不需要额外安装第三方库
  • 不需要长期暴露一个固定的“初始化页面”
  • 初始化成功后入口会立即失效

但也要明确它的边界:

  • 它本质上仍然是一个能力型入口 URL
  • 任何能看到启动日志的人,都可能在有效期内访问它
  • 它可以降低误碰撞和普通扫描命中的概率,但不能替代防火墙、反向代理和 HTTPS

反向代理与公网部署注意事项

如果你通过 Nginx、Caddy 或其他代理暴露 CountBot:

  • CountBot 会把带代理头的请求视为远程请求
  • 即使代理和后端在同一台机器上,也不会被当成本地直连

这意味着:

  • 你不能依赖“代理转发后 127.0.0.1 看起来像本地请求”来绕过认证
  • 这是刻意的安全设计

公网部署时建议至少配套以下措施:

  1. 启用 HTTPS
  2. 不要把启动日志随意暴露给无关人员
  3. 在 CountBot 前增加防火墙、反向代理或 WAF
  4. 视环境启用更严格的工作空间限制和命令限制

常见问题

1. 远程访问提示 AUTH_SETUP_REQUIRED 是什么意思

表示服务尚未完成认证初始化,远程 API 请求被保护住了。

处理方式:

  • 在本机完成初始化;或
  • 使用启动日志打印出的 /setup/<随机路径> 完成远程首次初始化

2. 访问 /setup/<随机路径> 返回 404

通常有几种原因:

  • 路径输错了
  • 入口已经过期
  • 入口已经被成功使用过
  • 服务已经完成初始化,不再允许访问该入口

3. 为什么根路径能打开,但接口返回 401

这是预期行为:

  • 前端静态页可以先加载
  • 真正受保护的是远程 /api/*/ws/chat
  • 未登录时,这些接口会返回认证错误

4. WebSocket 要不要单独认证

要。

/ws/chat 不会因为你已经能打开前端页面就自动放行。远程情况下,它仍要求:

  • 已登录 Cookie;或
  • 合法 Bearer Token

推荐阅读顺序

如果你是第一次配置远程访问,建议按这个顺序读:

  1. 本页:远程访问流程与边界
  2. /docs/advanced/deployment:部署与运维
  3. /docs/advanced/auth:认证机制细节
  4. /docs/advanced/security:工作空间、命令和审计策略

相关文件

  • backend/modules/auth/middleware.py
  • backend/modules/auth/router.py
  • backend/app.py
  • frontend/src/views/LoginView.vue
  • frontend/src/App.vue
  • frontend/src/api/client.ts
  • frontend/src/router/index.ts