利用Nginx+VLLM在本地部署多个大模型服务:TaoToken统一Key接入与端口转发配置实战
1. 本地多模型服务的端口困境与 Nginx 破局思路如果你在本地或容器里用 VLLM 跑大模型大概率会遇到一个很现实的问题vllm serve一次只能拉起一个模型想同时跑 DeepSeek、Qwen、GLM 就得开多个进程、占多个端口。宿主机上端口越开越多防火墙规则越写越乱客户端配置里 base_url 一改再改Cline、CC Switch 这类工具每换一个模型就要重新填一遍地址和 Key维护成本直线上升。这个场景在容器化部署里更明显。容器通常只映射一个端口到宿主机容器内部却可能跑着三四个 VLLM 实例分别监听 8001、8002、8003。你不可能把每个端口都映射出去那样宿主机端口资源很快被吃光。更合理的做法是容器内只暴露一个公共端口由容器内的 Nginx 根据 URI 路径把流量分发到不同的 VLLM 后端。这样宿主机只需要一个8000:8000映射就能访问容器内所有模型服务。Nginx 的反向代理能力天然适配这个需求。它支持基于 location 的路径匹配可以把/deepseek转发到127.0.0.1:8001把/qwen转发到127.0.0.1:8002同时保留 OpenAI 兼容接口的/v1/chat/completions路径结构。客户端只需要把 base_url 写成http://host:8000/deepseek/v1就能命中对应的后端模型。但光有 Nginx 还不够。多模型意味着多套 API Key如果每个模型服务都配一个独立 Key客户端侧还是要维护多份凭证。这时候可以引入 TaoToken 作为统一 Key 接入层本地 Nginx 负责端口转发和路径路由TaoToken 负责统一鉴权和 API 通道管理Cline 或 CC Switch 只需要配置一个 TaoToken 的 Key 和 base_url就能在多个本地模型之间切换。下面我会把 Nginx 配置、VLLM 启动参数、TaoToken 接入骨架和 curl 验证步骤完整走一遍。2. TaoToken 前置准备统一 Key 与 API 通道在开始配 Nginx 之前先把 TaoToken 侧的准备工作做完。TaoToken 在这里的角色是统一 Key 管理和 API 通道它不替代你的本地 VLLM 服务而是让客户端侧只需要维护一套凭证。你可以把它理解成一个「Key 网关」本地多个 VLLM 实例各自有各自的 api-key但对外只暴露 TaoToken 的一个 Key由 TaoToken 侧完成映射和转发。首先访问官网了解接入方式https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content注册后进入控制台创建 API Key。建议按用途分 Key比如「本地开发」「Cline 编码」「CC Switch 测试」各一个方便后续排查问题时定位是哪个客户端在调用。创建完成后在 API Keys 页面复制 Key 值格式通常是sk-开头的一串字符。TaoToken 的 API 入口是https://taotoken.net/api注意这个地址不加 UTM 参数直接作为 base_url 使用。如果你用的是 OpenAI 兼容客户端base_url 填https://taotoken.net/api/v1即可。接下来在 TaoToken 控制台里配置模型映射把本地 Nginx 暴露的模型路径和 TaoToken 侧的模型名称对应起来。比如TaoToken 模型名本地 Nginx 路径后端 VLLM 端口deepseek-r1-distill-qwen-14b/deepseek-r1-distill-qwen-14b8001qwen2.5-14b-instruct-awq/qwen2.5-14b-instruct-awq8002这样客户端请求 TaoToken 时TaoToken 会根据模型名把请求转发到你本地 Nginx 的对应路径。如果你暂时不想走 TaoToken 转发也可以先用本地 Nginx 直连验证确认路由通了之后再接入 TaoToken 做统一 Key 管理。需要提醒的是TaoToken 的 Key 不要硬编码在客户端配置文件里提交到 Git。建议用环境变量或者本地.env文件管理Cline 和 CC Switch 都支持从环境变量读取 API Key。3. 可复制配置VLLM 启动参数与 Nginx 路由这一节是全文的核心所有配置都可以直接复制修改。先确认环境依赖一个能跑 VLLM 的 Docker 容器容器有8000:8000端口映射到宿主机容器内已安装 Nginx 和 tmux。sudo apt install nginx tmux -y3.1 VLLM 多实例启动用 tmux 开多个 session每个 session 跑一个模型。先启动 DeepSeektmux new -s vllm_deepseek CUDA_VISIBLE_DEVICES0,1 vllm serve /models/DeepSeek-R1-Distill-Qwen-14B \ --port 8001 \ --served-model-name DeepSeek-R1-Distill-Qwen-14B \ --dtype auto \ --api-key sk-local-deepseek-001 \ --tensor-parallel-size 2 \ --max-model-len 10240 \ --enable-reasoning \ --reasoning-parser deepseek_r1按Ctrlb再按d退出当前 session继续启动 Qwentmux new -s vllm_qwen CUDA_VISIBLE_DEVICES2 vllm serve /models/Qwen2.5-14B-Instruct-AWQ \ --port 8002 \ --served-model-name Qwen2.5-14B-Instruct-AWQ \ --dtype auto \ --api-key sk-local-qwen-002 \ --tensor-parallel-size 1 \ --max-model-len 10240两个实例分别监听 8001 和 8002各自有独立的 api-key。注意--served-model-name要和后续 Nginx 路径、客户端 model 参数保持一致否则会出现模型名不匹配的 404。3.2 Nginx 路由配置新建配置文件vim /etc/nginx/sites-available/vllm_proxy写入以下内容server { listen 8000; server_name vllm_forwarding; location /deepseek-r1-distill-qwen-14b/ { proxy_pass http://127.0.0.1:8001/; 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 Authorization $http_authorization; proxy_read_timeout 300s; proxy_send_timeout 300s; } location /qwen2.5-14b-instruct-awq/ { proxy_pass http://127.0.0.1:8002/; 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 Authorization $http_authorization; proxy_read_timeout 300s; proxy_send_timeout 300s; } }这里有几个细节值得说明。proxy_pass末尾的/很关键当 location 是/deepseek-r1-distill-qwen-14b/且 proxy_pass 是http://127.0.0.1:8001/时Nginx 会把 location 匹配到的前缀替换掉请求/deepseek-r1-distill-qwen-14b/v1/chat/completions会被转发到http://127.0.0.1:8001/v1/chat/completions。如果 proxy_pass 末尾不加/路径会原样拼接导致后端收到/deepseek-r1-distill-qwen-14b/v1/chat/completionsVLLM 会返回 404。proxy_read_timeout设成 300s 是因为大模型推理首 token 延迟可能较长默认 60s 容易在长上下文场景下超时断连。Authorization头透传是为了让 VLLM 侧的 api-key 校验生效如果你在 Nginx 层不做鉴权这个头会直接传给后端。启用配置并重载ln -s /etc/nginx/sites-available/vllm_proxy /etc/nginx/sites-enabled/vllm_proxy nginx -t service nginx reload service nginx statusnginx -t输出syntax is ok和test is successful才算配置无误。如果报duplicate location或conflicting server name检查是否有其他配置文件占用了 8000 端口。3.3 客户端配置骨架Cline 的settings.json骨架{ apiProvider: openai, openAiBaseUrl: https://taotoken.net/api/v1, openAiApiKey: sk-your-taotoken-key, openAiModelId: deepseek-r1-distill-qwen-14b }CC Switch 的config.toml骨架[provider] name taotoken base_url https://taotoken.net/api/v1 api_key sk-your-taotoken-key [model] id qwen2.5-14b-instruct-awq max_tokens 8192 temperature 0.7如果你暂时不走 TaoToken直接把 base_url 改成http://localhost:8000/deepseek-r1-distill-qwen-14b/v1api_key 填 VLLM 启动时的sk-local-deepseek-001即可。4. 验证请求curl 多模型路由与 Key 生效配置完成后先用 curl 验证 Nginx 路由是否通。请求 DeepSeek 后端curl -s http://localhost:8000/deepseek-r1-distill-qwen-14b/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer sk-local-deepseek-001 \ -d { model: DeepSeek-R1-Distill-Qwen-14B, messages: [{role: user, content: 用一句话解释什么是反向代理}], max_tokens: 128 }如果返回 JSON 里choices[0].message.content有内容说明 Nginx 到 8001 的转发链路通了。再验证 Qwencurl -s http://localhost:8000/qwen2.5-14b-instruct-awq/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer sk-local-qwen-002 \ -d { model: Qwen2.5-14B-Instruct-AWQ, messages: [{role: user, content: 你是谁}], max_tokens: 128 }两个请求都返回正常内容说明多模型路由生效。接下来验证 TaoToken 统一 Key 通道。把 base_url 换成 TaoToken 的 API 地址api_key 换成 TaoToken 控制台创建的 Keycurl -s https://taotoken.net/api/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer sk-your-taotoken-key \ -d { model: deepseek-r1-distill-qwen-14b, messages: [{role: user, content: 测试统一 Key 通道}], max_tokens: 128 }如果 TaoToken 侧配置了到本地 Nginx 的转发规则这个请求会先到 TaoToken再由 TaoToken 转发到你的本地http://host:8000/deepseek-r1-distill-qwen-14b/v1最终命中 8001 的 VLLM 实例。返回内容正常即表示统一 Key 通道打通。Python 客户端验证from openai import OpenAI client OpenAI( base_urlhttps://taotoken.net/api/v1, api_keysk-your-taotoken-key ) resp client.chat.completions.create( modelqwen2.5-14b-instruct-awq, messages[{role: user, content: 你好}], max_tokens64 ) print(resp.choices[0].message.content)实测下来从客户端发出请求到收到响应中间经过 TaoToken 和本地 Nginx 两层转发额外延迟通常在几十毫秒级别对推理本身的首 token 延迟影响可以忽略。5. 本篇常见错排查502 Bad GatewayNginx 能收到请求但后端 VLLM 没响应。先确认 VLLM 进程还在跑tmux attach -t vllm_deepseek进去看日志。如果 VLLM 启动时报显存不足检查CUDA_VISIBLE_DEVICES是否和--tensor-parallel-size匹配比如 2 张卡配--tensor-parallel-size 21 张卡配 1。404 Not Found路径拼接问题。重点检查proxy_pass末尾有没有/以及 location 路径和客户端 base_url 是否一致。比如 location 是/deepseek-r1-distill-qwen-14b/客户端 base_url 就必须是http://host:8000/deepseek-r1-distill-qwen-14b/v1少一段都会 404。401 UnauthorizedKey 没透传或 Key 不对。确认 Nginx 配置里有proxy_set_header Authorization $http_authorization;并且客户端请求头里带了Authorization: Bearer sk-xxx。如果走 TaoToken检查 TaoToken 控制台的 Key 是否启用、额度是否充足。模型名不匹配VLLM 的--served-model-name和客户端请求里的model字段必须一致。比如 VLLM 启动时写的是DeepSeek-R1-Distill-Qwen-14B客户端请求里写deepseek-r1就会报模型不存在。Nginx 配置不生效改完配置后必须nginx -t检查再service nginx reload。如果 reload 报错用nginx -T输出完整生效配置对比看是不是软链接没建对或者有其他配置文件冲突。长请求超时默认proxy_read_timeout60s长上下文推理容易超。在 location 里加proxy_read_timeout 300s;和proxy_send_timeout 300s;同时确认 VLLM 的--max-model-len足够大。6. 接入方式选择与后续操作排障和接入配置相关的问题优先看 API Keys 和接入文档https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content想先验证模型对话效果不急着配本地 Nginx可以直接用模型对话页面测试https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content如果你长期用 Cline 做编码、或者跑 Agent 任务建议直接上 Coding Plan省去每次手动切 Key 的麻烦https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content控制台入口https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentClaude Code 用户走 Anthropic 通道https://taotoken.net/claudecode-anthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content最后说一个我踩过的坑Nginx 的 location 匹配是前缀匹配/qwen会同时匹配/qwen2.5-14b-instruct-awq如果你有多个以相同前缀开头的模型路径建议用更精确的路径或者加做精确匹配。另外 tmux session 名字不要用中文和特殊字符否则tmux attach时容易找不到 session。配置改完后养成nginx -t再 reload 的习惯能省掉很多「为什么没生效」的排查时间。