我最早在 Linux 服务器上部署 DeepSeek Harness Web 版时,心里想得特别简单:源码拉到服务器上,跑起来,浏览器打开就能用。结果真上手才发现,从前端构建到后端启动,从 Nginx 反代到路由器端口映射,每一步都有意想不到的细节。尤其是"远程访问"这四个字,牵扯到防火墙、DDNS、IPv6,甚至还会遇到 Windows 和 Linux 混用时才有的权限怪问题。这篇文章就把我从零到远程访问的完整过程拆开讲清楚,基于 Ubuntu 22.04 实操记录,Debian、CentOS Stream 等发行版原理相同,命令稍作替换即可。适合刚拿到一台 Linux 服务器、想把 Harness Web 跑起来并让外部网络访问到的朋友参考。
1. 部署前必须想清楚的三件事:环境、模式与网络通路
1.1 为什么选择源码部署而不是现成镜像
如果你手头有 Docker 环境,用现成镜像确实省事。但我更推荐源码部署,原因很实际:
第一,源码部署能让你完整看到项目结构。DeepSeek Harness 的插件和 Skill 机制需要了解目录布局,用容器跑的时候经常要靠挂载卷,容器一升级路径就可能对不上,排查起来很麻烦。
第二,内网服务器经常不能直接拉取镜像。源码包可以通过 U 盘、内网传输工具拷贝进去,离线部署完全没问题。
第三,源码方式方便改代码。比如你想调前端页面、改后端逻辑或者二次开发,直接改仓库里的文件比修改容器镜像要直观得多。
我给的建议是:只要能访问外网且只是快速试用,Docker 更方便;如果要做正式环境、要加私有插件和 Skill,源码部署才是正路。
1.2 硬件与系统版本的最低要求
先给出一份我在实际部署中验证过的底线配置:
| 项目 | 最低要求 | 建议配置 |
|---|---|---|
| CPU | 2 核 | 4 核及以上 |
| 内存 | 4 GB | 8 GB |
| 磁盘 | 10 GB 可用空间 | 20 GB SSD |
| 操作系统 | Ubuntu 22.04 / Debian 12 / CentOS Stream 9 | 任意 LTS 版本 |
| Python | 3.10+ | 3.11 或 3.12 |
| Node.js | 18+ | 20 LTS |
| Git | 任意较新版本 | 最新稳定版 |
我实际部署用的是一台 2 核 4G 的轻量服务器,Web 服务跑起来之后内存占用在 2GB 左右,4GB 属于"能用但紧"的状态。如果你想同时跑多个 Skill 或者给模型留推理空间,直接上 8GB,省得后面内存告警折腾。
1.3 先画清楚远程访问的网络拓扑
这一步很多教程不讲,但恰恰是最容易翻车的环节。拿到服务器后先问自己三个问题:
- 服务器有没有公网 IP?
- 服务器是不是在路由器内网后面?
- 访问者要从公网访问还是只在内网访问?
我的习惯是先画一张简单的访问链路图:客户端 → 公网 → 路由器(可选)→ 服务器防火墙 → Nginx → 后端服务。搞清楚链路之后,每一步需要做什么就清晰了。
如果服务器本身有公网 IP,最简单,防火墙放行 80/443 即可。如果服务器在家庭或办公室内网,需要路由器做端口映射,配合 DDNS 解决公网 IP 变化问题。如果连路由器管理权限都没有,只能走内网穿透工具(比如 frp、ZeroTier 这类方案),这部分不在本文展开。
2. Linux 上的源码部署全过程:克隆、构建与启动
2.1 拉取源码与确认版本分支
先安装基础依赖:
sudo apt update && sudo apt install -y git curl build-essential然后把 DeepSeek Harness 的官方仓库克隆到服务器上。我建议加--depth 1只拉取最新版本,省流量也省时间:
git clone --depth 1 <DeepSeek Harness 官方仓库地址> cd <仓库目录>进去之后先别急着跑,做两件事:第一,看 README 中关于 Web 部署的部分;第二,确认当前分支和版本号。不同版本的 Web 界面目录结构、默认端口可能不一样。我踩过的第一个坑就是没仔细看 README,默认端口猜错了,结果 Nginx 反代一直 502,排查了半小时才发现端口压根不是我以为的那个。
2.2 前端 Web 界面的构建流程
这类项目通常是前后端混在一个仓库里。先确认 Node.js 版本:
node -v npm -v如果 Node.js 版本低于 18,建议先升级。然后安装前端依赖并构建:
npm install npm run build如果 npm 安装依赖慢,可以换用国内镜像源:
npm config set registry https://registry.npmmirror.com构建完成后,产物一般在dist或者build目录下。我后面配置 Nginx 的时候就需要指向这个目录,所以构建完之后先记住这个路径。
这里有一个细节:构建过程偶尔会因为内存不足失败(尤其是 2G 小内存机器)。如果遇到JavaScript heap out of memory,可以用:
NODE_OPTIONS=--max-old-space-size=2048 npm run build临时把 Node.js 的内存上限调大再试。
2.3 后端服务启动方式与进程守护
前端构建完成后,处理后端。先安装 Python 依赖:
pip install -r requirements.txt如果服务器同时有 Python 2 和 Python 3,注意用pip3而不是pip。也可以用虚拟环境隔离,避免污染系统 Python:
python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt启动命令不同版本有差异,常见的是:
uvicorn main:app --host 127.0.0.1 --port 8000注意这里我监听的是127.0.0.1,不是0.0.0.0。原因后面讲 Nginx 的时候会说——让 Nginx 做转发,后端服务不直接暴露到公网,多一层安全。
先在终端前台跑一次,确认日志没有报错、服务正常响应。然后用 systemd 做成开机自启的服务,这样服务器重启后不用手动拉起。我实际使用的服务文件如下:
[Unit] Description=DeepSeek Harness Web Backend After=network.target [Service] User=deploy Group=deploy WorkingDirectory=/opt/deepseek-harness ExecStart=/opt/deepseek-harness/.venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000 Restart=always RestartSec=3 Environment=PYTHONUNBUFFERED=1 [Install] WantedBy=multi-user.target把文件放到/etc/systemd/system/dsh-web.service,然后:
sudo systemctl daemon-reload sudo systemctl enable --now dsh-web sudo systemctl status dsh-web以后查日志用journalctl -u dsh-web -e,重启用sudo systemctl restart dsh-web,方便很多。
提示:建议创建一个独立的系统用户
deploy来运行服务,不要用 root 跑。因为 Skill 和插件涉及文件读写,用专属用户隔离权限,后续排查问题也清晰。
3. Nginx 反代与 HTTPS:给 Web 界面加上正确的外网入口
3.1 为什么不能直接裸跑端口
见过不少朋友部署完服务直接拿http://服务器IP:8000访问。如果仅仅是内网临时测试,问题不大;但只要涉及外网访问,裸跑端口有三个问题:
第一,没有 TLS 加密。对话内容、配置信息在公网明文传输,这在大模型 Web 工具场景下风险很高。
第二,端口号既不专业也不好记。你还得记着 8000 端口,不如直接一个域名 80/443 访问来得清爽。
第三,公网直接暴露应用端口,会面临大量扫描和探测请求,Nginx 层可以做更细粒度的控制,比如限流、访问认证、请求大小限制。
所以我的标准做法是:后端服务监听 127.0.0.1,Nginx 监听 80/443,用反向代理把请求转发到后端的 8000 端口。
3.2 一份可以直接抄的 Nginx 配置
安装 Nginx:
sudo apt install -y nginx然后在/etc/nginx/sites-available/下新建一个配置文件,比如dsh-web:
server { listen 80; server_name your.domain.com; client_max_body_size 20m; location / { proxy_pass http://127.0.0.1:8000; 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; } }启用站点:
sudo ln -s /etc/nginx/sites-available/dsh-web /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx这里有几个关键点,缺一个都可能导致功能异常:
client_max_body_size根据实际需求设,如果你会上传文件或者使用某些需要提交大段内容的 Skill,默认 1M 会导致 413 错误,我直接调到 20M。X-Forwarded-Proto一定要传。不传的话,后端生成的回调地址或重定向链接还是 http,某些功能(尤其是 OAuth 类的)会莫名失败。- 如果前端静态资源也是由这个服务托管,可以单独配一个
location /static指向构建产物目录,减轻后端压力。不过多数情况下反代就够了。
3.3 HTTPS 与基础认证的取舍
外网访问的话,我的态度很明确:至少要在 HTTPS 和基础认证之间选一个。两个都做更好。
用 certbot 申请免费证书最省事:
sudo apt install -y certbot python3-certbot-nginx sudo certbot --nginx -d your.domain.com证书自动续期配置也会被 certbot 处理好,基本不用管。
如果暂时没有域名,也可以先用 Basic Auth 顶一阵:
sudo apt install -y apache2-utils sudo htpasswd -c /etc/nginx/htpasswd admin然后在 Nginx 的 server 块里加两行:
auth_basic "Restricted"; auth_basic_user_file /etc/nginx/htpasswd;我个人不推荐长期只用 Basic Auth,但临时对外开放、又暂时没域名的情况下,有总比没有好。
4. 远程访问链路打通:防火墙、路由器映射与 DDNS 三件套
4.1 服务器侧防火墙放行策略
服务已经在本机跑起来了,接下来的目标是让外部网络能进来。第一步是服务器本身的防火墙。
Ubuntu 如果启用了 ufw,放行 HTTP/HTTPS:
sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw reload这里有个非常容易忽略的点:如果你用的是云服务器厂商的机器,云控制台里的安全组规则和系统防火墙是两套系统。很多时候你在系统防火墙放行了,安全组没放行,外部依然访问不了。我自己就遇到过:在 ufw 里放行了 443,但云安全组默认只开了 22 端口,折腾半天才发现问题出在上面那层。
建议检查顺序是:云安全组规则 → 路由器端口映射 → 系统防火墙,从外到内逐层排查。
4.2 路由器端口映射与公网 IP 缺失时的方案
如果服务器在家庭或办公室网络后面,只有内网 IP,那需要在路由器上做端口映射。登录路由器管理界面,找到"端口转发"或者"虚拟服务器"选项,把外网端口 80/443 转发到服务器的内网 IP 地址。
做映射时有三个要点,我没见过哪个朋友没踩过其中一个:
第一,给服务器设置静态内网 IP 或者 DHCP 地址保留。否则服务器重启后 IP 变了,端口映射就失效了,你从外网怎么都访问不通,还以为是服务挂了。
第二,外网端口不一定非要和服务器端口一致。比如你内网已经有一台机器占用了 80 端口,可以设置外网 8080 转发到内网 80。
第三,不要忘了在路由器防火墙上放行对应端口。有的路由器端口转发和防火墙是分开配置的,两个地方都要设置。
没有固定公网 IP 的话,配合 DDNS 使用。现在很多路由器自带 DDNS 功能,支持花生壳、No-IP 等服务商,把动态 IP 绑定到一个固定域名上,域名解析不通时路由器会自动更新记录。这样你只需要记住域名,不用关心 IP 又变到哪去了。
4.3 IPv6 直连与动态域名解析的联动配置
现在很多宽带没有公网 IPv4,但有公网 IPv6。如果你的服务器和访问端网络都支持 IPv6,可以直接用 IPv6 地址访问,绕开 NAT 和端口映射的麻烦。
我的做法是用 ddns-go 这类开源 DDNS 工具,把服务器的 IPv6 地址自动绑定到域名上,域名只配置 AAAA 记录。这样即使在纯 IPv6 网络环境下,也能通过域名稳定访问。
需要注意的是:
- 云服务器的 IPv6 默认可能没开启,需要去控制台申请。
- 系统防火墙要放行 IPv6 的对应端口:
sudo ufw allow 80/tcp默认会同时处理 IPv4 和 IPv6,但要确认ufw status里协议显示正确。 - IPv6 地址变化频率高,必须搭配 DDNS,否则几个小时之后地址变了就访问不到了。
纯 IPv6 的方案在没有公网 IPv4 的环境里特别省事,也是我最推荐优先尝试的方案。
5. 插件与 Skill 部署:给 Harness 装上真实可用的扩展能力
5.1 插件机制的基本位置和安装方式
部署好 Web 服务只是第一步,真正让它发挥价值的是插件和 Skill。DeepSeek Harness 的插件一般放在项目指定的plugins目录下,常见安装方式有两种:
一种是直接把插件目录放进项目指定目录,然后在配置里启用,重启服务生效。我实际用下来,这种方式最稳,出了问题也好排查。
另一种是通过 Web 界面或命令行工具安装。界面安装对新手友好,但我在内网环境遇到过上传插件后界面卡住、实际文件没写入成功的情况,最后还是回到手动放目录 + 重启的方式。
安装插件需要注意版本兼容性。插件是跟着 Harness 主版本走的,主版本升级后部分插件可能不兼容,启动日志里会直接报错,这时候优先去插件仓库看是否发布了适配新版本的分支。
5.2 Skill 部署到内网服务器的关键路径与权限
Skill 是 DeepSeek Harness 中让我觉得最有价值的部分。一个 Skill 通常由一个描述文件(YAML 或 JSON)外加若干脚本组成。部署到内网服务器时,有几个环节特别容易出问题:
第一,目录结构必须和描述文件里的路径一致。Skill 描述文件里写了脚本的相对路径,如果你把脚本放到别的位置,执行时就会报找不到文件。
第二,脚本要有执行权限:
chmod +x /opt/deepseek-harness/skills/your-skill/run.sh第三,如果 Skill 需要读取某些文件或访问某些目录,确保运行服务的用户对这些路径有读权限。这里我强烈建议不要让服务以 root 身份运行,否则任何权限错误都会被掩盖,反而不利于问题定位。
第四,改完 Skill 之后要重启服务或触发重新加载。有些朋友改了 Skill 配置发现不起作用,其实是因为服务进程还在用旧的配置。
5.3 Windows 与 Linux 混用时最容易踩的权限坑
这是我在实际排查中遇到最多的场景之一:开发者在 Windows 上写好 Skill,然后传到 Linux 服务器上部署,结果运行时报权限错误。有一类报错信息特别典型,包含setnamedsecurityinfow failed这样的字样。
这个函数是 Windows API,报这个错说明文件权限在 Windows 侧就已经被设置成了不可正确继承的状态,文件传到 Linux 之后,属主、权限位、甚至换行符都变得很奇怪。
Linux 端的处理办法是先统一属主和权限:
chown -R deploy:deploy /opt/deepseek-harness/skills chmod -R 755 /opt/deepseek-harness/skills如果脚本是在 Windows 上编辑的,还要注意换行符和 BOM 的问题。CRLF 换行会让 shell 脚本在执行时报$'\r': command not found这类错误。用 dos2unix 处理一下:
sudo apt install -y dos2unix dos2unix /opt/deepseek-harness/skills/your-skill/*.sh处理完再确认一下文件内容没有异常,然后重启服务。这类问题最麻烦的地方不在报错本身,而是报错信息往往只显示"Permission denied",不会告诉你根因在 Windows 侧的文件属性继承,所以我把这个场景单独列出来提醒一下。
6. 高频故障排查手册:端口、权限与访问链路
6.1 服务启动失败与端口占用
先给一个我常用的排查链路。服务起不来时,第一步永远是看日志:
journalctl -u dsh-web -e常见原因和对应的处理方式如下表:
| 现象 | 可能原因 | 解决方式 |
|---|---|---|
ModuleNotFoundError | 依赖没装完整 | 重新执行pip install -r requirements.txt,确认虚拟环境已激活 |
Address already in use | 端口被占用 | `ss -tlnp |
Permission denied启动即退出 | 工作目录无权限 | 检查WorkingDirectory目录权限,确保服务用户可读写 |
| 启动成功但请求 502 | Nginx 反代端口与后端不一致 | 确认 Nginx 配置的proxy_pass端口与后端监听端口一致 |
我特别想强调一点:不要一看到Permission denied就chmod 777。先弄清楚是哪个用户在执行、哪个文件缺权限、父目录是否有执行权限。这个习惯能帮你省掉很多后续麻烦。
6.2 远程访问不通的四大检查点
外网访问不通的时候,不要急着怀疑服务挂了。按从内到外的顺序排查,能快速定位问题:
- 在内网环境用
curl http://服务器内网IP测一下服务是否正常响应。这一步不通,问题在服务本身或系统防火墙。 - 检查系统防火墙:
sudo ufw status,确认 80/443 已放行。 - 如果是云服务器,检查安全组规则,确认外网端口已放行。
- 如果经过路由器映射,登录路由器确认映射规则还在、目标 IP 还是服务器的当前 IP。
我之前排查过一个案例:同事反馈外网完全访问不了,我从服务日志查到 Nginx 层也没有任何外网请求进来,最后发现是路由器上一周断电重启后,DHCP 把服务器 IP 从.100换成了.105,映射规则失效了。所以再次强调:静态内网 IP 是端口映射的前提。
6.3 权限相关的经典报错处理
权限问题在 Linux 部署 Harness 时出现频率相当高,常见的几个场景和最快解法:
| 报错场景 | 排查方法 | 推荐处理 |
|---|---|---|
脚本执行Permission denied | ls -l 脚本文件 | 文件加执行位:chmod +x |
| Skill 读取文件失败 | 确认服务运行用户与文件属主 | chown -R deploy:deploy 目录 |
| 父目录无权限导致执行失败 | ls -ld 父目录 | 父目录加x权限 |
| SELinux 拦截(CentOS 常见) | ausearch -m avc查看拦截记录 | 按记录调整 SELinux 策略或文件上下文 |
| 跨 Windows/Linux 编辑脚本报错 | 查看换行符是否 CRLF | 用dos2unix转换 |
最后一条建议:在服务器上操作时,尽量少用root跑业务服务,多用专属用户;多关注日志而不是凭感觉猜。这套排查思路不仅适用于 DeepSeek Harness,其他 Linux 服务部署项目也基本通用。
如果还要继续扩展,可以在这个基础上给 Harness 接入更多自定义 Skill,或者研究一下插件之间的依赖关系。部署这件事没有太多玄学,链路一层层梳理清楚,问题自然无处遁形。我自己的体会是:每次部署新版本前多花五分钟读一遍更新日志,能少走很多弯路。