你真的了解如何将 Nginx 配置为Web服务器吗

2016-11-2723:14|Nginx|4|2810

阅读之前,建议先阅读初识Nginx。之后,我们来了解一下Nginx配置。

抽象来说,将Nginx配置为Web服务器就是定义处理哪些URLS和如何处理这些URLS对应的请求。具体来说,就是定义一些虚拟服务器(VirtualServers),控制具有特定IP和域名的请求。

更具体的来说,Nginx通过定义一系列locations来控制对URIS的选择。每一个location定义了对映射到自己的请求的处理场景:返回一个文件或者代理请求,或者根据不同的错误代码返回不同的错误页面。另外,根据URI的不同,请求也可以被重定向到其它server或者location。

设置虚拟服务器

listen:

Nginx配置文件至少包含一个server命令,用来定义虚拟服务器。当请求到来时,Nginx会首先选择一个虚拟服务器来处理该请求。

虚拟服务器定义在http上下文中的server中:

http{

server{

#Serverconfiguration

}

}

注意:http中可以定义多个server

server配置块使用listen命令监听本机IP和端口号(包括Unixdomainsocketandpath),支持IPv4、IPv6,IPv6地址需要用方括号括起来:

server{

listen127.0.0.1:8080;#IPv4地址,8080端口

#listen[2001:3CA1:10F:1A:121B:0:0:10]:80;#IPv6地址,80端口

#listen[::]:80;#听本机的所有IPv4与IPv6地址,80端口

#Therestofserverconfiguration

}

上述配置,如果不写端口号,默认使用80端口,如果不写IP,则监听本机所有IP。

server_name:

如果多个server的listenIP和端口号一模一样,Nginx通过请求头中的Host与server_name定义的主机名进行比较,来选择合适的虚拟服务器处理请求:

server{

listen80;

server_namelufficc.comwww.lufficc.com;

...

}

server_name的参数可以为:

完整的主机名,如:api.lufficc.com。

含有通配符(含有*),如:*.lufficc.com或api.*。

正则表达式,以~开头。

通配符只能在开头或结尾,而且只能与一个.相邻。www.*.example.org和w*.example.org均无效。但是,可以使用正则表达式匹配这些名称,例如~^www\..+\.example\.org$和~^w.*\.example\.org$。而且*可以匹配多个部分。名称*.example.org不仅匹配www.example.org,还匹配www.sub.example.org。

对于正则表达式:Nginx使用的正则表达式与Perl编程语言(PCRE)使用的正则表达式兼容。要使用正则表达式,且必须以~开头。

命名的正则表达式可以捕获变量,然后使用:

server{

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

location/{

root/sites/$domain;

}

}

小括号()之间匹配的内容,也可以在后面通过$1来引用,$2表示的是前面第二个()里的内容。因此上述内容也可写为:

server{

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

location/{

root/sites/$2;

}

}

一个server_name示例:

server{

listen80;

server_nameapi.lufficc.com*.lufficc.com;

...

}

同样,如果多个名称匹配Host头部,Nginx采用下列顺序选择:

完整的主机名,如api.lufficc.com。

最长的,且以*开头的通配名,如:*.lufficc.com。

最长的,且以*结尾的通配名,如:api.*。

第一个匹配的正则表达式。(按照配置文件中的顺序)

即优先级:api.lufficc.com>*.lufficc.com>api.*>正则。

如果Host头部不匹配任何一个server_name,Nginx将请求路由到默认虚拟服务器。默认虚拟服务器是指:nginx.conf文件中第一个server或者显式用default_server声明:

server{

listen80default_server;

...

}

配置location

URI与location参数的匹配

当选择好server之后,Nginx会根据URIs选择合适的location来决定代理请求或者返回文件。

location指令接受两种类型的参数:

前缀字符串(路径名称)

正则表达式

对于前缀字符串参数,URIs必须严格的以它开头。例如对于/some/path/参数,可以匹配/some/path/document.html,但是不匹配/my-site/some/path,因为/my-site/some/path不以/some/path/开头。

location/some/path/{

...

}

对于正则表达式,以~开头表示大小写敏感,以~*开头表示大小写不敏感。注意路径中的.要写成\.。例如一个匹配以.html或者.htm结尾的URI的location:

location~\.html?{

...

}

正则表达式的优先级大于前缀字符串。如果找到匹配的前缀字符串,仍继续搜索正则表达式,但如果前缀字符串以^~开头,则不再检查正则表达式。

具体的搜索匹配流程如下:

将URI与所有的前缀字符串进行比较。

=修饰符表明URI必须与前缀字符串相等(不是开始,而是相等),如果找到,则搜索停止。

如果找到的最长前缀匹配字符串以^~开头,则不再搜索正则表达式是否匹配。

存储匹配的最长前缀字符串。

测试对比URI与正则表达式。

找到第一个匹配的正则表达式后停止。

如果没有正则表达式匹配,使用4存储的前缀字符串对应的location。

=修饰符拥有最高的优先级。如网站首页访问频繁,我们可以专门定义一个location来减少搜索匹配次数(因为搜索到=修饰的匹配的location将停止搜索),提高速度:

location=/{

...

}

静态文件和代理

location也定义了如何处理匹配的请求:返回静态文件或者交给代理服务器处理。下面的例子中,第一个location返回/data目录中的静态文件,第二个location则将请求传递给https://lufficc.com域名的服务器处理:

server{

location/images/{

root/data;

}

location/{

proxy_passhttps://lufficc.com;

}

}

root指令定义了静态文件的根目录,并且和URI拼接形成最终的本地文件路径。如请求/images/example.png,则拼接后返回本地服务器文件/data/images/example.png。

proxy_pass指令将请求传递到URL指向的代理服务器。让后将来自代理服务器的响应转发给客户端。在上面的示例中,所有不以/images/开头的URI的请求都将传递给代理服务器处理。

比如我把proxy_pass设置为https://www.baidu.com/,那么访问http://search.lufficc.com/将得到百度首页一样的响应(页面)(感兴趣的童鞋可以自己试一试搜索功能,和百度没差别呢):

server{

listen80;

server_namesearch.lufficc.com;

location/{

proxy_passhttps://www.baidu.com;

}

}

使用变量(Variables)

你可以使用变量来使Nginx在不同的请求下采用不同的处理方式。变量是在运行时计算的,用作指令的参数。变量由$开头的符号表示。变量基于Nginx的状态定义信息,例如当前处理的请求的属性。

有很多预定义变量,例如核心的HTTP变量,你也可以使用set,map和geo指令定义自定义变量。大多数变量在运行时计算,并包含与特定请求相关的信息。例如,$remote_addr包含客户端IP地址,$uri保存当前URI值。

一些常用的变量如下:

变量名称作用

$uri请求中的当前URI(不带请求参数),它可以通过内部重定向,或者使用index指令进行修改,$uri不包含主机名,如/foo/bar.html。

$arg_name请求中的的参数名,即“?”后面的arg_name=arg_value形式的arg_name

$hostname主机名

$args请求中的参数值

$query_string同$args

$request代表客户端的请求地址

$request_uri这个变量等于包含一些客户端请求参数的原始URI,它无法修改,不包含主机名,如:/cnphp/test.php?arg=freemouse。

......

一个简单的应用就是从http重定向到https时带上路径信息:

server{

...

return301https://lufficc.com$request_uri;

...

}

返回特定状态码

如果你的网站上的一些资源永久移除了,最快最简洁的方法就是使用return指令直接返回:

location/wrong/url{

return404;

}

return的第一个参数是响应代码。可选的第二个参数可以是重定向(对应于代码301,302,303和307)的URL或在响应正文中返回的文本。例如:

location/permanently/moved/url{

return301http://www.example.com/moved/here;

}

return指令可以包含在location和server上下文中:

server{

location/{

return404;

}

}

或者:

server{

...

return404;

location/{

...

}

}

错误处理

error_page命令可以配置特定错误码的错误页面,或者重定向到其他的页面。下面的示例将在404错误发生时返回/404.html页面。

error_page404/404.html;

error_page命令定义了如何处理错误,因此不会直接返回,而return确实会立即返回。当代理服务器或者Nginx处理时产生相应的错误的代码,均会返回相应的错误页面。

