nginx反向代理 https内部定向到http报302问题解决方案,【亲测】

本文介绍了一种客服系统的HTTPS改造方案,解决了因HTTP跳转导致的安全问题。通过在负载均衡器上配置SSL证书,并调整Nginx与Tomcat设置,确保所有内部通信使用一致的安全协议。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0. 环境信息

Linux:Linux i-8emt1zr1 2.6.32-573.el6.x86_64 #1 SMP Wed Jul 1 18:23:37 EDT 2015 x86_64 x86_64 x86_64 GNU/Linux

nginx:nginx version: openresty/1.9.3.2

Tomcat:Server version: Apache Tomcat/7.0.64

 

1. 问题描述
我们开发的客服系统,因为消息的到来,有的谷歌浏览器(V62)不支持http的消息提醒,要求https,故而,我们的系统,要将系统改造成https模式,另外,我们的系统,也有必要转化为https,为后续推广做准备。

 

2. 系统架构
LB+nginx+tomcat集群

 

3. 当前配置情况
SSL证书配置在LB上,nginx和tomcat服务器上,任然采用http协议通讯。即LB在接收到客户浏览器https请求消息后,将转发给LB下挂载的nginx上,都是以http的方式转发,nginx对这些请求进行反向代理,代理到后面的tomcat服务器上。

 

4. 遇到的问题
客服系统,有权限控制,基于tomcat的web应用,用户登录后,执行redirect跳转到指定的服务页面。就是这个跳转,遇到了问题,redirect在这里都被当做http跳转了

登录前的样子:

登录后的样子:

问题主要发生在Tomcat7上,验证过tomcat8,是不存在问题的。

 

5. 如何解决

针对Tomcat7的这个问题,思路很简单,重点是解决redirect的时候,通知客户端浏览器以正确的scheme(https还是http)进行再次发起请求。
问题是, nginx这个时候收到的请求是来自LB的http请求了,怎么弄?其实是有办法的,可以利用HttpRequest中的referer字段,这个字段的含义,自行科普吧。将referer的请求scheme信息,用来作为当前请求的scheme,如此可以保证所有的请求都是同一个scheme,不会因为redirect而遗漏信息。

nginx里面相应的配置如下:

复制代码
     location /CSS/websocket {
            proxy_pass http://css_ws_svr;
            proxy_set_header Host $host;
            proxy_set_header Remote_Addr $remote_addr;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }

        location /CSS {
            proxy_pass http://css_svr;
            proxy_set_header Host $host;
            proxy_set_header Remote_Addr $remote_addr;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            set $mscheme $scheme;
            if ($http_referer ~* ^https.*) {
                set $mscheme "https";
            }
            proxy_set_header X-Forwarded-Proto $mscheme;
        }
复制代码

如上配置,经过nginx反向代理后的HttpServletRequest中header部分就带上了字段X-Forwarded-Proto。

 

另外一方面,就是tomcat里面,要做一个配置,让tomcat在解析请求和做重定向的时候,知道用什么协议。主要的配置在server.xml里面的Engine下,定义一个Value元素。

具体配置如下:

复制代码
<Engine name="Catalina" defaultHost="localhost">

      
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <!-- This Realm uses the UserDatabase configured in the global JNDI
             resources under the key "UserDatabase".  Any edits
             that are performed against this UserDatabase are immediately
             available for use by the Realm.  -->
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>

      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
        
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log." suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

        <Valve className="org.apache.catalina.valves.RemoteIpValve" remoteIpHeader="X-Forwarded-For" protocolHeader="X-Forwarded-Proto" protocolHeaderHttpsValue="https"/>

        <Context path="/CSS" docBase="/home/tomcat/app/cssv2"/>
      </Host>
    </Engine>
复制代码

这个配置里面,重点是protocolHeader字段,意思就是说,当protocolHeader字段的值为protocolHeaderHttpsValue的https的时候,认为是安全连接,否则就是http的非安全连接。
对应的代码逻辑,可以看org.apache.catalina.valves.RemoteIpValve这个类的源码

复制代码
public void invoke(org.apache.catalina.connector.Request request, Response response)
 throws IOException, ServletException
{
......
if (protocolHeader != null) {
    String protocolHeaderValue = request.getHeader(protocolHeader);
    if (protocolHeaderValue != null)
    {

        if (protocolHeaderHttpsValue.equalsIgnoreCase(protocolHeaderValue)) {
            request.setSecure(true);
            
            request.getCoyoteRequest().scheme().setString("https");
        
            setPorts(request, httpsServerPort);
        } else {
            request.setSecure(false);
                
            request.getCoyoteRequest().scheme().setString("http");
                
            setPorts(request, httpServerPort);
        }
    }
}
......
}
复制代码

 

经过上面的分析和配置修改,最终很灵活的实现https和http同时工作。搞定这个问题,重点还是要对Http协议工作的流程有所了解,才能很容易的找到解决问题的思路。

若各位伙伴有更好的解决方案,也请分享或者一起探讨。

文章出处:https://www.cnblogs.com/shihuc/p/9047636.html

