配置 Nginx 反向代理模型 API,核心不在 location 写得多花哨,而在三件事是否处理对:上游地址是否固定、请求头与路径是否原样传到模型服务、流式响应和大请求体是否被 Nginx 的默认缓冲和超时规则截断。判断顺序建议先看模型接口是不是 SSE 流式返回、单次推理是否可能超过默认 60 秒、请求体是否带图片或长上下文,这三点决定了配置里必须放开哪些参数。
如果模型 API 是流式返回(SSE 或 chunked),Nginx 反向代理必须关闭 proxy_buffering、拉长 proxy_read_timeout、并把 HTTP 版本设为 1.1 且清空 Connection 头,否则表现为“首字很快、后面卡住”或整段延迟返回。如果只是普通的 JSON 一问一答,配置可以简化,但仍要确认 client_max_body_size 与上游一致。改完后用 curl -N 观察是否逐块输出、用 nginx -t 与 error.log 确认加载无误;不具备流式需求的场景不必全局关闭 buffering。
先确认当前场景和目标
动手前先确认四类信息,否则配置写完也很难判断对错。第一,模型服务的地址是内网固定 IP 还是外部域名:固定 IP 可以直接写进 upstream,域名且会变动则需要 resolver,否则 Nginx 只在启动时解析一次。第二,接口是否流式返回:聊天补全类接口常见 SSE,一次性补全或不支持流式的接口则走普通响应,两者对 buffering 的要求相反。第三,单次请求的耗时上限:本地小模型可能几秒,远端大模型带长输出时 60 秒不够用,需要按实际业务的超时容忍度上调。第四,请求体和响应体大小:带 base64 图片或多轮长上下文时,请求体可能达到几 MB,Nginx 默认的 1m 会在入口直接返回 413。
还要确认鉴权方式。如果客户端把 Authorization 直接带给模型服务,Nginx 只做透传即可;如果密钥要收在 Nginx 侧,就需要在入口校验,并避免把明文密钥写进会暴露的配置或日志里。这一步决定了下文片段里是否需要额外的 proxy_set_header 与访问日志裁剪。
按这个顺序处理
建议按“先固定上游,再对齐路径,最后放开流式与超时”的顺序改,每改一步都能单独验证。下面片段中的 IP、端口、域名、超时值都需替换成你自己的环境。
upstream model_api {
server 10.0.0.12:8000; # 替换为模型服务实际地址
keepalive 32;
}
server {
listen 80;
server_name api.example.internal;
client_max_body_size 32m; # 与上游允许的上限保持一致
location /v1/ {
proxy_pass http://model_api;
# 长连接与头部透传
proxy_http_version 1.1;
proxy_set_header Connection "";
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_buffering off;
proxy_cache off;
proxy_request_buffering off;
# 超时按实际推理耗时上调
proxy_connect_timeout 10s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
}
如果上游是外部域名且地址可能变化,把 proxy_pass 改成带变量的写法,并补上 resolver,其中 DNS 地址需按你的环境替换:
resolver 127.0.0.53 valid=30s ipv6=off;
set $model_host api.vendor.example;
proxy_pass https://$model_host;
如果请求要经 Nginx 到上游的 WebSocket 或需要保持升级头,还要在 location 中补 Upgrade 与 Connection 的映射;但注意这与上面清空 Connection 的写法冲突,需要按路径拆成两个 location,而不是在同一段里同时满足。另一个常见取舍是:proxy_buffering off 会占用更久的连接资源,如果只有部分接口需要流式,可以只为该路径单独关闭,其余路径保持默认。

改完后怎么验证
配置加载层先做两步:执行 nginx -t 确认语法通过,再 reload;如果 reload 报错,先看 error.log 的提示行,不要直接重启覆盖现场。随后按接口类型分别验证。
- 流式接口:用 curl -N 请求,观察响应是否逐块出现而不是等全部生成完才一次性打印。命令示例:
curl -N -i http://127.0.0.1/v1/chat/completions -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" -d @payload.json。逐块输出说明缓冲已关闭;长时间无输出或迟迟一次性返回,回到 proxy_buffering 与上游是否自行缓冲这两处排查。 - 头部透传:用 curl -i 看响应状态码与关键头,同时在上游服务的访问日志里确认收到的路径、Host、Authorization 与客户端发出的值一致,避免出现路径被改写或缺头导致的 401。
- 大请求体:用一个接近上限的 payload 文件配合
--data-binary提交,确认不再出现 413;如果仍失败,区分是 Nginx 的 client_max_body_size 还是模型服务自身的限制。 - 长耗时:对推理较慢的请求计时,确认不会在预期完成前收到 504。出现 504 时优先核对 proxy_read_timeout 与上游实际耗时,而不是盲目继续加大。
预期的正常信号是:短请求与直连上游结果一致;流式请求首块返回时间与直连接近;错误码由上游原样透出,而不是被 Nginx 改写成 502 或 504。若结果与直连有差异,先摘掉 Nginx 直连复现,再回到配置逐项比对。
容易忽略的边界
一是版本差异。不同 Nginx 版本对 proxy_request_buffering、HTTP/2 与 SSE 组合的行为不完全相同,升级或迁移前建议在同一版本上验证,不要照搬其他环境的配置。二是权限与端口。监听 80 或 443 通常需要相应权限,容器或非 root 运行时需要调整端口映射,而不是简单改端口了事。三是日志与密钥。若在 Nginx 侧注入密钥,访问日志默认会记录 URL,但不会记录请求头,仍需确认没有把密钥写进会外泄的位置。四是缓存。模型 API 的响应通常不适合做 proxy_cache,若为了减少重复请求而开启缓存,要明确只对确定性的接口生效,否则会返回过期结果。
不适用的情形也要说清楚:如果模型服务本身不支持流式输出,关闭 buffering 不会让它变成流式,只是减少中间层等待;如果上游已经做了网关限流和鉴权,Nginx 再叠加一层校验会造成重复维护,此时建议只保留转发与超时控制。回退方案是先退回最简配置——保留 proxy_pass 与必要的头部透传,去掉所有 buffering 与超时调整,确认基础链路通后再逐项加回,这样出问题时能快速定位是哪一项引起的。