背景介绍

大家在使用 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. 面向对象(this关键字)

    package com_package2; public class Person3 { private int age; private String name; public int getAge ...

  2. ENFP喜欢的职业

    外向(E)+直觉(N)+情感(F)+知觉(P). 1. 设计:设计本身很能满足ENFP对工作的各种要求,但是有个附加条件就是,这份工作不能让ENFP长时间的一个人工作,没机会和别人交流,也就是说有一个 ...

  3. 【250】◀▶IEW-Unit15

    Unit 15 Youth Issues 1.model1题目分析 Young people who are still at school often feel just as much stres ...

  4. STL::next_permutation();

    next_permutation()可以按字典序生成所给区间的全排列. 在STL中,除了next_permutation()外,还有一个函数prev_permutation(),两者都是用来计算排列组 ...

  5. NFS资料

      Linux NFS服务器的安装与配置 http://www.cnblogs.com/mchina/archive/2013/01/03/2840040.html Linux NFS服务器的安装与配 ...

  6. # program once 用途 及与 ifndef使用异同

    在头文件中用这种写法就是为了该头文件被重复包含时不会出现符合重定义的错误. 效果等同于     #ifndef __xxx__     #define __xxx__     ...    #endi ...

  7. spring发布和接收定制的事件(spring事件传播)[转]

    有事件,即有事件监听器. 有人问你spring监听器有哪些你看了下文即也知道了.   事件传播 ApplicationContext基于Observer模式(java.util包中有对应实现),提供了 ...

  8. Jmeter接口自动化参数化 (转自软件测试部落)

    测试场景: 有个查询城市(大概一百个 )天气预报的接口(需求参考第一课),需要根据不同的citycode,去查询对应城市的天气预报,这种接口该如何去测试呢? 分析需求: 不管是功能测试需求,还是接口测 ...

  9. IT兄弟连 JavaWeb教程 AJAX常见问题

    1  中文乱码问题 ●  POST提交乱码 乱码原因:所有浏览器对Ajax请求参数都使用UTF-8进行编码,而服务器默认使用ISO-8859-1去解码,所以产生乱码. 解决方法:在服务器接收请求参数前 ...

  10. java利用URL发送get和post请求

    import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import ...