Nginx 反向代理 New-API 服务引发 401 Unauthorized 问题的排查与解决

目录

在构建 AI 中转服务(如基于 New-API 或 One-API)时,通常会使用 Nginx 作为反向代理来提供 HTTPS 支持和域名解析。然而,在部署完成后进行客户端测试时,常会遇到 POST /v1/chat/completions 请求直接返回 401 Unauthorized 错误的情况。本文将针对该现象进行深度排查、定位,并提供彻底的解决方案。

1. 问题背景与现象

1.1 环境栈

  • 前端/客户端​:NextChat / LobeChat 或其他标准 OpenAI 格式客户端
  • 反向代理层​:Nginx
  • 后端服务​:New-API (运行于本地 127.0.0.1:3000)

1.2 故障现象

客户端在发送对话请求时失败,提示鉴权失败。查阅 Nginx 的 access.log,可以看到如下明确的错误日志:

0.0.0.0 - - [20/Jul/2026:17:49:10 +0800] "POST /v1/chat/completions HTTP/1.1" 401 126 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" "-"

现象特征分析​:

  • 状态码为 401,代表未通过身份验证。
  • 返回体大小为 126 字节,这符合 New-API 标准的 JSON 报错回包长度(如 {"error":{"message":"Invalid external token...","type":"new_api_error"}}),说明请求已经到达了后端,但后端认为没有携带有效的 Token。

2. 原因分析与故障定位

引发该问题的核心原因可以划分为以下三个方向:

2.1 原因一:Nginx 默认丢弃带下划线的非标准请求头

New-API 服务在处理特定客户端流式传输或联动请求时,有时会包含带有下划线 _ 的自定义 HTTP 头部(例如 Authorization_ 或客户端用于传递渠道的自定义 Header)。

  • Nginx 默认行为​:出于安全考虑,Nginx 默认将 underscores_in_headers 设置为 off,会自动过滤并丢弃所有请求头名称中包含下划线的 Header。当后端服务拿不到必要的 Header时,就会触发 401。

2.2 原因二:Authorization 头部在代理过程中丢失或被覆盖

在一些复杂的 Nginx 环境中(例如特定的默认模板、集成了外部安全模块或上层全局配置),客户端传入的 Authorization: Bearer sk-... 头部在进入 location / 匹配块时,未被正确继承或透传给 upstream,导致后端收到的 HTTP 请求中 Authorization 字段为空。

2.3 原因三:客户端混淆了管理密码与 API Key

在 New-API 系统中存在两种凭证:

  • 系统管理员密码​:用于登录 Web 管理控制台。
  • ​**令牌 (Token)**​:在控制台“令牌”页面生成的、以 sk- 开头的密钥。
    如果用户在客户端中错误地将“管理密码”填入 API Key 栏,后端接口层通过 /v1/chat/completions 校验时会直接拒绝,返回 401。

3. 深度排查步骤

为了快速缩小故障范围,必须通过边界隔离法确定是 Nginx 代理层的问题,还是后端服务本身的问题。

步骤一:绕过代理进行本地环回测试

在 Nginx 所在的服务器本地,使用 curl 直接向后端服务的 3000 端口发起接口请求,以此判定后端状态。执行以下标准命令:

curl http://127.0.0.1:3000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-your_actual_token_here" \
  -d '{
    "model": "gpt-3.5-turbo",
    "messages": [{"role": "user", "content": "say hi"}]
  }'

定位结论分流:

  1. ​**若本地直接请求成功(返回 200 或模型真实的额度报错)**​:
    • 诊断结果​:后端服务正常,Token 有效。故障根源绝对在 ​Nginx 代理层​(请求头被拦截或剥离)。
  2. 若本地直接请求依然返回 401​:
    • 诊断结果​:Nginx 配置无误。故障根源在 ​后端校验​。应立即去 New-API 检查该令牌是否被禁用、过期、额度耗尽,或确认是否误填了管理密码。

4. 解决方案

确定为 Nginx 层面的问题后,通过调整 Nginx 配置文件进行修复。

4.1 开启下划线请求头支持

server 块内(与 listen 同级)显式声明允许下划线 Header:

server {
    listen 443 ssl;
    server_name example.com;

    # 核心修复项:允许请求头中包含下划线
    underscores_in_headers on;
    
    # 后续其他配置...
}

4.2 显式透传验证请求头与清理冲突配置

  1. location / 块内部,明确补充 proxy_set_header Authorization 映射,确保 Token 强行透传。
  2. 清理掉写在 location 块外部的“悬空” proxy_set_header 语句,避免作用域继承混乱。

优化后的完整 server 块配置示例如下:

server {
    listen 443 ssl ; 
    server_name example.com; 
    
    # 允许包含下划线的请求头进入
    underscores_in_headers on;

    index index.php index.html index.htm default.php default.htm default.html; 
    access_log /var/log/nginx/access.log main; 
    error_log /var/log/nginx/error.log; 

    # 安全过滤块
    location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md) {
        return 404; 
    }
    
    location ^~ /.well-known/acme-challenge {
        allow all; 
        root /usr/share/nginx/html; 
    }
    
    if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) {
        return 403; 
    }
    
    # 核心反向代理路由
    location / {
        proxy_set_header Host $host; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
        proxy_set_header X-Forwarded-Host $server_name; 
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-Proto $scheme; 
        
        # 显式传递客户端真实的验证信息,防止被覆盖或漏传
        proxy_set_header Authorization $http_authorization;

        # WebSocket 支持
        proxy_set_header Connection upgrade; 
        proxy_set_header Upgrade $http_upgrade; 
        
        proxy_http_version 1.1; 
        proxy_ssl_server_name off; 
        proxy_ssl_name $proxy_host; 
        
        proxy_pass http://127.0.0.1:3000; 
    }

    # SSL 协议及安全策略
    http2 on; 
    if ($scheme = http) {
        return 301 https://$host$request_uri; 
    }
    
    ssl_certificate /etc/nginx/ssl/fullchain.pem; 
    ssl_certificate_key /etc/nginx/ssl/privkey.pem; 
    ssl_protocols TLSv1.3 TLSv1.2; 
    ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256; 
    ssl_prefer_server_ciphers off; 
    ssl_session_cache shared:SSL:10m; 
    ssl_session_timeout 10m; 
    
    error_page 497 https://$host$request_uri; 
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains"; 
}

4.3 载入配置

配置修改完毕后,执行标准命令验证并平滑重载:

nginx -t
# 确认显示:nginx: configuration file ... test is successful

nginx -s reload

5. 总结

在 Nginx 反代大模型上游 API服务时,401 Unauthorized 常见于 Header 信息的非标准截断。通过开启 underscores_in_headers on; 并显式声明 proxy_set_header Authorization $http_authorization;,可以确保鉴权令牌完好无损地送达后端。在实际运维中,善用 curl 绕过反代层进行端口直连,是快速隔离代理层故障与应用层故障的最佳工程实践。