整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

基于 Nginx 的 HTTPS 性能优化实践

要: 随着相关浏览器对HTTP协议的“不安全”、红色页面警告等严格措施的出台,以及向 iOS 应用的 ATS 要求和微信、支付宝小程序强制 HTTPS 需求,以及在合规方面如等级保护对传输安全性的要求都在推动 HTTPS 的发展。

前言

分享一个卓见云的较多客户遇到HTTPS优化案例。

随着相关浏览器对HTTP协议的“不安全”、红色页面警告等严格措施的出台,以及向 iOS 应用的 ATS 要求和微信、支付宝小程序强制 HTTPS 需求,以及在合规方面如等级保护对传输安全性的要求都在推动 HTTPS 的发展。

虽然 HTTPS 优化了网站访问体验(防劫持)以及让传输更加安全,但是很多网站主赶鸭子上架式的使用了 HTTPS 后往往都会遇到诸如:页面加载速度变慢、服务器负载过高以及证书过期不及时更新等问题。

所以本文就来探讨一下 HTTPS 的优化实践。

选型

其实像 Apache Httpd、LigHttpd、Canddy 等 Web 服务软件都可以设置 HTTPS,但是在相应的扩展生态和更新率上都不如 Nginx。 Nginx 作为大型互联网网站的 Web 入口软件有着广泛的支持率,例如阿里系的 Tengine、CloudFlare 的 cloudflare-nginx、又拍云用的 OpenResty 都是基于 Nginx 而来的,Nginx 是接受过大规模访问验证的。同时大家也将自己开发的组件回馈给 Nginx 社区,让 Nginx 有着非常良好的扩展生态。

​ 图1-1 Nginx 在全网的使用情况

所以说 Nginx 是一款很好的 Web 服务软件,选择 Nginx 在提升性能的同时能极大的降低我们的扩展成本。

新功能

围绕 Web 服务已经有非常多的新功能需要我们关注并应用了,这里先罗列相关新功能。

HTTP/2

相比廉颇老矣的 HTTP/1.x,HTTP/2 在底层传输做了很大的改动和优化包括有:

  1. 每个服务器只用一个连接,节省多次建立连接的时间,在TLS上效果尤为明显
  2. 加速 TLS 交付,HTTP/2 只耗时一次 TLS 握手,通过一个连接上的多路利用实现最佳性能
  3. 更安全,通过减少 TLS 的性能损失,让更多应用使用 TLS,从而让用户信息更安全

在 Akamai 的 HTTP/2 DEMO中,加载300张图片,HTTP/2 的优越性极大的显现了出来,在 HTTP/1.X 需要 14.8s 的操作中,HTTP/2 仅需不到1s。

HTTP/2 现在已经获得了绝大多数的现代浏览器的支持。只要我们保证 Nginx 版本大于 1.9.5 即可。当然建议保持最新的 Nginx 稳定版本以便更新相关补丁。同时 HTTP/2 在现代浏览器的支持上还需要 OpenSSL 版本大于 1.0.2。

TLS 1.3

和 HTTP/1.x 一样,目前受到主流支持的 TLS 协议版本是 1.1 和 1.2,分别发布于 2006年和2008年,也都已经落后于时代的需求了。在2018年8月份,IETF终于宣布TLS 1.3规范正式发布了,标准规范(Standards Track)定义在 rfc8446。

TLS 1.3 相较之前版本的优化内容有:

  1. 握手时间:同等情况下,TLSv1.3 比 TLSv1.2 少一个 RTT
  2. 应用数据:在会话复用场景下,支持 0-RTT 发送应用数据
  3. 握手消息:从 ServerHello 之后都是密文。
  4. 会话复用机制:弃用了 Session ID 方式的会话复用,采用 PSK 机制的会话复用。
  5. 密钥算法:TLSv1.3 只支持 PFS (即完全前向安全)的密钥交换算法,禁用 RSA 这种密钥交换算法。对称密钥算法只采用 AEAD 类型的加密算法,禁用CBC 模式的 AES、RC4 算法。
  6. 密钥导出算法:TLSv1.3 使用新设计的叫做 HKDF 的算法,而 TLSv1.2 是使用PRF算法,稍后我们再来看看这两种算法的差别。

总结一下就是在更安全的基础上还做到了更快,目前 TLS 1.3 的重要实现是 OpenSSL 1.1.1 开始支持了,并且 1.1.1 还是一个 LTS 版本,未来的 RHEL8、Debian10 都将其作为主要支持版本。在 Nginx 上的实现需要 Nginx 1.13+。