在下面的示例中,当Nginx找不到页面时,它将使用代码301替换代码404,并将客户端重定向到http://example.com/new/path.html。此配置很有用,比如当客户端仍尝试用旧的URI访问页面时,301代码通知浏览器页面已永久移除,并且需要自动替换为返回的新地址。

location/old/path.html{

error_page404=301http:/example.com/new/path.html;

}

重写URIs

rewrite指令可以多次修改请求的URI。rewrite的第一个参数是URI需要匹配的正则表达式,第二个参数是将要替换的URI。第三个参数可选,指示是否继续可以重写或者返回重定向代码(301或302)。例如:

location/users/{

rewrite^/users/(.*)$/show?user=$1break;

}

您可以在server和location上下文中包括多个rewrite指令。Nginx按照它们发生的顺序一个一个地执行指令。当选择server时,server中的rewrite指令将执行一次。

在Nginx处理一组rewrite指令之后,它根据新的URI选择location。如果所选location仍旧包含rewrite指令,它们将依次执行。如果URI匹配所有,则在处理完所有定义的rewrite指令后,搜索新的location。

以下示例将rewrite指令与return指令结合使用:

server{

...

rewrite^(/download/.*)/media/(.*)\..*$$1/mp3/$2.mp3last;

rewrite^(/download/.*)/audio/(.*)\..*$$1/mp3/$2.ralast;

return403;

...

}

诸如/download/some/media/file的URI被改为/download/some/mp3/file.mp3。由于last标志,后续指令(第二个rewrite指令和return指令)被跳过,但Nginx继续以更改后的URI处理请求。类似地,诸如/download/some/audio/file的URI被替换为/download/some/mp3/file.ra。如果URI不匹配rewrite指令,Nginx将403错误代码返回给客户端。

last与break的区别是:

last:在当前server或location上下文中停止执行rewrite指令,但是Nginx继续搜索与重写的URI匹配的location,并应用新location中的任何rewrite指令(这意味着URI可能再次改变)。

break:停止当前上下文中rewrite指令的处理,并取消搜索与新URI匹配的location。不会执行新location中的rewrite指令。

附录

常用正则

.:匹配除换行符以外的任意字符

?:重复0次或1次

+:重复1次或更多次

*:重复0次或更多次

\d:匹配数字

^:匹配字符串的开始

$:匹配字符串的介绍

{n}:重复n次

{n,}:重复n次或更多次

[c]:匹配单个字符c

[a-z]:匹配a-z小写字母的任意一个

全局变量

$args:#这个变量等于请求行中的参数,同$query_string

$content_length:请求头中的Content-length字段。

$content_type:请求头中的Content-Type字段。

$document_root:当前请求在root指令中指定的值。

$host:请求主机头字段,否则为服务器名称。

$http_user_agent:客户端agent信息

$http_cookie:客户端cookie信息

$limit_rate:这个变量可以限制连接速率。

$request_method:客户端请求的动作,通常为GET或POST。

$remote_addr:客户端的IP地址。

$remote_port:客户端的端口。

$remote_user:已经经过AuthBasicModule验证的用户名。

$request_filename:当前请求的文件路径,由root或alias指令与URI请求生成。

$scheme:HTTP方法(如http,https)。

$server_protocol:请求使用的协议,通常是HTTP/1.0或HTTP/1.1。

$server_addr:服务器地址,在完成一次系统调用后可以确定这个值。

$server_name:服务器名称。

$server_port:请求到达服务器的端口号。

$request_uri:包含请求参数的原始URI,不包含主机名,如:/foo/bar.php?arg=baz。

$uri:不带请求参数的当前URI,$uri不包含主机名,如/foo/bar.html。

$document_uri:与$uri相同。

例如请求:http://localhost:88/test1/test2/test.php

$host:localhost

$server_port:88

$request_uri:/test1/test2/test.php

$document_uri:/test1/test2/test.php

$document_root:/var/www/html

$request_filename:/var/www/html/test1/test2/test.php

参考

https://www.nginx.com/resources/admin-guide/nginx-web-server/

http://seanlook.com/2015/05/17/nginx-location-rewrite/

Nginx服务器

相关推荐