首页
/ 如何把 Odysseus Cookbook 接入远程服务器下载并服务模型(SSH 密钥配置)

如何把 Odysseus Cookbook 接入远程服务器下载并服务模型(SSH 密钥配置)

2026-09-08 17:07:32作者:韦蓉瑛

Odysseus 的 Cookbook 负责模型的硬件适配推荐、下载与服务。当本机 GPU 显存不够或干脆没有 GPU 时,可以把一台远程 GPU 服务器接入 Cookbook:在 Odysseus 里生成一个专用 SSH 密钥,把公钥装到远程服务器的 authorized_keys,之后模型下载(后台 tmux 会话)和模型服务(llama.cpp / vLLM / SGLang 等)都跑在远程机器上,Odysseus 自动把服务注册为 OpenAI 兼容端点。本文按 docs/setup.md 和 Cookbook 路由/前端代码中的实际实现,走通"添加服务器 → 生成密钥 → 安装公钥 → 验证连接 → 在远程下载并服务模型"这条完整路径。

前提条件

  • Odysseus 已在运行(Docker Compose 或原生安装),并且你使用 admin 账户登录。SSH 密钥相关接口(/api/cookbook/ssh-key/api/cookbook/test-ssh)在 routes/cookbook_routes.py 中均由 require_admin 守卫,非管理员不可操作。
  • 远程服务器为 Linux/POSIX 环境并已安装 tmux:Cookbook 的后台下载和服务依赖 tmux 会话,发起远程下载前会先在远程探测 tmux,缺失时直接报"missing binary"错误而不是静默继续。
  • 如果远程 SSH 不走 22 端口,服务器条目里有独立的端口字段,后续验证命令和 known_hosts 条目都会按 [host]:port 处理,无需手工转换。

第一步:在 Cookbook 的服务器列表中登记远程主机

打开 Cookbook → Settings → Servers,为远程服务器建一个条目:

  • 主机字段填 user@host 格式(例如 root@gpu-node-01);前端会校验必须是普通 SSH 目标加可选的纯数字端口,含非法字符时输入框会提示 Use a plain SSH target like user@host and an optional numeric port.
  • 端口字段留空表示默认 22,非标准端口填数字即可。

注意前端代码明确要求带 @(校验 user@host),只填裸 host 时连接测试面板会直接提示 Enter user@host to test

第二步:生成 Odysseus 专用 SSH 密钥

在服务器条目对应的密钥面板里点击生成(按钮文案为 Generate key),前端调用 POST /api/cookbook/ssh-key。服务端执行的是:

ssh-keygen -t ed25519 -N "" -C odysseus-cookbook -f <key_path>

即生成一把无密码短语的 ed25519 密钥,注释为 odysseus-cookbook,私钥权限 0600、公钥 0644。密钥路径取决于部署方式(见 routes/cookbook_routes.py_cookbook_ssh_dir 的逻辑):

部署方式 密钥目录 私钥/公钥
Docker 容器内 /app/.ssh,由宿主机 ${APP_DATA_DIR:-./data}/ssh 挂载而来 ./data/ssh/id_ed25519 / ./data/ssh/id_ed25519.pub
原生安装(非容器) 当前用户主目录 ~/.ssh ~/.ssh/id_ed25519 / ~/.ssh/id_ed25519.pub

docker-compose.yml 中对该挂载的注释写得很直接:"Cookbook remote-server SSH identity. Odysseus can generate a key here; add the shown public key to each remote server's authorized_keys." 生成成功后面板会给出公钥内容;GET /api/cookbook/ssh-key 返回 {configured, public_key}configuredtrue 表示已有可用公钥。

第三步:把公钥装到远程服务器

docs/setup.md 给出两条路径,UI 里还有一条自动生成的粘贴命令。

方式 A:执行 UI 生成的一行 ssh 命令(推荐,免登录远程) 主机与公钥就绪后,密钥面板的输入框会生成形如下面的命令({host}{port}、公钥值均由 UI 自动填入,直接点复制按钮取完整命令,在 Odysseus 所在机器上执行;{port} 仅在非 22 端口时出现):

ssh -o StrictHostKeyChecking=accept-new {port} {host} 'KEY={public_key} && mkdir -p ~/.ssh && chmod 700 ~/.ssh && touch ~/.ssh/authorized_keys && (grep -qxF "$KEY" ~/.ssh/authorized_keys || printf "%s\n" "$KEY" >> ~/.ssh/authorized_keys) && chmod 600 ~/.ssh/authorized_keys'