Brotli

Brotli 是由 Google 于 2015 年 9 月推出的无损压缩算法,它通过用变种的 LZ77 算法,Huffman 编码和二阶文本建模进行数据压缩,是一种压缩比很高的压缩方法。

根据Google 发布的研究报告,Brotli 具有如下特点:

  1. 针对常见的 Web 资源内容,Brotli 的性能要比 Gzip 好 17-25%;
  2. Brotli 压缩级别为 1 时,压缩速度是最快的,而且此时压缩率比 gzip 压缩等级为 9(最高)时还要高;
  3. 在处理不同 HTML 文档时,brotli 依然提供了非常高的压缩率;

在兼容 GZIP 的同时,相较 GZIP:

  1. JavaScript 上缩小 14%
  2. HTML上缩小 21%
  3. CSS上缩小 17%

Brotli 的支持必须依赖 HTTPS,不过换句话说就是只有在 HTTPS 下才能实现 Brotli。

ECC 证书

椭圆曲线密码学(Elliptic curve cryptography,缩写为ECC),一种建立公开金钥加密的算法,基于椭圆曲线数学。椭圆曲线在密码学中的使用是在1985年由Neal Koblitz和Victor Miller分别独立提出的。

内置 ECDSA 公钥的证书一般被称之为 ECC 证书,内置 RSA 公钥的证书就是 RSA 证书。由于 256 位 ECC Key 在安全性上等同于 3072 位 RSA Key,加上 ECC 运算速度更快,ECDHE 密钥交换 + ECDSA 数字签名无疑是最好的选择。由于同等安全条件下,ECC 算法所需的 Key 更短,所以 ECC 证书文件体积比 RSA 证书要小一些。

ECC 证书不仅仅可以用于 HTTPS 场景当中,理论上可以代替所有 RSA 证书的应用场景,如 SSH 密钥登陆、SMTP 的 TLS 发件等。

不过使用 ECC 证书有两个点需要注意:

一、 并不是每一个证书类型都支持的,一般商业证书中带增强型字眼的才支持ECC证书的签发。

二、 ECC证书在一些场景中可能还不被支持,因为一些产品或者软件可能还不支持 ECC。 这时候就要虚线解决问题了,例如针对部分旧操作系统和浏览器不支持ECC,可以通过ECC+RSA双证书模式来解决问题。

安装

下载源码

综合上述我们要用到的新特性,我们整合一下需求:

HTTP/2 要求 Nginx 1.9.5+,,OpenSSL 1.0.2+

TLS 1.3 要求 Nginx 1.13+,OpenSSL 1.1.1+

Brotli 要求 HTTPS,并在 Nginx 中添加扩展支持

ECC 双证书 要求 Nginx 1.11+

这里 Nginx,我个人推荐 1.15+,因为 1.14 虽然已经能支持TLS1.3了,但是一些 TLS1.3 的进阶特性还只在 1.15+ 中提供。

然后我们定义一下版本号:

# Version
OpenSSLVersion='openssl-1.1.1a';
nginxVersion='nginx-1.14.1';

建议去官网随时关注最新版:

http://nginx.org/en/download.html

https://www.openssl.org/source/

https://github.com/eustas/ngx_brotli/releases

Nginx

cd /opt
wget http://nginx.org/download/$nginxVersion.tar.gz
tar xzf $nginxVersion.tar.gz

OpenSSL

cd /opt
wget https://www.openssl.org/source/$OpenSSLVersion.tar.gz
tar xzf $OpenSSLVersion.tar.gz

Brotli

cd /opt
git clone https://github.com/eustas/ngx_brotli.git
cd ngx_brotli
git submodule update --init --recursive

编译

cd /opt/$nginxVersion/
./configure \
--prefix=/usr/local/nginx \ ## 编译后安装的目录位置
--with-openssl=/opt/$OpenSSLVersion \ ## 指定单独编译入 OpenSSL 的源码位置
--with-openssl-opt=enable-tls1_3 \ ## 开启 TLS 1.3 支持
--with-http_v2_module \ ## 开启 HTTP/2 
--with-http_ssl_module \ ## 开启 HTTPS 支持
--with-http_gzip_static_module \ ## 开启 GZip 压缩
--add-module=/opt/ngx_brotli ## 编译入 ngx_BroTli 扩展
make && make install ## 编译并安装

