Fullstar

Archives

  • August 2026
  • December 2025
  • August 2024
  • July 2024
  • February 2024
  • November 2023
  • August 2023
  • July 2023
  • January 2023
  • November 2022
  • October 2022
  • September 2022
  • February 2022
  • January 2022
  • September 2021
  • January 2021
  • December 2020
  • November 2020
  • October 2020
  • September 2020
  • August 2020
  • July 2020

Categories

  • Code
  • Lens
  • Life
0
Fullstar
  • Code

排查 LiteLLM 经 Cloudflare 访问出现 502:Nginx Response Header 太大

  • August 16, 2026
  • Brandon

Looking for a Shorter Overview?

AI Summary

经 Cloudflare 访问 LiteLLM 出现 502,不应先把问题归咎于 CDN:用 curl --resolve 绕过 Cloudflare 后仍复现,Nginx 错误日志明确指出上游响应头过大。将 proxy_buffer_size 调至 64k 后恢复 SSE,并应把公网扫描与 502 故障分开处理。

Key Moments

AI-generated
1

绕过 CDN 锁定源站

使用 curl --resolve 直连源站后仍返回 Nginx 502,排除了 Cloudflare 作为本次根因。
2

错误日志确认响应头过大

Nginx 的 upstream sent too big header 日志直接表明上游响应头超出读取缓冲区。
3

增大响应头缓冲区修复

将 proxy_buffer_size 设置为 64k,使 LiteLLM 与上游附带的大量元数据能够被 Nginx 读取。
4

扫描流量单独防护

失败的弱密钥枚举与 502 没有因果证据,应通过强密钥、限流和收紧端口暴露处理。
Total
0
Shares
0
0
0

自建 LiteLLM Proxy 时,我遇到了一次稳定复现的 502:同一个模型,本机直连 LiteLLM 能正常返回流式响应,经过域名和 Cloudflare 却失败。排查期间还出现了大量异常 API 请求,一度让我怀疑服务被扫描流量拖垮。

最终定位到的原因是 Nginx 响应头缓冲区不足。绕过 Cloudflare 后,Nginx 仍返回 502;错误日志中的 upstream sent too big header while reading response header from upstream 则给出了直接证据。扫描流量是另一个独立问题,放在本文后半部分记录。

部署结构与故障现象

请求链路为:Client → Cloudflare → Nginx :443 → LiteLLM → OpenAI / Codex Backend。

LiteLLM 运行在 Docker 中,宿主机的 6111 端口映射到容器的 4000 端口。Nginx 将 https://one.fullstar.tech 转发到 http://127.0.0.1:6111。

通过公网域名请求 Responses API 时,返回的状态与响应头如下:

HTTP/2 502
server: cloudflare

Cloudflare 页面显示 “Browser Working / Cloudflare Working / Host Error”。这只能作为继续检查源站的线索,不能仅凭页面或 server: cloudflare 就认定故障出在 Cloudflare。

分层排查:从本机服务到反向代理

我先保持请求内容一致,逐次改变请求经过的链路。各次测试的结果如下:

测试路径结果定位意义
本机直连 LiteLLM Responses API200,SSE 正常本次请求的应用与上游链路正常
本机直连 Chat Completions API正常未复现接口兼容性问题
通过 Cloudflare 域名请求502故障出现在加入代理后的链路中
使用 curl –resolve 直连源站 Nginx502,server: nginx绕过 Cloudflare 仍可复现
检查 Nginx error.logupstream sent too big header定位到上游响应头缓冲区

1. 确认 Docker 端口映射

先查看实际监听端口,避免把 LibreChat 和 LiteLLM 的端口混用:

sudo docker ps --format "table {{.Names}}\t{{.Ports}}"
NAMES                   PORTS
LibreChat               0.0.0.0:3080->3080/tcp
litellm                 0.0.0.0:6111->4000/tcp

这里 3080 对应 LibreChat,6111 才是 LiteLLM 的宿主机端口。

2. 绕过两层代理,直接请求 LiteLLM

