为什么自托管 DeepSeek Harness

把推理跑在自己机器或内网,对外只暴露一个受控入口,换来三件事:数据不出域、API 形态统一、成本可控。DeepSeek Harness(下称 dsh)把模型服务、会话与工具链收敛成一个可托管的服务进程,适合作为团队内部的统一 AI 工作台底座。

进程托管:systemd

最稳的方式是用 systemd 托管 dsh 进程,而不是 nohup 丢到后台。关键是三层保障:自动拉起、内存上限、不污染环境。

[Unit]
Description=DeepSeek Harness
After=network.target

[Service]
Type=simple
User=dsh
WorkingDirectory=/opt/dsh
ExecStart=/opt/dsh/dsh --host 127.0.0.1 --port 19527 --trusted-host dsh.eu-as.cn
Restart=on-failure
RestartSec=5
MemoryMax=12G
TasksMax=512

[Install]
WantedBy=multi-user.target

MemoryMax 是 OOM 韧性的核心:推理进程偶发吃内存,不设上限可能把宿主机一起拖垮。限制后最坏情况是该服务被 OOM Killer 回收,systemd 再按 Restart=on-failure 拉起。

可信代理闭环:/api loopback trust fence

dsh 只监听 127.0.0.1,经反向隧道把本地 19527 映射出去;前端经过 nginx 反代,Host/Origin 由 nginx 重写。这条「本地回环 + 头部重写」的信任边界,就是 loopback trust fence:后端永远只看到来自可信主机的请求。

--trusted-host 声明哪些域名被信任;nginx 在反代时改写 Host 与 Origin,使后端认为请求来源可信,从而避免 403。二者必须配套,缺一个都会破防。

反代:nginx

location /api/ {
    proxy_pass http://127.0.0.1:19527;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_read_timeout 86400s;
}

流式输出(SSE / token 流)是长连接,proxy_read_timeout 必须拉大到分钟级以上,否则前端会中途断流。

远程可达:autossh 反向隧道

若 dsh 跑在内网机器,用 autossh 建稳定反向隧道,把本地端口映射到公网跳板,再由跳板上的 nginx 暴露:

autossh -M 0 -o ServerAliveInterval=30 \
  -R 19527:localhost:19527 bastion

-M 0 关闭 autossh 自带保活、交给 ServerAliveInterval;这样隧道断了能自动重连,是远程可达的保命机制。

排查:403 与 502

  • 403:几乎总是可信域 / Host 校验问题。检查 --trusted-host 是否包含当前访问域名;nginx 是否真的改写了 Host/Origin;浏览器实际发出的 Origin 与后端信任列表是否一致。
  • 502:后端没起来或隧道断了。ss -tlnp | grep 19527 确认端口在听;systemctl status dsh 看进程;journalctl -u dsh -f 看实时错误;再 curl -s 127.0.0.1:19527 直打后端,确认不是隧道而是后端本身的问题。

经验

自托管 AI 服务的稳定性 = 进程托管 + 可信边界 + 隧道保活,三者缺一不可。任何一环断开,对外表现就是 403 或 502,而根因往往不在模型,而在这一圈基础设施。