LLM 服务一键启动与端口转发架构
记录于 2026/06/01
一、背景与目标
场景:本地 Mac → SSH 免密登录 lab-server(内网服务器)→ 在 lab-server 上启动 Qwen3-32B vLLM 服务 → 通过双层 autossh 隧道暴露到公网。
目标:写一个本地启动脚本,一键完成:
- 远程启动 LLM 服务(后台)
- 本地监控启动状态(后台子进程)
- 启动成功后自动开启端口映射
- 主脚本立即退出,不占用终端
- 统一停止脚本(关闭 LLM + 隧道)
二、架构图
本地 Mac lab-server(内网)
+--------+ SSH +------------------+ vLLM (port 8001)
| 客户端 | <------ | autossh 隧道 | <------------------+
+--------+ | L:18001 → 8001 | |
+------------------+ |
| SSH 远程端口转发 |
v |
+--------------------+ |
| llm.litearch.cn | <---------------+
| R:18001 → :18001 |
+--------------------+
|
v 公网可访问
三、已实现的脚本
| 文件 | 作用 |
|---|---|
llm_start.sh |
启动 LLM + 隧道的总脚本 |
llm_stop.sh |
停止 LLM + 隧道的总脚本 |
tunnel_start.sh |
仅启动 autossh 隧道(手动) |
tunnel_stop.sh |
仅停止 autossh 隧道(手动) |
status_llm.sh |
查看 LLM 进程、端口、健康状态、远程日志 |
四、核心问题排查记录
问题 1:vLLM 找不到命令
- 现象:
exec: vllm: not found - 原因:SSH 非交互式命令不加载 conda 环境
- 解决:使用绝对路径
/root/miniconda3/bin/vllm
问题 2:网络不通,模型下载失败
- 现象:
Network is unreachable → huggingface.co:443 - 原因:SSH 远程命令不加载
.bashrc,proxy_on函数未定义 - 排查方法:
ssh lab-server "type proxy_on" # not found ssh lab-server "grep -r proxy_on ~/.bash*" # 发现在 .bashrc 里 - 解决:直接在 SSH 命令里设置代理环境变量:
export https_proxy=http://kb314314.asuscomm.com:8007 export http_proxy=http://kb314314.asuscomm.com:8007 export all_proxy=http://kb314314.asuscomm.com:8007
问题 3:服务已启动但端口未监听
- 原因:vLLM 加载模型需要时间,未加载完时端口未打开
- 解决:monitor 子进程每 10s 通过
curl http://127.0.0.1:8001/health检查,直到返回 200 才启动隧道
问题 4:测试模式调试
- 解决:加了
--test参数,所有步骤前台执行,实时显示日志./llm_start.sh --test
五、关键实现细节
5.1 启动流程(llm_start.sh)
cleanup_existing() → 清理旧进程
start_remote_llm() → SSH 设置代理 + nohup 启动 vLLM
run_monitor() → 后台轮询 /health,超时 600s
launch_tunnel() → 健康检查通过后启动双层 autossh
5.2 非交互式 SSH 的坑
- SSH 远程执行
ssh host "cmd"走的是非交互式 non-login shell .bashrc里有[ -z "$PS1" ] && return,非交互式直接 return.bash_profile/.profile才会被加载- 教训:不要假设远程函数在 SSH 里可用,直接设置环境变量最稳妥
5.3 健康检查机制
ssh lab-server "curl -sf http://127.0.0.1:8001/health"
- vLLM 的
/health端点在模型加载完成后才响应 - 轮询间隔 10s,超时 600s(10分钟)
- 成功后才启动 autossh 隧道
5.4 日志位置
| 日志 | 路径 |
|---|---|
| 远程 vLLM 日志 | ~/llm_server.log(服务器) |
| 本地启动日志 | ~/.llm/startup.log |
| 隧道1日志 | ~/.llm/tunnel1.log |
| 隧道2日志 | ~/.llm/tunnel2.log |
| Monitor PID | ~/.llm/monitor.pid |
| 隧道 PID | ~/.llm/tunnel.pid.{1,2} |
六、代理信息
- 代理地址:
http://kb314314.asuscomm.com:8007 - 代理函数
proxy_on定义在~/.bashrc(非交互式 SSH 不可用) - 直接设置
https_proxy/http_proxy/all_proxy环境变量即可
七、使用方法
# 启动(立即返回)
./llm_start.sh
# 查看状态
./status_llm.sh
# 停止
./llm_stop.sh
# 调试模式(前台运行,实时日志)
./llm_start.sh --test
八、后续可优化方向
- 隧道断开后自动重连(autossh 已有
-M 0监控) - LLM 启动失败时自动发通知(邮件/钉钉)
- 支持多卡(
CUDA_VISIBLE_DEVICES参数化) - 模型加载进度从日志中解析百分比显示
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 kipleyarch@gmail.com