Nginx跨域代理的完整排坑指南(从证书错误到CORS配置)

 更新时间:2026年04月09日 08:29:05   作者:码上有潜  
本文详细记录了一个项目中使用Nginx作为反向代理解决跨域问题的过程,从为子域名申请独立SSL证书、处理CORS预检请求、避免add_header语法错误、正确设置代理Host头、以及后端HTTPS证书问题等方面逐一排查并解决,最终得到正确的Nginx配置,需要的朋友可以参考下

一、背景与需求

最近在做一个项目,架构如下:

  • 前端域名https://www.example.com
  • 第三方APIhttps://thirdparty-api.example.net(不支持 CORS)
  • 目标:前端需要调用该第三方 API,但存在跨域问题

解决方案:使用 Nginx 做反向代理,将请求转发到自己的子域名 https://api.example.com,并在 Nginx 层添加 CORS 响应头。

预期请求链路:

浏览器 → api.example.com (Nginx) → thirdparty-api.example.net

本以为是个简单的配置,结果前后踩了 6 个坑,耗时整整一天。本文将完整记录排坑过程,希望对遇到类似问题的朋友有所帮助。

二、踩坑全记录

坑位1:SSL 证书域名不匹配

错误现象

ERR_CERT_COMMON_NAME_INVALID

原因分析
api.example.com 使用了 www.example.com 的 SSL 证书,导致浏览器校验证书时发现域名不匹配。

解决方案
api.example.com 申请独立的 SSL 证书:

certbot certonly --nginx -d api.example.com

教训:每个子域名都需要自己的证书,或使用通配符证书 *.example.com

坑位2:CORS 预检请求失败

错误现象

Access to fetch at 'https://api.example.com/...' from origin 'https://www.example.com' 
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present

原因分析
浏览器在发送实际请求前,会先发送一个 OPTIONS 预检请求。Nginx 没有正确处理这个请求,也没有返回必要的 CORS 响应头。

解决方案
在 Nginx 配置中添加 CORS 头和 OPTIONS 请求处理:

location / {
    # CORS 响应头
    add_header 'Access-Control-Allow-Origin' 'https://www.example.com' always;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
    add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
    
    # 处理预检请求
    if ($request_method = 'OPTIONS') {
        add_header 'Content-Length' 0;
        add_header 'Content-Type' 'text/plain charset=utf-8';
        return 204;
    }
    
    # 代理配置...
}

坑位3:add_header 语法错误

错误现象

[emerg] "add_header" directive is not allowed here in /etc/nginx/conf.d/ssl.conf:47

原因分析
add_header 指令被放在了 Nginx 不允许的位置。这个指令只能出现在 httpserverlocation 块中,不能随意放置。

错误示例

server {
    # 正确位置
    add_header 'Header1' 'value1' always;
    
    location / {
        # 正确位置
        add_header 'Header2' 'value2' always;
    }
}

# ❌ 错误:在 server/location 块外面
add_header 'Header3' 'value3' always;

解决方案
确保所有 add_header 都在 serverlocation 块内部。

坑位4:Access-Control-Allow-Origin 重复

错误现象

The 'Access-Control-Allow-Origin' header contains multiple values 
'https://www.example.com, https://www.example.com', but only one is allowed.

原因分析
Nginx 配置中 add_header 'Access-Control-Allow-Origin' ... 被写了两次,导致响应头中出现重复值。

解决方案
检查配置文件,确保每个 CORS 头只添加一次。如果同时在 serverlocation 块中添加了,保留一处即可。

坑位5:代理 Host 头不正确

错误现象
后端 API 返回 502 或 404,但直接访问后端 API 是正常的。

原因分析
默认情况下 proxy_set_header Host $host 会将 Host 头设置为 api.example.com,而后端 API 可能期望的是自己的域名 thirdparty-api.example.net

解决方案
使用 $proxy_host 变量,它保存的是 proxy_pass 中指定的域名:

# ❌ 错误:Host 头变成 api.example.com
proxy_set_header Host $host;

# ✅ 正确:Host 头保持 thirdparty-api.example.net
proxy_set_header Host $proxy_host;

坑位6:后端使用 HTTPS 导致证书问题

错误现象
Nginx 代理到 https://thirdparty-api.example.net 时出现 SSL 错误。

原因分析
Nginx 作为代理去访问 HTTPS 后端时,需要验证后端证书。如果后端证书有问题(自签名、过期、域名不匹配等),Nginx 会拒绝连接。

解决方案
有两种方式:

方案A(推荐):使用 HTTP 协议代理

# 如果后端支持 HTTP,直接用 HTTP
proxy_pass http://thirdparty-api.example.net$request_uri;

方案B:忽略证书验证(仅临时使用)

proxy_pass https://thirdparty-api.example.net$request_uri;
proxy_ssl_verify off;  # 关闭证书验证

三、最终正确的配置

经过以上所有坑位的修复,最终配置如下:

