配置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_pass:将请求传递到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指令。