后续还有相关变量设置和设置服务、开启启动等步骤,篇幅限制就省略了,这篇文章有介绍在 Ubuntu 下的 Nginx 编译:https://www.mf8.biz/ubuntu-nginx/ 。

配置

接下来我们需要修改配置文件。

HTTP2

listen 443 ssl http2;

只要在 server{} 下的lisen 443 ssl 后添加 http2 即可。而且从 1.15 开始,只要写了这一句话就不需要再写 ssl on 了,很多小伙伴可能用了 1.15+ 以后衍用原配置文件会报错,就是因为这一点。

TLS 1.3

ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;

如果不打算继续支持 IE8,或者一些合规的要求,可以去掉TLSv1。

然后我们再修改对应的加密算法,加入TLS1.3引入的新算法:

ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+ECDSA+AES128:EECDH+aRSA+AES128:RSA+AES128:EECDH+ECDSA+AES256:EECDH+aRSA+AES256:RSA+AES256:EECDH+ECDSA+3DES:EECDH+aRSA+3DES:RSA+3DES:!MD5;

如果不打算继续支持 IE8,可以去掉包含 3DES 的 Cipher Suite。

默认情况下 Nginx 因为安全原因,没有开启 TLS 1.3 0-RTT,可以通过添加 ssl_early_data on; 指令开启 0-RTT的支持。

————

实验性尝试

众所周知,TLS1.3 由于更新了很久,很多浏览器的旧版本依旧只支持 Draft 版本,如 23 26 28 分别在 Chrome、FirFox 上有支持,反而正式版由于草案出来很久,导致TLS1.3在浏览器上兼容性不少太好。

可以使用 https://github.com/hakasenyang/openssl-patch/ 提供的 OpenSSL Patch 让 OpenSSL 1.1.1 同时支持草案23,26,28和正式版输出。 不过由于不是官方脚本,稳定性和安全性有待考量。

ECC双证书

双证书配置的很简单了,保证域名的证书有RSA和ECC各一份即可。

 ##证书部分
 ssl_certificate /usr/local/nginx/conf/ssl/www.mf8.biz-ecc.crt; #ECC证书
 ssl_certificate_key /usr/local/nginx/conf/ssl/www.mf8.biz-ecc.key; #ECC密钥
 ssl_certificate /usr/local/nginx/conf/ssl/www.mf8.biz.crt; #RSA证书
 ssl_certificate_key /usr/local/nginx/conf/ssl/www.mf8.biz.key; #RSA密钥

Brotli

需要在对应配置文件中,添加下面代码即可:

 brotli on;
 brotli_comp_level 6;
 brotli_min_length 1k;
 brotli_types text/plain text/css text/xml text/javascript text/x-component application/json application/javascript application/x-javascript application/xml application/xhtml+xml application/rss+xml application/atom+xml application/x-font-ttf application/vnd.ms-fontobject image/svg+xml image/x-icon font/opentype;

为了防止大家看糊涂了,放一个完整的 server{}供大家参考:

 server {
 listen 443 ssl http2; # 开启 http/2
 server_name mf8.biz www.mf8.biz;
 
 #证书部分
 ssl_certificate /usr/local/nginx/conf/ssl/www.mf8.biz-ecc.crt; #ECC证书
 ssl_certificate_key /usr/local/nginx/conf/ssl/www.mf8.biz-ecc.key; #ECC密钥
 ssl_certificate /usr/local/nginx/conf/ssl/www.mf8.biz.crt; #RSA证书
 sl_certificate_key /usr/local/nginx/conf/ssl/www.mf8.biz.key; #RSA密钥
 
 #TLS 握手优化
 ssl_session_cache shared:SSL:1m;
 ssl_session_timeout 5m;
 keepalive_timeout 75s;
 keepalive_requests 100;
 
 #TLS 版本控制
 ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
 ssl_ciphers 'TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+ECDSA+AES128:EECDH+aRSA+AES128:RSA+AES128:EECDH+ECDSA+AES256:EECDH+aRSA+AES256:RSA+AES256:EECDH+ECDSA+3DES:EECDH+aRSA+3DES:RSA+3DES:!MD5';
 # 开启 1.3 o-RTT
 ssl_early_data on;
 
 # GZip 和 Brotli
 gzip on;
 gzip_comp_level 6;
 gzip_min_length 1k;
 gzip_types text/plain text/css text/xml text/javascript text/x-component application/json application/javascript application/x-javascript application/xml application/xhtml+xml application/rss+xml application/atom+xml application/x-font-ttf application/vnd.ms-fontobject image/svg+xml image/x-icon font/opentype;
 brotli on;
 brotli_comp_level 6;
 brotli_min_length 1k;
 brotli_types text/plain text/css text/xml text/javascript text/x-component application/json application/javascript application/x-javascript application/xml application/xhtml+xml application/rss+xml application/atom+xml application/x-font-ttf application/vnd.ms-fontobject image/svg+xml image/x-icon font/opentype;
 location / {
 root html;
 index index.html index.htm;
 }
 }

