资讯详情

AionUi 远程连接 WebUI 服务完全指南:从启停开关到 QR 码登录与扩展贡献

📅 2026/9/11 3:04:15 | 华诺云谱 👁 阅读
AionUi 远程连接 WebUI 服务完全指南:从启停开关到 QR 码登录与扩展贡献
AionUi 远程连接 WebUI 服务完全指南从启停开关到 QR 码登录与扩展贡献【免费下载链接】AionUiOpen-source 24/7 Cowork app for OpenClaw, Hermes, Claude Code, Codex, OpenCode and 20 more CLI Agent | Customize your assistants | Team them upStar if you like it!项目地址: https://gitcode.com/GitHub_Trending/ai/AionUi本文聚焦 AionUi「设置 → 远程连接」页面 WebUI Tab 的完整能力涵盖 WebUI 服务启停、配置持久化与启动恢复、远程访问控制、用户名/密码认证管理、QR 码登录、状态实时同步以及扩展系统如何向 WebUI 服务器贡献 API 路由与静态资源。读完本文你将掌握 WebUI 服务的完整使用流程、认证安全机制、IPC 通信链路并能在桌面端、CLI/服务器模式和扩展开发三种场景下正确配置与排查问题。AionUi 内置的 WebUI 服务允许用户在桌面端一键启动一个可在浏览器中访问的 Web 界面静态站点 aioncore 后端封装并支持开启局域网远程访问、二维码扫码登录等能力。本文档主体整理自 docs/prds/remote/webui/webui.md并结合 WebuiModalContent.tsx、webuiBridge.ts、webuiConfig.ts、ipcBridge.ts 与 static-server.ts 等源码做纵深补充。Channels Tab 相关能力见 docs/prds/remote/channels/channels.md。1. 页面结构与双 Tab 布局F-WEBUI-09「远程连接」页面位于左侧栏「应用」分组下「显示」与「桌面宠物」之间URL hash 为#/settings/webui。在 Electron 桌面端页面顶部渲染两个 TabWebUI地球图标— 默认选中负责 WebUI 服务管理Channels通讯图标 Telegram / Lark / DingTalk / WeChat / WeCom / Slack / Discord 7 个渠道 logo 缩略图— 内容通过React.lazy懒加载加载期间显示「加载中...」占位。WebUI Tab 内部结构自顶向下为标题WebUIh2→ 功能描述 3 步引导提示条启用 WebUI → 访问地址 → 允许远程访问→WebUI 服务卡片蓝色提示横幅 启用开关 访问地址 远程访问开关→登录信息卡片用户名 密码 QR 码登录。关键的平台分支逻辑在源码中有明确体现WebuiModalContent组件首先通过isElectronDesktop()检测运行环境WebuiModalContent.tsx。非桌面端即通过浏览器访问 WebUI 自身不渲染任何服务管理功能直接渲染 Channels 配置内容无 Tab 切换——这避免了浏览器端对 Electron 主进程 IPC 的依赖也保证了服务管理只能从桌面端操作。2. WebUI 服务启停F-WEBUI-01前置条件运行在 Electron 桌面端isElectronDesktop() true。打开「启用 WebUI」Switch 后UI 依次经历Switch 显示 loading 旋转旁侧出现橙色「启动中...」文字启动成功后 Switch 变为蓝色 checked 状态旁侧显示绿色「✓ 运行中」toast 提示「WebUI 启动成功」i18n keysettings.webui.startSuccess下方出现「访问地址」行若为首次启动且有初始密码密码行显示明文关闭开关后访问地址行与 QR 码区域消失toast 提示「WebUI 已停止」settings.webui.stopSuccess。2.1 启动路径的源码实现从源码看启动链路是渲染进程handleToggle(true)→webui.start.invoke({ port, allowRemote })→ 主进程 webuiBridge.ts 的 start provider →startDesktopWebUI()webuiConfig.ts→startWebHost()来自aionui/web-host包。其中有两个值得注意的实现细节先种子化初始密码maybeSeedInitialPassword()会先探测后端/api/auth/status若needs_setup true全新安装后用户表只有空密码哈希的种子行则调用/api/webui/reset-password生成并持久化随机密码再把明文暂存用于设置页一次性展示webuiBridge.ts。复用既有后端startDesktopWebUI不会新建 aioncore 进程而是通过globalThis.__backendPort复用应用启动时由backendManager.start()拉起的后端避免两个进程竞争同一 SQLite 文件webuiConfig.ts。2.2 异常与边界行为场景行为启动 IPC 失败网络错误/主进程异常Switch 回滚到关闭状态toast「操作失败」settings.webui.operationFailed启动 IPC 超时3 秒未返回UI 乐观认为已启动显示运行中并持久化enabledtrue已知局限UI 可能与实际状态不一致端口被占用服务器自动尝试port 1递增上限固定为DEFAULT_PORT 10用户通过 CLI/环境变量指定的端口超出此范围时不触发递增直接报错停止操作fire-and-forgetUI 与 ConfigStorage 先更新为停止态并 toast「WebUI 已停止」随后才异步调用webui.stop.invoke()。Toast 出现时服务器可能仍在运行运行中再次收到启动请求先停止旧实例关闭所有 WebSocket 连接、释放端口再启动新实例端口递增逻辑的默认值定义在 webuiConfig.ts生产环境25808开发环境25809多实例开发AIONUI_MULTI_INSTANCE1为25810即递增上限为25818/25819。同时注意代码注释强调Switch 必须跟随真实服务器状态running而非持久化偏好——过去直接读webui.desktop.enabled会导致自动恢复静默失败端口冲突等时 Switch 仍显示为开用户点击保存的 URL 得到白屏WebuiModalContent.tsx。主进程是webui.desktop.enabled的唯一写者渲染进程只读running、不回写。3. 启动恢复与配置持久化F-WEBUI-02启用 WebUI 后系统将webui.desktop.enabled true写入 ConfigStorage实际为后端/api/settings/client存储见 webuiConfig.ts下次启动时应用在后台非阻塞地自动恢复服务进入设置页即显示为已启动状态。3.1 端口解析优先级覆盖式CLI 参数--port / --webui-port 环境变量AIONUI_PORT / PORT 配置文件userData/webui.config.json 默认值25808/25809对应实现为resolveWebUIPort()webuiConfig.tsparsePortValue会校验端口必须在 1–65535 之间非法值直接视为未配置。3.2 远程访问解析多源 OR 聚合只要任一来源为 true 即启用远程访问isRemoteMode || AIONUI_ALLOW_REMOTE / AIONUI_REMOTEtrue || AIONUI_HOST0.0.0.0或 ::、::0|| 配置文件 allowRemote: true || ConfigStorage 偏好对应实现为resolveRemoteAccess()webuiConfig.ts布尔环境变量解析支持1/true/yes/on与0/false/no/off。3.3 两条启动路径的配置差异启动路径端口解析远程访问解析CLI/服务器模式经过resolveWebUIPortCLI env config default经过resolveRemoteAccess多源 OR 聚合桌面自动恢复仅从 ConfigStorage 读取不经过 resolve仅从 ConfigStorage 读取不经过 resolve这一差异源自restoreDesktopWebUIFromPreferences()直接从/api/settings/client读取偏好webuiConfig.ts意味着CLI 和环境变量在桌面自动恢复路径下不生效已知局限 #13。该函数在自动恢复失败时会反向写回enabledfalse避免每次启动都静默重试失败服务——这也与 PRD 中「持久化在启动成功后才写入」的验收标准呼应。配置文件位于 ElectronuserData目录下的webui.config.json写入采用「先写 tmp 再 rename」的原子方式mode0o600且重写时自动剥离旧版密码字段passwordHash/passwordUpdatedAt凭据的唯一事实来源是 SQLite users 表webuiConfig.ts。4. 访问地址展示F-WEBUI-03WebUI 运行后status.running true服务卡片出现「访问地址」行根据远程访问状态显示不同地址远程访问关闭http://localhost:{port}远程访问开启http://{局域网IP}:{port}如http://192.168.3.15:25809地址以蓝色等宽链接样式显示点击通过shell.openExternal.invoke(url)在系统默认浏览器打开旁侧复制按钮调用navigator.clipboard.writeTexttoast 提示「复制成功」common.copySuccess。UI 计算逻辑见getDisplayUrl()WebuiModalContent.tsx优先使用status.lanIP其次cachedIP再退到从networkUrl中正则提取主机名。异常兜底点击链接打开浏览器失败仅记日志局域网 IP 获取失败无网卡/无 IPv4 地址时退回localhost。局域网 IP 由getLanIP()遍历os.networkInterfaces()取第一个非 internal 的 IPv4 地址webuiConfig.ts。5. 远程访问控制F-WEBUI-04「允许远程访问」Switch 决定 WebUI 监听地址在127.0.0.1本地与0.0.0.0局域网之间切换。开关下方有说明文字与「查看方式」链接点击打开远程访问指南页面以及「让管家帮我设置」Let the butler set it up的 AI 引导入口见 WebuiModalContent.tsx。核心行为差异WebUI 运行中切换执行「停止最多等待 1.5s→ 启动 → 持久化」的重启流程切换监听地址必须重启期间显示 loading成功 toast「WebUI 已重启」settings.webui.restartSuccess访问地址从localhost变为局域网 IPQR 码区域出现WebUI 未运行仅保存偏好不触发重启下次启动生效重启失败系统二次调用getStatus确认若确认未运行则回滚开关 toast「操作失败」整体最长等待 6s停止 1.5s 启动 3s 状态确认 1.5s持久化失败同样回滚开关状态 toast。实现中停止步骤使用Promise.race([webui.stop.invoke(), 1.5s 超时])启动步骤await webui.start.invoke({ port, allowRemote: checked })全部成功后才configService.set(DESKTOP_WEBUI_ALLOW_REMOTE_KEY, checked)并 toastWebuiModalContent.tsx。6. 用户名管理F-WEBUI-05登录信息卡片中的「用户名:」行始终可见无论 WebUI 是否启用默认显示admin旁有复制按钮与铅笔编辑按钮。点击编辑弹出「设置新用户名」弹窗输入框预填当前用户名。6.1 表单校验规则规则前端校验后端校验错误提示必填是-前端 i18n 提示最少 3 字符是是前端 i18n / 后端英文原文未 i18n 化最多 32 字符是是前端 i18n / 后端英文原文未 i18n 化仅允许[a-zA-Z0-9_-]是是前端 i18n / 后端英文原文未 i18n 化不能以_或-开头/结尾是是前端 i18n / 后端英文原文未 i18n 化用户名已存在不同用户-是Username already exists英文原文前端校验在表单 validator 中完整实现WebuiModalContent.tsx。注意与密码修改不同用户名后端错误码未做前端 i18n 翻译失败时直接 toast 后端返回的英文原文。6.2 会话失效机制修改用户名成功后所有已存在的登录 token 失效——实现方式是 JWT secret 轮转invalidateAllTokens生成新 secret。这是被动失效已建立的 WebSocket 连接不会立即断开需等到下次请求或心跳时才被拒绝。修改用户名走 HTTP 通道webui.changeUsername.invoke→ POST/api/webui/change-username见 ipcBridge.ts。7. 密码显示与密码修改F-WEBUI-06 / 077.1 初始密码的显示策略「初始密码:」行同样始终可见首次启动有初始密码显示明文——12 至 16 字符含小写 大写 数字 特殊字符!#$%^*非首次启动已修改密码/无初始密码显示******遮罩密码可见状态canShowPlainPassword是组件内存状态页面刷新后重置为遮罩密码行仅有编辑按钮无复制按钮与用户名行的「复制 编辑」不对称编辑按钮 hover 时 tooltip 提示「忘记密码点击设置新密码不需要当前密码」。7.2 修改密码流程点击编辑按钮弹出「设置新密码」弹窗新密码Password 输入框带可见性切换图标placeholder「请输入新密码至少8位」 确认密码「请再次输入新密码」。表单校验规则规则校验端错误提示新密码必填前端「请输入新密码」最少 8 字符前端后端i18n 提示 /PASSWORD_TOO_SHORT最多 128 字符后端PASSWORD_TOO_LONG弱密码黑名单后端PASSWORD_TOO_COMMON确认密码必填前端「请再次输入新密码」两次密码一致前端「两次密码不一致」弱密码黑名单password,12345678,123456789,qwertyui,abcdefgh。前端校验在 WebuiModalContent.tsx 的 Form rules 中实现。后端可能一次返回多个错误码以; 分隔前端通过errorCodeMap翻译后合并展示PASSWORD_TOO_SHORT→ 短密码提示等未知错误码显示原文或兜底「密码修改失败」WebuiModalContent.tsx。技术要点不需要当前密码验证changePasswordAPI 直接设置新密码安全性依赖 Electron 本地环境信任修改后全部 token 被动失效JWT secret 轮转旧 token 在下一次请求/心跳/重连时验证失败被拒绝清除初始密码后端clearInitialPasswordAdminPassword()清除内存中的初始密码后续getStatus不再返回initialPassword成功提交后 toast「密码修改成功」settings.webui.passwordChanged弹窗关闭密码行切换为******。8. QR 码登录F-WEBUI-08前置条件WebUI 运行中status.running true且允许远程访问status.allowRemote true。此时登录信息卡片下方出现分隔线 「二维码登录」区块说明「使用手机扫描二维码即可在手机浏览器中自动登录」。8.1 交互细节系统自动生成140×140 SVG二维码qrcode.react的QRCodeSVG纠错级别 M懒加载无需用户操作二维码下方显示有效期本地化时间格式toLocaleTimeString的hour: 2-digit, minute: 2-digit12h/24h 取决于系统 locale旁有复制按钮复制二维码对应 URL与刷新按钮加载中旋转动画自动刷新token 5 分钟过期定时器 4 分钟触发重新生成setTimeout(generateQRCode, 4*60*1000)服务停止或关闭远程访问时自动清除二维码并取消定时器。QR 码 URL 格式http://{lanIP}:{port}/qr-login?token{64位hex}。注意前端只从后端拿到{ token, expires_at_ms }完整 URL 由前端基于当前 status 拼装远程开启用networkUrl否则用localUrl见 WebuiModalContent.tsx。IPC 对应webui.generateQRToken.invoke→ POST/api/webui/generate-qr-tokenipcBridge.ts。8.2 Token 安全机制安全特性说明随机生成crypto.randomBytes(32)→ 64 位 hex有效期5 分钟QR_TOKEN_EXPIRY 5 * 60 * 1000一次性使用验证后标记used: true并立即从内存中删除IP 限制非远程模式下仅允许本地/局域网 IP 使用内存存储存储在进程内Map进程重启后全部失效异常提示文案Token 过期 →「QR token has expired」重复扫码已使用→「QR token has already been used」非本地 IP 使用 local-only token →「QR login is only allowed from local network」生成失败/初始未生成状态共用占位文案settings.webui.qrGenerateFailed组件无法区分两种状态。9. 状态实时同步F-WEBUI-10组件挂载时自动加载 WebUI 状态偏好 运行状态此后主进程触发的任何状态变更启动/停止/端口变化包括来自应用菜单、启动恢复的变更通过事件实时推送更新 UI。IPC 双通道机制Electron 环境优先electronAPI.webuiGetStatus()直接 IPC无超时问题非 Electron 后备webui.getStatus.invoke()bridge 模式1.5s 超时实时事件webui.statusChanged.on()监听主进程推送的状态变更。兜底默认值getStatus 失败或超时时使用{ running: false, port: DEFAULT_PORT, adminUsername: admin }WebuiModalContent.tsx。主进程侧webui.statusChanged.emit在 start/stop provider 中触发webuiBridge.tsgetStatusprovider 还会实时探测后端用户表拿到当前adminUsernamewebuiBridge.ts。10. 扩展系统 WebUI 贡献F-WEBUI-11扩展开发者可通过扩展 manifest 的contributes.webui声明apiRoutes和/或staticAssets应用加载扩展时由resolveWebuiContributions校验并注册到 WebUI 服务器。10.1 安全校验规则规则说明命名空间化路径必须以/{extensionName}/开头保留路径保护不允许使用/,/api,/login,/logout,/qr-login,/static,/assets路径冲突检测跨扩展重复路径后者被跳过路径遍历防护isPathWithinDirectory确保所有文件在扩展目录内入口存在性检查同时查找 dist 和 source 路径静态资源目录存在性existsSync检查目录已知局限wsHandlers和middleware虽已在类型中声明但运行时暂不支持仅console.warn提示。仓库内 examples/hello-world-extension/contributes/acp-adapters.json 等示例可参考扩展 manifest 的声明方式。11. 附录状态矩阵、IPC 链路与已知局限11.1 WebUI 状态矩阵WebUI 开关允许远程访问地址QR 码区域登录信息OFF(any)不显示不显示显示ONOFFhttp://localhost:{port}不显示显示ONONhttp://{lanIP}:{port}显示显示11.2 IPC 通信链路┌──────────────────────────────────────────────────────────────────────┐ │ 渲染进程 (Renderer) - WebuiModalContent.tsx │ │ │ │ 状态加载: │ │ ├─ ConfigStorage.get(webui.desktop.enabled) │ │ ├─ ConfigStorage.get(webui.desktop.allowRemote) │ │ ├─ electronAPI.webuiGetStatus() [优先] │ │ └─ webui.getStatus.invoke() [后备, 1.5s timeout] │ │ │ │ 服务启停: │ │ ├─ webui.start.invoke({ port, allowRemote }) [3s timeout] │ │ ├─ webui.stop.invoke() [fire-and-forget] │ │ └─ webui.statusChanged.on(callback) [实时监听] │ │ │ │ 认证管理 (双通道: electronAPI 优先, bridge 后备): │ │ ├─ webuiChangePassword / webui.changePassword.invoke │ │ ├─ webuiChangeUsername / webui.changeUsername.invoke │ │ └─ webuiGenerateQRToken / webui.generateQRToken.invoke │ │ │ │ 外部操作: │ │ ├─ shell.openExternal.invoke(url) [打开浏览器/指南] │ │ └─ navigator.clipboard.writeText(text) [复制] │ └──────────────────────────────────────────────────────────────────────┘ │ IPC Bridge Direct IPC ┌─────────────────────▼────────────────────────────────────────────────┐ │ 主进程 (Main) - webuiBridge.ts │ │ │ │ Bridge providers: │ │ ├─ webui.getStatus → WebuiService.getStatus() │ │ ├─ webui.start → startWebServerWithInstance() │ │ ├─ webui.stop → server.close() cleanupWebAdapter() │ │ ├─ webui.changePassword → WebuiService.changePassword() │ │ ├─ webui.changeUsername → WebuiService.changeUsername() │ │ ├─ webui.generateQRToken → generateQRLoginUrlDirect() │ │ └─ webui.verifyQRToken → verifyQRTokenDirect() │ │ │ │ Emitters (主→渲染): │ │ ├─ webui.statusChanged.emit({ running, port, localUrl }) │ │ └─ webui.resetPasswordResult.emit({ success, newPassword }) │ └─────────────────────┬────────────────────────────────────────────────┘ │ ┌─────────────────────▼────────────────────────────────────────────────┐ │ 服务层 │ │ WebuiService: getStatus / changePassword / changeUsername / │ │ resetPassword / getLanIP │ │ webuiQR: generateQRLoginUrlDirect / verifyQRTokenDirect │ │ AuthService: validatePasswordStrength / validateUsername / │ │ generateRandomPassword / hashPassword / invalidateAllTokens │ └──────────────────────────────────────────────────────────────────────┘注凭据类操作改密/改用户名/重置密码/生成 QR token实际走 HTTP 路由/api/webui/*经 ipcBridge HTTP 转发桌面主进程 bridge 仅拥有生命周期与状态快照webuiBridge.ts静态服务器与 WebSocket 代理的底层实现在 static-server.ts。11.3 Toast 通知汇总触发操作Toast 类型i18n KeyWebUI 启动成功successsettings.webui.startSuccessWebUI 停止成功successsettings.webui.stopSuccess远程访问切换重启成功successsettings.webui.restartSuccess启动/停止/重启失败errorsettings.webui.operationFailed复制成功successcommon.copySuccess用户名修改成功successsettings.webui.usernameChanged用户名修改失败errorsettings.webui.usernameChangeFailed密码修改成功successsettings.webui.passwordChanged密码修改失败errorsettings.webui.passwordChangeFailedQR 码生成失败errorsettings.webui.qrGenerateFailed11.4 已知局限汇总#功能点局限描述1F-WEBUI-01启动 IPC 超时 3s 后乐观设置running: true并持久化enabledtrue可能导致 UI 与实际状态不一致且下次启动循环恢复失败服务2F-WEBUI-01停止操作 fire-and-forgetToast 出现时服务器可能仍在运行停止失败用户无感知3F-WEBUI-04远程访问切换需重启服务器期间短暂不可用最长 6s4F-WEBUI-06密码首次可见状态是组件内存状态页面刷新后丢失5F-WEBUI-06密码行仅有编辑按钮无复制功能与用户名行功能不对称6F-WEBUI-07修改密码不需要当前密码安全性依赖 Electron 本地环境信任7F-WEBUI-05用户名后端校验错误信息为硬编码英文未做前端 i18n 翻译8F-WEBUI-05/07Token 失效通过 JWT secret 轮转被动失效已建立的 WebSocket 连接不会立即断开9F-WEBUI-08QR token 存储在进程内存 Map主进程重启后全部失效10F-WEBUI-08isLocalIP不覆盖 IPv6 ULA 地址fd00::/811F-WEBUI-08QR 码初始状态与生成失败共用同一占位文案组件无法区分12F-WEBUI-02UI 未暴露端口修改入口仅可通过配置文件/CLI/环境变量修改13F-WEBUI-02桌面自动恢复不经过resolveWebUIPort/resolveRemoteAccessCLI 和环境变量在此路径下不生效14F-WEBUI-01端口递增上限固定为DEFAULT_PORT 10用户指定端口超出此范围时递增不生效12. 深入阅读docs/prds/remote/webui/webui.md本文的原始 PRD11 个功能点、验收标准与异常分支全量定义docs/prds/remote/webui/README.mdPRD 索引与功能点总览、工作记录WebuiModalContent.tsx渲染进程 UI 全部实现双 Tab、启停、认证、QR 码webuiBridge.ts主进程生命周期 IPC bridge 与初始密码种子化webuiConfig.ts端口/远程访问解析、配置持久化、桌面自动恢复ipcBridge.tswebui命名空间下所有 IPC/HTTP 通道定义static-server.ts静态服务器、端口监听与 WebSocket 代理底层实现【免费下载链接】AionUiOpen-source 24/7 Cowork app for OpenClaw, Hermes, Claude Code, Codex, OpenCode and 20 more CLI Agent | Customize your assistants | Team them upStar if you like it!项目地址: https://gitcode.com/GitHub_Trending/ai/AionUi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。