nginx系统学习【命令行参数、配置文件、SSL开启、负载均衡、请求处理过程】

目录

  1. 命令行参数
  2. 配置文件
  3. 服务器名称
  4. Nginx如何处理请求
  5. 使用Nginx作为HTTP负载均衡器
  6. 配置HTTPS服务器

一.命令行参数

nginx支持以下命令 行参数:

  • -?| -h :打印命令行参数帮助。

  • -c file :使用选择的配置file替代默认的文件。

  • -e file: 使用选的错误日志file来存储日志来取代默认的错误日志文件(1.19.5支持)。特殊值stderr选择标准错误文件。

  • -g directives:设置全局配置指令

    例如:

    nginx -g "pid /var/run/nginx.pid; worker_processes `sysctl -n hw.ncpu`;"
    
  • -p prefix: 设置nginx路径前缀,即nginx服务文件的目录(默认值为/usr/local/nginx)。

  • -q:在配置测试期间抑制非错误消息。

  • -s signal:向主进程发送信号。

    参数信号可以是以下之一:

    stop:快速关闭
    quit:正常关闭
    reload:重新加载配置,使用新配置启动新工作进程,并正常关闭旧工作进程。
    reopen:重新打开日志文件
    
  • -t :测试配置文件:nginx检查配置的语法是否正确,然后尝试打开配置中引用的文件。

  • -T :与-t相同,但另外将配置文件转储到标准输出(1.9.2)。

  • -v :打印nginx版本。

  • -V :打印nginx版本,编译器版本和配置参数。

二.配置文件

nginx有一个主进程和几个工作进程。主流程的主要目的是读取和评估配置,以及维护工作进程。工作进程对请求进行实际处理。nginx使用基于事件的模型和依赖于操作系统的机制来有效地在工作进程之间分配请求。工作进程的数量在配置文件中定义,可以针对给定的配置固定,也可以自动调整为可用CPU内核数。

nginx是由配置文件中指定的指令控制的模块组成的。指令分为简单指令和块指令。一个简单的指令由名称和参数组成,这些名称和参数之间用空格分隔,并以分号(;)结尾。块指令的结构与简单指令的结构相同,但是它不是以分号结尾,是以({})结尾的。如果块指令在括号内包含其他指令,则称为上下文(例如: eventshttpserverlocation)。

任何不在上下文中的指令被认为是在主上下文中,events、user、http是在主上下文中,server在http中,location在server中,此时server和location就不在主上下文中。

1.user

Syntax:	user user [group];
Default:	
user nobody nobody;
Context:	main

定义工作进程使用的user和group。如果group省略,则group就是user

2.error_log

Syntax:	error_log file [level];
Default:	
error_log logs/error.log error;
Context:	main, http, mail, stream, server, location

error_log file [level]

第一个参数定义存储日志文件的文件名。

