1. 项目缘起与整体架构拆解把大模型跑在自己的云服务器上,再通过一个带鉴权的网页界面随时访问,这件事听起来像是只有运维老手才能折腾明白的活儿。但实际动手之后你会发现,核心步骤就那么几步,真正耗时间的反而是各种环境依赖和权限配置的细节。我这次部署的目标很明确:在一台入门级云主机上跑起来一个轻量的大模型交互界面,外部网络能访问,但必须经过身份验证才能用,避免被扫到之后变成公开的免费接口。先把这个项目的全貌说清楚。所谓“Harness”,在这里指的是一套面向大模型推理服务的轻量级交互外壳,它负责把用户在前端输入的文字转发给后端模型,再把模型生成的结果流式返回给浏览器。它本身不包含模型权重,只是一个中间层。你需要自己准备好模型文件或者接入已有的推理服务,Harness 负责的是会话管理、流式输出、历史记录这些交互层面的东西。那为什么要在云服务器上部署,而不是直接用本地的电脑跑?原因很直接:本地机器的网络环境不稳定,关掉电脑服务就断了,而且很多云服务商提供的入门配置价格已经很低,一个月几十块钱就能拿到 2 核 4G 的实例,跑一个轻量交互层绰绰有余。更重要的是,云服务器有固定的公网地址,你在外面用手机、平板、公司的电脑都能随时访问,体验上跟用在线服务没什么区别。整体架构可以拆成四层来看。最底层是操作系统和运行时环境,我选的是 Ubuntu 22.04,这个版本在云服务商那边的兼容性最好,社区资料也最全。往上是模型推理层,你可以选择在本地加载模型权重,也可以对接一个已经跑起来的推理接口。再往上是 Harness 应用层,它监听一个本地端口,处理 HTTP 请求和 WebSocket 连接。最顶层是反向代理和鉴权层,由 Nginx 负责对外暴露服务,同时加上基础的认证机制,确保只有持有凭证的人才能访问。这个分层设计的好处在于,每一层都可以独立替换和调试。比如你后面想换一个模型,只需要动推理层;想换鉴权方式,只需要改 Nginx 配置。耦合度低,排查问题的时候也容易定位到底是哪一层出了状况。注意:整个部署过程中,公网鉴权是最容易被忽视但最关键的一环。很多人把服务跑起来之后直接暴露在公网上,结果没几天就发现被人扫到并滥用。加上一层身份验证,成本很低,但能挡掉绝大多数无效访问。2. 环境准备与依赖安装的实操细节2.1 云主机选型与系统初始化选云主机这件事,我的经验是不要一上来就追求高配置。Harness 本身对 CPU 和内存的消耗并不大,真正吃资源的是模型推理那部分。如果你打算在同一个实例上跑模型,那内存至少要到 16G 起步,因为一个 7B 参数的模型加载进来就要占掉十几个 G。但如果你的推理服务是独立部署的,Harness 单独跑在一个 2 核 4G 的实例上完全够用。我这次用的是 2 核 4G 的配置,系统盘 40G,带宽选了按量计费的模式。这里有个细节:带宽的选择直接影响你后续使用的流畅度。如果你只是自己用,1M 到 3M 的带宽其实也能跑,因为 Harness 传输的主要是文本数据,流量并不大。但如果你打算分享给几个同事一起用,建议至少 5M 起步,否则并发请求一多,页面加载会明显变慢。系统初始化的时候,有几件事是必须做的。第一是更新软件源并升级已有包,这个操作能避免很多因为版本过旧导致的依赖冲突。第二是创建一个非 root 的普通用户,后续所有操作都在这个用户下进行,降低误操作的风险。第三是配置好时区,不然你后面看日志的时候时间戳会对不上,排查问题很麻烦。sudo apt update && sudo apt upgrade -y sudo timedatectl set-timezone Asia/Shanghai sudo adduser deploy sudo usermod -aG sudo deploy这几条命令执行完之后,用su - deploy切换到新用户,后续的操作都在这个用户下完成。2.2 运行时环境与核心依赖Harness 这类应用通常是用 Node.js 或者 Python 写的,我这次部署的版本是基于 Node.js 的。安装 Node.js 的方式有很多种,我推荐用版本管理工具来装,而不是直接用系统自带的包管理器。原因很简单:系统自带的 Node.js 版本往往偏旧,而 Harness 可能依赖一些较新的语言特性,版本不够会导致启动报错。curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash source ~/.bashrc nvm install 20 nvm use 20装完之后用node -v确认一下版本号,确保是 20.x 以上。接下来是包管理器的选择,npm 和 pnpm 都可以,我用的是 pnpm,因为它在处理依赖树的时候更快,磁盘占用也更小。npm install -g pnpm除了 Node.js 运行时,还需要装几个系统级的依赖库。比如build-essential用于编译一些原生模块,git用于拉取代码,nginx用于后面的反向代理。这些都是一次性安装,花不了几分钟。sudo apt install -y build-essential git nginx实操心得:在安装 Node.js 之前,先确认一下系统里有没有残留的旧版本。如果有,先用包管理器卸载干净,再装新的。我遇到过好几次因为新旧版本混在一起导致node命令指向错误的问题,排查起来很费时间。2.3 模型推理服务的对接方式Harness 本身不包含模型,所以你需要提前准备好推理服务。有两种常见的做法:一种是在本地加载模型权重,用类似 llama.cpp 或者 ollama 这样的工具跑起来一个本地接口;另一种是对接一个已经部署好的推理服务地址。如果你选择本地加载,那就要考虑模型文件的存放位置和加载方式。模型文件通常比较大,建议放在单独的数据盘或者挂载的存储卷上,不要放在系统盘里,否则系统盘满了之后整个实例都会出问题。加载模型的时候,要根据你的硬件配置调整参数,比如线程数、上下文长度、批处理大小这些。参数设得太高,内存扛不住会直接崩掉;设得太低,推理速度又慢得让人着急。如果你选择对接外部推理服务,那就简单很多,只需要在 Harness 的配置文件里填好服务地址和必要的认证信息就行。但这种方式的前提是你已经有一个稳定运行的推理服务,而且网络延迟要足够低,否则用户体验会很差。我这次采用的是本地加载的方式,模型选了一个参数量适中的版本,在 4G 内存的实例上跑起来虽然有点吃力,但处理日常的文本交互任务已经足够了。加载的时候把上下文长度设成了 2048,线程数设成了 2,这两个参数是根据实例的 CPU 核心数来定的,基本能跑满但不会把系统拖垮。3. Harness 部署与公网鉴权配置全流程3.1 代码拉取与依赖安装把 Harness 的代码拉到服务器上,这一步没什么特别的,直接用 git clone 就行。拉下来之后进入项目目录,先看一眼 README 和配置文件模板,了解需要填哪些参数。git clone <仓库地址> harness cd harness pnpm install依赖安装的过程可能会比较慢,因为有些包需要从外部源下载。如果遇到网络超时,可以配置一下镜像源,或者多试几次。安装完成后,通常会有一个.env.example或者config.example.yaml这样的模板文件,你需要复制一份并改成自己的配置。cp .env.example .env配置文件里需要关注几个关键项:监听端口、模型服务地址、会话密钥、日志级别。监听端口默认可能是 3000 或者 8080,你可以根据自己的需要改。模型服务地址要填你实际跑起来的推理接口地址,通常是http://127.0.0.1:11434这样的本地地址。会话密钥是一个随机字符串,用于加密会话数据,一定要改成一个足够复杂的值,不要用默认的。# .env 文件示例 PORT=3000 MODEL_API=http://127.0.0.1:11434 SESSION_SECRET=your_random_secret_here LOG_LEVEL=info注意:SESSION_SECRET 这个值千万不要用默认的,也不要用简单的单词。建议用openssl rand -hex 32生成一个随机字符串,这样安全性才有保障。3.2 服务启动与进程守护配置改好之后,可以先手动启动一下看看有没有报错。pnpm start如果一切正常,你会看到日志里输出监听端口的提示。这时候用curl http://127.0.0.1:3000测试一下,应该能返回一些内容。确认没问题之后,按 Ctrl+C 停掉,然后配置进程守护,让服务在后台稳定运行。我用的进程守护工具是 systemd,这是 Linux 系统自带的,不需要额外安装。创建一个 service 文件,把启动命令、工作目录、环境变量都写进去。[Unit] Description=Harness Service After=network.target [Service] Type=simple User=deploy WorkingDirectory=/home/deploy/harness ExecStart=/home/deploy/.nvm/versions/node/v20.11.0/bin/node /home/deploy/harness/dist/index.js Restart=on-failure RestartSec=5 Environment=NODE_ENV=production [Install] WantedBy=multi-user.target这里有几个细节需要注意。ExecStart 里的 node 路径要写绝对路径,因为 systemd 不会加载你的 shell 环境变量。WorkingDirectory 要指向项目根目录,这样应用才能正确读取配置文件。Restart 设为 on-failure 表示进程异常退出时自动重启,RestartSec 设为 5 表示重启前等待 5 秒,避免频繁重启导致系统负载过高。配置好之后,启用并启动服务。sudo systemctl daemon-reload sudo systemctl enable harness sudo systemctl start harness sudo systemctl status harness如果状态显示 active (running),说明服务已经正常跑起来了。3.3 Nginx 反向代理与鉴权配置服务跑在本地端口上,外部是访问不到的,需要 Nginx 做一层反向代理。同时,鉴权也是在这一层加上去的。Nginx 提供了多种鉴权方式,最简单的是 HTTP Basic Auth,配置起来快,兼容性也好。首先创建密码文件。用htpasswd工具生成,如果没有这个工具,先安装apache2-utils。sudo apt install -y apache2-utils sudo htpasswd -c /etc/nginx/.htpasswd your_username执行后会提示你输入密码,输入两次确认即可。这个文件里存储的是加密后的凭证,Nginx 在收到请求时会比对用户输入的用户名和密码。接下来配置 Nginx 的站点文件。在/etc/nginx/sites-available/下创建一个新的配置文件。server { listen 80; server_name your_domain_or_ip; location / { auth_basic "Restricted Access"; auth_basic_user_file /etc/nginx/.htpasswd; 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; proxy_send_timeout 300s; } }这里有几个关键配置需要解释一下。auth_basic和auth_basic_user_file这两行就是鉴权的核心,开启之后,所有访问这个站点的请求都会先要求输入用户名和密码。proxy_pass指向本地服务地址,Nginx 会把请求转发过去。Upgrade和Connection这两行是为了支持 WebSocket,Harness 的流式输出通常依赖 WebSocket,如果不配这两行,流式效果会失效。proxy_read_timeout和proxy_send_timeout设成了 300 秒,因为模型生成回复有时候会比较慢,超时时间太短会导致连接被中断。配置写好后,创建一个软链接到sites-enabled目录,然后测试配置并重载 Nginx。sudo ln -s /etc/nginx/sites-available/harness /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginxnginx -t是测试配置文件语法是否正确,如果输出 syntax is ok 和 test is successful,说明没问题。然后 reload 让配置生效。3.4 防火墙与安全组配置Nginx 配好之后,还需要确保云服务商的安全组和系统防火墙都放行了 80 端口。安全组是在云服务商的控制台里配置的,找到你的实例,在安全组规则里添加一条入站规则,允许 TCP 协议的 80 端口访问。系统防火墙这边,如果你用的是 ufw,执行以下命令。sudo ufw allow 80/tcp sudo ufw allow 22/tcp sudo ufw enable22 端口是 SSH 用的,千万不要忘了放行,否则你下次就连不上服务器了。启用防火墙之前,确认一下规则有没有写错,不然把自己关在外面就很尴尬了。实操心得:在启用防火墙之前,先确认 SSH 端口已经放行,并且当前连接不会断开。我建议在另一个终端窗口里保持一个 SSH 连接,这样即使当前窗口断了,还能用备用窗口进去修复。4. 常见问题排查与性能调优实录4.1 服务启动失败的排查思路服务起不来是最常见的问题,表现可能是 systemd 状态显示 failed,或者日志里有报错信息。排查的时候按顺序来,先看 systemd 的日志。sudo journalctl -u harness -n 50 --no-pager这条命令会显示最近 50 行日志,通常能直接看到报错原因。常见的启动失败原因有几种:端口被占用、配置文件路径不对、依赖没装全、Node.js 版本不匹配。端口被占用的话,用ss -tlnp | grep 3000看一下是谁占用了这个端口,然后要么改 Harness 的监听端口,要么把占用端口的进程停掉。配置文件路径不对的话,检查一下 WorkingDirectory 和配置文件的实际位置是否一致。依赖没装全的话,重新执行pnpm install并观察有没有报错。Node.js 版本不匹配的话,用node -v确认版本,必要时切换版本。还有一种情况是服务能启动但立刻退出,日志里没有明显报错。这种通常是环境变量的问题,比如 SESSION_SECRET 没有设置,或者 MODEL_API 地址填错了导致连接失败。检查.env文件里的每一项配置,确保没有遗漏。4.2 鉴权不生效或反复弹窗Basic Auth 配置好之后,正常情况下浏览器会弹出一个登录框,输入正确的用户名密码后就能访问。如果出现反复弹窗或者鉴权不生效的情况,通常是以下几个原因。第一种是密码文件路径写错了,Nginx 找不到文件,自然就无法验证。检查auth_basic_user_file指向的路径是否存在,权限是否正确。Nginx 进程通常以 www-data 用户运行,确保这个用户对密码文件有读取权限。sudo chown www-data:www-data /etc/nginx/.htpasswd sudo chmod 640 /etc/nginx/.htpasswd第二种是浏览器缓存了错误的凭证。清除浏览器缓存或者换一个无痕窗口试试。第三种是 Nginx 配置没有生效,可能是忘了 reload 或者配置文件没有正确链接到 sites-enabled 目录。用nginx -T可以查看当前生效的完整配置,确认你的配置有没有被加载进去。还有一种比较隐蔽的情况是,你在 Nginx 前面还套了另一层代理,比如云服务商自带的负载均衡或者 CDN,这些服务可能会把 Authorization 头丢掉,导致 Nginx 收不到凭证。如果是这种情况,需要在上一层代理的配置里也放行 Authorization 头。4.3 流式输出中断与超时处理Harness 的流式输出体验很好,但有时候会出现输出到一半就断了的情况。这个问题通常和超时设置有关。Nginx 默认的proxy_read_timeout是 60 秒,如果模型生成一段长文本超过了这个时间,连接就会被断开。我在配置里把它设成了 300 秒,基本能覆盖大多数场景。如果还是遇到中断,可以检查一下 Harness 本身的超时设置。有些应用会在代码里设置请求超时,这个需要看具体的配置文件或者源码。另外,WebSocket 连接本身也有心跳机制,如果心跳间隔设置得太长,中间的网络设备可能会把空闲连接断掉。可以在 Nginx 配置里加上proxy_ping_interval和proxy_ping_timeout来主动发送心跳包。proxy_ping_interval 30s; proxy_ping_timeout 60s;这两个参数的作用是每隔 30 秒发一个心跳包,如果 60 秒内没有收到响应就认为连接断了。这样能保持连接活跃,避免被中间设备回收。4.4 性能调优与资源监控服务跑起来之后,还需要关注一下资源占用情况。用htop或者top可以实时查看 CPU 和内存的使用率。如果发现内存占用持续走高,可能是模型加载占用了太多内存,或者 Harness 本身有内存泄漏的问题。对于模型推理这部分,可以调整的参数包括线程数、批处理大小、上下文长度。线程数一般设为 CPU 核心数,设多了反而会因为上下文切换导致性能下降。批处理大小影响的是并发处理能力,设大了会占用更多内存,设小了吞吐量上不去。上下文长度直接影响内存占用,2048 和 4096 的内存消耗差别很大,根据实际需要来定。Harness 本身的调优空间不大,主要是日志级别和会话缓存。日志级别设成 info 就够了,debug 级别会产生大量日志,既占磁盘又影响性能。会话缓存如果设得太大,内存占用会明显上升,建议根据实际用户数量来调整。调优项建议值影响模型线程数CPU 核心数过高导致上下文切换开销上下文长度2048过高导致内存占用翻倍批处理大小根据并发量调整过高导致内存不足日志级别infodebug 级别产生大量日志会话缓存根据用户数调整过大导致内存占用上升避坑技巧:在调整任何参数之前,先用free -h看一下当前的内存使用情况,留出至少 20% 的余量。内存打满之后,系统会触发 OOM Killer,把占用内存最多的进程杀掉,通常是你的模型服务或者 Harness,导致服务突然不可用。4.5 日志管理与故障回溯日志是排查问题的第一手资料,但日志文件如果不管理,很快就会把磁盘占满。systemd 的日志默认存储在/var/log/journal/目录下,可以通过配置限制日志大小。sudo journalctl --vacuum-size=500M这条命令会把日志总量控制在 500M 以内,超出部分会自动清理。也可以设置定时任务,定期清理旧日志。Harness 自身的日志通常在项目目录下的 logs 文件夹里,同样需要定期清理或者配置轮转。如果遇到偶发性的问题,比如某个时间段服务突然变慢或者报错,可以通过日志的时间戳来定位。先确定问题发生的时间点,然后用journalctl --since和--until参数筛选出那个时间段的日志,逐条分析。sudo journalctl -u harness --since "2024-01-01 10:00:00" --until "2024-01-01 10:30:00"这种方式能快速缩小排查范围,避免在海量日志里盲目翻找。5. 日常维护与安全加固建议5.1 定期更新与备份策略服务跑起来之后,日常维护主要是两件事:更新和备份。更新包括系统包更新和 Harness 代码更新。系统包更新用apt update && apt upgrade就行,建议每个月做一次。Harness 代码更新要看项目的发布节奏,如果有新版本,先看一下更新日志,确认没有破坏性变更再拉取。备份主要是备份配置文件和会话数据。配置文件包括.env、Nginx 配置、systemd service 文件,这些文件不大,直接复制到本地或者另一个存储位置就行。会话数据如果存在数据库里,需要定期导出;如果存在文件里,直接打包备份。备份的频率根据使用情况来定,我一般是每周备份一次,重要变更之前额外备份一次。tar -czf harness_backup_$(date +%Y%m%d).tar.gz .env /etc/nginx/sites-available/harness /etc/systemd/system/harness.service这条命令把关键配置文件打包成一个压缩包,文件名带日期,方便区分。5.2 访问安全加固的额外措施Basic Auth 是最基础的鉴权方式,能满足大部分个人使用场景。如果你对安全性有更高的要求,可以考虑以下几个额外的措施。第一是限制访问来源 IP。在 Nginx 配置里加上allow和deny规则,只允许特定的 IP 段访问。这个适合你的访问地点比较固定的情况,比如只在公司网络或者家里访问。allow 192.168.1.0/24; deny all;第二是启用 HTTPS。Basic Auth 的凭证是 Base64 编码传输的,虽然编码了但并没有加密,中间人截获之后可以轻易解码。启用 HTTPS 之后,整个通信过程都是加密的,凭证就不会泄露。可以用 Let's Encrypt 的免费证书,配置起来也不复杂。第三是定期更换密码。Basic Auth 的密码文件是静态的,如果密码泄露了,别人就能一直访问。建议每隔一段时间换一次密码,用htpasswd命令更新密码文件即可。sudo htpasswd /etc/nginx/.htpasswd your_username执行后会提示输入新密码,更新完成后不需要重启 Nginx,配置是实时生效的。5.3 资源监控与告警设置如果服务是长期运行的,建议加一些基础的监控和告警。最简单的做法是用一个定时脚本,每隔几分钟检查一次服务的状态和资源占用,如果发现异常就发通知。#!/bin/bash if ! systemctl is-active --quiet harness; then echo "Harness service is down" | mail -s "Alert" your_email@example.com fi这个脚本检查 Harness 服务是否在运行,如果不在就发一封邮件。可以加到 crontab 里,每隔 5 分钟执行一次。资源监控可以用free和df命令获取内存和磁盘使用率,超过阈值就告警。#!/bin/bash MEM_USAGE=$(free | awk '/Mem/ {printf "%.0f", $3/$2 * 100}') if [ "$MEM_USAGE" -gt 90 ]; then echo "Memory usage is ${MEM_USAGE}%" | mail -s "Alert" your_email@example.com fi这些脚本虽然简单,但在关键时刻能帮你及时发现问题,避免服务长时间不可用。5.4 会话数据清理与隐私保护Harness 会保存会话历史,方便用户查看之前的对话记录。但这些数据如果一直不清理,一方面会占用磁盘空间,另一方面也可能涉及隐私问题。建议配置一个定期清理的策略,比如只保留最近 30 天的会话记录。如果会话数据存在数据库里,写一条 SQL 定期删除旧记录就行。如果存在文件里,用find命令找到超过 30 天的文件并删除。find /home/deploy/harness/data/sessions -type f -mtime +30 -delete这条命令会删除 sessions 目录下修改时间超过 30 天的文件。加到 crontab 里,每天凌晨执行一次。注意:在执行删除操作之前,先确认一下目录路径是否正确,最好先用-print参数看一下会删除哪些文件,确认无误后再换成-delete。5.5 后续扩展方向这套部署方案目前满足的是个人或者小团队的使用需求。如果后续想扩展,有几个方向可以考虑。一是接入更多的模型。Harness 通常支持配置多个模型后端,你可以在配置文件里添加多个模型地址,用户在使用的时候可以切换。这样就能同时用不同参数量、不同特长的模型,灵活性更高。二是增加用户体系。Basic Auth 是所有用户共用一套凭证,没法区分不同用户的权限和使用记录。如果需要更细粒度的管理,可以接入 OAuth 或者自建用户系统,每个用户有自己的账号和会话隔离。三是优化推理性能。如果并发量上来了,单实例的推理服务可能扛不住。可以考虑用多个推理实例做负载均衡,或者换用性能更好的硬件。也可以引入缓存机制,对于重复的问题直接返回缓存结果,减少推理压力。四是完善监控体系。目前只是简单的脚本告警,如果服务规模扩大,可以引入更专业的监控工具,把 CPU、内存、磁盘、网络、请求量、响应时间这些指标都采集起来,做成可视化面板,方便随时掌握服务状态。这些扩展方向不需要一次性全做,根据实际需求逐步迭代就行。先把基础服务跑稳,再考虑锦上添花的事情。
1. 项目缘起与整体架构拆解把大模型跑在自己的云服务器上,再通过一个带鉴权的网页界面随时访问,这件事听起来像是只有运维老手才能折腾明白的活儿。但实际动手之后你会发现,核心步骤就那么几步,真正耗时间的反而是各种环境依赖和权限配置的细节。我这次部署的目标很明确:在一台入门级云主机上跑起来一个轻量的大模型交互界面,外部网络能访问,但必须经过身份验证才能用,避免被扫到之后变成公开的免费接口。先把这个项目的全貌说清楚。所谓“Harness”,在这里指的是一套面向大模型推理服务的轻量级交互外壳,它负责把用户在前端输入的文字转发给后端模型,再把模型生成的结果流式返回给浏览器。它本身不包含模型权重,只是一个中间层。你需要自己准备好模型文件或者接入已有的推理服务,Harness 负责的是会话管理、流式输出、历史记录这些交互层面的东西。那为什么要在云服务器上部署,而不是直接用本地的电脑跑?原因很直接:本地机器的网络环境不稳定,关掉电脑服务就断了,而且很多云服务商提供的入门配置价格已经很低,一个月几十块钱就能拿到 2 核 4G 的实例,跑一个轻量交互层绰绰有余。更重要的是,云服务器有固定的公网地址,你在外面用手机、平板、公司的电脑都能随时访问,体验上跟用在线服务没什么区别。整体架构可以拆成四层来看。最底层是操作系统和运行时环境,我选的是 Ubuntu 22.04,这个版本在云服务商那边的兼容性最好,社区资料也最全。往上是模型推理层,你可以选择在本地加载模型权重,也可以对接一个已经跑起来的推理接口。再往上是 Harness 应用层,它监听一个本地端口,处理 HTTP 请求和 WebSocket 连接。最顶层是反向代理和鉴权层,由 Nginx 负责对外暴露服务,同时加上基础的认证机制,确保只有持有凭证的人才能访问。这个分层设计的好处在于,每一层都可以独立替换和调试。比如你后面想换一个模型,只需要动推理层;想换鉴权方式,只需要改 Nginx 配置。耦合度低,排查问题的时候也容易定位到底是哪一层出了状况。注意:整个部署过程中,公网鉴权是最容易被忽视但最关键的一环。很多人把服务跑起来之后直接暴露在公网上,结果没几天就发现被人扫到并滥用。加上一层身份验证,成本很低,但能挡掉绝大多数无效访问。2. 环境准备与依赖安装的实操细节2.1 云主机选型与系统初始化选云主机这件事,我的经验是不要一上来就追求高配置。Harness 本身对 CPU 和内存的消耗并不大,真正吃资源的是模型推理那部分。如果你打算在同一个实例上跑模型,那内存至少要到 16G 起步,因为一个 7B 参数的模型加载进来就要占掉十几个 G。但如果你的推理服务是独立部署的,Harness 单独跑在一个 2 核 4G 的实例上完全够用。我这次用的是 2 核 4G 的配置,系统盘 40G,带宽选了按量计费的模式。这里有个细节:带宽的选择直接影响你后续使用的流畅度。如果你只是自己用,1M 到 3M 的带宽其实也能跑,因为 Harness 传输的主要是文本数据,流量并不大。但如果你打算分享给几个同事一起用,建议至少 5M 起步,否则并发请求一多,页面加载会明显变慢。系统初始化的时候,有几件事是必须做的。第一是更新软件源并升级已有包,这个操作能避免很多因为版本过旧导致的依赖冲突。第二是创建一个非 root 的普通用户,后续所有操作都在这个用户下进行,降低误操作的风险。第三是配置好时区,不然你后面看日志的时候时间戳会对不上,排查问题很麻烦。sudo apt update && sudo apt upgrade -y sudo timedatectl set-timezone Asia/Shanghai sudo adduser deploy sudo usermod -aG sudo deploy这几条命令执行完之后,用su - deploy切换到新用户,后续的操作都在这个用户下完成。2.2 运行时环境与核心依赖Harness 这类应用通常是用 Node.js 或者 Python 写的,我这次部署的版本是基于 Node.js 的。安装 Node.js 的方式有很多种,我推荐用版本管理工具来装,而不是直接用系统自带的包管理器。原因很简单:系统自带的 Node.js 版本往往偏旧,而 Harness 可能依赖一些较新的语言特性,版本不够会导致启动报错。curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash source ~/.bashrc nvm install 20 nvm use 20装完之后用node -v确认一下版本号,确保是 20.x 以上。接下来是包管理器的选择,npm 和 pnpm 都可以,我用的是 pnpm,因为它在处理依赖树的时候更快,磁盘占用也更小。npm install -g pnpm除了 Node.js 运行时,还需要装几个系统级的依赖库。比如build-essential用于编译一些原生模块,git用于拉取代码,nginx用于后面的反向代理。这些都是一次性安装,花不了几分钟。sudo apt install -y build-essential git nginx实操心得:在安装 Node.js 之前,先确认一下系统里有没有残留的旧版本。如果有,先用包管理器卸载干净,再装新的。我遇到过好几次因为新旧版本混在一起导致node命令指向错误的问题,排查起来很费时间。2.3 模型推理服务的对接方式Harness 本身不包含模型,所以你需要提前准备好推理服务。有两种常见的做法:一种是在本地加载模型权重,用类似 llama.cpp 或者 ollama 这样的工具跑起来一个本地接口;另一种是对接一个已经部署好的推理服务地址。如果你选择本地加载,那就要考虑模型文件的存放位置和加载方式。模型文件通常比较大,建议放在单独的数据盘或者挂载的存储卷上,不要放在系统盘里,否则系统盘满了之后整个实例都会出问题。加载模型的时候,要根据你的硬件配置调整参数,比如线程数、上下文长度、批处理大小这些。参数设得太高,内存扛不住会直接崩掉;设得太低,推理速度又慢得让人着急。如果你选择对接外部推理服务,那就简单很多,只需要在 Harness 的配置文件里填好服务地址和必要的认证信息就行。但这种方式的前提是你已经有一个稳定运行的推理服务,而且网络延迟要足够低,否则用户体验会很差。我这次采用的是本地加载的方式,模型选了一个参数量适中的版本,在 4G 内存的实例上跑起来虽然有点吃力,但处理日常的文本交互任务已经足够了。加载的时候把上下文长度设成了 2048,线程数设成了 2,这两个参数是根据实例的 CPU 核心数来定的,基本能跑满但不会把系统拖垮。3. Harness 部署与公网鉴权配置全流程3.1 代码拉取与依赖安装把 Harness 的代码拉到服务器上,这一步没什么特别的,直接用 git clone 就行。拉下来之后进入项目目录,先看一眼 README 和配置文件模板,了解需要填哪些参数。git clone <仓库地址> harness cd harness pnpm install依赖安装的过程可能会比较慢,因为有些包需要从外部源下载。如果遇到网络超时,可以配置一下镜像源,或者多试几次。安装完成后,通常会有一个.env.example或者config.example.yaml这样的模板文件,你需要复制一份并改成自己的配置。cp .env.example .env配置文件里需要关注几个关键项:监听端口、模型服务地址、会话密钥、日志级别。监听端口默认可能是 3000 或者 8080,你可以根据自己的需要改。模型服务地址要填你实际跑起来的推理接口地址,通常是http://127.0.0.1:11434这样的本地地址。会话密钥是一个随机字符串,用于加密会话数据,一定要改成一个足够复杂的值,不要用默认的。# .env 文件示例 PORT=3000 MODEL_API=http://127.0.0.1:11434 SESSION_SECRET=your_random_secret_here LOG_LEVEL=info注意:SESSION_SECRET 这个值千万不要用默认的,也不要用简单的单词。建议用openssl rand -hex 32生成一个随机字符串,这样安全性才有保障。3.2 服务启动与进程守护配置改好之后,可以先手动启动一下看看有没有报错。pnpm start如果一切正常,你会看到日志里输出监听端口的提示。这时候用curl http://127.0.0.1:3000测试一下,应该能返回一些内容。确认没问题之后,按 Ctrl+C 停掉,然后配置进程守护,让服务在后台稳定运行。我用的进程守护工具是 systemd,这是 Linux 系统自带的,不需要额外安装。创建一个 service 文件,把启动命令、工作目录、环境变量都写进去。[Unit] Description=Harness Service After=network.target [Service] Type=simple User=deploy WorkingDirectory=/home/deploy/harness ExecStart=/home/deploy/.nvm/versions/node/v20.11.0/bin/node /home/deploy/harness/dist/index.js Restart=on-failure RestartSec=5 Environment=NODE_ENV=production [Install] WantedBy=multi-user.target这里有几个细节需要注意。ExecStart 里的 node 路径要写绝对路径,因为 systemd 不会加载你的 shell 环境变量。WorkingDirectory 要指向项目根目录,这样应用才能正确读取配置文件。Restart 设为 on-failure 表示进程异常退出时自动重启,RestartSec 设为 5 表示重启前等待 5 秒,避免频繁重启导致系统负载过高。配置好之后,启用并启动服务。sudo systemctl daemon-reload sudo systemctl enable harness sudo systemctl start harness sudo systemctl status harness如果状态显示 active (running),说明服务已经正常跑起来了。3.3 Nginx 反向代理与鉴权配置服务跑在本地端口上,外部是访问不到的,需要 Nginx 做一层反向代理。同时,鉴权也是在这一层加上去的。Nginx 提供了多种鉴权方式,最简单的是 HTTP Basic Auth,配置起来快,兼容性也好。首先创建密码文件。用htpasswd工具生成,如果没有这个工具,先安装apache2-utils。sudo apt install -y apache2-utils sudo htpasswd -c /etc/nginx/.htpasswd your_username执行后会提示你输入密码,输入两次确认即可。这个文件里存储的是加密后的凭证,Nginx 在收到请求时会比对用户输入的用户名和密码。接下来配置 Nginx 的站点文件。在/etc/nginx/sites-available/下创建一个新的配置文件。server { listen 80; server_name your_domain_or_ip; location / { auth_basic "Restricted Access"; auth_basic_user_file /etc/nginx/.htpasswd; 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; proxy_send_timeout 300s; } }这里有几个关键配置需要解释一下。auth_basic和auth_basic_user_file这两行就是鉴权的核心,开启之后,所有访问这个站点的请求都会先要求输入用户名和密码。proxy_pass指向本地服务地址,Nginx 会把请求转发过去。Upgrade和Connection这两行是为了支持 WebSocket,Harness 的流式输出通常依赖 WebSocket,如果不配这两行,流式效果会失效。proxy_read_timeout和proxy_send_timeout设成了 300 秒,因为模型生成回复有时候会比较慢,超时时间太短会导致连接被中断。配置写好后,创建一个软链接到sites-enabled目录,然后测试配置并重载 Nginx。sudo ln -s /etc/nginx/sites-available/harness /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginxnginx -t是测试配置文件语法是否正确,如果输出 syntax is ok 和 test is successful,说明没问题。然后 reload 让配置生效。3.4 防火墙与安全组配置Nginx 配好之后,还需要确保云服务商的安全组和系统防火墙都放行了 80 端口。安全组是在云服务商的控制台里配置的,找到你的实例,在安全组规则里添加一条入站规则,允许 TCP 协议的 80 端口访问。系统防火墙这边,如果你用的是 ufw,执行以下命令。sudo ufw allow 80/tcp sudo ufw allow 22/tcp sudo ufw enable22 端口是 SSH 用的,千万不要忘了放行,否则你下次就连不上服务器了。启用防火墙之前,确认一下规则有没有写错,不然把自己关在外面就很尴尬了。实操心得:在启用防火墙之前,先确认 SSH 端口已经放行,并且当前连接不会断开。我建议在另一个终端窗口里保持一个 SSH 连接,这样即使当前窗口断了,还能用备用窗口进去修复。4. 常见问题排查与性能调优实录4.1 服务启动失败的排查思路服务起不来是最常见的问题,表现可能是 systemd 状态显示 failed,或者日志里有报错信息。排查的时候按顺序来,先看 systemd 的日志。sudo journalctl -u harness -n 50 --no-pager这条命令会显示最近 50 行日志,通常能直接看到报错原因。常见的启动失败原因有几种:端口被占用、配置文件路径不对、依赖没装全、Node.js 版本不匹配。端口被占用的话,用ss -tlnp | grep 3000看一下是谁占用了这个端口,然后要么改 Harness 的监听端口,要么把占用端口的进程停掉。配置文件路径不对的话,检查一下 WorkingDirectory 和配置文件的实际位置是否一致。依赖没装全的话,重新执行pnpm install并观察有没有报错。Node.js 版本不匹配的话,用node -v确认版本,必要时切换版本。还有一种情况是服务能启动但立刻退出,日志里没有明显报错。这种通常是环境变量的问题,比如 SESSION_SECRET 没有设置,或者 MODEL_API 地址填错了导致连接失败。检查.env文件里的每一项配置,确保没有遗漏。4.2 鉴权不生效或反复弹窗Basic Auth 配置好之后,正常情况下浏览器会弹出一个登录框,输入正确的用户名密码后就能访问。如果出现反复弹窗或者鉴权不生效的情况,通常是以下几个原因。第一种是密码文件路径写错了,Nginx 找不到文件,自然就无法验证。检查auth_basic_user_file指向的路径是否存在,权限是否正确。Nginx 进程通常以 www-data 用户运行,确保这个用户对密码文件有读取权限。sudo chown www-data:www-data /etc/nginx/.htpasswd sudo chmod 640 /etc/nginx/.htpasswd第二种是浏览器缓存了错误的凭证。清除浏览器缓存或者换一个无痕窗口试试。第三种是 Nginx 配置没有生效,可能是忘了 reload 或者配置文件没有正确链接到 sites-enabled 目录。用nginx -T可以查看当前生效的完整配置,确认你的配置有没有被加载进去。还有一种比较隐蔽的情况是,你在 Nginx 前面还套了另一层代理,比如云服务商自带的负载均衡或者 CDN,这些服务可能会把 Authorization 头丢掉,导致 Nginx 收不到凭证。如果是这种情况,需要在上一层代理的配置里也放行 Authorization 头。4.3 流式输出中断与超时处理Harness 的流式输出体验很好,但有时候会出现输出到一半就断了的情况。这个问题通常和超时设置有关。Nginx 默认的proxy_read_timeout是 60 秒,如果模型生成一段长文本超过了这个时间,连接就会被断开。我在配置里把它设成了 300 秒,基本能覆盖大多数场景。如果还是遇到中断,可以检查一下 Harness 本身的超时设置。有些应用会在代码里设置请求超时,这个需要看具体的配置文件或者源码。另外,WebSocket 连接本身也有心跳机制,如果心跳间隔设置得太长,中间的网络设备可能会把空闲连接断掉。可以在 Nginx 配置里加上proxy_ping_interval和proxy_ping_timeout来主动发送心跳包。proxy_ping_interval 30s; proxy_ping_timeout 60s;这两个参数的作用是每隔 30 秒发一个心跳包,如果 60 秒内没有收到响应就认为连接断了。这样能保持连接活跃,避免被中间设备回收。4.4 性能调优与资源监控服务跑起来之后,还需要关注一下资源占用情况。用htop或者top可以实时查看 CPU 和内存的使用率。如果发现内存占用持续走高,可能是模型加载占用了太多内存,或者 Harness 本身有内存泄漏的问题。对于模型推理这部分,可以调整的参数包括线程数、批处理大小、上下文长度。线程数一般设为 CPU 核心数,设多了反而会因为上下文切换导致性能下降。批处理大小影响的是并发处理能力,设大了会占用更多内存,设小了吞吐量上不去。上下文长度直接影响内存占用,2048 和 4096 的内存消耗差别很大,根据实际需要来定。Harness 本身的调优空间不大,主要是日志级别和会话缓存。日志级别设成 info 就够了,debug 级别会产生大量日志,既占磁盘又影响性能。会话缓存如果设得太大,内存占用会明显上升,建议根据实际用户数量来调整。调优项建议值影响模型线程数CPU 核心数过高导致上下文切换开销上下文长度2048过高导致内存占用翻倍批处理大小根据并发量调整过高导致内存不足日志级别infodebug 级别产生大量日志会话缓存根据用户数调整过大导致内存占用上升避坑技巧:在调整任何参数之前,先用free -h看一下当前的内存使用情况,留出至少 20% 的余量。内存打满之后,系统会触发 OOM Killer,把占用内存最多的进程杀掉,通常是你的模型服务或者 Harness,导致服务突然不可用。4.5 日志管理与故障回溯日志是排查问题的第一手资料,但日志文件如果不管理,很快就会把磁盘占满。systemd 的日志默认存储在/var/log/journal/目录下,可以通过配置限制日志大小。sudo journalctl --vacuum-size=500M这条命令会把日志总量控制在 500M 以内,超出部分会自动清理。也可以设置定时任务,定期清理旧日志。Harness 自身的日志通常在项目目录下的 logs 文件夹里,同样需要定期清理或者配置轮转。如果遇到偶发性的问题,比如某个时间段服务突然变慢或者报错,可以通过日志的时间戳来定位。先确定问题发生的时间点,然后用journalctl --since和--until参数筛选出那个时间段的日志,逐条分析。sudo journalctl -u harness --since "2024-01-01 10:00:00" --until "2024-01-01 10:30:00"这种方式能快速缩小排查范围,避免在海量日志里盲目翻找。5. 日常维护与安全加固建议5.1 定期更新与备份策略服务跑起来之后,日常维护主要是两件事:更新和备份。更新包括系统包更新和 Harness 代码更新。系统包更新用apt update && apt upgrade就行,建议每个月做一次。Harness 代码更新要看项目的发布节奏,如果有新版本,先看一下更新日志,确认没有破坏性变更再拉取。备份主要是备份配置文件和会话数据。配置文件包括.env、Nginx 配置、systemd service 文件,这些文件不大,直接复制到本地或者另一个存储位置就行。会话数据如果存在数据库里,需要定期导出;如果存在文件里,直接打包备份。备份的频率根据使用情况来定,我一般是每周备份一次,重要变更之前额外备份一次。tar -czf harness_backup_$(date +%Y%m%d).tar.gz .env /etc/nginx/sites-available/harness /etc/systemd/system/harness.service这条命令把关键配置文件打包成一个压缩包,文件名带日期,方便区分。5.2 访问安全加固的额外措施Basic Auth 是最基础的鉴权方式,能满足大部分个人使用场景。如果你对安全性有更高的要求,可以考虑以下几个额外的措施。第一是限制访问来源 IP。在 Nginx 配置里加上allow和deny规则,只允许特定的 IP 段访问。这个适合你的访问地点比较固定的情况,比如只在公司网络或者家里访问。allow 192.168.1.0/24; deny all;第二是启用 HTTPS。Basic Auth 的凭证是 Base64 编码传输的,虽然编码了但并没有加密,中间人截获之后可以轻易解码。启用 HTTPS 之后,整个通信过程都是加密的,凭证就不会泄露。可以用 Let's Encrypt 的免费证书,配置起来也不复杂。第三是定期更换密码。Basic Auth 的密码文件是静态的,如果密码泄露了,别人就能一直访问。建议每隔一段时间换一次密码,用htpasswd命令更新密码文件即可。sudo htpasswd /etc/nginx/.htpasswd your_username执行后会提示输入新密码,更新完成后不需要重启 Nginx,配置是实时生效的。5.3 资源监控与告警设置如果服务是长期运行的,建议加一些基础的监控和告警。最简单的做法是用一个定时脚本,每隔几分钟检查一次服务的状态和资源占用,如果发现异常就发通知。#!/bin/bash if ! systemctl is-active --quiet harness; then echo "Harness service is down" | mail -s "Alert" your_email@example.com fi这个脚本检查 Harness 服务是否在运行,如果不在就发一封邮件。可以加到 crontab 里,每隔 5 分钟执行一次。资源监控可以用free和df命令获取内存和磁盘使用率,超过阈值就告警。#!/bin/bash MEM_USAGE=$(free | awk '/Mem/ {printf "%.0f", $3/$2 * 100}') if [ "$MEM_USAGE" -gt 90 ]; then echo "Memory usage is ${MEM_USAGE}%" | mail -s "Alert" your_email@example.com fi这些脚本虽然简单,但在关键时刻能帮你及时发现问题,避免服务长时间不可用。5.4 会话数据清理与隐私保护Harness 会保存会话历史,方便用户查看之前的对话记录。但这些数据如果一直不清理,一方面会占用磁盘空间,另一方面也可能涉及隐私问题。建议配置一个定期清理的策略,比如只保留最近 30 天的会话记录。如果会话数据存在数据库里,写一条 SQL 定期删除旧记录就行。如果存在文件里,用find命令找到超过 30 天的文件并删除。find /home/deploy/harness/data/sessions -type f -mtime +30 -delete这条命令会删除 sessions 目录下修改时间超过 30 天的文件。加到 crontab 里,每天凌晨执行一次。注意:在执行删除操作之前,先确认一下目录路径是否正确,最好先用-print参数看一下会删除哪些文件,确认无误后再换成-delete。5.5 后续扩展方向这套部署方案目前满足的是个人或者小团队的使用需求。如果后续想扩展,有几个方向可以考虑。一是接入更多的模型。Harness 通常支持配置多个模型后端,你可以在配置文件里添加多个模型地址,用户在使用的时候可以切换。这样就能同时用不同参数量、不同特长的模型,灵活性更高。二是增加用户体系。Basic Auth 是所有用户共用一套凭证,没法区分不同用户的权限和使用记录。如果需要更细粒度的管理,可以接入 OAuth 或者自建用户系统,每个用户有自己的账号和会话隔离。三是优化推理性能。如果并发量上来了,单实例的推理服务可能扛不住。可以考虑用多个推理实例做负载均衡,或者换用性能更好的硬件。也可以引入缓存机制,对于重复的问题直接返回缓存结果,减少推理压力。四是完善监控体系。目前只是简单的脚本告警,如果服务规模扩大,可以引入更专业的监控工具,把 CPU、内存、磁盘、网络、请求量、响应时间这些指标都采集起来,做成可视化面板,方便随时掌握服务状态。这些扩展方向不需要一次性全做,根据实际需求逐步迭代就行。先把基础服务跑稳,再考虑锦上添花的事情。