dsh 怎么开机自启、后台常驻?DeepSeek Harness 三平台自启配置与验证方法
dsh 本身是前台进程,关掉终端就停;要开机自启必须交给系统进程管理器托管——macOS 用 launchd、Linux 用 systemd 用户服务、Windows 用任务计划程序。 DSH插件 与 DeepSeek插件 都跑在 dsh 本体之上,所以自启只需托管这一个进程;三平台的配置骨架不同,但有三个共同点必须写对:用 dsh 的绝对路径、补全环境变量、启动命令加 --no-open。
为什么 DeepSeek Harness 关掉终端就停:自启要交给系统进程管理器
dsh 是挂在当前终端会话下的前台进程,会话结束进程就被回收,所以「开机自启」这件事它自己做不到,必须由操作系统的进程管理器拉起(来源)。 动手前先确认两件事:
- 拿到可执行文件的绝对路径 — 执行
which dsh(Windows 执行where dsh)。预期:得到类似/usr/local/bin/dsh或 nvm 版本目录下的完整路径;自启配置里一律写这个绝对路径。 - 确认平时是怎么启动的 — 就是你手动敲的那条命令(例如
dsh web)。预期:把这条命令原样搬进自启配置,只在末尾加--no-open,不要凭想象改参数。
为什么强调绝对路径:系统进程管理器不经过你的 shell,不会读取 .zshrc / .bash_profile 里配的 PATH,只写 dsh web 会直接找不到命令。这个坑在 macOS 上尤其常见,完整的报错特征与修法见《macOS 上 DeepSeek Harness 报错》。
macOS 下 DeepSeek Harness 开机自启:用 launchd LaunchAgent 托管
macOS 上正确的位置是用户级 LaunchAgent(~/Library/LaunchAgents/ 下的 plist),它随登录加载、能访问你自己的数据目录,比系统级 LaunchDaemon 更适合托管 dsh(来源)。 五步配好:
-
创建 plist — 新建
~/Library/LaunchAgents/org.dsh.web.plist,核心内容:xml<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>org.dsh.web</string> <key>ProgramArguments</key> <array> <string>/usr/local/bin/dsh</string> <string>web</string> <string>--no-open</string> </array> <key>RunAtLoad</key> <true/> <key>KeepAlive</key> <true/> <key>EnvironmentVariables</key> <dict> <key>PATH</key> <string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin</string> </dict> <key>StandardOutPath</key> <string>/tmp/dsh-web.out.log</string> <key>StandardErrorPath</key> <string>/tmp/dsh-web.err.log</string> </dict> </plist> -
把路径换成你自己的 — 用第 1 步
which dsh的结果替换<string>/usr/local/bin/dsh</string>。预期:路径与实际安装位置一致,nvm 用户会是版本目录下的完整路径。 -
补全 PATH — 在
EnvironmentVariables的PATH里加上node所在目录。预期:启动时不再报env: node之类找不到命令的错误。 -
加载并立即启动 — 执行
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/org.dsh.web.plist(旧版系统可用launchctl load -w)。预期:命令无输出即加载成功。 -
确认进程在跑 — 执行
launchctl list | grep org.dsh.web。预期:能看到该 label,首列是进程 PID(而非-)。
Linux 下 DeepSeek Harness 开机自启:用 systemd 用户服务常驻
Linux 上把它做成 systemd 用户服务,服务随用户会话启动、日志由 journal 统一收集,配合 enable-linger 可以在未登录时也保持运行(来源)。 五步配好:
-
创建单元文件 — 新建
~/.config/systemd/user/dsh.service:ini[Unit] Description=DeepSeek Harness Web After=network.target [Service] ExecStart=/usr/local/bin/dsh web --no-open Restart=on-failure RestartSec=5 [Install] WantedBy=default.target -
替换 ExecStart 路径 — 换成
which dsh的结果。预期:绝对路径正确,避免服务环境里找不到命令。 -
重载并启用 — 执行
systemctl --user daemon-reload && systemctl --user enable --now dsh。预期:enable让它在每次启动时自动拉起,--now让它立刻开始运行。 -
允许未登录也运行 — 执行
loginctl enable-linger $USER。预期:注销后服务不被回收;不做这一步,服务只在你登录期间存在。 -
看状态与日志 — 执行
systemctl --user status dsh,日志用journalctl --user -u dsh -f。预期:状态为 active (running),日志有正常启动输出。
Windows 下 DeepSeek Harness 开机自启:任务计划程序与启动文件夹
Windows 上没有等价于 launchd / systemd 的常驻服务概念,最稳的做法是任务计划程序(触发器选「登录时」),临时省事可以把快捷方式丢进启动文件夹(来源)。 四步配好:
- 找到 dsh 的实际入口 — 在终端执行
where dsh。预期:npm 全局安装一般是%APPDATA%\npm\dsh.cmd,把它记下来。 - 建一个基础任务 — 打开「任务计划程序」→「创建任务」→ 常规 页勾选「不管用户是否登录都要运行」按需选择,触发器选「登录时」,操作选「启动程序」并把程序填成第 1 步的
.cmd完整路径、参数填web --no-open。预期:任务保存后手动「运行」一次能起服务。 - 或者用启动文件夹(更简单) — 按
Win+R输入shell:startup回车,把 dsh 的快捷方式复制进去,并在「属性 → 目标」末尾补上web --no-open。预期:下次登录会自动执行;这种方式只在你登录后触发。 - 确认端口已在监听 — 执行
netstat -ano | findstr 3080。预期:有监听行与对应 PID,说明服务真的起来了。
DSH plugin 自启必配项、生效验证与常见坑
无论哪个平台,只要这三点写错,配置看着完整也不会生效;验证一律看端口,不看配置文件。 逐项对齐:
- 可执行文件用绝对路径 — 三平台都用第 1 步查到的路径,而不是
dsh这个命令名。预期:自启日志里不再出现 command not found 一类报错。 - 环境变量按需补全 — 至少保证 PATH 里有
node;如果你改过$DSH_HOME,也要在服务定义里显式声明这个变量。预期:自启拉起后加载的 profile 与你手动启动时是同一个。 - 启动命令加
--no-open— 后台常驻时不需要每次弹浏览器。预期:服务在跑但不会弹出浏览器窗口,自己访问http://127.0.0.1:3080即可。 - 验证看端口 — macOS / Linux 执行
lsof -i :3080,Windows 执行netstat -ano | findstr 3080。预期:有监听才算成功;没有监听先看自启日志,再排查端口占用(见《DeepSeek Harness 启动端口被占用》)。
另外五条是最常踩的坑:
- 不要装成系统级 root 服务:dsh 的配置与插件都在你的用户目录下,用 root 或系统服务运行会去读另一套
$DSH_HOME,表现为「自启起来了但插件全没了」。 - 崩溃循环先看日志再改配置:
KeepAlive与Restart=on-failure会让进程反复拉起,看起来像「一直重启」,真正原因通常在日志第一行。 - 端口冲突会让自启静默失败:3080 被别的程序占用时,进程会退出或报错,配置本身没错,别反复重写 plist / service 文件。
- 自启只解决「进程起没起来」:插件是否加载、模型是否连得上属于另外的排查范围,不要混在一起判断。
- 改完配置要重新加载:launchd 用
launchctl bootout再bootstrap,systemd 用daemon-reload再restart,否则跑的还是旧配置。
用 DSH Plugin Hub 确认自启起来的实例装对了插件
自启的实例与手动启动的实例共用同一份 profile 目录,用 DSH Plugin Hub 的已安装列表就能确认这个 profile 里到底装了什么,避免「服务起来了但插件不在」。 访问自启实例的 http://127.0.0.1:3080,打开「已安装」页核对清单;如果清单和你预期的不一致,多半是自启实例用了另一套 $DSH_HOME,回到上面的必配项第 2 条检查环境变量。