第二个参数定义了日志的级别。所有的日志级别:debuginfonoticewarnerrorcritalert,或emerg。以上日志级别按严重性从低到高的顺序列出。设置某个日志级别将导致所有指定级别或更严重的日志级别的消息被记录下来。例如,设置日志级别error,将导致errorcritalert,和emerg都会被记录。如果省略此参数,则使用error`级别。

3.worker_processes(工作进程)

Syntax:	worker_processes number | auto;
Default:	
worker_processes 1;
Context:	main

定义工作进程数。

最佳值取决于许多因素,包括(但不限于)CPU内核数,存储数据的硬盘驱动器数以及加载模式。如有不清楚如何设置,则可以将其简单设置为可用的CPU内核数(值“ auto”会自动设置为CPU可用内核数)。

4.events

Syntax:	events { ... }
Default:	—
Context:	main

提供配置文件上下文,在其中指定影响连接处理的指令。

5.include

Syntax:	include file | mask;
Default:	—
Context:	any

将另外的配置文件引入当前的配置文件中,引入的配置文件语法要正确。

常用示例:

include mime.types;
include vhosts/*.conf;

6.pid

Syntax:	pid file;
Default:	
pid logs/nginx.pid;
Context:	main

定义一个文件,里面存储的是主进程的进程ID。

7.http

①location

语法详解

Syntax:	location [ = | ~ | ~* | ^~ ] uri { ... }
location @name { ... }
Default:	—
Context:	server, location

位置可以由前缀字符串或正则表达式定义。

  • location的搜索顺序。nginx首先检查使用前缀字符串定义的位置(前缀位置)。其中,将选择并记住具有最长匹配前缀的location。然后按照在配置文件中出现的顺序检查正则表达式。正则表达式的搜索在第一个匹配项上终止,并使用相应的location。如果未找到与正则表达式匹配的内容,则使用前面记住的最长匹配前缀的location。
  • 正则表达式由前面的“ ~*”修饰符(大小写不敏感)
  • 正则表达式由前面的“ ~”修饰符(大小写敏感)。
  • 如果最长的匹配前缀位置具有“ ^~”修饰符,则不检查正则表达式。
  • 用“ =”修饰符可以定义精确匹配。如果找到完全匹配的内容,搜索将终止,不在查找前缀字符最长匹配前缀,不再搜索正则。

让我们通过一个例子说明以上内容:

location = / {
    [ configuration A ]
}

location / {
    [ configuration B ]
}

location /documents/ {
    [ configuration C ]
}

location ^~ /images/ {
    [ configuration D ]
}

location ~* \.(gif|jpg|jpeg)$ {
    [ configuration E ]
}

 “ /”请求将与配置A匹配,
 “ /index.html”请求将与配置B匹配,
 “ /documents/document.html”请求将与配置C匹配,
 “ /images/1.gif”请求将与配置D匹配,
 “ /documents/1.jpg”请求将与配置E匹配。

@”前缀定义命名位置。这样的位置不用于常规请求处理,而是用于请求重定向。它们不能嵌套,也不能包含嵌套位置。

location /user/ {
    proxy_pass http://user.example.com;
}

location /user {
    proxy_pass http://login.example.com;
}

[302重定向]访问ip/user/的时候,浏览器中ip/user/的地址保持不变,实际的网页内容已经变为http://user.example.com的内容
[301重定向]访问ip/user的时候,浏览器中ip/user的地址变为http://login.example.com,实际的网页内容已经变为http://login.example.com的内容
location /user/ {
    proxy_pass http://user.example.com;
}

location = /user {
    proxy_pass http://login.example.com;
}

[302重定向]访问ip/user/的时候,浏览器中ip/user/的地址保持不变,实际的网页内容已经变为http://user.example.com的内容
[302重定向]访问ip/user的时候,浏览器中ip/user/的地址保持不变,实际的网页内容已经变为http://login.example.com的内容

301和302状态码详解

概述

301 Moved Permanently 代表永久性转移,资源被移动到新地址,旧地址弃用。

302 Temporarily Moved 代表暂时性转移

301表示旧地址A的资源已经被永久地移除了(这个资源不可访问了),搜索引擎在抓取新内容的同时也将旧的网址交换为重定向之后的网址。

302表示旧地址A的资源还在(仍然可以访问),这个重定向只是临时地从旧地址A跳转到地址B,搜索引擎会抓取新的内容而保存旧的网址。

使用场景

301使用场景:
  1. 域名到期不想续费(或者发现了更适合网站的域名),想换个域名。
  2. 在搜索引擎的搜索结果中出现了不带www的域名,而带www的域名却没有收录,这个时候可以用301重定向来告诉搜索引擎我们目标的域名是哪一个。
  3. 空间服务器不稳定,换空间的时候。

302使用场景

  1. 比如未登陆的用户访问用户中心重定向到登录页面。
  2. 访问404页面会重新定向到首页

尽可能的使用301,使用302可能发生网址劫持

网址劫持:从网址A 做一个302 重定向到网址B 时,主机服务器的隐含意思是网址A 随时有可能改主意,重新显示本身的内容或转向其他的地方。大部分的搜索引擎在大部分情况下,当收到302 重定向时,一般只要去抓取目标网址就可以了,也就是说网址B。如果搜索引擎在遇到302 转向时,百分之百的都抓取目标网址B 的话,就不用担心网址URL 劫持了。问题就在于,有的时候搜索引擎,尤其是Google,并不能总是抓取目标网址。比如说,有的时候A 网址很短,但是它做了一个302 重定向到B 网址,而B 网址是一个很长的乱七八糟的URL 网址,甚至还有可能包含一些问号之类的参数。很自然的,A 网址更加用户友好,而B 网址既难看,又不用户友好。这时Google 很有可能会仍然显示网址A。由于搜索引擎排名算法只是程序而不是人,在遇到302 重定向的时候,并不能像人一样的去准确判定哪一个网址更适当,这就造成了网址URL 劫持的可能性。也就是说,一个不道德的人在他自己的网址A 做一个302 重定向到你的网址B,出于某种原因, Google 搜索结果所显示的仍然是网址A,但是所用的网页内容却是你的网址B 上的内容,这种情况就叫做网址URL 劫持。你辛辛苦苦所写的内容就这样被别人偷走了。302 重定向所造成的网址URL 劫持现象,已经存在一段时间了。不过到目前为止,似乎也没有什么更好的解决方法。在正在进行的谷歌大爸爸数据中心转换中,302 重定向问题也是要被解决的目标之一。从一些搜索结果来看,网址劫持现象有所改善,但是并没有完全解决。

niginx 301/302配置

rewrite后面接上permenent就代表301跳

//把来自veryyoung.me的请求301跳到 www.veryyoung.me
if ($host != 'veryyoung.me') {
 rewrite ^/(.*)$ http://www.veryyoung.me/$1 permanent;
}

redirect就代表302跳

//把来自veryyoung.me的请求302跳到 www.veryyoung.me
if ($host != 'veryyoung.me') {
 rewrite ^/(.*)$ http://www.veryyoung.me/$1 redirect;
}

参考:https://www.cnblogs.com/weixuechao/p/12131444.html

具体使用

Web服务器的一项重要任务是分发文件(例如图像或静态HTML页面)。您将实现一个示例,其中将根据请求从不同的本地目录提供文件:(/data/www 可能包含HTML文件)和/data/images (包含图像)。这将需要编辑配置文件,并 在 带有两个location 块的http块内设置 server块。

首先,创建/data/www目录并在其中放置index.html包含任何文本内容的文件,然后创建/data/images目录并在其中放置一些图像。

http {
 server {
     location / {
         root /data/www;
     }

     location /images/ {
         root /data;
     }
 }
}

解释

location /块指定“ /”前缀。对于匹配的请求,会将URI添加到root 指令中指定的路径 ,即添加到/data/www,以形成本地文件系统上所请求文件的路径。如果有多个匹配的location块,nginx将选择前缀最长的块location /的块提供了最短的前缀,长度为1,因此只有当所有其他location 块都不能提供匹配项时,才会使用该块。

location /images/块将匹配以/images/ 开头的请求(location /也匹配此类请求,但前缀较短,所以忽略)。

nginx默认在标准端口80上侦听,并且可以在本地计算机上访问 http://localhost/。响应以/images/开头的URI请求,服务器将从/data/images目录中发送文件。例如,响应 http://localhost/images/example.png请求,nginx将发送/data/images/example.png文件。如果该文件不存在,nginx将发送一个指示404错误的响应。URI不以/images/开头的请求将被导入到location /块中,然后映射到/data/www目录中。例如,响应 http://localhost/some/example.html请求,nginx将发送/data/www/some/example.html文件。

②代理服务器

nginx的一种常用用法是将其设置为代理服务器,这意味着服务器可以接收请求,然后将请求传递给代理服务器,从请求中检索响应并将它们发送给客户端。

我们将配置一个基本的代理服务器,该服务器为图像请求和本地目录中的文件提供服务,并将所有其他请求发送到代理服务器。

server {
 listen 8080;
 root /data/up1;

 location / {
 }
}

此时会监听8080端口的请求,并且把请求路由到location /块中,最终访问/data/up1文件夹中的内容。

注意:由于此时location /块中没有root选项,此时location /默认使用的是server上下文中的root参数,所以会访问/data/up1文件夹中的内容

接下来在第一个location块中,将 proxy_pass 指令设置指定的代理服务器的协议,名称和端口

server {
 location / {
     proxy_pass http://localhost:8080;
 }

 location /images/ {
     root /data;
 }
}

我们将修改第二个location 块,该块当前是将带有/images/ 前缀的请求映射到目录下的/data/images文件夹,现在将其更改为符合一定正则规则的location块。

location ~ \.(gif|jpg|png)$ {
 root /data/images;
}

该参数是一个正则表达式,匹配所有URI以 .gif.jpg.png结尾的。正则表达式应以开头~。相应的请求将被映射到/data/images 目录。当nginx选择一个location块来匹配服务请求时,它首先检查指定前缀的location指令,记住location 最长的前缀,然后检查正则表达式。如果存在与正则表达式匹配的内容,则nginx会优先选择正则匹配项location,否则,它将选择之前记住的匹配项 。

代理服务器的最终配置如下所示:

server {
 location / {
     proxy_pass http://localhost:8080/;
 }

 location ~ \.(gif|jpg|png)$ {
     root /data/images;
 }
}

该服务器将过滤以.gif.jpg.png 结束的请求,并将它们映射到/data/images目录,并将所有其他请求通过location /传递到上面配置的代理服务器。

三.服务器名称

1.服务器名称的形式

server {
listen       80;
server_name  example.org  www.example.org;
...
}

server {
listen       80;
server_name  *.example.org;
...
}

server {
listen       80;
server_name  mail.*;
...
}

server {
listen       80;
server_name  ~^(?<user>.+)\.example\.net$;
...
}

当通过server_name是搜索server的时候,如果有多个符合条件,则按照下面的顺序进行选择server

  1. 确切的名字的server
  2. 以星号开头的最长通配符名称,例如“ *.example.org
  3. 以星号结尾的最长的通配符名称,例如“ mail.*
  4. 第一个匹配的正则表达式(在配置文件中出现的顺序)

2.通配符名称

通配符名称只能在名称的开头或结尾以及点边界上包含星号。名称“ www.*.example.org”和“ w*.example.org”是无效的。

但是,可以使用正则表达式指定这些名称,例如“ ~^www\..+\.example\.org$”和“ ~^w.*\.example\.org$”。

星号可以匹配多个名称部分。名称“ *.example.org”不仅匹配www.example.org而且也匹配www.sub.example.org`

