对话笔记直发:5.8 JP NAS 本地部署 Kimi GLM 统一网关。分类:网络基建。
JP NAS 本地部署 Kimi GLM 统一网关
时间
- 日期:2026-05-08
- 场景:在本地
jpNAS 上部署多个 free-api 项目,先逐个验证,再收敛为一个统一 API 入口。
用户目标
- 在本地
jpNAS 上部署多个国模免费 API 代理项目。 - 最终希望通过一个统一 API 地址调用这些模型能力。
- 本轮优先级:
- 内网使用
- 快速跑起来
- 先接入
DeepSeek + GLM + Spark + Kimi - 先单个跑通,后续再统一
- 后续实际执行中,最终稳定方案聚焦在
Kimi + GLM,并已落地统一网关。
背景与上下文
- 工作目录:
D:\Program\0\home\vps\jp - 服务器:
jp - SSH:
ssh root@局域网IP(已脱敏)“ - 架构:
aarch64 - 操作系统:
Linux 6.1.62-current-rockchip64 - 这是一个多服务 Docker 主机,已有容器包括:
n8n、homeassistant、openlist、vaultwarden、grok2api、cli-proxy-api等。 - 用户给了一篇整理好的文章路径:
C:\Users\fengx\onedrive\Apps\remotely-save\feng\000_Raw\30_剪藏\2026-05-07\国模免费渠道大全(授人以渔).md - 先阅读了文章内容,确认涉及的部署方式主要是 Cloudflare Worker 和 Docker 2API 项目。
- 由于
jp是 ARM64,部署前重点关注镜像是否能在aarch64上拉起。
过程摘要
- 初始阶段先做规划,没有直接套用文章里的
8000端口方案,而是决定采用独立端口逐个验证。 - 用户明确选择:内网使用、快速跑起来、优先接入
DeepSeek + GLM + Spark + Kimi、先单个跑通,后续再考虑统一。 - 在远端服务器上确认:Docker 与 Docker Compose 已安装,端口
18001-18004空闲,可作为 4 个服务的宿主映射端口。 - 新建了工作区服务记录目录:
D:\Program\0\home\vps\jp\llm-free-api - 编写了服务记录文档:
D:\Program\0\home\vps\jp\llm-free-api\AGENTS.mdD:\Program\0\home\vps\jp\llm-free-api\DEPLOYMENT.md
- 在远端创建目录:
/opt/llm-free-api - 依次拉起 4 个服务容器:
deepseek-free-api->18001:8000kimi-free-api->18002:8000glm-free-api->18003:8000spark-free-api->18004:8000
- 所有容器都成功在
aarch64上启动,并且/ping健康检查返回pong,说明镜像层面与 ARM64 兼容。 - 随后用户准备手动登录各站点获取 token,并在本地保存到:
C:\Users\fengx\Desktop\token.md - 读取
token.md后确认:- 已有
DeepSeek userToken - 已有
Kimi refresh_token - 已有一版
GLM chatglm_refresh_token Spark决定不接入
- 已有
- 开始真实联调:
Kimi成功返回正常响应GLM第一次失败,日志显示refresh_token已过期DeepSeek失败,返回Invalid character in header content ["X-App-Version"]
- 对
DeepSeek做了进一步尝试:- 重建容器并注入环境变量
DEEP_SEEK_CHAT_AUTHORIZATION - 发现当前镜像即使已注入环境变量,接口层仍强制校验客户端
headers.authorization - 同时仍存在上游
X-App-Version相关错误,因此当前版本不适合纳入可用方案
- 重建容器并注入环境变量
- 用户随后补充了新的
GLM chatglm_refresh_token - 使用新 token 重新测试
GLM,成功返回正常响应,确认GLM成为第二个可用服务。 - 由此确定当前稳定组合为:
Kimi + GLM - 在此基础上,继续落地一个统一的本地 OpenAI 兼容网关,而不是引入现成重量级平台。
- 新建工作区目录:
D:\Program\0\home\vps\jp\llm-gateway - 自定义编写了一个轻量 Node.js 网关,不是第三方开源现成项目。
- 网关职责:
- 提供
GET /health - 提供
GET /v1/models - 提供
POST /v1/chat/completions - 根据
model路由到Kimi或GLM - 服务端自动注入上游 token,客户端无需再传真实 provider token
- 提供
- 网关文件:
D:\Program\0\home\vps\jp\llm-gateway\app.jsD:\Program\0\home\vps\jp\llm-gateway\DockerfileD:\Program\0\home\vps\jp\llm-gateway\AGENTS.mdD:\Program\0\home\vps\jp\llm-gateway\DEPLOYMENT.mdD:\Program\0\home\vps\jp\llm-gateway\USAGE.md
- 初始构建时使用
node:22-alpine失败,错误为拉取元数据时描述符异常;随后切换为node:20-alpine成功构建。 - 将网关部署到远端目录:
/opt/llm-gateway/app - 构建并启动容器:
llm-gateway - 统一网关宿主端口:
19000 - 使用现有
Kimi + GLMtoken 作为网关环境变量注入 - 验证统一入口成功:
GET http://局域网IP(已脱敏):19000/healthGET http://局域网IP(已脱敏):19000/v1/modelsPOST http://局域网IP(已脱敏):19000/v1/chat/completions,model=kimiPOST http://局域网IP(已脱敏):19000/v1/chat/completions,model=glm-4-plus
- 用户随后询问为什么模型列表里只有一个
Kimi模型。 - 解释结论:当前统一网关中,
Kimi被有意只暴露为一个基础模型名kimi;这不是 Kimi 只能有一个,而是当前网关模型映射策略的结果。GLM则显式暴露了多个模型名:glm-4-plus、glm-4-zero、glm-4-think。 - 用户询问刚才使用的网关是什么。
- 说明结论:当前网关不是开源现成项目,而是根据当前场景自定义编写的最小 Node 网关。
关键结论
jp服务器上的 4 个 free-api 镜像都能在aarch64上启动。- 当前稳定可用的 provider 组合是:
KimiGLM
DeepSeek当前镜像版本存在实现问题:- 注入环境变量后仍要求客户端传
Authorization - 上游还会报
Invalid character in header content ["X-App-Version"] - 不适合作为当前可用 provider
- 注入环境变量后仍要求客户端传
Spark本轮未接入,保持未使用状态。- 统一入口已可用,地址为:
http://局域网IP(已脱敏):19000/v1/chat/completionshttp://局域网IP(已脱敏):19000/v1/modelshttp://局域网IP(已脱敏):19000/health
- 统一入口当前支持模型:
kimiglm-4-plusglm-4-zeroglm-4-think
- 客户端调用统一网关时,不再需要手动带
Kimi或GLM的真实 token。 Kimi在模型列表里只有一个,是因为当前网关只注册了一个基础模型名kimi,这是网关设计选择,不是平台限制。
执行动作
- 阅读文章并分析部署方式。
- 核查远端
jpDocker 环境、端口占用、Compose 能力。 - 新建
llm-free-api工作区文档与远端目录。 - 拉起
deepseek-free-api、kimi-free-api、glm-free-api、spark-free-api容器。 - 验证 4 个容器健康状态。
- 读取本地
token.md,识别可用 token。 - 联调
Kimi、GLM、DeepSeek:Kimi成功GLM第一次 token 过期,第二次新 token 成功DeepSeek失败并确认镜像实现问题
- 为
DeepSeek尝试服务端环境变量固化,验证未能解决核心问题。 - 确立稳定组合为
Kimi + GLM。 - 自定义编写轻量统一网关
llm-gateway。 - 部署统一网关到
19000,服务端注入Kimi + GLMtoken。 - 验证统一入口的健康检查、模型列表与两条真实路由。
- 更新了
llm-free-api与llm-gateway的部署/使用文档。
执行命令记录
-
ssh root@局域网IP(已脱敏)"hostname && uname -m && docker --version && (docker compose version || docker-compose --version) && docker ps --format '{{.Names}}\t{{.Image}}\t{{.Ports}}' && ss -ltnp | grep -E ':1800[1-4]\b' || true && test -d /opt && ls -ld /opt && test -d /opt/llm-free-api || true"- 目的:确认远端主机、架构、Docker 能力、容器情况与端口空闲情况。
- 结果:确认
jp-tvbox-3566为aarch64,Docker/Compose 可用,18001-18004端口空闲。
-
ssh root@局域网IP(已脱敏)"docker rm -f deepseek-free-api >/dev/null 2>&1 || true && docker run -d --init --name deepseek-free-api --restart unless-stopped -p 18001:8000 -e TZ=Asia/Shanghai vinlic/deepseek-free-api:latest ..."- 目的:启动 DeepSeek 代理容器。
- 结果:容器成功拉起,说明镜像可在 ARM64 运行。
-
ssh root@局域网IP(已脱敏)"docker rm -f kimi-free-api >/dev/null 2>&1 || true && docker run -d --init --name kimi-free-api --restart unless-stopped -p 18002:8000 -e TZ=Asia/Shanghai vinlic/kimi-free-api:latest ..."- 目的:启动 Kimi 代理容器。
- 结果:容器成功拉起。
-
ssh root@局域网IP(已脱敏)"docker rm -f glm-free-api >/dev/null 2>&1 || true && docker run -d --init --name glm-free-api --restart unless-stopped -p 18003:8000 -e TZ=Asia/Shanghai vinlic/glm-free-api:latest ..."- 目的:启动 GLM 代理容器。
- 结果:容器成功拉起。
-
ssh root@局域网IP(已脱敏)"docker rm -f spark-free-api >/dev/null 2>&1 || true && docker run -d --init --name spark-free-api --restart unless-stopped -p 18004:8000 -e TZ=Asia/Shanghai vinlic/spark-free-api:latest ..."- 目的:启动 Spark 代理容器。
- 结果:容器成功拉起。
-
`Invoke-RestMethod -Uri ‘http://1
注:本文涉及的服务器公网 IP / Tailnet / 局域网 IP 已脱敏,请替换为你自己的地址。