来源:Apple developer documentation(launchd)、systemd 官方文档、Microsoft Learn - Task Scheduler、dsh CLI README
常见问题
DeepSeek Harness 是前台进程,必须交给系统进程管理器托管才能开机自启,而且要用 dsh 可执行文件的绝对路径而不是命令名。自启环境不继承终端里的 PATH,只写 dsh web 往往找不到命令;先用 which dsh(Windows 用 where dsh)拿到绝对路径再写进配置。
DeepSeek Harness 在 macOS 上用 launchd 的 LaunchAgent:plist 放在 ~/Library/LaunchAgents/ 下,用 RunAtLoad 让它随登录启动、KeepAlive 让进程退出后自动拉起,再用 launchctl 加载。plist 里还要用 EnvironmentVariables 补全 PATH,否则找不到 node。
写一个 DeepSeek Harness 的 systemd 用户服务:在 ~/.config/systemd/user/ 下建一个 dsh.service,把启动命令写成 ExecStart,配 Restart=on-failure 与 WantedBy=default.target,然后 systemctl --user enable --now dsh。要让它在你没登录时也运行,再执行 loginctl enable-linger 你的用户名。
给 DeepSeek Harness 的自启命令末尾加 --no-open 即可。dsh web 默认会在本机自动打开浏览器,交互式使用时很方便,但作为后台服务反复启动时就成了干扰;加 --no-open 只起服务不开浏览器,之后自己访问 http://127.0.0.1:3080 即可。
验证 DeepSeek Harness 的开机自启用端口,而不是看配置文件:重启或重新登录后,执行 lsof -i :3080(Windows:netstat -ano | findstr 3080),有进程在监听才算生效。没有监听时先看自启日志,再确认端口是不是被别的程序占用。
相关术语
- LaunchAgent
- LaunchAgent 是 macOS launchd 的用户级后台任务类型,配置文件是 ~/Library/LaunchAgents/ 下的 plist。它随用户登录加载,适合托管 dsh 这类用户目录下的常驻服务,与系统级 LaunchDaemon 相对。— Apple developer documentation
- systemd user service
- systemd user service 是 Linux 上以用户身份运行的服务单元,文件放在 ~/.config/systemd/user/,用 systemctl --user 管理。配合 loginctl enable-linger 可以让服务在用户未登录时也保持运行。— systemd 官方文档
- KeepAlive
- KeepAlive 是 launchd plist 中的键,设为 true 后进程退出时会被自动重新拉起,适合常驻服务;排查崩溃循环时它也是让进程反复重启的原因,需要与日志一起看。— Apple developer documentation
- --no-open
- --no-open 是 dsh web 的启动参数,加上后只启动 Web 服务、不自动打开浏览器。交互式启动时默认会打开浏览器,托管为后台服务时应加上它。— dsh CLI README
来源
- Apple developer documentation - Managing background processes(launchd)· Apple
- systemd 官方文档 - systemd.service 与 user 实例· freedesktop.org
- Microsoft Learn - Task Scheduler· Microsoft
- dsh CLI README· deepseek-ai