Skip to content

[反馈]Docker 部署下 Dashboard 无法启用模型:保存后提示重启但(1)重启请求 401(2)restartBridge() 在 Docker 非 systemd 下不生效 #4

Description

@SwiftFloatFlow

[Bug] Dashboard 保存后无法通过重启生效 / Dashboard-saved config does not take effect after restart


中文

问题描述

在 Docker 容器中部署(非 systemd 托管),通过 Dashboard 管理模型时遇到两个连锁问题,导致模型启用后无法生效:

现象 1:Dashboard 上保存配置(带上了正确的 authorization: Bearer <BRIDGE_API_KEY>)能成功,保存后提示“需要重启”。

现象 2:点击「重启 Bridge」按钮时,请求没有携带 authorization 头,返回 401 Unauthorized。

现象 3:手动在浏览器/curl 中带上正确的 authorization: Bearer <key> 重新调用 POST /admin/restart,返回 {"ok":true},但容器进程实际没有重启(启动时间不变),因此配置没有重新加载,已启用(enabled:true)的模型始终不生效。


复现步骤

  1. 在 .env 设置 BRIDGE_API_KEY=sk-xxx(带 sk- 前缀)
  2. Docker 启动 Bridge,从 http://<IP>:9992 访问 Dashboard
  3. 在 Dashboard 开启某个模型(如 deepseek/deepseek-v4.1-flash)
  4. 点击「JSON 保存」→ 成功,提示重启
  5. 点击「重启 Bridge」→ 401 Unauthorized
  6. 用 curl 手动带对 key 调 POST /admin/restart → 返回 ok,但容器进程未重启,模型仍未启用

根本原因分析

问题 A:auth() 函数未使用 pendingBridgeKey(src/dashboard.ts)

function auth(){
  const key = currentBridgeAuthKey() || (!pendingBridgeKey ? fullBridgeKey() : '') || '';
  return key ? {'authorization':'Bearer '+key,...} : {'content-type':'application/json'}
}
  • 当用户通过「💾/🎲」设置过 key 后,pendingBridgeKey 变为真值
  • 此时 currentBridgeAuthKey()(localStorage 无 key + 服务端返回 [REDACTED])返回空
  • 且 pendingBridgeKey 为真时,!pendingBridgeKey 为 false,fullBridgeKey() 不会被调用
  • 于是 auth() 返回不携带 Authorization 头的 headers → 服务端 401

抓包证据:保存请求(成功)带 authorization 头;但紧接着的重启请求(来自同一操作流)没有 authorization 头。原因是保存成功后 render()→syncBridgeKey() 把「客户端 API Key」输入框清空,且 pendingBridgeKey 处于异常状态。

建议修复:

const key = currentBridgeAuthKey() || pendingBridgeKey || fullBridgeKey() || '';

问题 B:Docker 非 systemd 下 restartBridge() 是 no-op(src/server.ts)

function restartBridge(): void {
  if (process.platform === "linux") {
    const supervisedBySystemd = Boolean(process.env.INVOCATION_ID || process.env.SYSTEMD_EXEC_PID);
    if (supervisedBySystemd || process.env.COMMANDCODE_BRIDGE_RESTART_MODE === "exit") {
      setTimeout(() => process.exit(0), 100).unref?.();
    }
    return;  // ← Docker 非 systemd 且未设 COMMANDCODE_BRIDGE_RESTART_MODE 时,直接 return,什么都不做
  }
  // macOS launchctl 逻辑
}

在 Docker 容器(非 systemd)中,如果既没有 INVOCATION_ID/SYSTEMD_EXEC_PID,也没设置 COMMANDCODE_BRIDGE_RESTART_MODE=exit,restartBridge() 什么都不做。POST /admin/restart 返回 {"ok":true},但进程没退出、容器没重启、运行中的配置没重新加载 → 保存的模型启用不生效。

这需要在 Docker 部署文档中明确说明(如设置 restart: unless-stopped + COMMANDCODE_BRIDGE_RESTART_MODE=exit,或手动 docker restart)。


建议

  1. 修复 auth() 函数,让 pendingBridgeKey 也参与认证
  2. 在 Docker 部署文档中补充 restartBridge() 的生效前提(systemd 或 COMMANDCODE_BRIDGE_RESTART_MODE=exit + 容器 auto-restart)

