Files
deploy.stack/shell/dsh_service.md
T

11 KiB
Raw Blame History

npx @deepseek-ai/dsh web 以系统服务方式启动

目标:让 DeepSeek Harness Web GUI(默认 http://127.0.0.1:3080)随系统自动启动、后台常驻、崩溃可自愈。 本文档含完整步骤、脚本与三种方案(Windows 任务计划程序 / NSSM 服务 / Linux systemd)。

0. 背景事实(已核对源码)

  • dsh webdsh --profile web 的别名;它只启动一个前台 HTTP 服务,不会自动打开浏览器,适合作为服务运行。
  • 应用参数只有三个:
    • --host <host>:仅允许 127.0.0.10.0.0.0 被故意拒绝,防远程代码执行);
    • --port <port>:默认 3080,传 0 由系统分配;
    • --trusted-host <authority...>:浏览器信任白名单,可重复。
  • 进程的当前工作目录(cwd)就是默认 workspace 根sandbox 的 workspaceRoot),服务必须显式设置工作目录。
  • 数据根目录默认是 ~/.dsh(按账户 homedir 计算)。服务账户不同 → DSH_HOME 不同 → 凭据/会话/设置全变,务必显式设置 DSH_HOME
  • 凭据来源:DEEPSEEK_API_KEY 环境变量,或 $DSH_HOME/.credentials.yaml(Web「设置 → Models」页面写入的那个)。
  • 服务进程无终端,权限审批(approval)会挂在 Web 界面里等用户点击,属正常行为。

1. 核心原则

  1. 不要直接把 npx 塞进服务npx 走带哈希的 npm 缓存,服务账户下 PATH/缓存经常对不上。先全局安装,再用 node.exe 直接调 CLI 入口。
  2. 工作目录必须设:设为实际 workspace 根(如 D:\DSH)。
  3. 显式设置 DSH_HOME:指向用户现有 ~/.dsh 并确保服务账户可读写,或让服务以用户账户运行。
  4. 准备凭据DEEPSEEK_API_KEY 环境变量或 $DSH_HOME/.credentials.yaml

本机路径表