先验证一下配置文件是否有误:

nginx -t

如果反馈的是:

nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

就可以重启 Nginx ,然后到对应网站中去查看效果了。

验证

HTTP/2

通过浏览器的开发者工具,我们可以在 Network 栏目中看到 Protocol 中显示 h2 有无来判断。

TLS 1.3

老地方,我们可以通过浏览器的开发者工具 中的 Security 栏目看到 Connection 栏目下是否有显示 TLS 1.3

ECC 双证书

ECC 双证书配置了以后无非就是在旧浏览器设别上的验证了。这里用足够老的上古XP虚拟机来给大家证明一波。

XP系统上:

现代操作系统上的:

Brotli

通过浏览器的开发者工具,我们可以在 Network 栏目中,打开具体页面的头信息,看到 accept-encoding 中有 br 字眼就行。

总结

通过上述手段应该可以让 HTTPS 访问的体验优化不少,而且会比没做 HTTPS 的网站访问可能更快。

这样的模式比较适合云服务器单机或者简单集群上搭建,如果有应用 SLB 七层代理、WAF、CDN 这样的产品可能会让我们的这些操作都白费。 我们的这几项操作都是自建的 Web 七层服务,如果有设置 SLB 七层代理、WAF、CDN 这样设置在云服务器之前就会被覆盖掉。

由于 SLB 七层和CDN这样的产品会更加追求广泛的兼容性和稳定性并不会第一时间就用上上述的这些新特性(HTTP/2 是普遍有的),但是他们都配备了阿里云的 Tengine 的外部专用算法加速硬件如 Intel® QuickAssist Technology(QAT) 加速器可以显著提高SSL/TLS握手阶段性能。 所有 HTTPS 的加密解密都在 SLB 或 CDN 上完成,而不会落到ECS上,可以显著降低 ECS 的负载压力,并且提升访问体验。

目前云上的网络产品中能支持四层的都是可以继续兼容我们这套设计的,例如:SLB 的四层转发(TCP UDP)、DDOS高防的四层转发。

作者:妙正灰

ginx

一 为什么要用Nginx?

我们之前有分析过,单台服务器可能会遇到的问题,比如服务器宕机,或者并发用户太多,单台服务器不够等问题,所以需要集群架构,就是将项目部署到多台服务器。

但这样会出现新的问题:

  1. 用户发送的请求会被发送到哪台服务器?
  2. 如果是有软件帮助分发,怎么做到尽量均衡?

对于这些问题的出现,我们可以用Nginx来解决,除此以外,Nginx还可以帮助我们区分动态服务器和静态服务器。

二 Nginx是什么?

Nginx (engine x) 是一个高性能的Http服务器和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。它可以用做反向代理服务器,邮件服务器,实现负载均衡和动静分离。

稳定性强、丰富的功能集、简单的配置文件和低系统资源的消耗,占用内存少,并发能力强。

中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。

三 Nginx安装和配置

1.使用docker安装Nginx

 docker pull daocloud.io/library/nginx:latest

 docker images

docker run -d -p 80:80 --name nginx 29


2.Nginx核心配置文件

2.1 找到Nginx内部的配置文件

先进入Nginx容器内部

docker exec -it 容器id bash   #进入容器的终端,可以执行一些如ls pwd等一些简单的shell命令

再进入容器的etc/nginx目录下:

将nginx.conf文件的内容复制出来

2.2 nginx.conf文件结构


# 全局块
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


#events块
events {
    worker_connections  1024;
}



http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

全局块:

从配置文件开始到 events 块之间的内容,主要会设置一些影响nginx 服务器整体运行的配置指令,主要包括配置运行 Nginx 服务器的用户(组)、允许生成的 worker process 数,进程 PID 存放路径、日志存放路径和类型以及配置文件的引入等。

worker_processes  1   #这是 Nginx 服务器并发处理服务的关键配置,worker_processes 值越大,可以支持的并发处理量也越多,但是会受到硬件、软件等设备的制约。

