资讯动态

将Deepseek Harness安全发布公网:反向代理、HTTPS与鉴权实战

发布时间:2026/10/20 8:38:34 来源:尧图企业网站定制
咱们先聊个场景本地把服务调通了接口文档也写好了想着发布到公网给团队用或者自己随时访问结果一堆问题就冒出来了——端口怎么开、域名怎么配、别人拿到地址就能访问怎么办、API Key 应该放在哪里、内网环境里跑通的一套东西到了公网是不是等于裸奔。Deepseek Harness 这类服务本身功能很明确但“把它部署到云服务器上”和“能公网访问且带鉴权”完全是两个难度等级。这篇文章我不打算只扔一份 docker-compose.yml 让你照抄而是把从零到一的全流程、每步选择背后的理由和踩过的坑都讲清楚服务器规划、服务启动、反向代理、HTTPS、鉴权方案、验证方法再到日常维护。如果你手里正好有一套 Harness 或类似的服务想发布到公网这篇文章应该能帮你省掉至少半天试错时间。1. 部署前先想清楚公网访问的真正风险点在哪1.1 “本地能跑”和“公网能用”之间差了什么本地调试的时候服务监听在127.0.0.1:8080curl 一下很顺畅前端联调也没问题。但一旦放到公网整个环境就变了。第一是暴露面。互联网上的扫描器几乎无时无刻不在扫 80/443/8080/22 这些端口。你的服务只要绑在0.0.0.0:8080上同时安全组又放行了 8080那等于直接告诉全世界“这里有个服务可能没做鉴权快来试试”。我不止一次见到有人部署服务时图省事把端口全开结果一天之内日志里就出现各种路径探测请求。第二是协议层。本地跑用 HTTP 就够了但公网必须上 HTTPS。原因很简单如果还是 HTTP那么客户端和服务端之间的 API Key、Token、密码全都是明文传输。这相当于你把家门钥匙贴在快递包装上寄出去任何经过路由节点的人都能复制一把。所以TLS 终结是公网部署的硬性要求不是可选项。第三是鉴权。本地访问时你知道访问者只有你自己跳过登录也问题不大。公网上任何人都可能访问到你的服务。如果没有鉴权层服务里配置的模型 API Key、对话记录、评测数据就全部暴露了。做 AI 类服务的朋友尤其要注意模型接口调用是花钱的被刷几次账单就不好看了。所以一个合理的公网部署模型应该是内部服务只监听本机网关负责 HTTPS 和鉴权这才是正路。1.2 服务器、域名与网络端口的一次性规划动手之前先做规划不要边装边想。我建议在部署前花 10 分钟确定下面三件事服务器规格、域名、端口策略。服务器规格方面如果你只是部署一个给个人或小团队使用的 Harness 服务2 核 4G 内存、40G 存储的云主机基本够用。系统我一般选 Debian 系 Linux例如 Debian 12 或相同内核的衍生产品省心、稳定软件源里的包也比较新。非要选其他系统也可以但不同包管理器的命令差异经常会成为意外麻烦。域名方面你需要一个能够解析的子域名例如harness.example.com。不要直接拿裸域或 IP 来做后面申请 TLS 证书、做反向代理跳转都不方便。没有域名的话短期内可以用改 hosts 的方式来自测但不适合生产长期使用。端口策略是这里最值得花心思的部分。我整理了一个常见的规划表按这个思路来做基本不会错端口用途对外开放备注22SSH 管理建议只对办公 IP 或跳板机开放必须使用密钥登录80HTTP 跳转入口是仅用于跳转到 HTTPS443HTTPS 对外入口是唯一真正对外开放的应用端口8080Harness 应用服务否只绑定 127.0.0.1不会暴露到公网8081鉴权旁路服务可选否只绑定 127.0.0.1供反向代理内部调用这里要特别强调一个三层防线的问题某个端口能不能从公网访问到取决于“云安全组放行规则 服务器本地防火墙 进程实际监听地址”三件事。你只改安全组是不够的进程如果绑了0.0.0.0:8080安全组不开 8080 的确也进不来但这属于“运气好”不是“配置好”。反过来进程绑了127.0.0.1:8080但安全组开了 8080虽然访问不到应用但暴露面白白扩大了一圈。两侧都要收紧才谈得上安全。1.3 鉴权方案横评Basic Auth、Token、OAuth2 Proxy 谁适合你鉴权选型往往决定了整个网关的复杂度。我的经验是先看使用场景再选方案不要一上来就上全家桶。方案配置复杂度适用人数优点缺点Basic Auth HTTPS低1-5 人配置最简单Nginx/Caddy 原生支持不好按人独立撤销浏览器弹窗交互不够友好Bearer Token 旁路校验中5-20 人可以独立发放和撤销 Token适合被脚本和 API 调用需要维护一个小的鉴权校验服务OAuth2 Proxy / 企业 SSO高20 人以上或企业环境与已有账号体系打通有审计功能部署重、配置复杂、还需要维护用户目录如果只是自己用或者给两三个同事分享页面Basic Auth 加一个随机生成的高强度密码就够了。密码不要用生日、姓名这类可猜测内容推荐直接用openssl rand -base64 24生成一段乱码然后存到密码管理器里。如果 Harness 主要面向程序调用、接口集成那么 Token 是更顺手的方案。因为 curl 里只要一个Authorization: Bearer xxx头就能完成认证而 Basic Auth 需要拼用户名和密码管理起来也麻烦。更关键的是Token 可以针对不同使用者分别发放哪个人不再需要了单独撤销一个 Token 就行不需要改公共密码。如果所在组织有现成的账号体系比如 LDAP 或企业微信那直接上 OAuth2 Proxy 或同类方案把认证交给统一身份源网关只负责信任它就行。不过自己搭个人项目没必要上这种重量级方案。下面我会按照“先用 Basic Auth 快速上线、后续再平滑升级到 Token”的路线把两种方案的配置都完整过一遍。2. 服务器端基础环境与 Harness 服务启动2.1 初始化 Linux 环境的第一批命令新服务器刚拿到手先不要急着装应用把基础环境收拾干净。登录服务器后第一件事是更新系统软件源并安装基础工具sudo apt update sudo apt upgrade -y sudo apt install -y curl ca-certificates git ufw接下来安装 Docker。官方脚本安装通常是最省事的方案它会帮你装好 Docker 引擎和 compose 插件curl -fsSL https://get.docker.com | sudo sh sudo systemctl enable --now docker安装完成后确认一下sudo docker version sudo docker compose version如果docker compose version有输出说明 compose 插件已经就绪。这里我不太推荐再单独安装一个docker-compose命令行工具官方 compose 子命令已经足够还会少一层版本兼容问题。SSH 安全方面务必在部署前完成两件事把本机公钥写入服务器的authorized_keys然后把 sshd 配置里的PasswordAuthentication设为no。密钥登录能用的前提下密码登录关掉会让暴力破解直接失去目标。修改配置后记得sudo systemctl restart ssh验证一下新连接没问题再断开当前会话。我曾经在改配置后没验证就退出结果把自己锁在门外只能去控制台重置密码印象很深。2.2 用容器编排文件把 Harness 跑起来我习惯把所有服务都容器化包括接下来的鉴权旁路服务。这样方便统一管理日志、重启和升级不会把服务器系统目录搞得乱七八糟。先创建项目目录sudo mkdir -p /opt/harness cd /opt/harness然后写一个docker-compose.yml。下面是一个两份服务共存的编排文件这里先把 Harness 服务放进去services: harness: image: your-registry/harness:latest container_name: harness restart: unless-stopped ports: - 127.0.0.1:8080:8080 env_file: - .env volumes: - ./data:/app/data healthcheck: test: [CMD, curl, -f, http://127.0.0.1:8080/healthz] interval: 30s timeout: 3s retries: 3这里有几个细节非常关键。第一ports写的是127.0.0.1:8080:8080而不是8080:8080。这一行才是 Harness 服务对外的第一道防线。前面那段127.0.0.1表示 Docker 只把端口映射到宿主机的回环地址上只有宿主机上的进程比如 Nginx 或 Caddy能访问到它公网路由根本够不着。后面会看到的鉴权旁路服务也是一样的思路。第二env_file指向.env文件不要在 compose 文件里直接写 API Key。compose 文件可能要提交到代码仓库里一旦泄露里面的密钥就全完了。密钥放.env文件本身做好权限限制才是正确做法。第三./data绑定挂载到容器里的数据目录。这样容器升级重建后对话记录、用户配置、评测结果都还能保留不会因为docker compose up -d --force-recreate就丢得干干净净。镜像地址your-registry/harness:latest不是真实存在的你需要换成实际使用的镜像仓库地址。如果这个服务没有现成镜像需要自己构建镜像那么构建完成后把镜像名填到这里流程是一样的。.env文件内容示例DEEPSEEK_API_KEYsk-xxxxxxxxxxxx APP_PORT8080启动服务sudo docker compose up -d sudo docker compose logs -f harness看到容器状态是 running日志里没有应用启动异常就可以进入下一环节了。2.3 密钥注入与配置文件的几个易错点配置密钥这个环节看着简单坑其实不少。我逐个说清楚。.env文件创建后记得收紧权限chmod 600 .env同时确认项目目录里的.gitignore包含了.env。如果你用 Git 管理配置哪怕只是给自己看也建议从一开始就把密钥排除在外避免哪一天把仓库推到远端时顺手把密钥一起推上去。环境变量改了之后要特别注意生效方式。docker restart harness不会重新加载环境变量必须这样操作sudo docker compose up -d --force-recreate harness只有容器被重建env_file里新的变量才会真正读到。变量名的坑也要留意。不同的 Harness 版本或分支环境变量命名可能不一样有的是DEEPSEEK_API_KEY有的是LLM_API_KEY有的还要配BASE_URL来指定模型接口的地址。写错一个字母容器照样能起来但实际发起请求时会一直报认证失败或者连接失败。配置完成后建议先触发一次真实请求不要只看“进程活着”就以为万事大吉。还有一点是关于时间同步的。如果 Harness 或鉴权服务里用到带过期时间的 Token或者要对照日志排查问题服务器时间不准是很头疼的。云厂商一般默认开了 NTP但我在部分自定义镜像上遇到过时间偏移。可以用timedatectl status快速确认没开 NTP 就打开花不了两分钟。3. 公网网关用反向代理做 HTTPS 与鉴权入口Harness 服务已经在跑但此刻它还只能从服务器本机访问。接下来这一步是全文重点怎么用一个合适的网关把 HTTPS 和鉴权做在前面。3.1 DNS 解析、安全组和防火墙怎么配才算对先把域名解析搞定。在 DNS 管理后台给harness.example.com添加一条 A 记录指向服务器公网 IP。等解析生效的这段时间不要急着申请证书否则会一直报验证失败。可以用下面的命令确认dig short harness.example.com nslookup harness.example.com输出的 IP 和服务器公网 IP 一致说明解析已经到位。然后配置云厂商的安全组。思路是只放行 22建议限定来源 IP、80、443。不要放行 8080、8081。不同云厂商控制台上叫法不一样有的是“安全组规则”有的是“防火墙规则”逻辑是一样的。服务器内部再用 ufw 兜一层sudo ufw allow 22/tcp sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw enable sudo ufw status verbose这里有一个很容易忽略的问题如果你对 22 端口本身只允许某些来源 IP 访问那么你的固定办公公网 IP 或者跳板机 IP 要提前确认好别把自己也挡在外面。ufw 的规则顺序是从上往下匹配默认 deny incoming所以规则放行的顺序和来源限定一定要检查清楚。3.2 选 Nginx 还是 Caddy一条判断标准在反向代理这一层我经常被问到“用 Nginx 还是 Caddy”。我的判断标准很简单你对现有运维体系熟不熟。Caddy 的最大优势是自动 HTTPS。配置好域名后它会自动申请证书、自动续期基本不需要人干预。对于个人项目或小团队能省很多操心。Caddyfile 的配置语法也比 Nginx 简洁几百行配置往往几十行就够。Nginx 的优势是灵活、文档丰富、团队里的同学大概率已经接触过。如果你需要做的转发规则比较复杂或者要同时代理多个服务、做精细化的路由控制Nginx 更顺手。代价是证书申请和续期要自己处理一般配合 certbot 来做也不算麻烦。我个人的习惯是快速验证方案用 Caddy一旦形态确定、要长期维护迁到 Nginx 或者其他统一网关。这篇文章两种工具都会给出配置你可以按自己的偏好选。3.3 带 Basic Auth 的完整反向代理配置Caddy 快速方案如果你选了 Caddy安装非常简单下载官方二进制或者用包管理器都行。然后写一个Caddyfileharness.example.com { basicauth { alice $2a$14$IW0J62.... } reverse_proxy 127.0.0.1:8080 }这里的密码 hash 不是自己编的需要生成。Caddy 提供了现成命令caddy hash-password --plaintext 你要设置的密码把输出结果填到 Caddyfile 里。注意 Caddyfile 中用户名和 hash 之间的空格格式错了会导致启动时解析失败。文件建好后权限也设置成 600chmod 600 Caddyfile启动 Caddy 后它会自动为harness.example.com申请并续期证书HTTPS 全部自动搞定。访问https://harness.example.com时浏览器会弹出用户名密码窗口输入正确后就放行到后端的 Harness 服务。Nginx 完整方案如果选 Nginx先安装sudo apt install -y nginx apache2-utilsapache2-utils是为了生成密码文件。生成密码文件sudo htpasswd -c /etc/nginx/.htpasswd alice输入两次密码后文件里会出现alice:$apr1$...这样的记录。不需要-c参数的时候比如再加第二个用户sudo htpasswd /etc/nginx/.htpasswd bob然后是证书。推荐用 certbot 自动申请sudo apt install -y certbot python3-certbot-nginx sudo certbot --nginx -d harness.example.comcertbot 会在申请成功后自动把证书路径写进 Nginx 配置里的ssl_certificate和ssl_certificate_key两行省得手填。接下来是核心配置。上 HTTPS 和 Basic Authserver { listen 80; server_name harness.example.com; return 301 https://$host$request_uri; } server { listen 443 ssl; http2 on; server_name harness.example.com; ssl_certificate /etc/letsencrypt/live/harness.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/harness.example.com/privkey.pem; auth_basic Access restricted; auth_basic_user_file /etc/nginx/.htpasswd; 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_buffering off; proxy_read_timeout 3600s; proxy_http_version 1.1; proxy_set_header Connection ; } }这里有几点要重点说。proxy_buffering off不是可有可无的配置。现在大模型应用几乎都是流式返回也就是服务端把响应内容一段一段推给客户端。Nginx 默认会先把上游响应缓冲完再发给浏览器导致你看到的界面一直转圈直到全部内容生成完才一次性出现。关掉缓冲后内容会像打字机一样实时出现体感完全不一样。如果你的 Harness 界面预期就是流式的这一行一定不能省。proxy_read_timeout 3600s也要特别注意。生成一段长文本可能耗时几十秒甚至几分钟Nginx 默认的 60 秒超时会导致接口在生成中途就断开。调大这个值之后长任务才能稳定跑完。HTTP 1.1 和Connection 的设置是为了避免与上游的 keep-alive 行为不一致引发问题。Nginx 在和上游通信时默认会用 HTTP/1.0而很多现代框架对 HTTP/1.0 的支持不完整显式声明为 1.1 是最省心的做法。把配置写好后测试并重载sudo nginx -t sudo systemctl reload nginx这时候从浏览器访问https://harness.example.com应该会弹出 Basic Auth 对话框输入正确后就能看到 Harness 界面。3.4 升级为 Token 鉴权小型校验服务方案Basic Auth 适合人用浏览器打开页面但如果 Harness 的更多使用场景是程序调用我建议升级到 Token 鉴权。升级的好处是每个使用者拿独立的 Token撤销某人只要删掉一条记录不需要所有人改密码。思路是这样的增加一个只监听127.0.0.1:8081的小型鉴权服务Nginx 收到请求后先通过auth_request把这个请求交给它校验校验通过才转发给 Harness。这个小服务本身不负责业务逻辑只判断“Authorization 头里的 Token 对我维护的列表里存不存在”。先写一个极简校验服务用 Python 标准库实现不需要装任何第三方依赖# auth-server.py import os import json from http.server import BaseHTTPRequestHandler, HTTPServer VALID_TOKENS set( os.getenv(VALID_TOKENS, ).split(,) ) class Handler(BaseHTTPRequestHandler): def do_GET(self): auth self.headers.get(Authorization, ) if auth.startswith(Bearer ) and auth[7:] in VALID_TOKENS: self.send_response(204) else: self.send_response(401) self.end_headers() def log_message(self, *args): pass if __name__ __main__: HTTPServer((127.0.0.1, 8081), Handler).serve_forever()注意这个代码是示例实际使用时你可以把 VALID_TOKENS 换成数据库或文件读取但思路一致它是整个鉴权链路上的“裁判”只返回 204 或 401不返回业务内容。把它也加进 compose 文件中services: harness: image: your-registry/harness:latest container_name: harness restart: unless-stopped ports: - 127.0.0.1:8080:8080 env_file: - .env volumes: - ./data:/app/data auth-server: image: python:3.11-alpine container_name: auth-server restart: unless-stopped command: python /app/auth-server.py environment: VALID_TOKENS: token-a,token-b,token-c ports: - 127.0.0.1:8081:8081 volumes: - ./auth-server.py:/app/auth-server.py:ro然后在 Nginx 配置里启用auth_requestserver { listen 443 ssl; server_name harness.example.com; ssl_certificate /etc/letsencrypt/live/harness.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/harness.example.com/privkey.pem; location /auth { internal; proxy_pass http://127.0.0.1:8081; proxy_pass_request_body off; proxy_set_header Content-Length ; proxy_set_header X-Original-URI $request_uri; } location / { auth_request /auth; auth_request_set $auth_status $upstream_status; 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_buffering off; proxy_read_timeout 3600s; proxy_http_version 1.1; proxy_set_header Connection ; } }这里的原理是Nginx 收到请求后会先向http://127.0.0.1:8081发一个子请求这个子请求带着原始请求的Authorization头。鉴权服务返回 204 就继续转发返回 401 就直接拒绝。Harness 应用本身完全不感知鉴权逻辑这就是一种很干净的“边界代理”做法。如果你用的是 Caddy也有对应的forward_auth指令但需要确认 Caddy 版本支持情况且语法细节因版本而异。为了避免版本差异带来的困惑我建议在需要 Token 鉴权时直接用 Nginx 方案稳定性更有把握Caddy 更适合一路 Basic Auth 到底的简单场景。4. 全链路验证从浏览器到 Harness 容器的请求流向配置全部就位接下来要验证。不要打开浏览器看一眼页面没挂就收工应该分层确认每一环都符合预期。4.1 用 curl 分步验证网关、鉴权、上游服务先在服务器本机验证 Harness 服务本身是健康的curl -i http://127.0.0.1:8080/healthz正常应该返回 200。这一步能确认上游服务还活着避免后面出问题时分不清是应用挂了还是网关挂了。然后从你的本地电脑上用公网域名测试分三种情况# 不带任何凭据预期 401 curl -i https://harness.example.com/ # 带 Basic Auth预期 200Caddy 方案 curl -u alice:你的密码 -i https://harness.example.com/ # 带 Bearer Token预期 200Token 方案 curl -H Authorization: Bearer token-a -i https://harness.example.com/浏览器方面建议用隐身窗口访问一次带 Basic Auth 的地址。出现用户名密码弹窗说明鉴权已生效。输入正确凭据后能看到 Harness 的页面。如果有 API 文档页面也可以顺手试一个真实接口观察是否正常返回。完整请求流是这样走的浏览器或客户端先做 DNS 解析拿到服务器 IP然后连接 443 端口通过安全组进入服务器到达 Nginx 后Nginx 先完成 TLS 握手再做鉴权校验校验通过请求经proxy_pass转发到127.0.0.1:8080进入 Harness 容器Harness 再按需调用模型接口。整个链路里用户能感知的只有域名和鉴权入口其余环节都在服务器内部的回环网络里完成。4.2 排查 401、502、超时的常见根因部署过程中总会出现各种状态码问题我整理了最常见的几种现象和对应的排查思路现象可能原因处理方式一直弹 401 登录框密码错误、密码文件路径不对、hash 格式不支持重新生成 htpasswd 或 Caddy hash确认路径与配置一致输入正确密码仍然 401鉴权配置只作用在某个子路径而你访问了其它路径把auth_basic放到 server 层或对应 location 上502 Bad Gateway上游 8080 没监听、容器没起来、proxy_pass 之后地址写错在服务器上执行curl 127.0.0.1:8080看有没有响应docker compose ps看容器状态504 或长时间无响应流式场景下缓冲没有关闭或 read timeout 太小确认proxy_buffering off和proxy_read_timeout已设置curl 能用但浏览器弹窗不出现浏览器缓存或隐私模式差异换隐身窗口重试确认访问的是 HTTPS 地址证书警告域名解析未生效时申请了证书、证书过期、用 IP 访问先确认 DNS再重新申请或续期证书排查的时候有个好习惯先在服务器本机直接 curl127.0.0.1:8080。能通说明应用没问题不能通再看容器日志。从内到外逐层排除效率比乱猜高得多。4.3 安全加固清单我能做完的最小集合服务上线后强烈建议做一轮安全加固。下面这几条都是代价很小、收益明确的项。SSH 方面关闭密码登录、使用密钥登录。如果你经常从不同网络环境登录可以考虑只允许跳板机 IP 访问 22 端口再通过跳板机进入服务器避免自己的公网 IP 变化导致被挡在外面。防火墙方面保持安全组和 ufw 都只放行 22/80/443。每隔一段时间回看一遍安全组规则确认没有因为临时调试留下的多余规则。文件权限方面.env、Caddyfile、.htpasswd都设置成 600。项目目录如果不是多人协作建议把目录权限收紧到 700避免其他系统用户读到配置。容器运行方面看一下 Harness 镜像是否支持非 root 运行支持的就在 compose 里加user: 1000:1000或指定普通用户。以 root 运行容器会增加容器逃逸后的风险等级能避免就避免。这些做完之后如果你有时间可以再考虑给整个链路上加一层监控比如定时探测https://harness.example.com/healthz关注它是否能正常返回 2xx包括鉴权失败的概率变化。这属于锦上添花但长期来看很有价值。5. 运行期的维护与踩坑记录服务上线不是终点后面还有日常维护。这里分享我的一些习惯和实际踩过的坑。5.1 日志、证书续期和容器重启日志是排查问题的第一手信息。Nginx 的访问日志和错误日志默认在/var/log/nginx/Docker 容器的日志用docker compose logs -f harness查看。遇到问题先看日志定位是哪个环节出错再动手改配置。证书续期方面Caddy 会自动搞定不用管。Nginx 加 certbot 的话certbot会创建定时任务自动续期。可以手动检查一下sudo systemctl list-timers | grep certbot确认定时器存在即可。如果发现证书接近过期但没有自动续期多半是 DNS 解析或端口访问有问题需要排查证书验证路径是否通。容器重启和升级时先备份数据再操作cd /opt/harness tar --zstd -cf>

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