环境

  • 版本:1.53.0.a
  • 部署:Docker 容器(非 systemd)
  • 访问:http://192.168.124.3:9992
  • BRIDGE_API_KEY:以 sk- 开头

English

Description

Deployed in a Docker container (not managed by systemd). When managing models through the Dashboard, two cascading issues occur, causing enabled models to remain ineffective:

Symptom 1: Saving the configuration in the Dashboard (with the correct authorization: Bearer <BRIDGE_API_KEY>) succeeds, and after saving it prompts “restart required”.

Symptom 2: When clicking the “Restart Bridge” button, the request does not include the authorization header and returns 401 Unauthorized.

Symptom 3: Manually calling POST /admin/restart again in the browser/curl with the correct authorization: Bearer <key> returns {"ok":true}, but the container process does not actually restart (start time unchanged). Therefore, the configuration is not reloaded, and models with enabled:true never take effect.


Steps to Reproduce

  1. Set BRIDGE_API_KEY=sk-xxx in .env (with the sk- prefix)
  2. Start Bridge in Docker and access the Dashboard at http://<IP>:9992
  3. Enable a model in the Dashboard (e.g. deepseek/deepseek-v4.1-flash)
  4. Click “JSON Save” → succeeds, prompts restart
  5. Click “Restart Bridge” → 401 Unauthorized
  6. Manually call POST /admin/restart with the correct key via curl → returns ok, but the container process does not restart and the model remains ineffective

Root Cause Analysis

Cause A: The auth() function does not use pendingBridgeKey (src/dashboard.ts)

function auth(){
  const key = currentBridgeAuthKey() || (!pendingBridgeKey ? fullBridgeKey() : '') || '';
  return key ? {'authorization':'Bearer '+key,...} : {'content-type':'application/json'}
}
  • After the user sets a key via “💾/🎲”, pendingBridgeKey becomes truthy
  • At this point, currentBridgeAuthKey() returns empty (no key in localStorage + server returns [REDACTED])
  • Also, when pendingBridgeKey is truthy, !pendingBridgeKey is false, so fullBridgeKey() is not called
  • Therefore, auth() returns headers without the Authorization header → server returns 401

Packet capture evidence: The save request (successful) includes the authorization header; however, the immediately following restart request (from the same operation flow) does not include the authorization header. The reason is that after a successful save, render()→syncBridgeKey() clears the “Client API Key” input field, and pendingBridgeKey is left in an abnormal state.

Suggested fix:

const key = currentBridgeAuthKey() || pendingBridgeKey || fullBridgeKey() || '';

Cause B: restartBridge() is a no-op under Docker without systemd (src/server.ts)

function restartBridge(): void {
  if (process.platform === "linux") {
    const supervisedBySystemd = Boolean(process.env.INVOCATION_ID || process.env.SYSTEMD_EXEC_PID);
    if (supervisedBySystemd || process.env.COMMANDCODE_BRIDGE_RESTART_MODE === "exit") {
      setTimeout(() => process.exit(0), 100).unref?.();
    }
    return;  // ← Under Docker without systemd and without COMMANDCODE_BRIDGE_RESTART_MODE, it returns directly and does nothing
  }
  // macOS launchctl logic
}

In a Docker container (non-systemd), if neither INVOCATION_ID/SYSTEMD_EXEC_PID is present nor COMMANDCODE_BRIDGE_RESTART_MODE=exit is set, restartBridge() does nothing. POST /admin/restart returns {"ok":true}, but the process does not exit, the container does not restart, and the running configuration is not reloaded → the saved model enablement does not take effect.

This needs to be clearly documented in the Docker deployment docs (e.g. set restart: unless-stopped + COMMANDCODE_BRIDGE_RESTART_MODE=exit, or manually run docker restart).


Recommendations

  1. Fix the auth() function so that pendingBridgeKey also participates in authentication
  2. Add the prerequisites for restartBridge() to take effect in the Docker deployment documentation (systemd, or COMMANDCODE_BRIDGE_RESTART_MODE=exit + container auto-restart)

Environment

  • Version: 1.53.0.a
  • Deployment: Docker container (non-systemd)
  • Access: http://192.168.124.3:9992
  • BRIDGE_API_KEY: starts with sk-

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions