在飞牛 NAS 上用 Docker 运行 DeepSeek Harness

在飞牛 NAS 上用 Docker 运行 DeepSeek Harness


一、这是什么

DeepSeek Harness(下文简称 dsh)是一个跑在本地、基于网页的 AI 工作台。它本身不提供模型,而是把你已有的各种大模型 API(DeepSeek、OpenAI -compatible、Ollama 等)聚合到一起,统一管理 provider、预设(preset)、凭据和插件,还能跑 agent。

简单说,它是一个「自己托管的 AI 操作台」:

  • 配置一次 API Key,之后在网页里切换不同模型、不同预设来对话;
  • 支持插件和工作区,agent 能直接读写文件;
  • 数据全在自己机器上,不依赖任何第三方 SaaS。

因为官方没有放出成品镜像,本文用的是社区维护的 runzhliu/deepseek-harness 镜像。

二、部署完能怎么用

部署好之后,dsh 会作为一个应用出现在飞牛的 watchcow 面板里。点一下图标就能打开,不用记 IP、不用记端口:

  • 在外网,通过飞牛分配给你的 watchcow 域名访问,且必须先登录飞牛账号;
  • 在局域网,直接走 https://<你的 NAS 局域网 IP>:<端口> 打开。

打开后就是 dsh 的主界面,左边选 provider、配预设,右边直接对话,跟用本地软件一样。


三、搭建步骤

下面按步骤来。整体思路是:用 docker-compose 起两个容器,一个跑 dsh 本体(只在内部网络,不对外暴露),一个跑 nginx 反代(对外暴露端口、处理 HTTPS 和请求头改写),最后用 watchcow 把入口收进飞牛面板。

第 1 步:准备目录和证书

在存储池里建好 dsh 的数据目录和工作区目录,例如:

  • <你的存储池路径>/docker/deepseek-harness/dsh:dsh 的数据目录,API Key、会话、插件配置都存在这;
  • <你的存储池路径>/deepseek-harness:工作区,给 agent 读写文件用。

证书方面,飞牛系统里自带证书管理,去飞牛的「证书」功能里把对应域名的证书下载/导出出来,放进项目目录的 certs/ 文件夹,命名为 fullchain.crtprivate.key。后面 nginx 会用这两个文件在 443 上终止 TLS。

注意:飞牛 watchcow 网关对 https 服务做的是 TLS 透传,网关自己不解密流量,所以证书必须挂在后面的 nginx 容器里,而不是指望网关帮你处理。

第 2 步:在飞牛上装 watchcow 应用并绑定域名

在飞牛应用中心装好 watchcow(就是那个能把 docker 服务收进统一面板的工具)。装好后,给 dsh 预留一个域名(在 watchcow 里添加应用时填写),这个域名之后就是对外访问地址。

这一步本质上是「先占好入口」,后面的 docker 服务只要带对的 label,就会被 watchcow 自动识别并挂上这个域名。

第 3 步:写 docker-compose

新建一个目录放项目文件,结构大致如下:

复制代码
deepseek-harness/
├── docker-compose.yml
├── config/
│   └── nginx-config.conf
└── certs/
    ├── fullchain.crt
    └── private.key

docker-compose.yml 里定义两个服务:

  • deepseek-harness:用 runzhliu/deepseek-harness:0.1.0-rc.6 镜像,挂上面建好的两个目录,不映射端口,只在内部网络里跑;
  • nginx:用 nginx:alpine,把宿主端口(这里用 11013)映射到容器 443,挂上 nginx 配置和证书目录,并带上 watchcow 的 label(下面第 5 步细说)。

两个服务连同一个自定义的内部网络,dsh 只在内部可达,nginx 通过服务名 deepseek-harness:3080 访问它。

完整 docker-compose.yml

yaml 复制代码
services:
  deepseek-harness:
    image: runzhliu/deepseek-harness:0.1.0-rc.6
    container_name: deepseek-harness
    restart: always
    networks:
      - dsh-internal
    volumes:
      # 数据目录:API Key、会话、插件配置都在这
      - <你的存储池路径>/docker/deepseek-harness/dsh:/home/node/.dsh
      # 工作区:给 agent 读写文件用
      - <你的存储池路径>/deepseek-harness:/workspace
    environment:
      - DSH_TELEMETRY_DISABLED=1
    # 不映射 ports,仅在内部网络可达

  nginx:
    image: nginx:alpine
    container_name: dsh-nginx
    restart: always
    networks:
      - dsh-internal
    ports:
      - "11013:443"   # 飞牛网关 TLS 透传,nginx 在 443 终止 TLS
    volumes:
      - ./config/nginx-config.conf:/etc/nginx/conf.d/default.conf:ro
      - ./certs:/etc/nginx/certs:ro
    depends_on:
      - deepseek-harness
    labels:
      watchcow.enable: "true"
      watchcow.display_name: "deepseek-harness"
      watchcow.icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/deepseek-dark.png"
      watchcow.main.service_port: "11013"
      watchcow.main.protocol: "https"
      watchcow.main.title: "dsh"
      watchcow.main.all_users: "false"
      watchcow.main.ui_type: "url"

networks:
  dsh-internal:
    driver: bridge

上面 <你的存储池路径> 替换成你自己的实际路径即可。

第 4 步:配 nginx 反代

这是关键。dsh 有几道安全限制,从外部直接反代会被拦,所以 nginx 必须做两件事:

  1. 把请求头里的 Host 改写成 127.0.0.1:3080(骗过 dsh 的回环校验);
  2. Origin 头剥掉(dsh 在 Origin 不存在时直接放行)。

同时 nginx 要 listen 443 ssl,挂上第 1 步准备的证书,并做好 WebSocket 升级头、长超时等配置(AI 会话可能很久不断开)。

只改 Host 不剥 Origin,或者只剥 Origin 不改 Host,都会得到 HTTP 403,两个动作缺一不可。

完整 config/nginx-config.conf

nginx 复制代码
upstream dsh_backend {
    server deepseek-harness:3080;
    keepalive 32;
}

server {
    listen 443 ssl default_server;

    ssl_certificate     /etc/nginx/certs/fullchain.crt;
    ssl_certificate_key /etc/nginx/certs/private.key;
    ssl_protocols       TLSv1.2 TLSv1.3;

    client_max_body_size 100m;

    location / {
        # 核心:改写 Host 为回环 + 剥掉 Origin / Sec-Fetch
        proxy_set_header Host 127.0.0.1:3080;
        proxy_set_header Origin "";
        proxy_set_header Sec-Fetch-Site "";
        proxy_set_header Sec-Fetch-Mode "";

        # 标准反代头
        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 X-Forwarded-Host $host;

        # WebSocket 支持(dsh 事件流)
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # 长超时,适配长时间 AI 会话
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;

        proxy_buffering off;
        proxy_pass http://dsh_backend;
    }
}

证书路径 /etc/nginx/certs/... 对应第 1 步挂进去的 certs/ 目录。host 头里的 Sec-Fetch-* 一并剥掉,是为了让局域网用 IP 访问时不被判成跨站而拦掉。

第 5 步:配 watchcow 的 label

在 nginx 服务上加 watchcow 相关的 label,让面板识别它:

  • watchcow.enable: "true" 开启识别;
  • watchcow.display_name 面板里显示的名字;
  • watchcow.main.service_port 填对外端口(如 11013);
  • watchcow.main.protocolhttps
  • watchcow.main.ui_typeurl(用新页面打开,比 iframe 内嵌更稳,局域网下也不会被证书问题卡住);
  • 再配个 watchcow.icon 当图标。

第 6 步:启动

在 compose 目录里启动:

bash 复制代码
docker compose up -d

启动后,dsh 容器和 nginx 容器都会 restart: always 自动拉起。去 watchcow 面板看一眼,deepseek-harness 应该已经出现在列表里了。

第 7 步:验证

  • 外网:打开watchcow生成的应用(dsh),会跳转域名;
  • 局域网:打开 https://<你的 NAS 局域网 IP>:11013,浏览器可能会报证书不匹配(因为证书是给域名签的),点「继续访问」即可。

能正常加载 provider 列表、能对话,就说明整套通了。


四、常见问题

1. 页面能打开,但一加载提供方目录 / 读取设置就报 403?

这是 dsh 的安全栅栏在拦。确认 nginx 同时做了 Host → 127.0.0.1:3080 改写 剥掉 Origin 头,缺一不可。

2. 网关直接报 502,nginx 日志里一堆 \x16\x03\x01 这种乱码?

说明 nginx 在 listen 80 上收到了 HTTPS 握手字节。飞牛网关是 TLS 透传,不会帮你解密,必须让 nginx 在 443 ssl 上挂证书自己终止 TLS。

3. dsh 容器一直重启 / 起不来,nginx 那边 Host unreachable?

检查 dsh 数据目录里的 .credentials.yaml 文件权限,必须是 600。权限不对 dsh 启动即崩,改成 600 即可。

4. 局域网用 IP 访问时被拦(cross-site)?

在 nginx 里把 Sec-Fetch-SiteSec-Fetch-Mode 头也一起剥掉,dsh 就无法判定跨站而放行。另外建议 ui_typeurl 而不是 iframe,内嵌在局域网下容易被证书问题卡住。

5. 访问时浏览器说证书不安全?

证书是签给你域名的,用 IP 访问时 CN 对不上,属正常现象。点「继续访问 / 仍要发送」即可;追求干净体验就用域名访问。


部署完成之后,平时要切模型、试预设、跑 agent,点一下面板图标就进去了,不用记端口,也不用裸跑服务。dsh 这套安全限制在没搞明白之前确实容易卡很久,但本质就是改写 Host + 剥 Origin 两件事,配好就稳了。

相关推荐
Elastic 中国社区官方博客1 小时前
让大模型思考,让小模型执行:在 Elastic Workflows 中拆分 LLM 成本
大数据·运维·数据库·人工智能·elasticsearch·ai
艾伦_耶格宇2 小时前
【AI】-4 OpenCode Go 接入 Obsidian 完整指南
运维·开发语言·人工智能·agent·opencode
SXkehuirongsheng2 小时前
APP开发定制和模板开发哪个更实用?
大数据·运维·人工智能
虎王物联2 小时前
Docker Compose编排物联网平台后端:Nginx+PHP-FPM+EMQX+InfluxDB一键部署实战
物联网·nginx·docker
林浅不想努力2 小时前
k8s集群部署的方法原理
云原生·容器·kubernetes
輝太くん3 小时前
k8s中的pod管理
云原生·容器·kubernetes
fb_123453 小时前
Linux三剑客超全精讲(grep+sed+awk)零基础入门|正则+实战面试题
linux·运维·服务器
HiDev_4 小时前
【非标自动化】2、认识元器件(节流阀)
运维·自动化
火车叼位4 小时前
Bash 实现 IDE 式补全的组件与配置
linux·运维