背景介绍

大家在使用 Nginx 部署网站时,实现 HTTP 到 HTTPS 的强制跳转是非常容易的事情,一般可以使用rewrite 命令或者使用返回自定义 301 页面的方法对 HTTP 请求进行 HTTPS 重定向。如果大家把 Nginx 服务器部署在 Azure 应用程序网关后端时,会发现如果原封不动的采取原先的方法进行重定向就无法正常工作。

本文通过讲述 Azure 应用程序网关的工作原理,向大家介绍一种在使用应用程序网关和 Nginx 的环境下实现强制 HTTPS 跳转的方法。

应用程序网关工作原理

Azure 应用程序网关采用的是类似于反向代理服务器的工作方式,客户端直接访问应用程序网关的公网地址而无法感知后端实际的服务器。当应用程序网关接收到客户端的请求之后,它会以自身实例在虚拟网络内部的地址作为源地址对后端池内部的服务器发起新的请求来获取数据,再将获取的数据通过原先跟客户端建立的连接返回给客户端。

如上图所示,我们部署了三台 Nginx 服务器在应用程序网关后端。应用程序网关部署在 AppGw 子网之内,Nginx 服务器部署在 Nginx 子网之内。应用程序网关本质上是由多个虚拟机实例组成的群集,默认情况下建立的应用程序网关包含两个实例,每个实例都会占用子网内的一个地址,如上图所示实例 -0 占用地址 192.168.0.4,实例 -1 占用地址 192.168.0.5。当客户端对应用程序网关发起请求时,Azure 前端的负载均衡器会将请求发送到对应的应用程序网关实例,应用程序网关上面的服务会以实例本身的内网地址向后端服务器发起新的请求。比如客户端的请求被发送到实例 -0,该实例会以 192.168.0.4 作为源地址对后端服务器发起请求。

应用程序网关转发机制

由于应用程序网关向后端服务器发起的请求改变了客户端请求的源地址,所以从 TCP 层面来讲,客户端的信息会丢失,但是从 HTTP 层面来讲这个信息并未丢失。这主要是因为应用程序网关会在 HTTP 包头内部添加 X-Forwarded 字段来记录客户端访问的源 IP、源端口、访问协议和请求的目的地址端口。

假设我们成功部署下面的环境,应用程序网关前端开启 80 端口走 HTTP 协议, 443 端口走 HTTPS 协议(同时完成 SSL 卸载),后端只开启 80 端口走 HTTP 协议(目前中国区 Azure 应用程序网关在后端只支持 HTTP 协议)。

当客户端通过 80 端口使用 HTTP 协议访问时,如果我们从后端服务器上面抓包,我们可以看到 HTTP 包头的 X-FORWARDED-PROTO 为 HTTP, X-FORWARDED-PORT 为 80,同时也会在 X-Forwarded-For 部分记录访问者的源 IP 和源端口(实际 IP 以 x.x.x.x 代替)。

 
Frame: Number = 32, Captured Frame Length = 649, MediaType = ETHERNET
+ Ethernet: Etype = Internet IP (IPv4),DestinationAddress:[00-17-FA-00-73-C4],SourceAddress:[44-03-A7-A4-3F-41]
+ Ipv4: Src = 192.168.0.4, Dest = 192.168.1.4, Next Protocol = TCP, Packet ID = 32620, Total IP Length = 635
+ Tcp: Flags=...AP..., SrcPort=58266, DstPort=HTTP(80), PayloadLen=595, Seq=518190070 - 518190665, Ack=447095254, Win=515 (scale factor 0x8) = 131840
- Http: Request, GET /
Command: GET
+ URI: /
UserAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Upgrade-Insecure-Requests: 1
X-FORWARDED-PROTO: http
X-FORWARDED-PORT: 80
X-Original-URL: /
X-Forwarded-For: x.x.x.x:64397
X-ARR-LOG-ID: 3f7b9b21-a862-4b62-a850-dc378bc3c843
HeaderEnd: CRLF

