☰
云服务器部署 Deepseek Harness:Docker、反向代理与 HTTPS
2026/10/15 23:52:44 网站建设 项目流程

1. 为什么要在云服务器上部署 Deepseek Harness

先把话说在前面,这个项目不是我临时起意折腾的玩具,而是我这边实际给团队内部做的一个中台服务。我们当时的需求很直白:团队里陆续有同事要用 Deepseek 的能力做对话聚合、工具调用、知识库检索这类二次开发,但每个人都在本地各自为政,环境不一致、密钥分散、调用记录也没地方查。后来我找到了一款叫 Deepseek Harness 的开源封装框架,它相当于在 Deepseek 的原始 API 之上加了一层“服务层”,把模型调用、会话管理、工具注册、权限校验、日志审计等逻辑集中收口。部署到云服务器之后,团队内部所有应用都通过统一网关去访问,不再需要各自持有密钥,权限和额度也能集中管控。

再说明白一点,Harness 解决的是“直接用大模型 API 开发时那些琐碎但绕不开的问题”。它帮你把上游模型能力和下游业务隔离,下游不需要关心今天接的是哪个模型版本、有没有限流、Prompt 要怎么写才能稳定,上游也不需要对每个内部应用单独授权。这块做完之后,团队里的 A 同学再开发他的对话机器人时,只需要关心“我该怎么把 Harness 的接口做成我想要的产品”,不用再去处理鉴权、审计、模型切换这些破事。

这次部署我选了云服务器上的 Linux 环境,整个过程包括环境初始化、容器化部署、反向代理、公网 HTTPS 访问、Token 鉴权、防火墙加固。整套下来不复杂,但踩了不少坑,这篇就把从零到公网可用的完整流程捋清楚,包括每个步骤为什么这么做、有哪些替代方案、哪些地方容易翻车。适合有 Linux 基础和 Docker 基础的人直接照着做,纯新手看的话需要先补一点 Docker 和 Nginx 的基本概念,但跟着一步步来也能跑通。

2. 部署前准备:服务器选型、账号规划与基础环境

2.1 云服务器选型与安全组设计

Deepseek Harness 本身不是一个吃资源的大户。它只是一个调度和代理层,真正的算力消耗在 Deepseek 模型服务侧,不在你这台云服务器上。所以服务器的配置不必刻意追求高配,重点在于网络质量和稳定性。我这边的选择是 2 核 4G 内存的常规实例,操作系统用的 Debian 系发行版,带宽选的按流量计费的 5Mbps 峰值。实际跑下来,API 请求的延迟瓶颈几乎都集中在模型侧和客户端网络,这台服务器本身很稳。

选服务器时有几个点需要提前定好。第一是地域,最好选离你主要用户群体近一点的数据中心,不要你人在沿海、服务器选在地球另一边,公网延迟上来之后你会很痛苦。第二是安全组规则,大多数云厂商控制台上的“安全组”会在系统层防火墙之前做一层拦截。我建议只放行 22(SSH)和 80/443(HTTP/HTTPS)三个端口,如果初始配置使用 Docker 映射内部端口,不要图省事把 3000、8080 之类的端口直接对所有公网放行,后面我会讲为什么要尽量避免这种做法。

安全组设计上我习惯用最小权限原则。放行 80/443 是因为要走公网 HTTPS 访问,22 是运维通道。如果你有固定的办公网出口 IP,可以把 22 端口源地址限制到你的公网 IP 范围,能极大降低被扫到之后爆破的风险。没有固定 IP 的话就退而求其次,靠强密码和密钥登录兜底。

2.2 基础用户与 Docker 环境初始化

拿到新服务器之后,不要直接拿 root 干活。创建一个普通用户用于日常操作,所有服务都用这个用户来维护。这个习惯能防止手滑把系统级依赖改坏,同时让审计更容易——谁用了什么命令都有迹可循。我这边创建了一个名为 deploy 的用户,并给这个用户加了 sudo 权限。

apt update && apt upgrade -y apt install -y curl wget git vim ca-certificates useradd -m -s /bin/bash deploy usermod -aG sudo deploy