在服务器本机测试 Responses API。下文命令中的 YOUR_LITELLM_KEY 和 YOUR_SERVER_IP 均为占位符;模型名沿用本次部署中的配置。

curl -v http://127.0.0.1:6111/v1/responses \
  -H "Authorization: Bearer YOUR_LITELLM_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.6-terra",
    "input": [
      {
        "role": "user",
        "content": "Reply with exactly OK."
      }
    ],
    "reasoning": {
      "effort": "medium"
    },
    "stream": true
  }'

响应状态为 200,内容类型为 SSE:

HTTP/1.1 200 OK
server: uvicorn
content-type: text/event-stream

流中返回了文本 OK。以下是截取并省略部分字段的事件示意:

data: {"type":"response.output_text.delta", ... "delta":"OK" ...}

这说明本次测试中的 Docker 端口映射、LiteLLM、模型调用和流式返回都能工作,排查范围可以先缩小到 Cloudflare 与 Nginx 所在的代理链路。

3. 交叉测试 Chat Completions

为判断问题是否仅发生在 /v1/responses,我又直接测试了 /v1/chat/completions:

curl -v http://127.0.0.1:6111/v1/chat/completions \
  -H "Authorization: Bearer YOUR_LITELLM_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.6-terra",
    "messages": [
      {
        "role": "user",
        "content": "Reply with exactly OK."
      }
    ],
    "stream": true
  }'

结果同样正常。至少在这两次本机请求中,没有复现应用接口故障。

4. 对比 Cloudflare 与源站直连

将同一份 Responses 请求改为访问公网域名后,仍得到 HTTP/2 502。此时还无法区分是 Cloudflare 回源失败,还是 Nginx 处理上游响应失败。

接着使用 curl --resolve,把域名临时解析到真实源站 IP,在请求仍使用该域名的情况下绕过 Cloudflare:

curl -vk \
  --resolve one.fullstar.tech:443:YOUR_SERVER_IP \
  https://one.fullstar.tech/v1/responses \
  -H "Authorization: Bearer YOUR_LITELLM_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.6-terra",
    "input": [
      {
        "role": "user",
        "content": "Reply with exactly OK."
      }
    ],
    "reasoning": {
      "effort": "medium"
    },
    "stream": true
  }'

这里保留了排查时使用的 -k,它会跳过 TLS 证书校验;证书校验正常时应去掉该选项。测试结果仍为:

HTTP/2 502
server: nginx/1.18.0 (Ubuntu)

绕过 Cloudflare 后,Nginx 自己仍返回 502。因此这次故障可以在 Nginx → LiteLLM 这一段继续定位。

5. 检查 proxy_pass 与错误日志

查看当前域名对应的 Nginx 配置:

sudo nginx -T | grep -A 40 -B 10 "one.fullstar.tech"

当时的配置如下:

server {
    listen 443 ssl;
    server_name one.fullstar.tech;
 
    client_max_body_size 128m;
    client_body_timeout 300;
 
    ssl_certificate     /etc/nginx/cert/one/one.crt;
    ssl_certificate_key /etc/nginx/cert/one/one.key;
 
    location / {
        add_header Access-Control-Allow-Origin *;
        proxy_pass http://127.0.0.1:6111;
    }
}

proxy_pass 指向已测试成功的 127.0.0.1:6111。随后检查错误日志:

sudo tail -n 100 /var/log/nginx/error.log

日志中反复出现以下记录:

upstream sent too big header while reading response header from upstream,
server: one.fullstar.tech,
request: "POST /v1/responses HTTP/2.0",
upstream: "http://127.0.0.1:6111/v1/responses"

这条错误比 502 页面更具体:Nginx 在读取 upstream 响应头时遇到了超出缓冲区容量的头部。

根因:上游响应头超过 Nginx 缓冲区

直连 LiteLLM 时,可以看到它返回了多项自身元数据:

x-litellm-call-id
x-litellm-model-id
x-litellm-model-name
x-litellm-model-api-base
x-litellm-version
x-litellm-response-duration-ms
...

本次响应还携带了上游 Codex Backend 的元数据:

llm_provider-x-codex-active-limit
llm_provider-x-codex-plan-type
llm_provider-x-codex-primary-used-percent
llm_provider-x-codex-primary-reset-after-seconds
llm_provider-x-codex-primary-reset-at
...

其中包括较长的 llm_provider-x-codex-turn-state,以及 Cookie 等头部。这些字段叠加后,使本次响应头超过了 Nginx 的读取缓冲区。

这也解释了为什么本机直连成功,而经 Nginx 失败:直连请求没有经过 Nginx 的响应头读取环节。

修复配置与验证

我在 /etc/nginx/sites-enabled/one.conf 中调整了对应的 location。以下是本次部署最终使用的配置:

location / {
    add_header Access-Control-Allow-Origin *;
 
    proxy_pass http://127.0.0.1:6111;
    proxy_http_version 1.1;
 
    proxy_buffer_size 64k;
    proxy_buffers 8 64k;
    proxy_busy_buffers_size 128k;
 
    proxy_buffering off;
 
    proxy_read_timeout 600s;
    proxy_send_timeout 600s;
}
  • proxy_buffer_size 64k:本次修复 502 的关键,增大读取上游响应头的缓冲区(Nginx 文档)。
  • proxy_buffers 与 proxy_busy_buffers_size:一并保留本次配置中的缓冲参数;不应把它们与响应头缓冲区混为一谈。
  • proxy_buffering off:关闭代理响应缓冲,用于此次 SSE 流式场景。
  • proxy_read_timeout 与 proxy_send_timeout:保留本次长连接场景采用的超时设置。

检查语法并重新加载

sudo nginx -t

确认检查成功后再重新加载 Nginx:

sudo systemctl reload nginx

本次不需要重启 LiteLLM。随后重新通过公网域名测试:

curl -v https://one.fullstar.tech/v1/responses \
  -H "Authorization: Bearer YOUR_LITELLM_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.6-terra",
    "input": [
      {
        "role": "user",
        "content": "Reply with exactly OK."
      }
    ],
    "reasoning": {
      "effort": "medium"
    },
    "stream": true
  }'

请求恢复正常,SSE 返回 OK。从本机直连、绕过 CDN 到完整公网链路,前后测试形成了对应验证。

这次排查留下的经验

  1. 先测试 upstream。先确认本机服务能否处理同一份请求,再检查反向代理与 CDN。
  2. 用 curl --resolve 对比源站。它适合在保持请求域名的情况下,判断绕过 CDN 后是否仍能复现。
  3. 尽早看 Nginx 错误日志。502 只是结果,error.log 通常能提供更明确的故障环节。
  4. 留意 AI 代理附带的响应元数据。本次 LiteLLM 与上游头部叠加,使默认缓冲区不够用;应根据实际日志和响应检查,而不是只猜模型 API 出错。

如果再次遇到类似问题,我会按 本机 upstream → 绕过 CDN → Nginx error.log → 对应配置或应用逻辑 的顺序排查。

另一个独立问题:公网 API 扫描

排查期间,LiteLLM Request Logs 中还出现了高频失败请求。请求尝试的 Key 呈现字典枚举特征,例如 12345、123456、111111 和 sk123456,并伴随大量不同的 Request ID / Session ID。

当时日志显示 Status: Failure、Duration: 0.00、Cost: -。这更符合 API 扫描和凭据猜测的特征;仅凭这些记录,没有证据表明对方已经获得有效 API Key。

它与此次 502 同时发生,但定位证据指向不同原因:一个是失败的认证请求,另一个是 Nginx 响应头缓冲区不足。

1. 使用强 API Key,并在边缘限制异常请求

LiteLLM 的 API Key 仍是应用层认证边界。即使弱 Key 枚举无法通过认证,请求也会建立连接、经过 Nginx、触发 LiteLLM 认证并写入日志,因此仍会消耗资源。

本次的防护思路是让明显异常的流量尽量在 Cloudflare 边缘被拦截,再由 LiteLLM 校验 API Key。

