DeepSeek Harness 服务器部署下实现跨会话长期记忆的完整配置
我想解决的问题很具体。
一个 DeepSeek Harness 对话已经把 100 万上下文用完,第二天直接新建聊天,希望 DeepSeek 还能知道项目背景、之前做过的决定、当前进度和资料位置,不需要重新把整套资料再投喂一次。
如果 Harness 只跑在自己的电脑上,这件事主要是记忆插件的问题。放到云服务器以后,事情会多出两层。第一层是长期记忆怎么保存,第二层是 Harness 对远程 Web 访问有 loopback 和浏览器认证限制。
我实际碰到的两个报错如下。
forbidden: loopback-only
以及
dsh web authentication required; reopen the URL printed by dsh web.
这篇把整套配置过程按实际排查顺序整理下来。
先确认我们要保存的到底是什么
跨会话记忆不适合把旧对话的 100 万 token 全部复制进新窗口。这样很快又会把新的上下文撑满。
更实用的做法是把旧会话中的重要信息提炼出来,长期保存到会话之外。
可以保存的内容包括
-
项目背景 -
已经完成的工作 -
关键决策 -
被否决的方案 -
重要参数 -
用户习惯 -
资料位置 -
当前项目进度 -
下一步任务
整个过程可以理解成下面这样。
对话 1
100 万 token
↓
提炼重要信息
↓
长期记忆文件
↓
关闭对话 1
↓
新建对话 2
↓
自动加载长期记忆
↓
继续之前的项目
这样,新对话不需要知道过去每一句聊天记录,只需要先拿到项目的状态。
如果需要历史中的某个具体细节,再从记忆或资料库中检索。
DeepSeek Harness 中可以先装长期记忆插件
前面的测试中,我优先考虑过几个 Memory 类插件。
其中一个比较直接的选择是
dsh-plugin-memory
安装命令可以这样执行。
dsh plugin --profile web add dsh-plugin-memory
安装完成后重新启动 Harness。
dsh web
这个插件的目标正好对应跨会话使用。
旧会话里的信息写入长期记忆以后,新 session 可以重新加载这些内容。
另一个尝试过的方向是
dsh-auto-memory
它更偏向自动提炼用户信息、项目状态和每天产生的记忆。
如果插件市场已经安装,也可以直接在 Harness 的插件市场中搜索 Memory 类插件。
插件市场本身可以通过下面的命令安装。
dsh plugin --profile web add dshmarket
然后启动 Web 版。
dsh web
不建议同时装很多 Memory 插件
长期记忆插件一般都会向当前上下文注入一部分记忆。
如果同时安装多个类似插件,可能出现几件事。
同一条项目背景被重复注入。
不同插件保存出来的总结产生冲突。
大量重复记忆占掉当前会话 token。
因此先选一个插件测试完整流程更容易排错。
最简单的测试方法是先在旧聊天中保存一句明确的信息。
记住,当前测试项目名称是 Project ABC。
然后新建聊天,再问。
我们之前的测试项目叫什么?
如果能够回答 Project ABC,跨 session 的基础记忆已经工作。
大量原始资料需要和长期记忆分开处理
如果旧会话中的主要内容是项目状态和聊天结论,一个 Memory 插件通常能处理相当一部分需求。
如果里面有大量 PDF、Word、代码、表格或者其他原始资料,情况就不同了。
这种情况下,合理的结构是把记忆和资料拆开。
DeepSeek Harness
│
├─ 长期记忆
│ │
│ ├─ 项目背景
│ ├─ 决策
│ ├─ 进度
│ └─ 下一步
│
└─ 原始资料
│
├─ PDF
├─ Word
├─ 代码
└─ 历史资料
长期记忆回答的是 DeepSeek 应该记住哪些事情。
资料库回答的是旧资料原文放在哪里,以及什么时候需要重新取回来。
这种结构更接近实际需要的连续工作方式。
对话 1 可以用掉 100 万 token。
对话 2 再继续使用新的上下文。
项目状态留在长期记忆里,原始资料继续留在外部存储里。
Harness 放到服务器以后会碰到 loopback 限制
服务器部署结构可以采用下面这种形式。
浏览器
↓
https://dsh.example.com
↓
Nginx
↓
127.0.0.1:3080
↓
DeepSeek Harness
服务器环境可以先确认几个关键项目。
Nginx
Linux 服务器
Harness 监听 127.0.0.1:3080
域名配置文件通常类似下面这样。
/etc/nginx/sites-available/dsh.example.com
启用的配置一般位于
/etc/nginx/sites-enabled/dsh.example.com
如果使用 Let’s Encrypt,证书路径通常类似
/etc/letsencrypt/live/dsh.example.com/fullchain.pem
/etc/letsencrypt/live/dsh.example.com/privkey.pem
Harness 的端口状态应该接近
LISTEN 127.0.0.1:3080
3080 不需要直接暴露到公网,外部访问全部走 Nginx 的 443。
先检查自己现有的 Nginx 配置
如果不确定当前域名到底用了哪个配置文件,可以先跑一组检查命令。
先把下面的 dsh.example.com 替换成自己的域名。
DOMAIN="dsh.example.com"
echo "===== NGINX VERSION ====="
nginx -v 2>&1
echo
echo "===== CONFIG FILES CONTAINING DOMAIN ====="
sudo grep -Rni "$DOMAIN" /etc/nginx 2>/dev/null
echo
echo "===== ENABLED SITES ====="
sudo ls -lah /etc/nginx/sites-enabled/ 2>/dev/null
echo
echo "===== CONF.D ====="
sudo ls -lah /etc/nginx/conf.d/ 2>/dev/null
echo
echo "===== DOMAIN CONFIG ====="
sudo nginx -T 2>&1 | grep -n -B 20 -A 100 "server_name.*$DOMAIN"
echo
echo "===== PORT 3080 ====="
sudo ss -lntp | grep ':3080'
echo
echo "===== HARNESS LOCAL TEST ====="
curl -I http://127.0.0.1:3080 2>&1 | head -30
实际排查时,本机请求可能返回
HTTP/1.1 401 Unauthorized
这里的 401 不一定说明 Harness 挂了。
如果 3080 已经处于监听状态,同时 HTTP 有正常响应,说明请求已经到达 Harness。
后续浏览器如果提示需要 dsh web authentication,也能进一步确认服务本身已经启动。
原来的 Nginx 配置为什么会触发 loopback-only
常见反向代理配置里会有这一行。
proxy_set_header Host $host;
浏览器访问的是
https://dsh.example.com
因此 Nginx 转发给 Harness 时,Host 仍然会是
dsh.example.com
随后在插件设置、Credentials、Settings 之类的功能中可能出现
forbidden: loopback-only
为了让经过 Nginx 的 Harness 请求使用本机回环 Host,可以将上游 Host 改成 127.0.0.1:3080。
修改前一定先备份。
DOMAIN="dsh.example.com"
sudo cp "/etc/nginx/sites-available/$DOMAIN" \
"/etc/nginx/sites-available/$DOMAIN.bak-$(date +%Y%m%d-%H%M%S)"
可以通过下面这条命令确认备份文件。
ls -lh /etc/nginx/sites-available/dsh.example.com*
一份可参考的 Nginx 完整配置
下面用 dsh.example.com 作为示例域名。
实际使用时需要替换成自己的域名,同时确认 SSL 证书路径一致。
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name dsh.example.com;
ssl_certificate /etc/letsencrypt/live/dsh.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/dsh.example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
client_max_body_size 500m;
location / {
proxy_pass http://127.0.0.1:3080;
proxy_http_version 1.1;
proxy_set_header Host 127.0.0.1:3080;
proxy_set_header Origin http://127.0.0.1:3080;
proxy_set_header Referer http://127.0.0.1:3080/;
proxy_set_header Sec-Fetch-Site same-origin;
proxy_set_header Sec-Fetch-Mode cors;
proxy_set_header Sec-Fetch-Dest empty;
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 https;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 60s;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_request_buffering off;
proxy_buffering off;
}
}
server {
listen 80;
listen [::]:80;
server_name dsh.example.com;
return 301 https://dsh.example.com$request_uri;
}
如果要直接覆盖配置,可以先定义域名变量,再根据自己的实际路径操作。
为了避免误覆盖生产环境,建议先用编辑器打开原文件。
sudo nano /etc/nginx/sites-available/dsh.example.com
粘贴配置并保存以后,先检查语法。
sudo nginx -t
正常情况下会看到类似输出。
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
通过以后再重新加载。
sudo systemctl reload nginx
然后查看状态。
sudo systemctl status nginx --no-pager
这里有个操作习惯很重要。
不要为了远程访问就把 Harness 从
127.0.0.1:3080
改到
0.0.0.0:3080
目前这种部署结构里,3080 只给本机 Nginx 使用已经够了。
loopback 处理完以后还会碰到浏览器认证
修改反向代理以后,可能继续出现下面这个提示。
dsh web authentication required; reopen the URL printed by dsh web.
这个提示说明访问已经进入了另一个阶段。
Nginx 能访问 Harness。
Harness 也在正常响应。
当前浏览器缺的是 dsh web 启动时建立的认证会话。
dsh web 启动后会打印一个带 token 的 URL。
形式大致是
http://127.0.0.1:3080/?token=<REDACTED_TOKEN>
远程服务器场景下,浏览器不能直接打开服务器自己的 127.0.0.1。
需要保留后面的 token,把前面的地址换成自己的公网域名。
服务器如果显示
http://127.0.0.1:3080/?token=<REDACTED_TOKEN>
浏览器应该访问
https://dsh.example.com/?token=<REDACTED_TOKEN>
第一次认证成功以后,浏览器会建立对应的会话。
后面再访问
https://dsh.example.com
即可继续使用。
认证 token 不要发送给其他人,也不要放进公开文章、截图、日志或代码仓库。
找不到启动时的 token 怎么办
如果 Harness 是后台运行的,可以先查 systemd journal。
sudo journalctl --no-pager | grep 'dsh web:' | tail -20
如果里面能看到
dsh web: http://127.0.0.1:3080/?token=<REDACTED_TOKEN>
把地址中的主机部分换成自己的域名即可。
如果没有任何输出,需要先确认 Harness 是怎么启动的。
先找监听 3080 的进程。
sudo ss -lntp | grep ':3080'
输出里会出现类似
users:(("node",pid=<PID>,fd=<FD>))
记录 <PID>,然后继续检查。
PID="<PID>"
ps -fp "$PID"
查看完整启动命令。
sudo tr '\0' ' ' < "/proc/$PID/cmdline"
echo
继续查看父进程。
ps -o pid,ppid,user,lstart,cmd -p "$PID"
查看进程树。
pstree -sp "$PID"
还可以检查这个进程是否属于 systemd 服务。
sudo systemctl status "$PID" --no-pager 2>&1 | head -80
这几条命令可以区分 Harness 当前大致是由哪种方式运行。
systemd
PM2
nohup
Docker
screen
tmux
直接运行 dsh web
知道启动方式以后,才能去对应的位置找 dsh web 打印出来的认证地址。
trusted-host 可以一起保留
如果能控制 Harness 的启动命令,可以把自己的域名加入 trusted host。
dsh web \
--no-open \
--port 3080 \
--trusted-host dsh.example.com \
--trusted-host dsh.example.com:443
这项配置和浏览器 token 认证处理的是两个不同的问题。
即使已经设置 trusted-host,浏览器没有完成 token 认证时,仍然可能看到
dsh web authentication required
因此排查时最好按顺序处理。
先确认 3080 正常监听。
再确认 Nginx 正常反代。
处理 loopback-only。
最后处理浏览器 token。
混在一起改,很容易不知道到底是哪一层已经通了。
最终需要测试的是跨会话记忆
Nginx 和登录都处理完成以后,真正要测试的是长期记忆。
可以先在聊天 A 中明确写入一条测试信息。
请记住下面的信息。
当前项目名称是 Project ABC。
目前已经完成服务器部署和 Nginx 反代。
下一步测试跨会话长期记忆。
确认 Memory 插件已经保存后,新建聊天 B。
直接问
当前项目叫什么?
我们已经完成了哪些工作?
下一步是什么?
如果新聊天能够回答这些信息,说明整个链路已经开始工作。
对话 A
↓
Memory 插件
↓
服务器持久化记忆
↓
关闭旧聊天
↓
创建对话 B
↓
重新加载项目记忆
↓
继续工作
最终需要的是这种效果。
旧聊天可以达到上下文上限,新聊天仍然能够延续项目状态。
服务器上的记忆一定要做持久化
如果 Harness 直接安装在 Linux 主机上,长期记忆文件通常会留在服务器磁盘中。
如果以后改成 Docker,就要额外检查插件数据、Workspace、Session 和记忆目录有没有映射到持久化磁盘。
否则容器删除或重新创建以后,即使 Memory 插件工作正常,容器里的本地文件也可能一起消失。
因此服务器部署需要关注几种不同的持久状态。
公开技术文章里哪些信息应该隐藏
服务器排错文章很容易无意间把环境信息一起公开。
发布前可以统一检查下面这些内容。
-
真实业务域名 -
公网 IP -
SSH 用户名 -
API Key -
Harness 启动 token -
Cookie -
Authorization 请求头 -
Cloudflare Token -
数据库密码 -
私钥内容 -
.env文件内容 -
内网机器名 -
可以定位具体服务器的特殊路径 -
当前真实进程 PID
普通系统路径通常可以保留。
例如
/etc/nginx/sites-available/
/etc/letsencrypt/live/
127.0.0.1:3080
这些信息本身通常无法直接获得服务器访问权限。
文章中的真实值可以统一改成下面这种形式。
dsh.example.com
203.0.113.x
<SSH_USER>
<PID>
<API_KEY>
<REDACTED_TOKEN>
操作清单速览
按常见的服务器反向代理环境,可以依次检查下面这些项目。
-
Harness 保持监听 127.0.0.1:3080 -
Nginx 对外提供 HTTPS 域名 -
修改前备份站点配置 -
Nginx 上游继续使用 http://127.0.0.1:3080 -
根据当前方案调整 Host、Origin 和 Referer -
执行 sudo nginx -t -
执行 sudo systemctl reload nginx -
找到 dsh web启动时生成的 token URL -
把 127.0.0.1:3080换成自己的 HTTPS 域名 -
使用带 token 的地址完成第一次浏览器认证 -
不公开真实 token -
安装一个长期 Memory 插件 -
在旧会话写入明确的测试记忆 -
新建 session 检查是否能自动继承 -
大量 PDF、代码和原始资料单独长期保存
FAQ
curl http://127.0.0.1:3080 返回 401 是不是 Harness 没启动
从这类排查结果看不一定。
如果端口已经处于 LISTEN 状态,HTTP 也能收到响应,后续浏览器又提示需要 dsh web authentication,通常说明服务已经起来,当前缺的是认证会话。
为什么浏览器可以打开网站,插件设置却提示 loopback-only
常见原因是反向代理继续把浏览器域名作为 Host 传给 Harness。
例如原配置使用
proxy_set_header Host $host;
当前方案中可以调整为
proxy_set_header Host 127.0.0.1:3080;
并同步处理 Origin 和 Referer。
为什么改完 Nginx 又出现 authentication required
这代表请求已经走到 Harness 的浏览器认证阶段。
需要找到 dsh web 启动时打印的 ?token= 地址,并通过自己的 HTTPS 域名完成一次认证。
token 可以直接写进公开的 Nginx 配置吗
不建议。
token 用于建立浏览器认证会话,应当作为敏感信息保存,避免进入公开配置、文章截图和代码仓库。
100 万上下文结束以后 Memory 插件会保存全部 100 万 token 吗
这里更适合保存需要跨会话保留的信息。
项目背景、结论、进度和下一步适合进入长期记忆。
大量原始文档和历史材料应继续放在外部资料库里,需要时再检索。
每次新对话都需要重新打开 token URL 吗
token URL 处理的是浏览器认证。
新建 Harness 对话和重新进行浏览器登录属于两个不同动作。只要当前浏览器认证会话仍然有效,新建聊天本身不需要重新执行一次 token 登录。
可以把 Harness 直接监听到 0.0.0.0:3080 吗
当前这套服务器结构没有这个必要。
保持 127.0.0.1:3080,让公网流量只经过 Nginx 的 443,更符合现有部署方式。
怎么确认长期记忆真的成功
不要只看插件是否显示已安装。
在旧聊天里保存一个明确的项目名称、当前进度和下一步,然后新建聊天直接提问。新 session 能准确取回这些内容,才算通过实际测试。