该命令在远程侧创建/修正 ~/.ssh(权限 700)与 authorized_keys(权限 600),grep -qxF 保证同一公钥重复执行不会产生重复行。

方式 B:手工追加公钥 把面板里显示的公钥内容复制后,登录远程服务器追加进 ~/.ssh/authorized_keys,即 docs/setup.md 中 "add the public key to the remote server's ~/.ssh/authorized_keys" 描述的默认做法。

方式 C:从宿主机用 ssh-copy-id docs/setup.md 给出的宿主机命令(Docker 布局,密钥在 data/ssh):

ssh-copy-id -i data/ssh/id_ed25519.pub user@server

user@server 替换为你的实际登录用户名与主机名。原生安装时对应的是 ~/.ssh/id_ed25519.pub

第四步:验证 SSH 连通性

回到服务器条目,点击测试按钮(状态点显示 Testing SSH…)。前端调用 POST /api/cookbook/test-ssh,传入 {host, ssh_port},服务端用 5 秒连接超时、8 秒总超时对该目标执行 echo ok,返回 stdout/stderr/exit_code。前端的判定逻辑(见 static/js/cookbook-hwfit.js):

  • 成功:exit_code === 0 且 stdout 以 ok 开头,状态点变绿并显示 Connected · {N} ms
  • 失败:状态点变红,显示 Failed · {stderr 或 exit code 摘要},鼠标悬停可看完整错误(截断到 240 字符)。

超时场景下接口返回 exit_code: 124、stderr 为 SSH test timed out。测试通过后,提示文案会建议你用 Cookbook 的 Dependencies 面板检查该服务器上的 tmux / HuggingFace 环境。

第五步:在远程服务器上下载并服务模型

SSH 验证通过后,在 Cookbook 的下载/服务界面把目标服务器选为你刚登记的这台:

  • 下载:发起下载时,Odysseus 把本次的 runner 脚本 scp 到远程(临时文件 .{session_id}_run.sh,执行完即删),再在远程创建 tmux 会话后台执行,日志经 SSE 推回界面;返回体形如 {"ok": true, "session_id": "...", "remote": "user@host"}remotelocal 时表示本机下载。若模型需要 HuggingFace 访问,下载 runner 会在目标服务器上实际检查 HF token 是否已到达该服务器,避免密钥配了但下载仍 401 的情况。
  • 服务:远程 serve 同样通过 SSH 在远程 tmux 中拉起 llama-server / vLLM / SGLang / Ollama 等进程。命令中若能解析出 --port(llama.cpp 默认 8080,扩散服务默认 8100),Cookbook 会自动注册一个指向该服务器 /v1 的 OpenAI 兼容端点,并探测 /v1/models 自动发现模型 id;在服务器真正就绪前该端点会置灰,服务起来后即可在模型选择器中使用。

已知边界与排查提示

  • 远程缺 tmux:下载/服务请求会直接失败并报缺失 tmux,先在远程安装 tmux 再重试;这也是发起前探测的目的。
  • 主机密钥变更:如果远程服务器的 host key 发生变化,Cookbook 会自动通过 ssh-keyscan 刷新其自己的 known_hosts(条目按 [host]:port 和 host 两种形式维护),无需手工跑 ssh-keygen;刷新失败(超时或取不到密钥)会原样报出错误。
  • 密钥位置与保密data/ssh/(或原生部署的 ~/.ssh/)里的私钥等价于远程服务器的登录凭据,属于 docs/setup.md 安全一节要求保持在 Git 和共享目录之外的 data/ 数据范围。
  • Docker 挂载:Docker 部署下公钥必须写到宿主机 data/ssh 目录对应的挂载卷中才能被容器读到,直接往容器内写而不经过挂载卷的密钥在容器重建后会丢失。
  • 平台差异:远程为 Windows 时下载/服务走 PowerShell runner(Start-Process 后台执行),不要求远程 tmux;本文主路径面向 Linux 远程。

完成后,远程服务器的模型下载与服务全部经由这一把 odysseus-cookbook 密钥的 SSH 通道运行;如果之后需要接入多机,按第一到第四步对每台服务器重复登记即可,服务器列表中只配置一台远程服务器时 Cookbook 下载界面会自动默认选中它。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.81 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
920
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.79 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
390