<think>我们遇到一个需求:将HTTP(80端口)的请求重定向HTTPS的8443端口(非默认443端口)。根据用户描述和引用内容,常规重定向到443端口的配置不适用,因为目标端口是8443。分析引用:引用[1]展示了常规80重定向到443的配置(使用rewrite指令)。引用[2]提供了一个实际案例:将8443端口的HTTPS请求重定向到443端口(注意这里是反向情况),同时包含80端口重定向到443的配置(使用if判断协议)。引用[3]展示了80端口重定向到443的标准配置(使用return指令)。目标需求:80端口重定向https://域名:8443配置关键点:1.在80端口的server块中,使用重定向指令(return或rewrite)指定目标URL为https://$host:8443$request_uri。2.注意:由于目标端口是非标准的8443,因此必须在重定向URL中显式指定端口号。配置示例:```nginx#HTTP80端口重定向HTTPS8443端口server{listen80;server_nameyourdomain.com;#替换为实际域名#方法1:使用return指令(推荐,效率更高)return301https://$host:8443$request_uri;#或方法2:使用rewrite指令(与引用[1]类似但端口不同)#rewrite^(.*)$https://$host:8443$1permanent;}#另外,需要有一个监听8443端口的HTTPSserver块来处理请求server{listen8443ssl;server_nameyourdomain.com;ssl_certificate/path/to/cert.pem;ssl_certificate_key/path/to/private.key;#...其他SSL配置和业务配置}```注意事项:1.确保在目标HTTPSserver块中正确配置了8443端口的监听(如上述第二个server块)。2.如果服务器防火墙或安全组设置限制了端口访问,请开放8443端口的入站访问。3.由于使用非标准端口,用户访问时必须携带端口号(如https://example.com:8443)。但通过重定向,用户只需输入http://example.com(或直接输入域名)即可自动跳转到https://example.com:8443。验证方法:使用curl命令试:```bashcurl-Ihttp://yourdomain.com```应返回类似以下响应头,其中Location字段应为https://yourdomain.com:8443/...:```HTTP/1.1301MovedPermanentlyServer:nginxLocation:https://yourdomain.com:8443/requested_uri...```补充说明:如果同时存在需要重定向到443端口的其他域名,可以配置多个server块,根据server_name区分。根据引用[2]中的配置,他们使用了不同的策略(将8443重定向到443,而80重定向到443)。但我们的需求正好相反(80重定向到8443),因此配置方向不同。引用参考:[1]使用rewrite指令实现80重定向到443(无端口号,默认443)[^1][2]展示了在非标准端口(8443)上监听HTTPS并重定向到标准端口(443)的配置,以及80重定向到443的配置[^2][3]使用return指令实现80重定向到443(标准方式)[^3]因此,我们调整重定向的目标URL,显式加入:8443端口即可满足需求。</think>### 配置Nginx将80端口重定向HTTPS 8443端口 根据您的需求,需要将HTTP(80端口)重定向HTTPS的**8443端口**(非默认443端口)。以下是完整解决方案: #### 📝 配置示例(nginx.conf) ```nginx # HTTP 80端口重定向HTTPS 8443端口 server { listen 80; server_name yourdomain.com; # 替换为您的域名 # 关键点:显式指定8443端口 return 301 https://$host:8443$request_uri; } # HTTPS 8443端口服务配置 server { listen 8443 ssl; # 监听8443端口 server_name yourdomain.com; ssl_certificate /path/to/fullchain.pem; # SSL证书路径 ssl_certificate_key /path/to/privkey.pem; # 私钥路径 # 其他SSL配置 ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; # ... 您的业务配置 } ``` #### 🔧 关键配置说明 1. **显式指定目标端口** ```nginx return 301 https://$host:8443$request_uri; ``` - `:8443` 明确指定重定向目标端口 - `$host` 变量自动获取请求域名 - `$request_uri` 保留原始请求路径和参数 2. **8443端口监听配置** ```nginx listen 8443 ssl; ``` - 必须确保Nginx监听8443端口的HTTPS请求 - 需要有效的SSL证书配置 3. **301永久重定向** 使用`301`状态码有利于SEO和浏览器缓存优化 #### ⚙️ 验证与试步骤 1. **检查配置语法** ```bash nginx -t ``` 2. **重载Nginx配置** ```bash systemctl reload nginx ``` 3. **试重定向效果** ```bash curl -I http://yourdomain.com ``` 应返回类似响应: ``` HTTP/1.1 301 Moved Permanently Location: https://yourdomain.com:8443/path ``` #### ⚠️ 注意事项 1. **防火墙设置** 确保服务器防火墙开放8443端口: ```bash ufw allow 8443/tcp ``` 2. **证书有效性** 确认SSL证书包含目标域名,且未过期 3. **浏览器缓存问题** 试时使用隐身模式或清除缓存 4. **多域名处理** 若需支持多个域名: ```nginx server { listen 80; server_name domain1.com domain2.com; return 301 https://$host:8443$request_uri; } ``` #### 💡 技术原理 当用户访问 `http://domain.com` 时: 1. 80端口的server块捕获请求 2. 返回301重定向响应头:`Location: https://domain.com:8443/path` 3. 浏览器自动向 `https://domain.com:8443` 发起新请求 4. 8443端口的server块处理HTTPS请求 > 配置参考: [^2] --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值