博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

nginx笔记(三)

Posted on 2020-04-30 10:42  龙翔天下  阅读(370)  评论(0编辑  收藏  举报

配置web服务器

 

设置虚拟服务器:

      http语境内,定义server指令为一个虚拟服务器。当然也可以添加多个server指令到http语境中。

server配置块一般包含listen指令指示IP地址和端口。也接受IPV6,IPV6包含在方括号中。

server {
    listen 127.0.0.1:8080;
    # Additional server configuration
}

 

     如果端口忽略,则使用标准端口。如果地址忽略,则侦听所有地址。如果listen指令不写,则标准端口 80/tcp或默认商品8000/tcp,取决于superuser权限。

    如果有若干服务器匹配IP地址和端口,nginx会使用server块中的server_name指令,自动匹配请求中的host信息头。server_name参数可以是确切的全名称,通配符或正则表达式。

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

 

    如果有若干个名称匹配Host信息头,则nginx按以下顺序获取最先匹配的名字:

    (1)确切的名称;

     (2)最长的通配符字串,以*号开头(*符号匹配所有任何字符),例:*.example.org;

     (3)最长的通配符字串,以*号结尾,例:mail.*;

      (4)首先匹配的Perl语法的正则表达式,前置有~波浪符号。

   如果Host信息头不匹配server名称,则nginx将其转到默认服务器,默认服务器设置在nginx.conf文件中。

server {
    listen 80 default_server;
    #...
}

 

 

配置URI文件夹:

    nginx可通过在server指令内定义location指令将流量转发到不同的位置。每个location指令块内还可以定义更多location指令,以进一步特定请求。

    location指令有两种参数:前缀字符串(路径名)或正则表达式。

    以下示例 /some/path/ 的前缀路径匹配以此路径开头的URL,比如:/some/path/document.html。

location /some/path/ {
    #...
}

  正则表达式:

  正则表达式的前面有波浪号(〜),用于区分大小写的匹配;或波浪号(〜*)用于不区分大小写的匹配。

  Location指令匹配的优先级:

  为寻找URI最佳匹配,nginx会先用字符串前缀比较URI location。然后用正则表达式搜索这些位置。

  除了使用^~修饰符,其他的正则表达式会有更高优先级。通过字符串前缀nginx会选择最具体的字符串(即最长和最完整的字符串)。

  下面是处理请求location的确切逻辑:

   1、针对所有前缀字符串测试URI;

   2、=(等号)修饰符定义URI和前缀字符串的精确匹配。如果找到完全匹配的内容,搜索将停止。

   3、如果^〜(脱字符号)修饰符加上最长的匹配前缀字符串,则不检查正则表达式。

   4、存储最长的匹配前缀字符串;

   5、针对正则表达式测试URI;

   6、找到第一个匹配的正则表达式后停止处理,并使用相应的位置;

   7、如果没有正则表达式匹配,则使用已保存的前缀字符串相对应的位置。

 

   =号修饰符最典型用法就是对 / 的请求,如果对 / 的请求很频繁,则使用 =/ 可以加快搜索速度。

location = / {
    #...
}

 

   location指令上下文内包含了如何处理请求的方法。如下例:

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

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

   root指令:指定要搜索的静态文件的系统路径;

   proxy_pass指令:将请求转给被代理服务器处理,并将响应结果再返回给客户端。

 

使用变量:

变量以$符号开头。

nginx有许多预定义的变量,参考:https://nginx.org/en/docs/http/ngx_http_core_module.html?&_ga=2.160412349.1274850824.1587864344-45792041.1587182428#variables

也可自定义变量,使用set,map和geo指令。

 

返回具体的状态码:

有些URI需要立即返回返回特定的诸如错误或跳转码,比如临时或永久性转移,最简单方法 就是使用 return 指令:

location /wrong/url {
    return 404;
}

 

return 指令的第一个参数是状态码;第二参数为可选值,比如要跳转的URL或者响应的主体文字;

return指令可以出现在location和server上下文中。

 

重写请求URI:

通过 rewrite指令,可以重写请求URI。

rewrite指令的第一参数为正则表达式用于匹配URI,第二参数为替换后的URI,第三参数为可选值,可用于停止后面的rewrite指令的处理或重定向。

在server和location上下文中可以包含多个rewrite指令。nginx按指令的出现顺序一一执行。

当nginx处理了一级重写指令后,它会通过用新URI来选择location。如果这个被选择的location又包含rewrite指令,这些指令又会依次执行。如果URI匹配任何一个,则会在处理所有定义 的重写指令后再次开始对新location进行搜索。

server {
    #...
    rewrite ^(/download/.*)/media/(\w+)\.?.*$ $1/mp3/$2.mp3 last;
    rewrite ^(/download/.*)/audio/(\w+)\.?.*$ $1/mp3/$2.ra  last;
    return  403;
    #...
}

 

以上例说明:当URI诸如是  /download/some/media/file , 则会重写成 /download/some/mp3/file.mp3 , 因为 last 标记的原因 ,后续的指令(第二个rewrite和return指令)则会忽略 。同样,URI比如说是 /download/some/audio/file 会被替换成 /download/some/mp3/file.ra。如果URI都不匹配rewrite指令,则Nginx返回 403错误码。

   rewrite指令有两种标记会打断往下执行:

   last -- 停止在当前 server 或 location 上下文中执行重写指令,但是nginx搜索与重写的URI匹配的location,并应用新 location 中的所有 rewrite 指令(这意味着可以再次更改URI)。

  break -- 停止在当前 server 或 location 上下文中执行重写指令,并取消对新 URI的新一轮 location 搜索。

 

重写HTTP响应:

有时候你需要重写或改变http响应内容,则可以使用 sub_filter 指令。 该指令支持变量和一系列的替代,可以做出更复杂的变更。

以下例子,/blog/ 绝对链接变更为 /blog-staging/。

location / {
    sub_filter      /blog/ /blog-staging/;
    sub_filter_once off;
}

 

下例中,http:// 变成 https://, 并将 localhost 地址变成 hostname主机名。 sub_filter_once指令告诉 nginx 在 location 内连接执行 sub_filter指令。

location / {
    sub_filter     'href="http://127.0.0.1:8080/'    'href="https://$host/';
    sub_filter     'img src="http://127.0.0.1:8080/' 'img src="https://$host/';
    sub_filter_once on;
}

 

请注意,如果发生另一个sub_filter匹配,则已经用sub_filter修改的响应部分不会再次替换。

 

错误处理:

    error_page 指令能配置 nginx 返回自定义页面,并替换成不同的状态码给客户端响应。

error_page 404 /404.html;

 

   注意,此指令不会立即返回错误,而是指明错误发生时的处理方式。错误代码可能来自被代理的服务器也可能是nginx处理期间发生 。

   以下例子,当nginx找不到页面,则用301代替404码,并转到http:/example.com/new/path.html。当客户端仍尝试访问其旧URI的页面时,此配置很有用。301代码通知浏览器该页面已永久移动,并且需要在返回时自动用新地址替换旧地址。

location /old/path.html {
    error_page 404 =301 http:/example.com/new/path.html;
}

 

    以下配置是在找不到文件时将请求传递到后端的示例。由于在error_page指令中的等号后没有指定状态码,因此对客户端的响应具有代理服务器返回的状态码(不一定是404

server {
    ...
    location /images/ {
        # Set the root directory to search for the file
        root /data/www;

        # Disable logging of errors related to file existence
        open_file_cache_errors off;

        # Make an internal redirect if the file is not found
        error_page 404 = /fetch$uri;
    }

    location /fetch/ {
        proxy_pass http://backend/;
    }
}

 

   

    该 error_page指令指示NGINX在找不到文件时进行内部重定向。

   例如,如果未找到 /images/some/file,则将其替换为 /fetch/images/some/file,并开始对位置的新搜索。结果,请求在第二个location上下文中结束,并被到 http://backend/

open_file_cache_errors如果找不到文件,伪指令可防止写入错误消息。

 

 

提供静态内容

根目录和索引文件:

root指令能指明要搜索文件的根目录。为了获取请求文件的路径,nginx根据请求URI路径附加到root指令指定的路径。

该指令可以放在http,server 或 location 上下文。在下例中,root指令用于定义server主机,它应用到了所有未重定义root指令的location块当中:

server {
    root /www/data;

    location / {
    }

    location /images/ {
    }

    location ~ \.(mp3|mp4) {
        root /www/media;
    }
}

 

上例中,nginx搜索用/images/ 开始在系统的 /www/data/images 文件夹中搜索。但是如果URI以 .mp3 或 .mp4 扩展名结尾,则以 /www/media 目录搜索,因为它在匹配的location中重定义了root。

如果请求以斜杠结尾,NGINX会将其视为对目录的请求,并尝试在目录中查找索引文件。index指令用于定义索引文件名(默认值:index.html )。

   为了返回索引文件,NGINX检查其是否存在,然后对通过将索引文件的名称附加到基本URI所获得的URI进行内部重定向:

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

location ~ \.php {
    fastcgi_pass localhost:8000;
    #...
}

 

   按上例,如果URI请求是 /path,而 /data/path/index.html不存在,但/data/path/index.php存在。于是内部跳转到第二个location中处理,最后请求被代理。

 

若干选项:

     try_files指令:用于检查指定文件或目录是否存在,不存在则转到指定的状态码或路径。

location / {
    try_files $uri $uri/ $uri.html =404;
}

 

上例当找不到$uri变量对应的目录或文件时,则返回404错误码。

location / {
    try_files $uri $uri/ @backend;
}

location @backend {
    proxy_pass http://backend.example.com;
}

 

上例当找不到$uri文件或目录时,转到第二个location,然后反向代理给backend.example.com。

 

内容提供方面的性能优化:

(1)开启sendfile:

默认情况下,nginx在传输文件前会先前文件复制到缓存。而开启sendfile指令,则跳过步骤直接复制文件给另一端。另外,为防止一个快速连接完全占用工作进程,可以使用 sendfile_max_chunk 指令限制单个sendfile函数传输的数据量。如下例:

location /mp3 {
    sendfile           on;
    sendfile_max_chunk 1m;
    #...
}

 

(2)开启tcp_nopush:

使用tcp_nopush指令与sendfile指令一起,这使 NGINX 在 sendfile() 获得数据块之后立即在一个数据包中发送HTTP响应头。

(3)开启tcp_nodelay:

tcp_nodelay指令的开启能允许覆盖Nagle算法。此算法原来是用于解决在低速网络下传输问题,它将多个小数据包合并一个较大的数据包,发送时会有200ms的延迟。如今,在处理大型静态文件时,无论数据包大小如何,都可以立即发送数据。延迟还会影响在线应用程序(SSH,在线游戏,在线交易等)。

默认情况下,tcp_nodelay指令设置为on,这表示Nagle的算法已禁用。仅对保持连接使用此伪指令。

location /mp3  {
    tcp_nodelay       on;
    keepalive_timeout 65;
    #...
}

 

(4)优化积压队列

通常情况下,当建立连接后,会将其放入侦听套接字的“侦听”队列中。在正常负载下,队列很小或根本没有队列。但是在高负载下,队列会急剧增长,从而导致性能不均匀,连接断开和延迟增加。

 

查询侦听队列,使用此命令:

netstat -Lan

 

输出可能类似于以下内容,它显示端口80上的侦听队列中有10个未接受的连接,而已配置的最大128个排队的连接。这种情况是正常的:

Current listen queue sizes (qlen/incqlen/maxqlen)
Listen         Local Address         
0/0/128        *.12345            
10/0/128        *.80       
0/0/128        *.8080

 

 

相反,在以下命令中,不可接受的连接数(192)超过了限制128。当网站遇到大量流量时,这是很常见的。

Current listen queue sizes (qlen/incqlen/maxqlen)
Listen         Local Address         
0/0/128        *.12345            
192/0/128        *.80       
0/0/128        *.8080

 

为了获得最佳性能,您需要增加操作系统和NGINX配置中排队等待NGINX接受的最大连接数。

 

操作系统的调优:

将net.core.somaxconn内核参数的值从其默认值(128)增加到足够大的值以应对大量流量。在此示例中,此值增加到4096。

sudo sysctl -w net.core.somaxconn=4096

 

编辑添加以下行到 /etc/sysctl.conf文件:

net.core.somaxconn = 4096

 

Nginx调优:

如果将somaxconn内核参数设置为大于512的值,请将backlog参数更改为NGINX listen指令以匹配:

server {
    listen 80 backlog=4096;
    # ...
}

 

 

反向代理

当NGINX代理请求时,它将请求发送到指定的代理服务器,获取响应,然后将其发送回客户端。可以使用指定协议将请求代理到HTTP服务器(另一个NGINX服务器或任何其他服务器)或非HTTP服务器(可以运行使用特定框架开发的应用程序,例如PHP或Python)。支持的协议包括FastCGI,uwsgi,SCGI和memcached。

为了将请求传递到HTTP代理服务器,必须在一个位置内指定proxy_pass指令:

location /some/path/ {
    proxy_pass http://www.example.com/link/;
}

 

 

要将请求传递到非HTTP代理服务器,应使用适当的** _ pass指令:

fastcgi_pass:将请求传递给FastCGI服务器uwsgi_pass:将请求传递给uwsgi服务器scgi_pass:将请求传递到SCGI服务器memcached_pa​​ss:将请求传递到memcached服务器

 

传递请求标头:

默认情况下,NGINX在代理请求中重新定义两个标头字段“ Host”和“ Connection”,并消除其值为空字符串的标头字段。“Host”设置为 $proxy_host 变量,“Connection”设置为 close。

要更改这些设置以及修改其他标题字段,请使用proxy_set_header指令。可以在一个位置或更高位置指定此伪指令。也可以在server上下文或http块中指定它。

location /some/path/ {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_pass http://localhost:8000;
}

 

上例中,Host值设置为 $host 变量;

为了防止将标头字段传递给代理服务器,请按以下步骤将其设置为空字符串:

location /some/path/ {
    proxy_set_header Accept-Encoding "";
    proxy_pass http://localhost:8000;
}

 

 

配置缓存:

默认情况下,NGINX缓冲响应来源于被代理的服务器。响应存储在内部缓冲区中,直到接收到整个响应后才发送给客户端。缓冲有助于优化慢速客户端的性能,如果响应从NGINX同步传递到客户端,则这可能会浪费被代理服务器的时间。但是,启用缓冲后,NGINX允许被代理服务器快速处理响应,而NGINX将响应存储的时间与客户端下载响应所需的时间一样长。

负责启用和禁用缓冲的指令是proxy_buffering。默认情况下,它设置为on并且启用了缓冲。

proxy_buffers指令控制为请求分配的缓冲区的大小和数量。来自被代理服务器响应的第一部分存储在单独的缓冲区中,缓冲区的大小由proxy_buffer_size指令设置。这部分通常包含一个相对较小的响应头,并且可以使其小于其余响应的缓冲区。

在以下示例中,增加了默认缓冲区数,并使响应第一部分的缓冲区大小小于默认值。

location /some/path/ {
    proxy_buffers 16 4k;
    proxy_buffer_size 2k;
    proxy_pass http://localhost:8000;
}

 

如果禁用了缓冲,则响应将从客户端服务器接收到的响应同步发送到客户端。对于需要尽快开始接收响应的快速交互客户端,此行为可能是理想的。

location /some/path/ {
    proxy_buffering off;
    proxy_pass http://localhost:8000;
}

 

 

压缩与解压缩

压缩响应通常会大大减少传输数据的大小,由于压缩是在运行时发生的,因此也会增加相当大的处理开销。NGINX在将响应发送到客户端之前执行压缩,但不会“双重压缩”已压缩的响应(例如,由被代理服务器进行的响应)。

开启压缩:

gzip on;

 

默认情况下,NGINX仅压缩MIME类型为 text/html 的响应。要压缩其他MIME类型的响应,请包含gzip_types指令并列出其他类型。

gzip_types text/plain application/xml;

要指定要压缩的响应的最小长度,请使用gzip_min_length指令。默认值为20字节(此处调整为1000):

gzip_min_length 1000;

默认情况下,NGINX不压缩对代理请求的响应(来自代理服务器的请求)。请求来自代理服务器的事实取决于请求中是否存在Via标头字段。要配置这些响应的压缩,请使用gzip_proxied指令。该指令用于指定NGINX应该压缩哪些代理请求。例如,合理的做法是仅压缩对不会缓存在代理服务器上的请求的响应。为此,gzip_proxied指令具有参数,这些参数指示NGINX检查响应中的Cache-Control标头字段,并在该值是no-cache,no-store或private时压缩响应。此外,您必须包括expired参数才能检查Expires标头字段的值。在以下示例中,将与auth参数一起设置这些参数,该参数将检查Authorization标头字段的存在(授权响应特定于最终用户,并且通常不缓存):

gzip_proxied no-cache no-store private expired auth;

与大多数其他指令一样,配置压缩的指令可以包含在 http 上下文中或 server 或 location 配置块中。

gzip压缩的整体配置可能如下所示:

server {
    gzip on;
    gzip_types      text/plain application/xml;
    gzip_proxied    no-cache no-store private expired auth;
    gzip_min_length 1000;
    ...
}

 

 

开启解压缩:

某些客户端不支持使用gzip编码方法的响应。同时,可能希望存储压缩的数据,或者动态压缩响应并将其存储在缓存中。为了成功服务于接受和不接受压缩数据的两个客户端,NGINX可以在将数据发给后者时,即刻对数据进行解压缩。

gunzip on;

 

gunzip指令可以和gzip指令在同一上下文中设置:

server {
    gzip on;
    gzip_min_length 1000;
    gunzip on;
    ...
}

 

请注意,此指令是在单独的模块中定义的,默认情况下可能未包含在NGINX开源构建中。

传输压缩文件:

要将文件的压缩版本而不是常规文件发送到客户端,请在适当的上下文中将gzip_static指令设置为on。

location / {
    gzip_static on;
}

 

在这种情况下,为了满足对 /pathto/file 的请求,NGINX尝试查找并发送文件 /path/to/file.gz 。如果该文件不存在,或者客户端不支持gzip,则NGINX发送该文件的未压缩版本。

请注意,gzip_static指令不启用即时压缩。它仅使用任何压缩工具预先压缩的文件。要在运行时压缩内容(不仅是静态内容),请使用gzip指令。