当客户端通过 443 端口使用 HTTPS 协议访问时,从下面的抓包可以看到应用程序网关完成了 SSL 卸载之后仍然是通过 HTTP 80 端口来访问后端服务器,但是会在 HTTP 包头的 X-FORWARDED-PROTO 记录原始访问是 HTTPS 请求以及原始访问是请求服务器的 443 端口。

 
Frame: Number = 36, Captured Frame Length = 700, MediaType = ETHERNET
+ Ethernet: Etype = Internet IP (IPv4),DestinationAddress:[00-17-FA-00-73-C4],SourceAddress:[44-03-A7-A4-3F-41]
+ Ipv4: Src = 192.168.0.4, Dest = 192.168.1.4, Next Protocol = TCP, Packet ID = 15961, Total IP Length = 686
+ Tcp: Flags=...AP..., SrcPort=57271, DstPort=HTTP(80), PayloadLen=646, Seq=375761782 - 375762428, Ack=1033546289, Win=511
- Http: Request, GET /
Command: GET
+ URI: /
UserAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Upgrade-Insecure-Requests: 1
X-FORWARDED-PROTO: https
X-FORWARDED-PORT: 443
X-Original-URL: /
X-Forwarded-For: x.x.x.x:64390
X-ARR-SSL: 2048|256|CN=FredTest|CN=FredTest
X-ARR-LOG-ID: e93508a5-5242-4f0d-a778-84630f71541b
HeaderEnd: CRLF

通过上面的分析,我们可以看到客户端的 HTTP 和 HTTPS 请求到达后端服务器都是 HTTP 请求,但是应用程序网关会在 HTTP 包头的 X-FORWARDED-PROTO 和 X-FORWARDED-PORT 中对这两种请求加以区分。

配置 Nginx 实现强制 HTTPS 转换

在未使用应用程序网关的场景下,我们一般可以在 Nginx 配置里使用类似于下面的 rewrite 命令来重定向客户端的 HTTP 请求。

 
server {
listen 80;
server_name www.abc.com
rewrite ^/(.*) https://$host$1 permanent;
}

但是在使用应用程序网关的场景下会发生问题,因为 Nginx 服务器本身虽然将这个请求重写为 HTTPS 请求,但是当新的 HTTPS 的请求再次经过应用程序网关到达后端服务器时又会变为 HTTP 请求从而导致死循环。解决此问题的办法就是需要在后端服务器上来判断客户的原始请求时 HTTP 还是 HTTPS,当客户的原始请求是 HTTP 时进行重定向,而当客户的原始请求是 HTTPS 时不进行重定向。通过前面的分析,我们已经知道可以通过 HTTP 包头的 X-FORWARDED-PROTO 来判断客户端的实际请求,而 Nginx 又会将字段 X-FORWARDED-PROTO 的值保存在变量 $http_x_forwarded_proto 中,这样我们就可以加入类似下面的判断语句来实现强制 HTTPS 跳转了。

 
server {
listen 80;
server_name www.abc.com
if ($http_x_forwarded_proto = 'http')
{
rewrite ^/(.*) https://$host$1 permanent;
}
}

通过这样的设置,当访问网站时我们可以看到服务器端返回了 301 并请求跳转到 HTTPS。

客户端再次通过 HTTPS 访问时,服务端不再返回 301 而是返回 200 表示访问成功。

立即访问http://market.azure.cn