2. 为 /v1/* 设置合适的限流

我为机器调用的 /v1/* 设置了按来源 IP 计数的限流。本文记录的示例阈值是 每个 IP 每 10 秒 30 次请求,触发后封禁 10 秒。

这不是适合所有服务的通用阈值。LibreChat、OpenCode、Codex 和 Agent 的并行调用可能在短时间发出多次请求;阈值过低容易误伤正常使用。目标是降低单 IP 高频枚举与异常请求洪泛的影响。

3. 按私人服务的使用范围限制地域

对于只需在中国和美国使用的私人服务,本次采用了按域名限定的 Cloudflare Custom Rule:

(http.host eq "one.fullstar.tech"
 and not ip.src.country in {"CN" "US"})

规则动作为 Block,即阻止该域名上来源国家不在 CN / US 内的请求。域名条件让这条规则限定于 one.fullstar.tech,而不是整个站点。地域范围需要按实际使用情况选择,也不能替代 API Key 认证。

4. 区分机器 API 与管理后台

入口访问方式本文采用或考虑的策略
/v1/*程序调用限流、地域限制和 LiteLLM API Key
/ui浏览器管理可考虑 Cloudflare Access、人机验证或固定 IP 限制

不能直接要求普通 API 客户端完成浏览器式 Managed Challenge,否则正常机器请求也可能被挡住。

5. 关闭绕过 Cloudflare 的应用端口入口

当时 Docker 映射为 0.0.0.0:6111→4000/tcp,意味着端口监听所有网卡。如果安全组与防火墙也允许公网访问,就可以通过 http://SERVER_IP:6111 直接访问 LiteLLM,绕过 Cloudflare 上的规则。

在本文 Nginx 与 LiteLLM 位于同一宿主机的部署中,可将端口绑定改为本机地址:

ports:
  - "127.0.0.1:6111:4000"

同时应核对安全组中的应用端口暴露情况。该修改针对的是 6111 的直连入口;源站 Nginx 的 443 端口是否允许绕过 Cloudflare 访问,需要另行检查(Cloudflare 源站保护文档),不能仅凭绑定本机端口就认为所有绕过路径都已关闭。

结语:用证据区分同时发生的问题

此次 502 的修复点是 Nginx 的 proxy_buffer_size;扫描流量则通过强 API Key、限流、按需地域限制和收紧端口暴露来处理。

两个问题同时出现,并不代表存在因果关系。保持测试请求一致、逐层缩小范围,再用错误日志验证,才避免了把“看到攻击流量”直接当成“服务返回 502”的原因。

Questions Answered

AI-generated

如何判断 502 是否由 Cloudflare 引起?

用 curl --resolve 直连源站,比较是否仍能复现 502。

Nginx 为何代理 LiteLLM 时出现 502?

LiteLLM 与上游元数据叠加,导致响应头超过默认读取缓冲区。

怎样修复 SSE 请求的响应头过大问题?

增大 proxy_buffer_size,并关闭代理响应缓冲以适配流式返回。

公网 API 遭遇弱密钥扫描应如何处理?

使用强密钥、边缘限流、按需地域限制并关闭直连端口。
Total
0
Shares
Share 0
Tweet 0
Pin it 0
Brandon

Previous Article
  • Code

Letta部署记录

  • December 26, 2025
  • Brandon
View Post
You May Also Like
View Post
  • Code

Letta部署记录

  • Brandon
  • December 26, 2025
View Post
  • Code

WordPress 后台任务利器:使用 BGRunner 构建可靠的异步处理

  • Brandon
  • December 14, 2025
View Post
  • Code

WordPress image offload

  • Brandon
  • December 14, 2025
View Post
  • Code

ComfyUI应用手册

  • Brandon
  • December 6, 2025
View Post
  • Code

Leetcode Java常用代码

  • Brandon
  • February 17, 2024
View Post
  • Code

Golang入门

  • Brandon
  • February 4, 2024
View Post
  • Code

Setting Up and Maintaining a Ubuntu Environment for My Home Server

  • Brandon
  • November 24, 2023
View Post
  • Code

Swift Learning Log

  • Brandon
  • August 31, 2023

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Fullstar

Input your search keywords and press Enter.