events 块:

events 块涉及的指令主要影响 Nginx 服务器与用户的网络连接,常用的设置包括是否开启对多 work process 下的网络连接进行序列化,是否允许同时接收多个网络连接,选取哪种事件驱动模型来处理连接请求,每个 word process 可以同时支持的最大连接数等。 上述例子就表示每个 work process 支持的最大连接数为 1024. 这部分的配置对 Nginx 的性能影响较大,在实际中应该灵活配置。

http块:

http模块顾名思义,就是关于http服务请求的配置。这些配置包括http请求的文件类型(MIME-TYPE)的定义,http请求日志的输出,http连接的超时时长,单连接请求上限的配置。

http块的最后一句#include /etc/nginx/conf.d/*.conf ,是指引入了conf.d目录下的以.conf为结尾的配置文件。我们找到他们。

default.conf内容如下:

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

去掉注释部分

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

 
}

将其替换到nginx.conf文件中的include /etc/nginx/conf.d/*.conf,然后可以看到http块的内容为:

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       80;
        listen  [::]:80;
        server_name  localhost;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }

 
   }
}

http块结构包含:

server块: 每一个Server模块就是一个独立的虚拟主机,每个虚拟的主机可配置不同的域名或IP地址

今天主要介绍nginx的模块——ngx_http_proxy_module和ngx_http_upstream_module,严格来说,nginx自带是没有针对负载均衡后端节点的健康检查的,但是可以通过默认自带的ngx_http_proxy_module 模块和ngx_http_upstream_module模块中的相关指令来完成当后端节点出现故障时,自动切换到健康节点来提供访问。


01

ngx_http_proxy_module

反向代理( reverse proxy) 方式是指用代理服务器来接受 Internet 上的连接请求, 然后将请求转发给内部网络中的上游服务器, 并将从上游服务器上得到的结果返回给 Internet 上请求连接的客户端, 此时代理服务器对外的表现就是一个 Web 服务器。 充当反向代理服务器也是 Nginx 的一种常见用法( 反向代理服务器必须能够处理大量并发请求)。


由于Nginx具有“强悍”的高并发高负载能力, 因此一般会作为前端的服务器直接向客户端提供静态文件服务。 但也有一些复杂、 多变的业务不适合放到 Nginx 服务器上, 这时会用Apache、 Tomcat 等服务器来处理。 于是, Nginx 通常会被配置为既是静态Web服务器也是反向代理服务器( 如下图所示), 不适合Nginx处理的请求就会直接转发到上游服务器中处理。

ngx_http_proxy_module模块允许传送请求到其它服务器,也就是做反向代理。下面提供一个基本的配置示例:

location / {
  root /usr/share/nginx/html;
  proxy_redirect default;
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_connect_timeout 2;
  proxy_send_timeout 5;
  proxy_read_timeout 5;
  proxy_buffer_size 256k;
  proxy_buffers 4 256k;
  proxy_busy_buffers_size 256k;
  proxy_pass http://127.0.0.1:80;
}

ngx_http_proxy_module模块常用指令解释:

1)proxy_bind

Syntax: proxy_bind address [transparent] | off;
Default: —
Context: http, server, location
This directive appeared in version 0.8.22.


在调用connect()前将上游socket绑定到一个本地地址,如果主机有多个网络接口或别名,但是你希望代理的连接通过指定的接口或地址,可以使用这个指令。

透明传输模式允许传出连接到代理服务器起源于一个非本地IP地址,例如,从一个真实的IP地址的客户端 ︰

proxy_bind $remote_addr transparent;

为了使此参数工作,就必须以超级用户的特权运行nginx的工作进程和配置内核路由表拦截来自代理服务器的网络流量。

2)proxy_buffer_size

Syntax: proxy_buffer_size size;
Default:proxy_buffer_size 4k|8k;
Context:http, server, location

设置缓冲区的大小为size,nginx从被代理的服务器读取响应时,使用该缓冲区保存响应的开始部分。这部分通常包含着一个小小的响应头。该缓冲区大小默认等于proxy_buffers指令设置的一块缓冲区的大小,但它也可以被设置得更小。

3)proxy_buffers

Syntax: proxy_buffers number size;
Default:proxy_buffers 8 4k|8k;
Context:http, server, location

设置用于读取应答(来自被代理服务器)的缓冲区数目和大小,为每个连接设置缓冲区的数量是number参数,每块缓冲区的大小是size参数。这些缓冲区用于保存从被代理的服务器读取的响应。每块缓冲区默认等于一个内存页的大小。这个值默认是4K还是8K,取决于平台。

4)proxy_buffering

Syntax: proxy_buffering on | off;
Default:proxy_buffering on;
Context:http, server, location

代理的时候,开启或关闭缓冲后端服务器的响应。

当开启缓冲时,nginx尽可能快地从被代理的服务器接收响应,再将它存入proxy_buffer_size和proxy_buffers指令设置的缓冲区中。

如果响应无法整个纳入内存,那么其中一部分将存入磁盘上的临时文件。proxy_max_temp_file_size和proxy_temp_file_write_size指令可以控制临时文件的写入。

当关闭缓冲时,收到响应后,nginx立即将其同步传给客户端。nginx不会尝试从被代理的服务器读取整个请求,而是将proxy_buffer_size指令设定的大小作为一次读取的最大长度。

响应头“X-Accel-Buffering”传递“yes”或“no”可以动态地开启或关闭代理的缓冲功能。 这个能力可以通过proxy_ignore_headers指令关闭。

5)proxy_busy_buffers_size

Syntax: proxy_busy_buffers_size size;
Default:proxy_busy_buffers_size 8k|16k;
Context:http, server, location

当开启缓冲响应的功能以后,在没有读到全部响应的情况下,写缓冲到达一定大小时,nginx一定会向客户端发送响应,直到缓冲小于此值。

这条指令用来设置此值。 同时,剩余的缓冲区可以用于接收响应,如果需要,一部分内容将缓冲到临时文件。该大小默认是proxy_buffer_size和proxy_buffers指令设置单块缓冲大小的两倍。

6)proxy_max_temp_file

Syntax: proxy_max_temp_file_size size;
Default:proxy_max_temp_file_size 1024m;
Context:http, server, location

打开响应缓冲以后,如果整个响应不能存放在proxy_buffer_size和proxy_buffers指令设置的缓冲区内,部分响应可以存放在临时文件中。 这条指令可以设置临时文件的最大容量。

而每次写入临时文件的数据量则由proxy_temp_file_write_size指令定义。

将此值设置为0将禁止响应写入临时文件。

7)proxy_temp_file_write_size

Syntax: proxy_temp_file_write_size size;
Default:proxy_temp_file_write_size 8k|16k;
Context:http, server, location

在开启缓冲后端服务器响应到临时文件的功能后,设置nginx每次写数据到临时文件的size(大小)限制。 size的默认值是proxy_buffer_size指令和proxy_buffers指令定义的每块缓冲区大小的两倍, 而临时文件最大容量由 proxy_max_temp_file_size指令设置。

8)proxy_temp_path

Syntax: proxy_temp_path path [level1 [level2 [level3]]];
Default:proxy_temp_path proxy_temp;
Context:http, server, location

定义从后端服务器接收的临时文件的存放路径,可以为临时文件路径定义至多三层子目录的目录树。 比如,下面配置

proxy_temp_path /spool/nginx/proxy_temp 1 2;  

那么临时文件的路径看起来会是这样:

/spool/nginx/proxy_temp/7/45/00000123457

9)proxy_connect_timeout

Syntax: proxy_connect_timeout time;
Default:proxy_connect_timeout 60s;
Context:http, server, location

设置与后端服务器建立连接的超时时间,应该注意这个超时一般不可能大于75秒。默认为60s,建议生产环境连接时间设置为1到2s。

10)proxy_http_version

Syntax: proxy_http_version 1.0 | 1.1;
Default:proxy_http_version 1.0;
Context:http, server, location
This directive appeared in version 1.1.4.

设置代理使用的HTTP协议版本,默认使用的版本是1.0,而1.1版本则推荐在使用keepalive连接时一起使用。我接触的生产环境中都是设置http 1.1版本了。

11)proxy_ignore_client_abort

Syntax: proxy_ignore_client_abort on | off;
Default:proxy_ignore_client_abort off;
Context:http, server, location

决定当客户端在响应传输完成前就关闭连接时,nginx是否应关闭后端连接。

12)proxy_pass

Syntax: proxy_pass URL;
Default:—
Context:location, if in location, limit_except

设置后端服务器的协议和地址,还可以设置可选的URI以定义本地路径和后端服务器的映射关系。 这条指令可以设置的协议是“http”或者“https”,而地址既可以使用域名或者IP地址加端口(可选)的形式来定义:

proxy_pass http://localhost:8000/uri/;

对于URI可选,一般情况下使用是不需要指定的,除非你需要的访问方式就是这样的。

也可以使用UNIX域套接字路径来定义,该路径接在“unix”字符串后面,两端由冒号所包围,比如:

proxy_pass http://unix:/tmp/backend.socket:/uri/;

如果proxy_pass没有使用URI,传送到后端服务器的请求URI一般客户端发起的原始URI,如果nginx改变了请求URI,则传送的URI是nginx改变以后的完整规范化URI:

location /path/ {
  proxy_pass http://127.0.0.1;
}

虚拟路径代理就是,比如说访问”http://127.0.0.1/path/uri”地址,当匹配到这个location之后,通过”proxy_pass http://127.0.0.1/”代理到后端时,一个新的URL就成了”http://127.0.0.1/uri”这样。

其中的/path就称为虚拟路径,虚拟给用户的,后端没有真正的/path路径,这里要特别注意”proxy_pass http://127.0.0.1/”最后的”/”,如果没有这个”/”那么访问就会出现404,因为你没有给proxy_pass定义URI,所以不存在将规范化以后的请求路径(原始请求URI)与location配置中的路径的匹配部分将被替换为proxy_pass指令中定义的URI这一说法,切记。Nginx实现虚拟路径代理

注意

当使用一个正则表达式(~或~*)指定localtion时,在这种情况下,proxy_pass应该是一个没有URI的指令,如果指定了URI,那么代理到后端时,URI会被去掉,从而变成了http://127.0.0.1/some/path,也就是说原始访问URI不会做任何改变传送到后端。

还有一种情况,当URI使用rwrite重写指令后,在这种情况下,proxy_pass应该是一个没有URI的指令,如果指定了URI,那么代理到后端时,URI会被去掉,从而变成了http://127.0.0.1/some/path。

rewrite /name/([^/]+) /users?name=$1 break;

最后,这种以代理的工作方式,一般都会使用到Nginx upstream,以此来做负载均衡。这种情况下直接给定一个upstream的名称即可(需要先定义一个upstream),如下:

location / {
upstream test{
127.0.0.1:80;
}
proxy_pass http://test;
}


13)proxy_next_upstream

Syntax: proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 | 
http_403 | http_404 | non_idempotent | off ...;
Default:proxy_next_upstream error timeout;
Context:http, server, location

当你使用Nginx proxy代理时,如果是代理到后端是使用upstream,那么这个指令就是指定在何种情况下,一个失败的请求应该被发送到下一台后端服务器,有如下指令:

error – 和后端服务器建立连接时,或者向后端服务器发送请求时,或者从后端服务器读取响应时,出现错误;

timeout – 和后端服务器建立连接时,或者向后端服务器发送请求时,或者从后端服务器读取响应时,出现超时;

invalid_header – 后端服务器返回空响应或者非法响应头;

http_500 – 后端服务器返回的响应状态码为500;

http_502 – 后端服务器返回的响应状态码为502;

http_503 – 后端服务器返回的响应状态码为503;

http_504 – 后端服务器返回的响应状态码为504;

http_404 – 后端服务器返回的响应状态码为404;

off – 关闭proxy_next_upstream功能—出错就选择另一台上游服务器再次转发。

需要理解一点的是,只有在没有向客户端发送任何数据以前,将请求转给下一台后端服务器才是可行的。也就是说,如果在传输响应到客户端时出现错误或者超时,这类错误是不可能恢复的。

另外Nginx1.7开始提供了将请求传递给下一台服务器可以通过重试的次数和时间进行限制。

14)proxy_next_upstream_timeout

Syntax: proxy_next_upstream_timeout time;
Default:proxy_next_upstream_timeout 0;
Context:http, server, location
This directive appeared in version 1.7.5.

限制了重试请求可以被传递给下一台服务器的时间,默认值为0将关闭这一限制。

15)proxy_next_upstream_tries

Syntax: proxy_next_upstream_tries number;
Default:proxy_next_upstream_tries 0;
Context:http, server, location
This directive appeared in version 1.7.5.

限制了重试请求可以被传递给下一台服务器的次数,默认值为0将关闭这一限制。

16)proxy_read_timeout

Syntax: proxy_read_timeout time;
Default:proxy_read_timeout 60s;
Context:http, server, location

定义从后端服务器读取(接收)数据的超时时间(Nginx从客户端接收到请求,然后把数据包转发到后端服务器,后端服务器处理完请求后返回给Nginx服务器,Nginx接收后端数据包称为一次read),此超时是指相邻两次读操作之间的最长时间间隔,而不是整个响应传输完成的最长时间。如果后端服务器在超时时间段内没有传输任何数据,连接将被关闭。默认时间为60s,建议值为2-4s。

17)proxy_send_timeout

Syntax: proxy_send_timeout time;
Default:proxy_send_timeout 60s;
Context:http, server, location

定义向后端服务器发送一次数据包的超时时间(Nginx从客户端接收到请求,然后把数据包转发到后端服务器称为一次send),此超时是指相邻两次写操作之间的最长时间间隔,而不是整个请求传输完成的最长时间。

如果再向后端服务器发送数据包时,超过了超时时间的设置,那么连接将被关闭。默认时间为60s,建议值为2-4s。

18)proxy_set_header

Syntax: proxy_set_header field value;
Default:proxy_set_header Host $proxy_host;
proxy_set_header Connection close;
Context:http, server, location

允许重新定义或者添加发往后端服务器的请求头。value可以包含文本、变量或者它们的组合。 当且仅当当前配置级别中没有定义proxy_set_header指令时,会从上面的级别继承配置。 默认情况下,只有两个请求头会被重新定义:

proxy_set_header Host $proxy_host;
proxy_set_header Connection close;

如果不想改变请求头“Host”的值,可以这样来设置:

proxy_set_header Host $http_host;

但是,如果客户端请求头中没有携带这个头部,那么传递到后端服务器的请求也不含这个头部。 这种情况下,更好的方式是使用$host变量——它的值在请求包含“Host”请求头时为“Host”字段的值,在请求未携带“Host”请求头时为虚拟主机的主域名:

proxy_set_header Host $host;


此外,服务器名可以和后端服务器的端口一起传送:

proxy_set_header Host $host:$proxy_port;


如果某个请求头的值为空,那么这个请求头将不会传送给后端服务器:

proxy_set_header Accept-Encoding "";


proxy_add_x_forwarded_for内置变量,将proxy_add_x_forwarded_for内置变量,将remote_addr变量值添加在客户端“X-Forwarded-For”请求头的后面,并以逗号分隔。

如果客户端请求未携带“X-Forwarded-For”请求头,proxy_add_x_forwarded_for变量值将与proxy_add_x_forwarded_for变量值将与remote_addr变量相同。

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;


19)proxy_pass_header

Syntax: proxy_pass_header field;
Default:—
Context:http, server, location


允许指定跳过某些字段从代理服务器到客户端,一般用在CDN中传回来的字段信息,但不需要传回到后端服务器,就可以使用proxy_pass_header指令跳过。

20)proxy_redirect

Syntax: proxy_redirect default;
proxy_redirect off;
proxy_redirect redirect replacement;
Default:proxy_redirect default;
Context:http, server, location

设置后端服务器“Location”响应头和“Refresh”响应头的替换文本。 假设后端服务器返回的响应头是 “Location: http://localhost:8000/two/some/uri/”,那么指令

proxy_redirect http://localhost:8000/two/ http://frontend/one/;

将把字符串改写为 “Location: http://frontend/one/some/uri/”。


02

ngx_http_upstream_module

实例

upstream appservers { 
 zone appservers 64k; 
 #默认权重为1
 server appserv1.example.com weight=5; 
 server appserv2.example.com:8080 fail_timeout=5s slow_start=30s; 
 server 192.0.2.1 max_fails=3; 
 
 server reserve1.example.com:8080 backup; 
 server reserve2.example.com:8080 backup; 
} 
 
server { 
 location / { 
 proxy_pass http://appservers; 
 health_check; 
 } 
 
 location /upstream_conf { 
 upstream_conf; 
 allow 127.0.0.1; 
 deny all; 
 } 
} 

参数解释:

1.weight=number

设定服务器的权重,默认是1。

2.max_fails=number

设定Nginx与服务器通信的尝试失败的次数。

3.fail_timeout=time

设定

  • 统计失败尝试次数的时间段。在这段时间中,服务器失败次数达到指定的尝试次数,服务器就被认为不可用。
  • 服务器被认为不可用的时间段。

默认情况下,该超时时间是10秒。backup标记为备用服务器。当主服务器不可用以后,请求会被传给这些服务器。

4.down

标记服务器永久不可用,可以跟ip_hash指令一起使用。

5.route=string

设置服务器路由名称。


后面会分享更多devops和DBA方面的内容,感兴趣的朋友可以关注一下~