.example.org可以认为是特殊形式的通配符server名字,不仅可以匹配确切名称的“ example.org”,而且可以匹配下面的“ *.example.org”。

3.正则表达式名称

nginx使用的正则表达式与Perl编程语言(PCRE)使用的正则表达式兼容。要使用正则表达式,服务器名称必须以波浪号字符开头

server_name ~^www\d+.example.net$;

否则,它将被视为确切的名称,或者如果表达式包含星号,则将其视为通配符名称(并且最有可能被视为无效的名称)。不要忘记设置“ ^”和“ $”,在语法上不是必需的,但在逻辑上是必需的。另请注意,域名点应以反斜杠转义。包含字符“ {”和“ }”的正则表达式应加引号:

server_name "~^(?\w\d{1,3}+).example.net$";

否则,nginx将无法启动并显示错误消息:

directive "server_name" is not terminated by ";" in ...

命名的正则表达式捕获可以在以后用作变量:

server {
    server_name   ~^(www\.)?(?<domain>.+)$;

    location / {
        root   /sites/$domain;
    }
}

PCRE库支持使用以下语法名字捕获:

?<name>Perl 5.10 compatible syntax, supported since PCRE-7.0
?'name'Perl 5.10 compatible syntax, supported since PCRE-7.0
?P<name>Python compatible syntax, supported since PCRE-4.0

如果nginx无法启动并显示错误消息:

pcre_compile() failed: unrecognized character after (?< in ...

这意味着PCRE库较旧, ?P<name>语法太新了。捕获也可以以数字形式使用:

server {
    server_name   ~^(www\.)?(.+)$;

    location / {
        root   /sites/$2;
    }
}

但是,这种用法应限于简单的情况(如上述情况),因为数字参考很容易被覆盖。

4. 杂项名称

有些服务器名称经过特殊处理。

如果要处理的请求的"Host"属性是空的,server 块中应指定一个空名称:

server {
 listen       80;
 server_name  example.org  www.example.org  "";
 ...
}

如果 在server块中未定义server_name,则nginx使用空名称作为服务器名称。

在这种情况下,最高0.8.48的nginx版本将机器的主机名用作服务器名。

如果服务器名称定义为“ $hostname”(0.9.4),则使用计算机的主机名。

如果有人使用IP地址而不是server_name发出请求,则“Host”请求标头字段将包含IP地址,并且可以使用IP地址作为服务器名称来处理请求:

server {
    listen       80;
    server_name  example.org
                 www.example.org
                 ""
                 192.168.1.1
                 ;
    ...
}

有时候在server_name中会看到一个奇怪的名字“ _”:

server {
    listen       80  default_server;
    server_name  _;
    return       444;
}

这个名称没有什么特别的,它只是无效域名之一。同样可以使用其他无效名称,例如“ --”和“ !@#”。

直到0.6.25的nginx版本都支持特殊名称“ *”,该名称被错误地解释为通用名称。它从不用作通用或通配符服务器名称。

详细请看:http://nginx.org/en/docs/http/server_names.html#miscellaneous_names

可以定义侦听端口*:80和*:8080的服务器,并指示其中一个将是端口*:8080的默认服务器,而另一个将是端口*:80的默认服务器:

server {
    listen       80;
    listen       8080  default_server;
    server_name  example.net;
    ...
}

server {
    listen       80  default_server;
    listen       8080;
    server_name  example.org;
    ...
}

5.国际化名称

Internationalized domain names (IDNs) should be specified using an ASCII (Punycode) representation in the server_name directive:

server {
    listen       80;
    server_name  xn--e1afmkfd.xn--80akhbyknj4f;  # пример.испытание
    ...
}

6.优化

确切名称,以星号开头的通配符名称和以星号结尾的通配符名称存储在绑定到侦听端口的三个哈希表中。哈希表的大小在配置阶段进行了优化,以便可以找到花费最少的CPU缓存查找。设置哈希表的详细信息在单独的文档中提供 。

首先搜索确切名称哈希表。如果未找到名称,则搜索具有以星号开头的通配符名称的哈希表。如果在此处找不到名称,则搜索带有通配符名称以星号结尾的哈希表。

搜索通配符名称哈希表比搜索精确名称哈希表要慢,因为名称是按域部分搜索的。请注意,特殊的通配符形式“ .example.org”存储在通配符名称哈希表中,而不存储在确切的名称哈希表中。

正则表达式是按顺序测试的,因此是最慢的方法,并且不可缩放。

由于这些原因,最好在可能的地方使用确切的名称。例如,如果服务器最常请求的名称是example.orgwww.example.org,则显式定义它们的效率更高:

server {
 listen       80;
 server_name  example.org  www.example.org  *.example.org;
 ...
}

而不是使用简化形式:

server {
 listen       80;
 server_name  .example.org;
 ...
}

如果定义了大量服务器名称,或者定义了异常长的服务器名称,则可能有必要 在http级别调整server_names_hash_max_sizeserver_names_hash_bucket_size指令。server_names_hash_bucket_size 伪指令的默认值 可以等于32或64,或其他值,具体取决于CPU缓存行大小。如果默认值为32,并且服务器名称定义为“ too.long.server.name.example.org”,则nginx将无法启动并显示错误消息:

could not build the server_names_hash,
you should increase server_names_hash_bucket_size: 32

在这种情况下,指令值应增加到下一个2的幂:

http {
 server_names_hash_bucket_size  64;
 ...

如果定义了大量服务器名称,则会出现另一条错误消息:

could not build the server_names_hash,
you should increase either server_names_hash_max_size: 512
or server_names_hash_bucket_size: 32

在这种情况下,首先尝试将server_names_hash_max_size设置为接近服务器名称数量的数字。只有前面操作无济于事或nginx的启动时间过长而无法接受时,请尝试增加 server_names_hash_bucket_size

如果server是listen端口的唯一server,则nginx根本不会测试server_name(并且不会为listen端口构建哈希表)。但是,有一个例外。如果服务器名称是带有捕获的正则表达式,则nginx必须执行该表达式以获取捕获。

7.兼容性

  • $hostname从0.9.4开始支持 特殊服务器名称“ ”。
  • 自0.8.48起,默认的服务器名称值为空名称“”。
  • 从0.8.25开始,已支持命名正则表达式服务器名称捕获。
  • 从0.7.40开始,支持正则表达式服务器名称捕获。
  • 从0.7.12开始,支持空服务器名称“”。
  • 自0.6.25开始,已支持使用通配符服务器名称或正则表达式作为第一个服务器名称。
  • 从0.6.7开始,支持正则表达式服务器名称。
  • example.*自0.6.0开始支持 通配符格式。
  • .example.org自0.3.18开始支持 特殊格式。
  • *.example.org从0.1.13开始支持 通配符格式。

英文原义:

  • The special server name “$hostname” has been supported since 0.9.4.
  • A default server name value is an empty name “” since 0.8.48.
  • Named regular expression server name captures have been supported since 0.8.25.
  • Regular expression server name captures have been supported since 0.7.40.
  • An empty server name “” has been supported since 0.7.12.
  • A wildcard server name or regular expression has been supported for use as the first server name since 0.6.25.
  • Regular expression server names have been supported since 0.6.7.
  • Wildcard form example.* has been supported since 0.6.0.
  • The special form .example.org has been supported since 0.3.18.
  • Wildcard form *.example.org has been supported since 0.1.13.

四.Nginx如何处理请求

1.简单配置

让我们从一个简单的配置开始,其中所有三个虚拟服务器都在端口*:80上侦听

server {
listen      80;
server_name example.org www.example.org;
...
}

server {
listen      80;
server_name example.net www.example.net;
...
}

server {
listen      80;
server_name example.com www.example.com;
...
}

在此配置中,nginx仅通过request headers中的Host属性来决定将请求路由到哪个server。如果没有匹配的server或者Host属性为空,则nginx会将请求路由到该端口的默认服务器。在上面的配置中默认服务器是第一个server,这是nginx默认决定的。同时可以在listen指令中使用default_server参数来明确设置哪个服务器应该是默认服务器。如下设置:

server {
listen      80 default_server;
server_name example.net www.example.net;
...
}

default_server参数自0.8.21版本开始可用。在早期版本中,应改为使用default参数。

请注意,默认服务器是listen的属性,而不是server_name的属性。

如何防止使用未定义的服务器名称处理请求
server {
   listen      80;
   server_name "";
   return      444;
}

在这里,服务器名称设置为空字符串,该字符串将与没有“ Host”标头字段的请求进行匹配,并且返回特殊的nginx的非标准代码444,以关闭连接。

2.基于名称和基于IP的混合虚拟服务器

让我们看一个更复杂的配置,其中一些虚拟服务器侦听不同的地址:

server {
 listen      192.168.1.1:80;
 server_name example.org www.example.org;
 ...
}

server {
 listen      192.168.1.1:80;
 server_name example.net www.example.net;
 ...
}

server {
 listen      192.168.1.2:80;
 server_name example.com www.example.com;
 ...
}

在上面这种配置中,nginx首先根据Server块的listen指令来测试request的IP地址和端口 。然后,根据匹配的server块的server_name 属性测试request headers的“Host”属性 。如果找不到匹配的server,则由默认服务器处理该请求。

例如,一个请求从192.168.1.1:80发出,其Host为www.example.com,此时这个请求将由192.168.1.1:80端口的默认服务器(即第一台服务器)处理,因为192.168.1.1:80匹配之后,再去匹配server_name,此时没有匹配上,进而由192.168.1.1:80的默认服务器,即第一台服务器进行请求处理。

如果设置了默认服务器

server {
 listen      192.168.1.1:80;
 server_name example.org www.example.org;
 ...
}

server {
 listen      192.168.1.1:80 default_server;
 server_name example.net www.example.net;
 ...
}

server {
 listen      192.168.1.2:80 default_server;
 server_name example.com www.example.com;
 ...
}

上面的请求此时就会被192.168.1.1:80的第二个server接手处理。

3.简单的请求配置

server {
 listen      80;
 server_name example.org www.example.org;
 root        /data/www;

 location / {
     index   index.html index.php;
 }

 location ~* \.(gif|jpg|png)$ {
     expires 30d;
 }

 location ~ \.php$ {
     fastcgi_pass  localhost:9000;
     fastcgi_param SCRIPT_FILENAME
                   $document_root$fastcgi_script_name;
     include       fastcgi_params;
 }
}

无论location的顺序如何,nginx首先搜索文字字符串给定的最特定的前缀位置。在上面的配置中,唯一的前缀位置是“ /”,由于它与任何请求匹配,因此将被用作最后备用的手段。然后,nginx按照配置文件中列出的顺序检查与正则表达式匹配的,第一个匹配的表达式将停止搜索,nginx将使用此location。如果没有正则表达式与请求匹配,则nginx使用较早发现的最特定的前缀位置。

请注意,所有的location匹配的是没有参数的请求行的URI部分

例如:请求是/index.php?user=john&page=1,此时匹配的是index.php

现在让我们看一下在上面的配置中如何处理请求:

  • 请求“ /logo.gif”首先与前缀位置“ /”匹配,然后与正则表达式“ \.(gif|jpg|png)$”匹配,因此,请求由后一个位置处理。使用server中的指令“ root /data/www”将请求映射到文件/data/www/logo.gif,然后将文件发送到客户端。
  • 请求“ /index.php”也首先与“ /”前缀的location匹配,然后与正则表达式“ \.(php)$”也匹配。因此,它由后一个位置处理,并将请求传递到侦听localhost:9000的FastCGI服务器。该 fastcgi_param 指令设置FastCGI的参数 SCRIPT_FILENAME为“ /data/www/index.php”,并FastCGI的服务器执行文件。该变量$document_root等于root 指令的值, 并且该变量$fastcgi_script_name等于请求URI,即“ /index.php”。
  • 请求“ /about.html”仅与前缀location“ /”匹配,因此在该位置进行处理。使用指令“ root /data/www”将请求映射到文件/data/www/about.html,然后将文件发送到客户端。
  • 处理请求“ /”更为复杂。它仅与前缀位置“ /”匹配,因此,由该位置处理。然后, index 指令根据其参数和“ root /data/www”指令测试索引文件的存在。如果该文件/data/www/index.html不存在,并且该文件/data/www/index.php存在,则该指令将内部重定向到“ /index.php”,并且nginx再次搜索位置,就好像该请求是由客户端发送一样。如前所述,重定向的请求最终将由FastCGI服务器处理。

五.使用Nginx作为HTTP负载均衡器

跨多个应用程序实例的负载平衡是一种用于优化资源利用率,最大化吞吐量,减少延迟和确保容错配置的常用技术。

可以将nginx用作非常有效的HTTP负载平衡器,以将流量分配到多个应用程序服务器,并使用nginx改善Web应用程序的性能,可伸缩性和可靠性。

1.负载均衡方法

  • 轮询--对应用服务器发起的请求以轮询的方式分发,
  • 最少连接--将下一个请求分配给活动连接数量最少的服务器,
  • ip-hash--使用哈希函数确定下一个请求选择哪个服务器(基于客户端的IP地址)。

2.轮询、默认负载平衡配置

使用nginx进行负载平衡的最简单配置如下所示:

http {
 upstream myapp1 {
     server srv1.example.com;
     server srv2.example.com;
     server srv3.example.com;
 }

 server {
     listen 80;

     location / {
         proxy_pass http://myapp1;
     }
 }
}

在上面的示例中,同一应用程序的3个实例在srv1-srv3上运行。如果未特别配置负载平衡方法,则默认为轮询。所有请求都被 proxy_pass到服务器组myapp1,nginx应用HTTP负载平衡来分发请求。

nginx中的反向代理实现包括HTTP,HTTPS,FastCGI,uwsgi,SCGI,memcached和gRPC的负载平衡。

要为HTTPS(而非HTTP)配置负载平衡,只需使用“ https”作为协议。

为FastCGI,uwsgi,SCGI,memcached或gRPC设置负载平衡时,请分别使用 fastcgi_passuwsgi_passscgi_passmemcached_passgrpc_pass 指令。

3.最少连接的负载平衡

另一个负载平衡原则是连接最少的。最少连接允许在某些需要较长时间才能完成的请求的情况下更公平地控制应用程序实例上的负载。

使用最少连接的负载平衡,nginx将不会使繁忙的应用程序服务器因过多的请求而过载,而是将新的请求分配给不太繁忙的服务器。

least_conn指令在server配置中出现时,此时nginx负载平衡方案就是最少连接方法 :

upstream myapp1 {
 least_conn;
 server srv1.example.com;
 server srv2.example.com;
 server srv3.example.com;
}

4.ip-hash负载均衡方法、会话持久性

请注意,使用轮询或最少连接的负载平衡时,后续同一客户端的请求都可能分配给其他服务器。不能保证将同一客户端始终定向到同一服务器。

如果需要将客户端请求绑定到特定的应用程序服务器(换句话说,就始终尝试选择特定服务器,使客户端的会话“粘滞”或“持久”),可以使用ip-hash负载平衡方法。

使用ip-hash负载均衡方法,使用客户端的IP地址用作哈希密钥,借以确定客户端的请求选择服务器组中的哪个服务器。此方法可确保将来自同一客户端的请求始终定向到同一服务器,除非该服务器不可用。

要使用ip-hash负载平衡方法,只需将ip_hash 指令添加到upstream配置中即可:

upstream myapp1 {
 ip_hash;
 server srv1.example.com;
 server srv2.example.com;
 server srv3.example.com;
}

5.加权负载均衡

可以通过使用服务器权重来进一步影响nginx负载平衡算法。

在上面的示例中,未配置服务器权重,这意味着所有server的权重一样,被请求到的概率几乎相同。特别是对于轮询而言,如果服务器能够以同样的方式快速处理完请求且请求数量足够大的情况下,可以大致认为每个服务器被请求到的概率相同。

当为服务器指定weight参数时, weight将作为负载均衡决策的一部分。

upstream myapp1 {
 server srv1.example.com weight=3;
 server srv2.example.com;
 server srv3.example.com;
}

使用上面的配置,每5个新请求将按以下方式分布在应用程序实例中:3个请求将定向到srv1,一个请求将定向到srv2,另一个将定向到srv3。

在最新版本的nginx中,最少连接和ip-hash负载平衡方法也可以使用weight设置权重。

6.健康检查

nginx中的反向代理实现包括服务器运行状况检查。如果来自特定服务器的响应失败并出现错误,nginx会将其标记为失败服务器,并避免后续一段时间的请求分配到该服务器。

max_fails 指令设置在 fail_timeout时间中的最大失败次数。默认情况下, max_fails 设置为1。当它设置为0时,将禁用此服务器的运行状况检查。该 fail_timeout 参数还规定了服务器被设置为失败服务器的时长。 服务器失败后的 fail_timeout间隔后,nginx将开始使用客户端的请求来探测服务器。如果探测成功,则将服务器标记为可用服务器。

六.配置HTTPS服务器

要配置HTTPS服务器,ssl必须 在server块中的listen指令上启用该参数 ,并 应指定服务器证书私钥文件的位置 :

server {
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.crt;
    ssl_certificate_key www.example.com.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    ...
}

服务器证书它被发送到连接到服务器的每个客户端。私钥是一个安全实体,应存储在访问受限的文件中,但是,nginx的主进程必须可以读取它。私钥也可以与证书存储在同一文件中:

server {
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.crt;
    ssl_certificate_key www.example.com.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    ...
}

在这种情况下,文件访问权限也应受到限制。尽管证书和密钥存储在一个文件中,但是只有证书被发送到客户端。

指令ssl_protocolsssl_ciphers 可用于限制连接,使其仅包括SSL / TLS的强版本和密码。默认情况下,nginx使用“ ssl_protocols TLSv1 TLSv1.1 TLSv1.2”和“ ssl_ciphers HIGH:!aNULL:!MD5”,因此通常不需要显式配置它们。请注意,这些指令的默认值已 更改多次。

1.HTTPS服务器优化

SSL操作会消耗额外的CPU资源。在多处理器系统上, 应运行多个 worker processes,不少于可用CPU内核的数量。最耗CPU的操作是SSL握手。有两种方法可以最大程度地减少每个客户端的这些操作数量:第一种方法是通过启用 keepalive connections 来通过一个连接发送多个请求,第二种方法是重用SSL会话参数,以避免并行和后续连接的SSL握手。这些会话存储在工作程序之间共享的SSL会话缓存中,并由ssl_session_cache 指令进行配置 。1MB字节的缓存包含大约4000个会话。默认的缓存超时为5分钟。可以通过使用 ssl_session_timeout 指令。

这是针对具有10 MB共享会话缓存的多核系统进行优化的示例配置:

worker_processes auto;

http {
 ssl_session_cache   shared:SSL:10m;
 ssl_session_timeout 10m;

 server {
     listen              443 ssl;
     server_name         www.example.com;
     keepalive_timeout   70;

     ssl_certificate     www.example.com.crt;
     ssl_certificate_key www.example.com.key;
     ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
     ssl_ciphers         HIGH:!aNULL:!MD5;
     ...

2.SSL证书链

一些浏览器可能会对知名证书颁发机构签署的证书报错,而其他浏览器可能会毫无问题地接受该证书。发生这种情况的原因是,颁发机构已使用中间证书对服务器证书进行了签名,该中间证书在的可信证书颁发机构的证书库中不存在。在这种情况下,授权机构将提供一束链接的证书,这些证书应与已签名的服务器证书接合在一起。服务器证书必须出现在组合文件中的链接证书之前:

$ cat www.example.com.crt bundle.crt > www.example.com.chained.crt

生成的新文件应在 ssl_certificate指令中使用:

server {
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.chained.crt;
    ssl_certificate_key www.example.com.key;
    ...
}

如果服务器证书和分发包的连接顺序错误,nginx将无法启动,并显示错误消息:

SSL_CTX_use_PrivateKey_file(" ... /www.example.com.key") failed
   (SSL: error:0B080074:x509 certificate routines:
    X509_check_private_key:key values mismatch)

因为nginx尝试将私钥与捆绑包的第一个证书一起使用,而第一个不是服务器证书。

浏览器通常存储接收到的并由受信任的权威机构签名的中间证书,因此活跃使用的浏览器可能已经具有所需的中间证书,并且可能不会抱怨没有链式捆绑包发送的证书。为了确保服务器发送完整的证书链,openssl可以使用命令行实用程序,例如:

$ openssl s_client -connect www.godaddy.com:443
...
Certificate chain
 0 s:/C=US/ST=Arizona/L=Scottsdale/1.3.6.1.4.1.311.60.2.1.3=US
     /1.3.6.1.4.1.311.60.2.1.2=AZ/O=GoDaddy.com, Inc
     /OU=MIS Department/CN=www.GoDaddy.com
     /serialNumber=0796928-7/2.5.4.15=V1.0, Clause 5.(b)
   i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
     /OU=http://certificates.godaddy.com/repository
     /CN=Go Daddy Secure Certification Authority
     /serialNumber=07969287
 1 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
     /OU=http://certificates.godaddy.com/repository
     /CN=Go Daddy Secure Certification Authority
     /serialNumber=07969287
   i:/C=US/O=The Go Daddy Group, Inc.
     /OU=Go Daddy Class 2 Certification Authority
 2 s:/C=US/O=The Go Daddy Group, Inc.
     /OU=Go Daddy Class 2 Certification Authority
   i:/L=ValiCert Validation Network/O=ValiCert, Inc.
     /OU=ValiCert Class 2 Policy Validation Authority
     /CN=http://www.valicert.com//emailAddress=info@valicert.com
...

具体信息参照:http://nginx.org/en/docs/http/configuring_https_servers.html#chains

3.单个HTTP / HTTPS服务器

可以配置一个同时处理HTTP和HTTPS请求的服务器:

server {
 listen              80;
 listen              443 ssl;
 server_name         www.example.com;
 ssl_certificate     www.example.com.crt;
 ssl_certificate_key www.example.com.key;
 ...
}

如上所示,在0.7.14之前,无法为各个"listen"选择性地启用SSL。仅可以使用ssl指令为整个server启用 SSL,从而无法设置单个HTTP / HTTPS服务器。listen指令添加了ssl参数来解决此问题。因此不建议在现代版本中使用 ssl指令。

4.基于名称的HTTPS服务器

配置两个或多"listen"同义个IIP地址的HTTPS服务器时,会出现一个常见问题:

server {
 listen          443 ssl;
 server_name     www.example.com;
 ssl_certificate www.example.com.crt;
 ...
}

server {
 listen          443 ssl;
 server_name     www.example.org;
 ssl_certificate www.example.org.crt;
 ...
}

使用此配置,浏览器将接收默认服务器的证书,即www.example.com,而与请求的服务器名称无关。这是由SSL协议行为引起的。在浏览器发送HTTP请求之前,已建立SSL连接,nginx不知道所请求服务器的名称。因此,它可能仅提供默认服务器的证书。

解决此问题的最古老,最可靠的方法是为每个HTTPS服务器分配一个单独的IP地址:

server {
 listen          192.168.1.1:443 ssl;
 server_name     www.example.com;
 ssl_certificate www.example.com.crt;
 ...
}

server {
 listen          192.168.1.2:443 ssl;
 server_name     www.example.org;
 ssl_certificate www.example.org.crt;
 ...
}

5.多个server共用SSL证书

还有其他方法可以在多个HTTPS服务器之间共享一个IP地址。但是,它们都有缺点。一种方法是在SubjectAltName证书字段中使将同一个证书配置多个server_name,例如 www.example.comwww.example.org。但是,SubjectAltName字段的长度是有限的。

另一种方法是使用带有通配符名称的证书,例如 *.example.org。通配符证书可保护指定域的所有子域,但只能在一个级别上。此证书匹配www.example.org,但不匹配 example.orgwww.sub.example.org。这两种方法也可以结合使用。证书可以在SubjectAltName字段中包含确切的名称和通配符名称,例如 example.org*.example.org

最好将证书文件及其私钥文件配置在http级别,以在所有服务器中继承http级别的配置:

ssl_certificate     common.crt;
ssl_certificate_key common.key;

server {
 listen          443 ssl;
 server_name     www.example.com;
 ...
}

server {
 listen          443 ssl;
 server_name     www.example.org;
 ...
}

6.更好的解决办法,单个ip对应多个证书

TLS Server Name Indication extension(SNI,RFC 6066) 是在单个IP地址上运行多个HTTPS服务器的更通用的解决方案 ,它允许浏览器在SSL握手期间传递请求的服务器名称,因此,服务器将知道哪个用于连接的证书。目前 ,大多数现代浏览器都支持SNI ,尽管某些旧客户端或特殊客户端可能不使用SNI 。

在SNI中只能传递域名,但是,如果请求中包含文字IP地址,则某些浏览器可能会错误地将服务器的IP地址作为其名称传递。一个不应该依靠这一点。

为了在nginx中使用SNI,必须在已构建nginx二进制文件的OpenSSL库以及在运行时将其动态链接到的库中都支持它。如果OpenSSL使用配置选项“ --enable-tlsext”构建,则从0.9.8f版本开始支持SNI 。 从OpenSSL 0.9.8j开始,默认情况下启用此选项。如果nginx是使用SNI支持构建的,则当使用“ -V”开关运行时,nginx将显示此信息:

$ nginx -V
...
TLS SNI support enabled
...

但是,如果启用了SNI的Nginx动态链接到不支持SNI的OpenSSL库,则Nginx将显示警告:

nginx was built with SNI support, however, now it is linked
dynamically to an OpenSSL library which has no tlsext support,
therefore SNI is not available

7.兼容性

  • 从0.8.21和0.7.62开始,“-V”开关显示了SNI支持状态。
  • 从0.7.14开始,一直支持listen指令 的ssl参数 。在0.8.21之前,只能与参数一起指定 。 default
  • 自0.5.23起已支持SNI。
  • 从0.5.6开始,支持共享SSL会话缓存。
  • 版本1.9.1和更高版本:默认的SSL协议是TLSv1,TLSv1.1和TLSv1.2(如果OpenSSL库支持)。
  • 版本0.7.65、0.8.19和更高版本:默认SSL协议为SSLv3,TLSv1,TLSv1.1和TLSv1.2(如果OpenSSL库支持)。
  • 版本0.7.64、0.8.18和更早版本:默认SSL协议为SSLv2,SSLv3和TLSv1。
  • 1.0.5版及更高版本:默认SSL密码为“ HIGH:!aNULL:!MD5”。
  • 0.7.65、0.8.20和更高版本:默认SSL密码为“ HIGH:!ADH:!MD5”。
  • 版本0.8.19:默认的SSL密码为“ ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM”。
  • 0.7.64、0.8.18和更早版本:默认SSL密码为“ ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP”。

英文原文

  • The SNI support status has been shown by the “-V” switch since 0.8.21 and 0.7.62.

  • The ssl parameter of the listen directive has been supported since 0.7.14. Prior to 0.8.21 it could only be specified along with the default parameter.

  • SNI has been supported since 0.5.23.

  • The shared SSL session cache has been supported since 0.5.6.

  • Version 1.9.1 and later: the default SSL protocols are TLSv1, TLSv1.1, and TLSv1.2 (if supported by the OpenSSL library).

  • Version 0.7.65, 0.8.19 and later: the default SSL protocols are SSLv3, TLSv1, TLSv1.1, and TLSv1.2 (if supported by the OpenSSL library).

  • Version 0.7.64, 0.8.18 and earlier: the default SSL protocols are SSLv2, SSLv3, and TLSv1.

  • Version 1.0.5 and later: the default SSL ciphers are “HIGH:!aNULL:!MD5”.

  • Version 0.7.65, 0.8.20 and later: the default SSL ciphers are “HIGH:!ADH:!MD5”.

  • Version 0.8.19: the default SSL ciphers are “ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM”.

  • Version 0.7.64, 0.8.18 and earlier: the default SSL ciphers are
    ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP”.

# Nginx  

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×