server {
    listen 443 ssl;
    server_name api.example.com;
    # DNS 解析器(使用域名代理时推荐添加)
    resolver 114.114.114.114 223.5.5.5 valid=30s;
    resolver_timeout 10s;
    # SSL 证书(使用子域名自己的证书)
    ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
    # HSTS 安全头
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    # SSL 配置
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;
    client_max_body_size 100M;
    location / {
        # ========== CORS 配置 ==========
        add_header 'Access-Control-Allow-Origin' 'https://www.example.com' always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;
        add_header 'Access-Control-Allow-Credentials' 'true' always;
        # 处理预检请求
        if ($request_method = 'OPTIONS') {
            add_header 'Content-Length' 0;
            add_header 'Content-Type' 'text/plain charset=utf-8';
            return 204;
        }
        # ========== 代理配置 ==========
        # 核心转发(使用 HTTP 避免后端证书问题)
        proxy_pass http://thirdparty-api.example.net$request_uri;
        # 关键:使用 $proxy_host 保持原始 Host
        proxy_set_header Host $proxy_host;
        # 传递真实客户端信息
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        # HTTP 1.1 支持
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        # 超时设置
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
        # API 最佳实践:禁用缓存
        proxy_buffering off;
        proxy_cache off;
    }
}
# HTTP 重定向到 HTTPS
server {
    listen 80;
    server_name api.example.com;
    return 301 https://$server_name$request_uri;
}

四、核心经验总结

1. 关于 SSL 证书

要点说明
子域名需要独立证书api.example.com 不能使用 www.example.com 的证书
申请 命令certbot certonly --nginx -d api.example.com
通配符证书*.example.com 可以覆盖所有子域名

2. 关于 CORS 配置

要点说明
必须处理 OPTIONS浏览器预检请求需要返回 204
头不能重复Access-Control-Allow-Origin 只能出现一次
位置限制add_header 只能在 server/location 块内

3. 关于代理转发

要点说明
Host 头用 $proxy_host保持后端期望的域名
添加 $request_uri完整传递请求路径
后端可以用 HTTP浏览器到 Nginx 需要 HTTPS,Nginx 到后端可以用 HTTP

4. 调试技巧

# 测试 Nginx 配置语法
nginx -t

# 查看错误日志
tail -f /var/log/nginx/error.log

# 测试 CORS 响应头
curl -X OPTIONS https://api.example.com/api/test \
  -H "Origin: https://www.example.com" \
  -H "Access-Control-Request-Method: POST" \
  -v 2>&1 | grep -i "access-control"

五、一个重要的认知

Postman 能请求成功 ≠ 浏览器能请求成功

工具是否检查 CORS说明
Postman❌ 不检查桌面应用,不受浏览器安全策略限制
curl❌ 不检查命令行工具
浏览器✅ 严格检查为了用户安全,必须配置正确的 CORS

这个认知能帮助您在调试时快速定位问题:Postman 通但浏览器不通 → 99% 是 CORS 配置问题。

六、架构总结

最终的成功架构:

浏览器 -----------(HTTPS)-----------> Nginx -----------(HTTP)-----------> 后端
(www.example.com)              (api.example.com)              (thirdparty-api)
         ↑                              ↑                              ↑
    安全连接                      SSL证书 + CORS头                 内部通信

关键设计思想

  • 浏览器到 Nginx:必须 HTTPS,证书有效
  • Nginx 到后端:可以用 HTTP,避免证书麻烦
  • Nginx 层统一处理 CORS,后端无需改造

七、写在最后

这次排坑让我深刻体会到:

  1. Nginx 配置顺序和位置非常重要,一个小错误就能导致整个服务不可用
  2. CORS 不是后端的事,是 Nginx/网关层的事,统一处理比每个后端服务单独配置要优雅得多
  3. HTTPS 是端到端的,但中间代理可以用 HTTP 转发,不影响整体安全性
  4. 遇到问题先看日志,Nginx 的错误日志非常详细,能定位 90% 的问题

以上就是Nginx跨域代理的完整排坑指南(从证书错误到CORS配置)的详细内容,更多关于Nginx跨域代理排坑指南的资料请关注脚本之家其它相关文章!

相关文章

  • Nginx提高安全与性能的最好配置详解

    Nginx提高安全与性能的最好配置详解

    这篇文章主要介绍了Nginx提高安全与性能的最好配置详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-06-06
  • Nginx实现高并发的项目实践

    Nginx实现高并发的项目实践

    本文主要介绍了Nginx实现高并发的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-03-03
  • Nginx 重定向时获取域名的方法示例

    Nginx 重定向时获取域名的方法示例

    本篇文章主要介绍了Nginx 重定向时获取域名的方法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • nginx配置https加密访问的详细教程

    nginx配置https加密访问的详细教程

    这篇文章主要介绍了nginx配置https加密访问的详细教程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • 详解nginx配置url重定向-反向代理

    详解nginx配置url重定向-反向代理

    这篇文章主要介绍了详解nginx配置url重定向-反向代理 ,nginx的重定向和nginx的反向代理的原理还是有区别的。有兴趣的可以了解一下。
    2016-12-12
  • 使用nginx正向代理实现内网域名转发过程解析

    使用nginx正向代理实现内网域名转发过程解析

    这篇文章主要介绍了使用nginx正向代理实现内网域名转发过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • centos 7.0 使用Nginx部署flask应用教程

    centos 7.0 使用Nginx部署flask应用教程

    这篇文章主要介绍了centos 7.0 使用Nginx部署flask应用教程,需要的朋友可以参考下
    2017-12-12
  • nginx location匹配实例详解

    nginx location匹配实例详解

    这篇文章主要介绍了nginx location匹配实例详解的相关资料,需要的朋友可以参考下
    2017-06-06
  • Nginx配置虚拟主机的三种方法

    Nginx配置虚拟主机的三种方法

    本文主要介绍了Nginx配置虚拟主机的三种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • Nginx下修改WordPress固定链接导致无法访问的问题解决

    Nginx下修改WordPress固定链接导致无法访问的问题解决

    这篇文章主要介绍了Nginx下修改WordPress固定链接导致无法访问的问题解决,同时作者也给出了官方关于修改固定链接的方法,需要的朋友可以参考下
    2015-07-07

最新评论