1. 为什么要在 Linux 上源码部署 DeepSeek Harness Web
1.1 这个项目到底解决什么问题
先把话说清楚:DeepSeek Harness Web 本质上是一套把大模型能力"接出来"的 Web 服务层。它不是一个模型本身,而是一个"外壳"——负责把 DeepSeek 的推理接口、会话管理、工具调用、流式输出这些东西,包装成一个可以通过浏览器访问的 Web 应用。你可以把它理解成一个"自建的 AI 工作台",前端是网页,后端跑在 Linux 服务器上,模型能力通过 API 或者本地推理引擎接入。
那为什么不用官方网页版,非要自己折腾一套?我踩过几次坑之后总结下来,自建的核心价值有三个:第一是数据可控,所有会话记录、上传的文件、工具调用的中间结果都留在你自己的机器上,不经过第三方;第二是可定制,你可以改前端界面、加自己的工具插件、接自己的知识库,官方网页版给不了这种自由度;第三是可集成,把它部署在内网服务器上,团队里其他人通过浏览器就能用,还能和内部系统打通。
源码部署相比 Docker 一键拉镜像,好处是你能看到每一行配置、能改、能调优、出问题能定位。坏处也明显——依赖、环境、权限、进程守护,每一步都可能卡住。这篇就是把我从零到远程访问的完整过程拆开讲,包括那些文档里不会写的坑。
适合谁看?有基本 Linux 命令基础、想在自己服务器或内网机器上跑一套 AI Web 应用的人。如果你连cd、ls都不熟,建议先补一下基础命令再来,不然中间会很难受。
1.2 源码部署 vs 镜像部署:选型背后的逻辑
很多人第一反应是"有没有现成镜像,拉下来就跑"。确实有,但源码部署在几个场景下更合适,我把对比列出来你就明白了:
| 维度 | 源码部署 | 镜像部署 |
|---|---|---|
| 可定制性 | 高,任意改代码和配置 | 低,只能改环境变量 |
| 依赖透明度 | 完全可见,出问题好定位 | 黑盒,报错难查 |
| 版本控制 | 可锁定 commit,可回滚 | 依赖镜像 tag |
| 资源占用 | 可裁剪,按需装依赖 | 通常偏大 |
| 上手速度 | 慢,需要配环境 | 快,一条命令 |
| 适合场景 | 二次开发、内网集成、学习 | 快速验证、临时使用 |
我个人的判断标准很简单:如果你只是"想用一下看看效果",镜像部署;如果你打算长期跑、要改、要集成到别的系统里,源码部署。这篇讲的是后者。
还有一个现实原因——很多服务器是国产 Linux 发行版(比如某些基于 openEuler、Anolis 的系统),镜像不一定兼容,源码部署反而更稳。这一点在嵌入式场景(比如香橙派、全志平台的板子)上尤其明显,ARM 架构的镜像经常缺,源码编译是唯一出路。
2. 部署前的环境准备与依赖梳理
2.1 系统与硬件的最低要求
先说底线配置,低于这个数就别折腾了,跑起来也是卡:
- CPU:2 核起步,4 核舒服。如果模型走本地推理,核心越多越好。
- 内存:4GB 是底线,8GB 推荐。Node.js 构建阶段很吃内存,2GB 的机器大概率在
npm install阶段就被 OOM Killer 干掉。 - 磁盘:至少 20GB 空闲。源码 + 依赖 + 日志 + 可能的模型缓存,很容易吃掉十几个 G。
- 系统:主流发行版都行,Ubuntu 20.04/22.04、Debian 11/12、CentOS Stream、国产的 openEuler 我都试过,问题不大。内核建议 4.x 以上。
查看系统信息用这几条命令,先摸清家底:
# 看发行版 cat /etc/os-release # 看内核 uname -r # 看 CPU 核数 nproc # 看内存(单位 MB) free -m # 看磁盘 df -h提示:如果
free -m显示可用内存低于 2GB,先加 swap,否则构建阶段必挂。加 swap 的命令后面会讲。
2.2 依赖清单:一个都不能少
DeepSeek Harness Web 这类项目,典型技术栈是 Node.js 前端 + 后端服务,可能还带 Python 脚本做工具调用。所以依赖大致分三块:
基础工具链:git、curl、wget、build-essential(编译原生模块用)、python3(部分 npm 包需要)。
运行时:Node.js(建议 18 LTS 或 20 LTS)、npm 或 pnpm。如果后端有 Python 部分,还要 Python 3.10+。
进程管理:systemd(系统自带,用来做守护进程)。
一次性装齐(以 Debian/Ubuntu 系为例):
sudo apt update sudo apt install -y git curl wget build-essential python3 python3-pipCentOS/openEuler 系换成:
sudo dnf install -y git curl wget gcc gcc-c++ make python3 python3-pip2.3 Node.js 版本管理:别用系统自带的
这是第一个大坑。系统仓库里的 Node.js 版本往往很老(Ubuntu 20.04 自带的是 10.x),而现代前端项目基本要求 16 以上。直接用apt install nodejs装出来的版本,npm install阶段就会报一堆语法错误。
正确做法是用版本管理工具。我推荐nvm,理由是可以随时切版本,不污染系统:
# 安装 nvm curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash # 让当前 shell 生效 source ~/.bashrc # 装 Node 20 LTS nvm install 20 nvm use 20 nvm alias default 20 # 验证 node -v npm -v注意:
nvm装完后,node命令只在交互式 shell 里可用。后面配 systemd 服务时,必须写node的绝对路径,否则服务启动会报"command not found"。这个坑我踩过,排查了半小时。绝对路径一般是/root/.nvm/versions/node/v20.x.x/bin/node,用which node确认。
如果服务器访问外网受限,nvm的安装脚本拉不下来,那就手动下载 Node 二进制包解压,一样能用:
wget https://nodejs.org/dist/v20.11.0/node-v20.11.0-linux-x64.tar.xz tar -xf node-v20.11.0-linux-x64.tar.xz sudo mv node-v20.11.0-linux-x64 /opt/node # 加到 PATH echo 'export PATH=/opt/node/bin:$PATH' >> ~/.bashrc source ~/.bashrc3. 源码获取与构建实操
3.1 拉取源码与目录规划
源码从项目仓库拉。这里有个习惯问题——我建议把应用统一放在/opt下,而不是随手丢在/root或/home。原因是/opt是 Linux 约定的"第三方应用"目录,权限清晰,备份和迁移都方便。
# 建目录 sudo mkdir -p /opt/deepseek-harness sudo chown -R $USER:$USER /opt/deepseek-harness # 拉源码 cd /opt/deepseek-harness git clone <项目仓库地址> . # 看下当前 commit,记下来,方便回滚 git log -1 --oneline提示:如果仓库有多个分支,先确认要部署哪个分支。生产环境建议用打了 tag 的 release 分支,别直接上 main,main 随时可能挂。
3.2 依赖安装:npm 与 pnpm 的取舍
进到项目根目录,先看package.json,确认用哪个包管理器。有pnpm-lock.yaml就用 pnpm,有yarn.lock就用 yarn,只有package-lock.json就用 npm。
# 如果用 pnpm npm install -g pnpm pnpm install # 如果用 npm npm installnpm install慢是常态,尤其在国内网络下。换源能快不少:
npm config set registry https://registry.npmmirror.com如果安装过程中报node-gyp相关的编译错误,八成是缺build-essential或 Python,回头检查 2.2 节的依赖。
实操心得:
npm install卡在某个包上超过 5 分钟,先 Ctrl+C,删掉node_modules和package-lock.json重来。有时候是网络抖动导致的半成品缓存,重装比死等快。
3.3 环境变量配置:最容易出错的一步
几乎所有这类项目都靠.env文件读配置。项目里一般有个.env.example,复制一份改名:
cp .env.example .env vim .env关键配置项通常包括:
| 配置项 | 作用 | 典型值 |
|---|---|---|
PORT | 服务监听端口 | 3000 |
HOST | 监听地址 | 0.0.0.0 |
API_KEY | 模型接口密钥 | 你的密钥 |
API_BASE_URL | 接口地址 | 按服务商填 |
DATABASE_URL | 数据库连接 | sqlite 或 postgres 连接串 |
NODE_ENV | 运行环境 | production |
注意:
HOST一定要设成0.0.0.0,不能是127.0.0.1。设成后者,只有本机能访问,远程访问会一直连不上,而且报错很隐蔽——服务明明起来了,就是外部访问不了。这个坑我见过太多人踩。
.env文件权限也要收紧,里面有密钥:
chmod 600 .env3.4 构建与首次启动
配置好了就构建。前端项目一般有build脚本:
npm run build构建产物通常在dist或.next目录。构建完先手动启动一次,确认能跑起来:
npm run start # 或者 node server.js看到类似Server listening on 0.0.0.0:3000的日志,就说明起来了。这时候在服务器本机用curl测一下:
curl http://127.0.0.1:3000返回 HTML 就对了。如果报错,看日志,常见的是端口被占用、数据库连不上、密钥没配。
4. 用 systemd 做进程守护与开机自启
4.1 为什么必须用 systemd
手动npm run start启动的服务,一旦你关掉 SSH 窗口,进程就跟着没了。这就是热词里说的"让后台运行指令不因界面退出而退出"。有人用nohup ... &,能用,但不够优雅——进程挂了不会自动重启,开机也不会自启。
systemd是 Linux 标准的服务管理器,优势是:开机自启、崩溃自动重启、日志统一管理、资源限制。生产环境就该用它。
4.2 编写 service 文件
在/etc/systemd/system/下建一个deepseek-harness.service:
[Unit] Description=DeepSeek Harness Web Service After=network.target [Service] Type=simple User=root WorkingDirectory=/opt/deepseek-harness Environment=NODE_ENV=production EnvironmentFile=/opt/deepseek-harness/.env ExecStart=/root/.nvm/versions/node/v20.11.0/bin/node /opt/deepseek-harness/server.js Restart=on-failure RestartSec=5 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target几个关键点解释一下:
ExecStart里的 node 路径必须是绝对路径,原因前面说过,systemd 不读你的.bashrc。EnvironmentFile把.env加载进来,这样服务能读到配置。Restart=on-failure表示进程异常退出时自动重启,RestartSec=5是重启前等 5 秒,避免疯狂重启。WorkingDirectory很重要,很多项目用相对路径读文件,不设这个会找不到资源。
4.3 启动、验证与日志查看
# 重载 systemd 配置 sudo systemctl daemon-reload # 启动服务 sudo systemctl start deepseek-harness # 设置开机自启 sudo systemctl enable deepseek-harness # 看状态 sudo systemctl status deepseek-harness # 看实时日志 sudo journalctl -u deepseek-harness -f状态显示active (running)就成功了。如果显示failed,用journalctl -u deepseek-harness -n 50看最近 50 行日志定位问题。
实操心得:改完 service 文件一定要
daemon-reload,否则 systemd 用的还是旧配置。这个我踩过,改了ExecStart死活不生效,折腾半天才发现忘了 reload。
5. 远程访问的三种方案与安全加固
5.1 方案对比:直接暴露 vs 反向代理 vs 内网穿透
服务在本机跑起来了,怎么从外部访问?三条路:
| 方案 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 直接暴露端口 | 防火墙放行端口 | 简单 | 无加密、无认证 | 内网测试 |
| 反向代理 | Nginx 转发 + HTTPS | 安全、可加认证 | 配置稍复杂 | 公网生产 |
| 内网穿透 | 中转服务 | 无需公网 IP | 依赖第三方 | 家庭/内网 |
我一般推荐反向代理,因为能顺便把 HTTPS、访问认证、限流都做了。下面重点讲这个。
5.2 Nginx 反向代理配置
先装 Nginx:
sudo apt install -y nginx建一个站点配置/etc/nginx/sites-available/deepseek-harness:
server { listen 80; server_name your-domain.com; location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; 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 300s; } }这里几个 header 是给 WebSocket 用的——AI 应用的流式输出很多走 WebSocket,不配Upgrade和Connection,流式响应会断。proxy_read_timeout调大是因为模型推理可能很慢,默认 60 秒会超时。
启用配置:
sudo ln -s /etc/nginx/sites-available/deepseek-harness /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx5.3 加一层访问认证
公网暴露的服务,不加认证等于裸奔。最简单的办法是 Nginx 的 Basic Auth:
# 装工具 sudo apt install -y apache2-utils # 生成密码文件 sudo htpasswd -c /etc/nginx/.htpasswd youruser然后在 Nginx 配置的location里加两行:
auth_basic "Restricted"; auth_basic_user_file /etc/nginx/.htpasswd;reload 之后,访问就会弹用户名密码框。虽然简陋,但挡住了绝大部分扫描。
5.4 HTTPS:用 Let's Encrypt 免费证书
有域名的前提下,用certbot一键签证书:
sudo apt install -y certbot python3-certbot-nginx sudo certbot --nginx -d your-domain.comcertbot会自动改 Nginx 配置、加证书、配自动续期。签完访问https://your-domain.com就是加密的了。
注意:
certbot需要 80 端口能被外部访问到做验证。如果服务器前面还有一层防火墙或路由器,先把 80 和 443 放行。
5.5 防火墙配置
不管用哪种方案,防火墙都得配。ufw是最省心的:
sudo ufw allow 22/tcp sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw enable提示:
ufw enable之前一定先放行 22 端口,否则 SSH 会被自己关在门外。这个错误犯一次就够记一辈子。
6. 常见问题排查与避坑清单
6.1 服务起不来:从日志倒推
服务启动失败,90% 的问题能在日志里找到。排查顺序:
systemctl status看退出码和最后几行日志。journalctl -u 服务名 -n 100看完整日志。- 手动用
ExecStart里的命令跑一遍,看报错。
常见错误对照表:
| 报错信息 | 原因 | 解决 |
|---|---|---|
command not found | node 路径不对 | 用绝对路径 |
EADDRINUSE | 端口被占用 | lsof -i:3000找进程杀掉 |
Cannot find module | 依赖没装全 | 重跑npm install |
ENOENT .env | 工作目录不对 | 检查WorkingDirectory |
EACCES | 权限不足 | 检查文件属主和权限 |
connect ECONNREFUSED | 数据库/接口连不上 | 检查地址和网络 |
6.2 远程访问连不上:分层排查
外部访问不了,别急着改代码,按层排查:
- 服务层:本机
curl 127.0.0.1:3000通不通?不通是服务问题。 - 监听层:
ss -tlnp | grep 3000看监听地址是0.0.0.0还是127.0.0.1?后者外部访问不了。 - 防火墙层:
ufw status或iptables -L看端口放行没。 - 代理层:Nginx 配置对不对,
nginx -t过没过。 - 网络层:域名解析对不对,
ping和telnet测一下。
一层层往下,问题一定在某层暴露。
6.3 内存不足与 OOM
构建阶段或运行阶段被 OOM Killer 干掉,日志里会有Killed字样。解决办法:
# 加 2GB swap sudo fallocate -l 2G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile # 开机自动挂载 echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstabswap 是权宜之计,长期还是加内存。另外可以在 service 文件里限制内存,避免单个服务拖垮整机:
MemoryMax=2G6.4 更新与回滚
源码部署的好处就是更新方便:
cd /opt/deepseek-harness git pull npm install npm run build sudo systemctl restart deepseek-harness出问题要回滚,用 git 切回旧 commit:
git log --oneline git checkout <旧commit> npm install && npm run build sudo systemctl restart deepseek-harness实操心得:每次更新前先
git tag打个标记,或者记下当前 commit。回滚的时候不用翻日志找。我一般还会把.env单独备份一份,更新代码不会动它,但手滑覆盖过。
7. 性能调优与长期维护建议
7.1 日志轮转:别让日志撑爆磁盘
systemd 的 journal 默认会一直涨。限制一下大小:
sudo vim /etc/systemd/journald.conf # 改这两行 SystemMaxUse=500M MaxRetentionSec=1month然后重启 journald:
sudo systemctl restart systemd-journald7.2 资源监控:心里有数
装个htop看实时资源,或者用systemd-cgtop看各服务的资源占用。长期跑的话,建议配个简单的监控脚本,定时记录 CPU、内存、磁盘,出问题好回溯。
7.3 备份策略
要备份的东西就三样:.env配置、数据库文件(如果是 sqlite)、上传的文件目录。写个 cron 定时打包:
# 每天凌晨 3 点备份 0 3 * * * tar -czf /backup/deepseek-$(date +\%F).tar.gz /opt/deepseek-harness/.env /opt/deepseek-harness/data备份文件也要定期清理,别把磁盘塞满。
7.4 安全维护清单
长期跑在公网的服务,这几件事定期做:
- 系统补丁及时打:
apt update && apt upgrade。 - 密钥定期轮换,别一个密钥用到底。
- 看登录日志
last和journalctl -u ssh,发现异常登录及时处理。 - Nginx 和 Node 版本跟进安全公告。
这套流程我从头跑过好几遍,从裸机到能远程访问,顺利的话一两个小时,卡壳的话可能折腾一天。卡的地方基本都在环境依赖和 systemd 配置上,把这两块吃透,后面就顺了。源码部署最大的价值不是"跑起来",而是跑起来之后你知道每一环在哪、怎么改、坏了怎么修——这个掌控感,是拉镜像给不了的。