【虚拟机-网关】如何在使用应用程序网关和 Nginx 的环境下实现强制 HTTPS 跳转的更多相关文章

  1. 利用宏定义实现C++程序在Unix和Win32环境下的通用性

    [转] 1.1. 宏定义软件的代码,从跨平台的角度来看,可以分为平台相关的和平台无关的.采用C/C++编写的软件,在进行移植时,平台无关的的代码基本上不需要做大的改动,但平台相关的代码需要做很大的调整 ...

  2. Azure-如何排查应用程序网关返回 HTTP Code 502 或客户端得到应用程序网关响应慢的问题(二)

    问题描述 经过如何排查应用程序网关返回 HTTP Code 502 或客户端得到应用程序网关响应慢的问题(一)中的排查步骤,可以判断出是由于 Web 服务器自身问题导致的响应异常. 那么可以在 IIS ...

  3. Taurus.MVC 微服务框架 入门开发教程:项目集成:1、服务端:注册中心、网关(提供可运行程序下载)。

    系列目录: 本系列分为项目集成.项目部署.架构演进三个方向,后续会根据情况调整文章目录. 本系列第一篇:Taurus.MVC V3.0.3 微服务开源框架发布:让.NET 架构在大并发的演进过程更简单 ...

  4. 深入Java微服务之网关系列1:什么是网关

    ​ 前言 近来,在想着重构一个新的产品.准备采用微服务的技术解决方案,来搭建基础设施框架.网关,是一个必不可少的组件.那么,网关到底是什么? 其又有什么特点或者特性,成为微服务必不可少的组件呢?今天, ...

  5. [移动网关]2G环境下资源下载有一定概率失败,客户端日志显示收到403错误

    2G环境下资源下载有一定概率失败,客户端日志显示收到403错误 问题现象: 测试同学在使用联通号码在移动网络环境下,访问连接得到的response_code出现是403,导致资源读取失败表情显示异常. ...

  6. 微服务架构学习与思考(11):开源 API 网关02-以 Java 为基础的 API 网关详细介绍

    微服务架构学习与思考(11):开源 API 网关02-以 Java 为基础的 API 网关详细介绍 上一篇关于网关的文章: 微服务架构学习与思考(10):微服务网关和开源 API 网关01-以 Ngi ...

  7. 西门子S7-200 SMART在win10环境下,使用虚拟机进行网络通信问题一二

    原来的笔记本光荣退休,新买了小米笔记本17150.有个项目需要使用西门子S7-200 SMART,结果碰到了很多悲催的事情,新系统下的各种问题. 先贴下计算机配置,如下: 阶段一:安装问题 (1)在w ...

  8. Taurus.MVC 微服务框架 入门开发教程:项目部署:5、微服务应用程序发布到Docker部署(下)。

    系列目录: 本系列分为项目集成.项目部署.架构演进三个方向,后续会根据情况调整文章目录. 开源地址:https://github.com/cyq1162/Taurus.MVC 本系列第一篇:Tauru ...

  9. Linux环境下部署完JDK后运行一个简单的Java程序

    前言 前一篇文章详细讲解了如何在Windows环境下安装虚拟机+Linux系统,并且成功部署了JDK. 不过部署完JDK之后,我们判断部署是否成功的依据是看"java -version&qu ...

随机推荐

  1. C++源码学习

    C/C++是最主要的编程语言.这里列出了50名优秀网站和网页清单,这些网站提供c/c++源代码.这份清单提供了源代码的链接以及它们的小说明.我已尽力包括最佳的C/C++源代码的网站.这不是一个完整的清 ...

  2. Spring入门第十四课

    基于注解的方式配置bean(基于注解配置Bean,基于注解来装配Bean的属性) 在classpath中扫描组件 组件扫描(component scanning):Spring能够从classpath ...

  3. 2018上海大都会 J-Beautiful Numbers(数位dp-模未知)

    J-Beautiful Numbers 链接:https://www.nowcoder.com/acm/contest/163/J 来源:牛客网 时间限制:C/C++ 8秒,其他语言16秒 空间限制: ...

  4. JavaScript DOM知识 (一)

    特性.方法 类型.返回类型 说明 nodeName String 节点的名字:根据节点类型而定义 nodeValue String 节点的值:根据节点的类型而定义 nodeType Number 节点 ...

  5. display:block inline-block inlined的区别

    一.首先要了解什么是块级元素与行级元素 块级元素 会占领页面的一行,其后多个block元素自动换行. 可以设置width,height,设置了width后同样也占领一行.同样也可以设置   margi ...

  6. cf791B(完全图&dfs)

    题目链接:http://codeforces.com/contest/791/problem/B 题意:给出一个无向图,问是否满足若存在边ab, bc则存在边ac: 思路:题意即,对于一个点,其所有子 ...

  7. 洛谷P3704 [SDOI2017]数字表格(莫比乌斯反演)

    传送门 yyb大佬太强啦…… 感觉还是有一点地方没有搞懂orz //minamoto #include<cstdio> #include<iostream> #include& ...

  8. 获取URL地址栏参数(正则表达式)

    ]] = isEncode ? decodeURIComponent(arg[2]) : arg[2]; }); return obj;}

  9. vue、React Nactive的区别(转载)

    Vue与React的对比 Vue.js与React.js从某些反面来说很相似,通过两个框架的学习,有时候对一些用法会有一点思考,为加深学习的思索,特翻阅了两个文档,从以下各方面进行了对比,加深了对这两 ...

  10. jQuery EasyUI/TopJUI创建树形表格下拉框

    jQuery EasyUI/TopJUI创建树形表格下拉框 第一种方法(纯HTML创建) <div class="topjui-row"> <div class= ...