Nginx  配置  HTTPS  后出现无限重定向,通常是  Nginx、后端应用或  CDN  等多层之间,对请求协议(HTTP  或  HTTPS)的判断不一致导致的。

简单来说,就是“A  觉得该用  HTTPS,B  觉得该用  HTTP”,双方互相推诿,导致请求在两者间无限循环。

以下是几种最常见的原因和对应的排查、解决方法。

一、原因一:后端应用未正确识别  HTTPS(最常见)

这是最典型的情况。用户通过  HTTPS  访问,Nginx  将请求通过内部  HTTP  转发给后端。如果后端应用没有正确识别  `X-Forwarded-Proto`  头,会误以为收到的是  HTTP  请求,于是自身再发送一个  301  重定向到  HTTPS。这个重定向请求回到  Nginx,再次被转发,形成循环。

      解决方案:

        1.    让后端应用信任代理头:这是最彻底的解决方法。让后端程序读取  Nginx  传递的  `X-Forwarded-Proto`  头来判断真实协议。

                      Flask:  使用  `werkzeug.middleware.proxy_fix.ProxyFix`  中间件。

                      Express  (Node.js):  启用  `trust  proxy`  配置。

                      Django:  设置  `SECURE_PROXY_SSL_HEADER  =  ('HTTP_X_FORWARDED_PROTO',  'https')`。

                      Spring  Boot:  配置  `server.forward-headers-strategy=framework`。

        2.    在  Nginx  中强制设置协议头:如果无法修改后端代码,可以在  Nginx  的  `location`  块中强制指定协议为  HTTPS。

                ```nginx

                location  /  {

                        proxy_pass  http://backend_server;

                        proxy_set_header  X-Forwarded-Proto  https;

                        #  其他  proxy_set_header  ...

                }

                ```

                但更推荐传递真实协议,而非强制写死:

                ```nginx

                proxy_set_header  X-Forwarded-Proto  $scheme;

                ```

                `$scheme`  变量会自动获取  Nginx  收到的请求协议(HTTPS  或  HTTP)。

二、原因二:Nginx  自身的  HTTPS  配置错误

如果  Nginx  配置不当,也可能自己制造出循环。

      在  443  端口的  server  块中写了重定向:这是典型的错误。如果在监听  443  端口的  HTTPS  配置里也写了  `return  301  https://...`,那么所有  HTTPS  请求都会被重定向到  HTTPS,自己重定向自己,形成死循环。

              解决方案:强制跳转(从  HTTP  到  HTTPS)的逻辑,应该只写在监听  80  端口的  server  块中。

      正确的配置示例:

              HTTP  站点  (80端口):负责将请求重定向到  HTTPS。

                ```nginx

                server  {

                        listen  80;

                        server_name  example.com;

                        #  所有HTTP请求都重定向到HTTPS

                        return  301  https://$server_name$request_uri;

                }

                ```

              HTTPS  站点  (443端口):处理加密请求,里面不要写重定向。

                ```nginx

                server  {

                        listen  443  ssl;

                        server_name  example.com;


                        ssl_certificate  /path/to/certificate.crt;

                        ssl_certificate_key  /path/to/private.key;


                        location  /  {

                                #  你的网站配置,如  proxy_pass  或  root

                        }

                }

                ```

        注意  `$server_name`  和  `$host`  的区别:中提到使用  `$host`;中提到使用  `$server_name`  可能因  CDN  等问题导致跳转地址错误,建议直接硬编码域名或使用  `$host`。

三、原因三:CDN(如  Cloudflare)配置问题

当使用  Cloudflare  等  CDN  时,问题可能出在  CDN  的  SSL/TLS  模式上。

      Flexible  模式陷阱:如果  Cloudflare  设置为  Flexible  模式,它用  HTTPS  连接用户,但用  HTTP  连接你的源服务器。如果你的  Nginx  配置了强制  HTTPS  跳转,就会收到来自  Cloudflare  的  HTTP  请求,然后  301  重定向到  HTTPS,Cloudflare  再用  HTTP  转发,无限循环。

              解决方案:

                1.    修改  Cloudflare  SSL/TLS  模式:在  Cloudflare  控制台,将  SSL/TLS  模式改为  Full  (strict)(完全严格)。此模式要求你的源服务器必须配置有效的  SSL  证书。

                2.    优化  Nginx  跳转规则:在  80  端口的  server  块中,增加对  `$http_x_forwarded_proto`  的判断,避免对已通过  CDN  加密的请求再次跳转。

                ```nginx

                server  {

                        listen  80;

                        server_name  example.com;

                        #  如果  CDN  透传的协议是  http,才进行跳转

                        if  ($http_x_forwarded_proto  =  "http")  {

                                return  301  https://example.com$request_uri;

                        }

                        #  对于直连的  HTTP  请求,也进行跳转

                        return  301  https://example.com$request_uri;

                }

                ```

四、原因四:多重重定向规则叠加

你的应用可能有多处都设置了重定向逻辑,比如  Nginx  设了一次,后端应用(如  WordPress、Django)又设了一次。

      解决方案:统一由  Nginx  负责  HTTPS  跳转,关掉后端应用内部的重定向功能。

五、原因五:浏览器缓存与  HSTS  影响

浏览器会强缓存301  永久重定向。即使你修复了服务器配置,浏览器可能依然“顽固”地执行旧的跳转规则。

      解决方案:

        1.    使用无痕/隐私模式访问网站,这是最快的验证方法。

        2.    清除浏览器缓存和所有历史数据。

        3.    清除  HSTS  设置:在  Chrome  地址栏输入  `chrome://net-internals/#hsts`,在“Delete  domain  security  policies”中输入你的域名并删除。

        4.    在重定向响应中添加禁用缓存的头(可选):

                ```nginx

                add_header  Cache-Control  "no-cache,  no-store,  must-revalidate";

                ```

六、排查步骤总结

1.    查看浏览器开发者工具:打开  Network  面板,观察请求链路,确认是  301/302  重定向,并查看  `Location`  地址是否在  HTTP  和  HTTPS  间反复横跳。

2.    审查  Nginx  配置文件:

              检查443  端口的  server  块内是否有  `return  301`  或  `rewrite...`  重定向指令。

              检查80  端口的  server  块是否正确配置了跳转到  HTTPS。

3.    检查后端应用配置:确认后端应用(如  Java、Python、Node.js  应用)是否开启了“信任代理”或正确读取了  `X-Forwarded-Proto`  头。

4.    检查  CDN  设置:如果使用  Cloudflare  等  CDN,确认  SSL/TLS  模式不是“Flexible”。

5.    使用  `curl`  命令测试:用  `curl  -I  http://your-domain.com`  和  `curl  -I  https://your-domain.com`  直接查看响应头,可以绕过浏览器缓存。

总结

解决  HTTPS  无限重定向的核心,是确保从浏览器到  Nginx  再到后端应用,整个链路对“当前请求是  HTTPS”这件事达成一致。

排查时请遵循“先看浏览器,再看  Nginx,然后查后端,最后考虑  CDN  和缓存”的顺序,通常能快速定位问题。