之后把本机公钥写入 deploy 用户的~/.ssh/authorized_keys,并调整/etc/ssh/sshd_config打开PubkeyAuthentication yes。这一步做完之后建议先别急着关闭密码登录,等确认密钥能正常登录后再去修改PasswordAuthentication no,避免把自己锁在门外。

接下来安装 Docker。不同发行版的包名略有差异,我这里用的是最通用的安装方式:

curl -fsSL https://get.docker.com | sh systemctl enable docker systemctl start docker

装完之后确认docker run hello-world能正常跑通。另外建议把 deploy 用户加入 docker 组,这样不需要每次执行 docker 命令都加 sudo:

usermod -aG docker deploy

环境初始化还有一个容易被忽略的点:时区。服务器默认时区通常是 UTC,而日志时间是排查问题的重要依据,统一设成你所在的时区会更友好:

timedatectl set-timezone Asia/Shanghai

2.3 本项目所需组件准备

Deepseek Harness 部署时主要依赖三块:Docker 容器运行环境、Nginx 反向代理、自动化证书签发工具。Nginx 和证书工具我建议放在宿主机上,不放进 Docker,这样更直观,也方便改配置后直接nginx -s reload生效。

安装 Nginx:

apt install -y nginx systemctl enable nginx systemctl start nginx

证书签发这块,我用的是 Let's Encrypt 免费证书的自动化方案。整套流程不需要人工干预,证书快到期时能自动续签。安装对应的 certbot 客户端工具即可,具体配置在后文“公网访问与鉴权”章节统一展开。

最后检查一下云控制台的安全组是否已放行 80/443,然后用下面的命令确认端口已经被监听:

ss -lntp | grep -E ':(80|443)\s'

一切正常的话,环境准备阶段就收工了,接下来进入 Harness 本身的部署环节。

3. Deepseek Harness 核心设计与部署实操

3.1 Harness 在架构中的角色定位

在开始写 Docker 配置之前,先花一点篇幅说清楚 Harness 到底在你的整体系统里扮演什么角色。简单来说,它位于“调用方应用”和“Deepseek 模型”之间,成为一个可控的中介。调用方不直接请求 Deepseek 的接口,而是请求 Harness 暴露的接口;Harness 再去请求 Deepseek,并把回应返回给调用方。

这种架构至少带来四个实际好处。第一,凭据收敛。只有 Harness 这一处知道 Deepseek 的 API Key,下游应用拿到的只是 Harness 签发的访问令牌,泄不泄露都在可控范围内。第二,统一限流和配额管理。比如某个内部应用一天只能调 500 次,直接在 Harness 配置里写好,不用每个应用自己实现一遍。第三,全量日志。谁在什么时间调了什么模型、输入输出是什么都有记录,这对后续排查和成本核算非常关键。第四,模型切换免改造。后面如果想从某个模型切到另一个,只改 Harness,下游链路不用动。

所以部署 Harness 不是简单地“把容器跑起来”,你还要想清楚自己需要它承担多少职责。比如有的部署场景只用它做反向代理,有的则启用它的工具调用和 Agent 编排能力。第一步建议先跑通最基础的模式,再加高级特性,不要一上来全部功能都开,出问题都不好定位。

3.2 准备模型服务凭据与基础目录

在正式写配置文件之前,需要先准备好 Deepseek 侧的 API Key。这个 Key 负责让 Harness 去上游调用模型,它和后面要做的“公网访问鉴权令牌”是两码事,别搞混。

我把项目的所有数据放在统一目录下,方便管理和备份:

mkdir -p /opt/harness/{config,data,logs} cd /opt/harness

config目录放 Harness 的配置文件和启动编排文件,data目录放运行产生的会话数据、缓存或内嵌数据库文件,logs目录挂载容器日志。目录结构本身没有绝对标准,但保持清晰能让后续维护省很多事。

3.3 用 Docker Compose 编排 Harness 服务

我这边直接用 Docker Compose 来管理,而不是裸docker run。原因是 Compose 文件可以作为“基础设施即代码”留存下来,以后要迁移或重建环境时,只需要复制文件重新 up 一遍即可,不必回忆当初敲过的命令。

下面是一个最小可用版本的docker-compose.yml示例,已脱敏并做了简化,适合绝大多数部署场景:

services: harness: image: your-registry/harness:latest container_name: deepseek-harness restart: always environment: - HARNESS_API_KEY_ENV=${DEEPSEEK_API_KEY} - HARNESS_BIND_ADDR=0.0.0.0 - HARNESS_PORT=8080 - HARNESS_LOG_LEVEL=info ports: - "127.0.0.1:8080:8080" volumes: - ./config:/app/config - ./data:/app/data - ./logs:/app/logs

这里有两处需要专门解释。第一,HARNESS_BIND_ADDR设置为0.0.0.0,因为容器需要接受宿主机转发过来的流量;但宿主机上的端口映射我只绑到了127.0.0.1:8080,这样外部网络无法直接访问 8080 端口,所有请求必须经过 Nginx。这个设计是刻意为之,相当于多了一层安全检查点。第二,API Key 通过环境变量注入,而不是写在 Compose 文件明文里。实际我在服务器上是放在同目录的.env文件中,并把.env加入.gitignore,避免误提交到版本库。

参数配置这块还要补充一个细节:HARNESS_PORT指的是容器内部监听端口,Compose 文件里127.0.0.1:8080:8080左侧是宿主机端口,右侧是容器端口。改参数时不要搞反,我第一次上手就因为这个端口映射概念不清晰排查了半天。

3.4 首次启动与健康检查

配置写好后执行:

docker compose up -d

观察容器是否正常运行:

docker ps | grep harness docker logs -f deepseek-harness

看到日志输出类似“service started, listening on :8080”这样的内容,说明服务已经起来了。此时在服务器本地测试一下接口连通性:

curl http://127.0.0.1:8080/health

返回正常的 JSON 响应体(比如{"status":"ok"})就说明 Harness 进程本身没有问题。这里特别强调一下,很多人习惯在这一步直接拿服务器公网 IP 加端口测试,但因为我们绑定了127.0.0.1,公网是访问不通的。这不是故障,是预期行为,说明端口没有裸奔暴露。

健康检查通过后,下一步才进入“让外网能安全访问”的关键环节。

4. 公网访问方案:反向代理、证书与鉴权

4.1 反代架构设计思路

我不止一次强调内部服务不要直接暴露到公网,不是因为技术洁癖,而是直接暴露的内部服务往往自带调试接口、没有鉴权、日志不规范,任何一个问题都可能导致严重后果。正确做法是给 Harness 包一层反向代理,让所有外部请求先打到 Nginx,再由 Nginx 转发到本机的 8080 端口。

整体请求链路如下:

  • 客户端发起 HTTPS 请求到你的域名(443 端口)
  • Nginx 终止 TLS,校验访问令牌
  • 校验通过后,将请求转发到http://127.0.0.1:8080
  • Harness 处理业务逻辑,携带上游 Key 调用 Deepseek
  • 响应原路返回

这样做有两个直接好处。第一是集中终止 TLS,证书、加密策略全在 Nginx 这一层管,后端服务只处理明文 HTTP,简化了内部服务对 HTTPS 的支持要求。第二是鉴权前置,不合法的请求到不了 Harness 那个环节,从源头挡掉了一部分恶意流量。

4.2 配置域名与自动化证书

我建议直接给 Harness 绑一个二级域名,尽量不要用 IP 访问。原因有三:IP 不好记忆,IP 不好签发证书,IP 访问在后续调高安全性时会有很多限制。

先把域名的 A 记录解析到服务器公网 IP,确保能 ping 通。然后使用自动化证书签发工具申请证书。我对这个工具的配置很简单:

certbot certonly --nginx -d your-domain.example.com

它会自动检测 Nginx 配置、完成域名验证、把证书和私钥放到标准路径。证书有效期一般是一段时间,certbot 会通过系统定时任务自动续期。续期后自动重载 Nginx 不需要手动干预,但如果你的 Nginx 配置里写了证书绝对路径,务必确认续签后路径不变。我用的是/etc/letsencrypt/live/your-domain.example.com/fullchain.pem和privkey.pem,这个路径在续签后保持稳定,不用额外处理。

4.3 Nginx 配置与请求过滤

下面是我的 Nginx 站点配置,已经按通用方式脱敏。你需要替换成自己的域名:

server { listen 80; server_name your-domain.example.com; location /.well-known/acme-challenge/ { root /var/www/html; } location / { return 301 https://$host$request_uri; } } server { listen 443 ssl http2; server_name your-domain.example.com; ssl_certificate /etc/letsencrypt/live/your-domain.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your-domain.example.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; location / { proxy_pass http://127.0.0.1:8080; 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_pass指向的是宿主机 127.0.0.1 的 8080,而不是 Docker 容器名。因为我们用的是端口映射方式,并不是 Compose 自定义网络内的容器直连,所以 Nginx 要从宿主机访问 Harness 只能走本地回环地址。如果你用的是 Compose 定义的服务名做反向代理,需要使用对应的服务名作为 hostname,那是另一套配置思路。

写完后执行:

nginx -t nginx -s reload

Nginx 语法检查通过后,从外部访问https://your-domain.example.com/health,能正常返回就说明反向代理已经连通。

4.4 鉴权方案选型:为什么用访问令牌

反向代理通了之后,紧接着要解决鉴权。这一步最容易出现的误判是“反正有 HTTPS 加密,外面的人看不到内容,那就够了”。这种想法很危险,HTTPS 只解决传输加密的问题,不解决“谁有权限访问”的问题。任何人只要拿到你的域名,照样能往你的服务发请求。

Deepseek Harness 在鉴权方面通常提供两个选项:一是平台级 API Key,二是为多租户签发的访问令牌。我这里用的是访问令牌方式,因为每个人手里的只是 Harness 签发的短期令牌,而不是上游 Key。令牌一旦泄露,可以在不更换上游 Key 的情况下单独吊销,风险面小得多。

实际操作时,我在 Nginx 层对/api/路径统一做鉴权检查。使用 Nginx 的auth_request模块把请求转发到 Harness 的校验接口,或者直接用 Harness 自带的中间件校验Authorization请求头。不同版本的 Harness 配置方式有差异,但核心思路一致:请求带着Authorization: Bearer <token>,Harness 校验通过才执行下游调用。

如果你希望再严一层,可以在 Nginx 配置里加入 IP 白名单:

location /api/ { allow 203.0.113.0/24; deny all; proxy_pass http://127.0.0.1:8080; }

这个适合固定办公网络出口 IP 的团队,但如果成员分布在多个地域,维护白名单的成本可能高于收益,按需取舍。

4.5 防火墙与系统加固

最后一道防线是系统层的防火墙配置。我使用的是 ufw,使用起来比较直接:

apt install -y ufw ufw default deny incoming ufw default allow outgoing ufw allow 22/tcp ufw allow 80/tcp ufw allow 443/tcp ufw enable

特别注意:ufw default deny incoming会把所有入站流量默认挡掉。如果你之前安全组没放行某些端口,现在被 ufw 再挡一道,是双重阻断。这两层之间不要搞混:安全组在云端网络入口做过滤,ufw 在操作系统内核层做过滤,任何一个不同意,连接都进不来。

另外再给 SSH 做一次加固。编辑/etc/ssh/sshd_config:

PermitRootLogin no PasswordAuthentication no AllowUsers deploy

修改后重启 SSH 服务:

systemctl restart sshd

确认能通过密钥正常登录后再退出当前连接。有人改完配置后没有测试就断掉会话,结果永久把自己锁在服务器外,只能通过厂商控制台的“VNC 登录”救援,这个坑我已经见过不止一次了。

5. 部署中常见问题与排查实录

5.1 容器起了但外部访问超时

症状是:服务器本地curl 127.0.0.1:8080/health正常,但从公网访问域名超时或无法连接。

排查路径按顺序走。先确认安全组是否放行 80/443,这个在云厂商控制台看,不要在服务器上干瞪眼。再确认 ufw 状态,ufw status verbose看规则是否生效。接着确认 Nginx 是否在监听 443,ss -lntp | grep 443。最后抓包确认请求是否到达服务器,tcpdump -i eth0 port 443。

大多数情况下,问题出在“安全组已经放行 80/443 了但 ufw 默认策略是 deny”,或者反过来。两层防火墙都要放行,缺一不可。

5.2 请求到了 Nginx 但报 502 错误

502 说明 Nginx 能把请求接住,但转发给后端时失败了。用tail -f /var/log/nginx/error.log看具体错误信息。常见两类:

一是connect() failed (111: Connection refused),说明 Nginx 转发到的 127.0.0.1:8080 上没有服务在监听。确认 Harness 容器是否挂了:docker ps -a。如果容器起来了但没监听,用docker logs deepseek-harness看启动日志,多半是配置文件里的端口或环境变量问题。

二是connect() failed (111: Connection refused while connecting to upstream)中upstream指向错误,检查proxy_pass地址是否和 Compose 的宿主机映射端口一致。如果 Compose 文件把宿主机端口改成了 9090 但 Nginx 还指向 8080,那必然 502。

5.3 证书配置正确但浏览器提示不安全

先用openssl s_client -connect your-domain.example.com:443 -servername your-domain.example.com检查证书链是否完整。如果提示unable to get local issuer certificate,多半是证书路径引错了,fullchain 被配成了手动拼接但漏掉了中间证书。如果是certificate has expired,检查系统时间是否准确,服务器时间漂移会导致证书校验失败。

另外要确认域名 A 记录真的指向这台服务器。很多人申请证书时用的是某个域名,后来配置里 Nginx 的server_name又写成另一个域名,导致 TLS 握手阶段浏览器看到证书域名与访问域名不一致,自然报警。这种问题用curl -v https://your-domain.example.com/能很快看出端倪,响应里server certificate那一行会显示实际证书绑定的域名。

5.4 鉴权一直 401

401 的问题根源通常是“发送的令牌和 Harness 期望的不一致”。先从最基础的地方排查:请求头格式是否为Authorization: Bearer <token>,中间有没有多余空格、大小写是否一致。然后在 Harness 日志中看它解析出来的 token 和你看到的是否一致,有些网关层会改写请求头,导致 Harness 收到的值变了。

另一个常见原因是时间不同步。签发令牌时通常带有iat(签发时间)和exp(过期时间)字段,如果 Harness 所在服务器系统时间比令牌签发方慢了太多,令牌会被判定为过期。解决办法就是统一所有服务器的时间同步:安装chrony或ntp,确保系统时间偏差在秒级以内。

5.5 安全策略检查清单

部署完成后,我建议你逐条核对下面这些项,别嫌麻烦,这些钱花在前期比后期补救便宜得多:

  • 云安全组是否只放行 22、80、443?
  • 服务器防火墙是否deny incoming默认策略?
  • SSH 是否关闭密码登录、禁止 root 登录?
  • Docker 端口映射是否只绑定 127.0.0.1?
  • 上游 API Key 是否只存在于环境变量或密钥管理服务,没有写进代码仓库?
  • 访问令牌是否设置合理有效期?
  • 健康检查接口是否可以通过公网无鉴权访问?如果是,建议在内网使用或同样加保护。
  • 日志是否有轮转策略,避免日志文件无限膨胀占满磁盘?

6. 最后分享一点个人体会

整套流程走下来,我最大的感受是:Deepseek Harness 的部署门槛不高,真正的复杂度全在“怎么让别人安全地访问它”这件事上。很多人包括我自己,早期都容易犯一个毛病——服务能通就够了,剩下的以后再说。但公网服务一旦开通,扫流量、试探接口的行为半小时内就会出现,如果没有鉴权和防火墙兜底,这个服务基本上相当于半裸奔。我后来把所有内部 API 都按这套流程收敛到同一个入口,统一做鉴权和审计,团队内部再也没有人把模型密钥直接写进前端代码,这大概是我维护这套系统最值的一笔“投资”。

另外再分享一个小经验:不要嫌docker compose logs输出太多就不看了。Harness 这类代理型服务,日志里包含每一次请求的模型、令牌前缀、耗时、返回码,是排查线上问题最快的线索来源。我在初期的几次故障定位里,几乎全靠日志里那条unauthorized access attempt的记录找根因。

这篇写到这就差不多了。如果你在部署过程中遇到了跟我不一样的问题,先按“网络通不通、证书对不对、鉴权过不过、日志怎么说”四个方向去查,大概率能定位到症结所在。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询