路径
node.exe D:\sdk\nodejs\node.exe
全局 npm 前缀 D:\sdk\nodejs
全局包入口 D:\dsh-service\global\node_modules\@deepseek-ai\dsh\lib\bin.js(离线副本,含 D:\dsh-service\global\dsh.cmd shim
默认 DSH_HOME C:\Users\cnphp\.dsh
服务目录 D:\dsh-service\(启动脚本、systemd 参考文件、日志)

前置准备(管理员 PowerShell

# 方式一:正常全局安装(本机代理下可能失败,见常见坑 6)
npm install -g @deepseek-ai/dsh

# 方式二:使用离线副本(本机已就绪,与当前 GUI 同版本 0.1.0-rc.6
D:\dsh-service\global\dsh.cmd web --help    # 验证可运行

2. 方案 A:Windows 任务计划程序(最简单,无需额外工具)

适合「开机/登录后自动跑」。-AtStartup 需要管理员;-AtLogOn 不需要。

步骤

  1. 保存启动脚本 D:\dsh-service\start-dsh-web.cmd(内容见第 5 节,内含环境变量与端口守护)。
  2. 在管理员(或普通用户)PowerShell 执行下面的注册命令。
  3. Start-ScheduledTask -TaskName DSHWeb 立即测试。

注册脚本(登录后自动运行,交互式账户,无需密码)

$action = New-ScheduledTaskAction -Execute "cmd.exe" `
  -Argument '/c "D:\dsh-service\start-dsh-web.cmd"' `
  -WorkingDirectory "D:\DSH"
$trigger = New-ScheduledTaskTrigger -AtLogOn -User "$env:USERDOMAIN\$env:USERNAME"
$settings = New-ScheduledTaskSettingsSet -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1) `
  -ExecutionTimeLimit 0 -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
$principal = New-ScheduledTaskPrincipal -UserId "$env:USERDOMAIN\$env:USERNAME" -LogonType Interactive -RunLevel Limited
Register-ScheduledTask -TaskName "DSHWeb" -Action $action -Trigger $trigger -Settings $settings -Principal $principal -Force
Start-ScheduledTask -TaskName "DSHWeb"

注册脚本(开机即起、不登录也运行,管理员)

需要用户密码(-LogonType Password)或以 SYSTEM 运行(-LogonType ServiceAccount -UserId SYSTEM,此时 DSH_HOME 必须显式指向用户 .dsh 且 SYSTEM 有读写权限——本机已具备):

$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
Register-ScheduledTask -TaskName "DSHWeb" -Action $action -Trigger (New-ScheduledTaskTrigger -AtStartup) -Settings $settings -Principal $principal -Force

3. 方案 BNSSM 真·Windows 服务(推荐:开机即起 + 崩溃自愈)

步骤

  1. 安装 NSSM(任选其一):
    winget install NSSM.NSSM --accept-package-agreements --accept-source-agreements   # 已在本机执行成功
    # 或官网下载 https://nssm.cc/release/nssm-2.24.zip 解压(nssm.cc 在本机网络下直连不稳,优先 winget)
    
  2. 管理员 PowerShell 执行下方安装/配置命令(逐条)。
  3. nssm start DSHWeb 启动服务。

安装与配置命令

nssm install DSHWeb "D:\sdk\nodejs\node.exe" "D:\dsh-service\global\node_modules\@deepseek-ai\dsh\lib\bin.js web --port 3080"
nssm set DSHWeb AppDirectory "D:\DSH"                       # workspace 根,必设
nssm set DSHWeb AppEnvironmentExtra DSH_HOME=C:\Users\cnphp\.dsh DEEPSEEK_API_KEY=sk-你的key
nssm set DSHWeb AppStdout "D:\dsh-service\stdout.log"        # 日志(含 URL 行)
nssm set DSHWeb AppStderr "D:\dsh-service\stderr.log"
nssm set DSHWeb AppExit Default Restart                      # 非零退出自动重启
nssm set DSHWeb Start SERVICE_AUTO_START
nssm start DSHWeb

说明:

  • 默认以 LocalSystem 运行;本机 C:\Users\cnphp\.dsh 的 ACL 已含 NT AUTHORITY\SYSTEM:(OI)(CI)(F),无需额外授权。
  • 想以用户账户运行:nssm set DSHWeb ObjectName ".\cnphp" "你的Windows密码"(需要密码)。
  • 与方案 A 同开时的端口冲突由 start-dsh-web.cmd 里的端口守护解决:谁先占 3080 谁服务,另一个静默退出,不会重启循环。
  • DEEPSEEK_API_KEY 未设,DSH 会从 %DSH_HOME%\.credentials.yaml 读取,可省略该环境变量。

4. 方案 CLinux systemd

参考文件已生成:D:\dsh-service\dsh-web.service

# /etc/systemd/system/dsh-web.service
[Unit]
Description=DeepSeek Harness Web
After=network.target

[Service]
Type=simple
User=youruser
WorkingDirectory=/path/to/workspace
Environment=DSH_HOME=/home/youruser/.dsh
# Environment=DEEPSEEK_API_KEY=sk-xxx
ExecStart=/usr/bin/node /usr/lib/node_modules/@deepseek-ai/dsh/lib/bin.js web --port 3080
Restart=on-failure

[Install]
WantedBy=multi-user.target
npm i -g @deepseek-ai/dsh
sudo cp dsh-web.service /etc/systemd/system/
sudo systemctl enable --now dsh-web

5. 启动脚本 D:\dsh-service\start-dsh-web.cmd(完整内容)

@echo off
rem ============================================================================
rem DeepSeek Harness Web - service launcher
rem Design: both the NSSM service and the scheduled task point at this script;
rem a port guard makes them coexist: whoever reaches port 3080 first serves it,
rem the other exits silently (0 = no restart loop).
rem ============================================================================

set DSH_HOME=C:\Users\cnphp\.dsh

rem Optional: uncomment to force the key (default: loaded from %DSH_HOME%\.credentials.yaml)
rem set DEEPSEEK_API_KEY=sk-xxxx

rem --- Port guard: if 3080 is already listening, exit quietly ---
powershell -NoProfile -ExecutionPolicy Bypass -Command "try { if (Get-NetTCPConnection -LocalPort 3080 -State Listen -ErrorAction Stop) { exit 0 } } catch { }"

cd /d D:\DSH
"D:\sdk\nodejs\node.exe" "D:\dsh-service\global\node_modules\@deepseek-ai\dsh\lib\bin.js" web --port 3080

若走 NSSM 直接跑 node(不经脚本),则端口守护缺失,需保证同一时刻只有一种方式在运行。

6. 验证

Get-Service DSHWeb                                  # 或 nssm status DSHWeb
Get-ScheduledTask -TaskName DSHWeb                  # State = Ready
Invoke-WebRequest http://127.0.0.1:3080 -UseBasicParsing   # 返回 200 即 OK
Get-Content D:\dsh-service\stdout.log -Tail 20      # 应看到 "dsh web: http://127.0.0.1:3080"

7. 维护 / 卸载

# 方案 BNSSM
nssm restart DSHWeb          # 重启
nssm stop DSHWeb; nssm remove DSHWeb confirm   # 卸载

# 方案 A(任务计划程序)
Stop-ScheduledTask -TaskName DSHWeb
Unregister-ScheduledTask -TaskName DSHWeb

8. 常见坑

  1. 端口冲突:不要和正在运行的 npx 实例同时占用 3080(服务监听失败会以非零状态退出)。先停旧实例(Get-Process node 排查),或重启机器后服务自动接管。
  2. 工作目录:不设置时 DSH 把 cwd 当 workspace 根,可能落到 C:\Windows\System32,务必设置 AppDirectory / WorkingDirectory
  3. 账户与 DSH_HOME:服务账户改变会导致 ~/.dsh 换位置,凭据、会话、设置全部"消失"。要么显式 DSH_HOME,要么服务跑在用户账户下。
  4. 局域网访问--host 0.0.0.0 被 DSH 故意拒绝;需要局域网访问时保持 127.0.0.1 并用 --trusted-host 加白名单。
  5. 权限审批:服务无终端,approval 会挂在 Web 界面里等待点击,不是故障。
  6. npm 全局安装失败(Exit handler never called! / ECONNRESET:本机 npm 使用 registry.npmmirror.com 镜像,但环境变量 HTTPS_PROXY=socks5://127.0.0.1:7890——npm 不支持 socks5 协议,会把镜像连接全部重置导致安装失败。修正:7890 是 mixed 端口(HTTP/SOCKS5 都收),改用 HTTP 协议代理再装:
    $env:HTTP_PROXY='http://127.0.0.1:7890'; $env:HTTPS_PROXY='http://127.0.0.1:7890'
    npm install -g @deepseek-ai/dsh
    
    (直连 npmmirror 在本机也不通,必须走代理。) 兜底方案(本机已采用)npm install -g 在代理下反复崩溃(Exit handler never called! —— 单包 tarball 下载正常,npm 并发拉取时代理必崩)。把已完整可用的 npx 缓存复制到稳定目录即可离线使用:
    robocopy "$env:LOCALAPPDATA\npm-cache\_npx\<hash>\node_modules" 'D:\dsh-service\global\node_modules' /E
    # 验证:
    "D:\sdk\nodejs\node.exe" 'D:\dsh-service\global\node_modules\@deepseek-ai\dsh\lib\bin.js' web --help
    

附录:本机当前执行状态(2026-xx-xx 会话)

  • D:\dsh-service\start-dsh-web.cmd 已生成
  • D:\dsh-service\dsh-web.serviceLinux 参考)已生成
  • 方案 A:任务计划程序 DSHWeb 已注册(AtLogOn 交互式,State=Ready
  • 方案 BNSSM 已通过 winget install NSSM.NSSM 安装(命令别名 nssm 已添加)
  • 全局 CLI 已就绪:D:\dsh-service\global\node_modules\@deepseek-ai\dsh\lib\bin.js(离线复制自 npx 缓存,版本 0.1.0-rc.6,已验证 web --help 正常;npm install -g 两次均因代理问题失败,见常见坑 6
  • ⏸ 端口 3080 当前被会话中的 npx 实例占用,服务/任务注册后未启动;下次开机(无 npx 实例)由 NSSM 或任务自动接管
  • 备注:nssm.cc 在本机网络(socks5 代理 127.0.0.1:7890)下直连下载被重置,请用 winget 方式安装 NSSM