forked from DevOps/deploy.stack
11 KiB
11 KiB
将 npx @deepseek-ai/dsh web 以系统服务方式启动
目标:让 DeepSeek Harness Web GUI(默认
http://127.0.0.1:3080)随系统自动启动、后台常驻、崩溃可自愈。 本文档含完整步骤、脚本与三种方案(Windows 任务计划程序 / NSSM 服务 / Linux systemd)。
0. 背景事实(已核对源码)
dsh web是dsh --profile web的别名;它只启动一个前台 HTTP 服务,不会自动打开浏览器,适合作为服务运行。- 应用参数只有三个:
--host <host>:仅允许127.0.0.1(0.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. 核心原则
- 不要直接把
npx塞进服务:npx走带哈希的 npm 缓存,服务账户下 PATH/缓存经常对不上。先全局安装,再用node.exe直接调 CLI 入口。 - 工作目录必须设:设为实际 workspace 根(如
D:\DSH)。 - 显式设置
DSH_HOME:指向用户现有~/.dsh并确保服务账户可读写,或让服务以用户账户运行。 - 准备凭据:
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 不需要。
步骤
- 保存启动脚本
D:\dsh-service\start-dsh-web.cmd(内容见第 5 节,内含环境变量与端口守护)。 - 在管理员(或普通用户)PowerShell 执行下面的注册命令。
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. 方案 B:NSSM 真·Windows 服务(推荐:开机即起 + 崩溃自愈)
步骤
- 安装 NSSM(任选其一):
winget install NSSM.NSSM --accept-package-agreements --accept-source-agreements # 已在本机执行成功 # 或官网下载 https://nssm.cc/release/nssm-2.24.zip 解压(nssm.cc 在本机网络下直连不稳,优先 winget) - 管理员 PowerShell 执行下方安装/配置命令(逐条)。
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. 方案 C:Linux 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. 维护 / 卸载
# 方案 B(NSSM)
nssm restart DSHWeb # 重启
nssm stop DSHWeb; nssm remove DSHWeb confirm # 卸载
# 方案 A(任务计划程序)
Stop-ScheduledTask -TaskName DSHWeb
Unregister-ScheduledTask -TaskName DSHWeb
8. 常见坑
- 端口冲突:不要和正在运行的 npx 实例同时占用 3080(服务监听失败会以非零状态退出)。先停旧实例(
Get-Process node排查),或重启机器后服务自动接管。 - 工作目录:不设置时 DSH 把 cwd 当 workspace 根,可能落到
C:\Windows\System32,务必设置AppDirectory/WorkingDirectory。 - 账户与 DSH_HOME:服务账户改变会导致
~/.dsh换位置,凭据、会话、设置全部"消失"。要么显式DSH_HOME,要么服务跑在用户账户下。 - 局域网访问:
--host 0.0.0.0被 DSH 故意拒绝;需要局域网访问时保持127.0.0.1并用--trusted-host加白名单。 - 权限审批:服务无终端,approval 会挂在 Web 界面里等待点击,不是故障。
- 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 协议代理再装:(直连 npmmirror 在本机也不通,必须走代理。) 兜底方案(本机已采用):$env:HTTP_PROXY='http://127.0.0.1:7890'; $env:HTTPS_PROXY='http://127.0.0.1:7890' npm install -g @deepseek-ai/dshnpm 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.service(Linux 参考)已生成 - ✅ 方案 A:任务计划程序
DSHWeb已注册(AtLogOn 交互式,State=Ready) - ✅ 方案 B:NSSM 已通过
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