「Nginx」Nginx配置入门
转载请注明出处: blog.****.net/jinixin/article/details/89975303
本篇文章不会做深入讲解, 阅读本篇文章, 也只能使你对配置有简单了解. 配置这部分内容比较多, 像前篇所提到的静态资源服务器, 虚拟主机, 反向代理都是需要依靠合理配置来实现的.
配置文件
配置文件名为”nginx.conf”, 默认位于”/etc/nginx/nginx.conf”. 如不确定, 可以使用”nginx -t”或”locate nginx.conf”命令进行定位.
命令类型
配置文件是由各种命令构成的, 根据是否嵌套可分为简单命令与复杂命令两种.
1. 简单命令形如:
命令A 参数列表;
2. 复杂命令形如:
命令A 参数列表 {
命令B 参数列表;
}
命令A也被称为命令B的上下文.
配置文件结构
配置文件是由命令构成的, 命令间互相嵌套形成块, 块可分为main, events, http, server, location, upstream这6种, 大致结构如下:
main {
# 配置工作进程数量, 日志文件位置, 连接最长保持时间等
events {
# 配置处理连接的方式
}
http {
# 配置服务器与虚拟主机
server {
location {
# 配置URI的路由规则
}
upstream {
# 配置应用服务器集群
}
}
}
}
Nginx常用于在客户端与应用服务器间转发请求与响应, 下面就简单谈下路由算法, 即如何根据请求找到目标应用服务器.
路由算法
我理解的路由算法大致分为两步, 首先是根据请求的目标域名和端口来路由server, 接着是在选定的server中根据请求的URI来路由location.
路由server
http块下可以有多个server块, 用以表示不同的主机, 不同的主机监听不同的域名和端口.
server块中最重要的是listen与server_name命令. listen命令表示该server块所监听的端口, server上下文中支持多条listen命令. server_name命令表示该server块所监听的域名.
http {
server {
listen 80;
listen 81;
server_name example.org www.example.org;
# ...
}
server {
listen 80 default_server;
server_name example.net;
# ...
}
server {
listen 80;
server_name example.com;
# ...
}
}
上面3个server都在监听80端口, 但之间作用范围其实并不重叠. 所有发送给”[www.]example.org:80"或"[www.]example.org:81"端口的请求, 都会分给第1个server块处理; 所有发送给”example.net:80"端口的请求, 都会分给第2个server块处理; 所有发送给”example.com:80"端口的请求, 都会分给第3个server块处理. 此时相当于在1台机器上处理3个不同域名的请求, 这便是Nginx的虚拟主机服务.
那么你也许会有这样的疑惑, 如果当前Nginx收到发送给”monkey.com:80”端口的请求, 其会交给第几个server块处理呢?
这就涉及端口默认主机的情况了, 可以通过在listen命令后加上default_server参数, 将该server块指定为该端口的默认server. 若没有default_server参数显性指明, 其便会选取第一个监听该端口的server块. 所以发给”monkey.com:80”端口的请求会转给第2个server块处理, 第二个server块是80端口的默认主机.
这里顺带提下, default_server参数是关于端口的属性, 而不是关于域名的属性. 实际上常在配置中加入以下server块:
server {
listen 80 default_server;
return 404;
}
用于接收未知域名的请求, 该server块将返回404响应, 并关闭连接.
路由server的过程
首先匹配端口, 将请求头Host字段中携带的目标端口与server块中监听的端口依次比较, 过滤出所有匹配的server块. 接着匹配域名, 在先前过滤出的所有server块里, 将请求头Host字段中携带的目标域名与server_name比较, 如有匹配的server块, 即为目标server. 若没有server_name与目标域名相匹配, 则选择该端口的默认主机作为目标server.
上面的端口匹配, 仅有精确匹配, 即比较双方完全相等. 而域名匹配则不只有精确匹配, 还有通配符匹配与正则匹配, 下面详细介绍:
server {
listen 80;
server_name example.com mail.example.com;
# 精确匹配
}
server {
listen 80;
server_name *.example.com;
# 通配符匹配
}
server {
listen 80;
server_name mail.*;
# 通配符匹配
}
server {
listen 80;
server_name ~^.+\.example\.com$;
# 正则匹配
}
关于通配符匹配, 上面的“*”即为通配符, 要注意的是:
1) 通配符只能出现在开头或结尾, 不能出现在中间, 比如”mail.*.com”就是错误的;
2) 通配符可匹配一个或多个单词, 比如“*.example.org”可以匹配”www.example.org”和"www.sub.example.org";
3) ”.example.org”比较特殊, 不仅可以与"example.org"精确匹配, 也可进行通配符匹配"*.example.org"
关于正则匹配, 即正则表达式匹配, 必须以”~”开头:
1) 为便于识别, 记得配对”^”与”$”.
2) 域名分隔符”.”记得要用反斜杠转义.
3) 如果正则式中出现了{}, 记得给整个正则式加上双引号.
这里就要抛出一个问题了, Nginx收到发给”mail.example.com:80”端口的请求, 该发给哪个server块处理呢?
很明显”mail.example.com:80”符合上述所有的server块, 此时请参照以下规则:
当配置中多个server组拥有相同端口时, 目标域名将按以下顺序匹配server_name, 匹配成功即为目标server:
1) 精确匹配
2) 以*开头的最长通配符
3) 以*结尾的最长通配符
4) 在配置文件中从上至下第一个匹配的正则式
举例:
某个HTTP请求头:
GET / HTTP/1.1
Host: monkey.com:10002
Connection: keep-alive
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36
Accept: text/html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN, zh
Nginx配置如下:
server {
listen 10002 default_server;
return 403;
}
server {
listen 10002;
server_name www.monkey.com monkey.com;
}
server {
listen 10003 default_server;
server_name www.monkey.net monkey.net;
}
首先进行端口匹配, 过滤出第1个server和第2个server符合要求; 接着对过滤出的server组进行域名匹配, 目标域名精确匹配第2个server的server_name符合, 故该请求将转给第2个server块处理.
路由location
一个server块下可以有多个location块, Nginx在确认是哪个server块来处理请求后, 其就会在该server块下根据请求的URI匹配location块.
location命令支持最长前缀匹配与正则匹配, 前缀匹配的location参数是字符串, 正则匹配的location参数则以”~”开头. Nginx会首先对URI进行最长前缀匹配, 记录下最合适的location块. 接着对URI进行正则匹配, 如果有匹配到正则式, 则使用该式所对应的location块. 如果没有匹配到, 则使用之前通过最长前缀匹配所捕获的location块.
location上下文中较常用的有root命令与proxy_pass命令.
root命令, 会把URI拼接到root命令所示路径后构成本地路径, 获取并向客户端返回该文件, 此时Nginx就起到了静态资源服务器的作用, 这部分请求直接由Nginx处理, 从而减小其背后应用服务器的访问压力.
proxy_pass命令, 此时Nginx便起到反向代理服务器的作用. 即接收客户端请求并转发给应用服务器, 接收响应后再转发给客户端.
直接来看一个例子:
server {
listen 8080;
server_name example.com www.example.com;
root /data/www;
location / {
index index.html index.php;
}
location ~ \.(gif|jpg|png)$ {
expires 30d; # 响应缓存30天
}
location ~ \.php$ {
proxy_pass http://localhost:8080;
proxy_set_header Accept-language zh,zh-CN;
}
}
该主机监听8080端口, 注意root是放在server上下文中的, 此时若某请求匹配到的location块中没有root命令, 就会采用server块中的root命令.
假设URI为”/logo.gif”, 首先进行最长前缀匹配, 确定为第1个location块; 其次再进行正则匹配, 确定为第2个location块; 故最终选择后者, 并根据root命令映射URI到本机”/data/www/logo.gif”, 向客户端返回该资源.
例子中的proxy_set_header, 可对代理接收到的请求头增加或替换某字段, 以便将新值传给应用服务器. 当值为””时, 该字段便不会传给应用服务器.
proxy_set_header 域名 值;
捕获正则式
可以使用(?<domain>.+)捕获正则式, 配合root使用:
server {
server_name ~^(www\.)?(?<domain>.+)$;
location / {
root /sites/$domain;
}
}
负载均衡
location块可以通过proxy_pass命令, 将请求转发给某个应用服务器, 这里Nginx提供了一个便捷, 就是可以用upstream命令将多台服务器组成应用服务器阵列. 此时Nginx将成为一个负载均衡器, 将流量按算法分配到其背后的应用服务器上, 其支持以下几种方式的负载均衡:
1. 轮询(默认)
http {
upstream example_array {
server s1.example_array.com;
server s2.example_array.com;
server s3.example_array.com;
}
server {
listen 80;
location / {
proxy_pass http://example_array;
}
}
}
所有请求都会被转发给”example_array”服务器集群, 请求会依次轮流分配给集群中的服务器. 如果想要使用HTTPS协议, 把协议名改为https即可. 其他则需要更换命令名称: FastCGI使用fastcgi_pass, uwsgi使用uwsgi_pass, memcached使用memcached_pass, gRPC使用grpc_pass.
2. 最少连接数
Nginx会把请求转发给当前集群中活跃连接数最少的应用服务器.
http {
upstream example_array {
least_conn;
server s1.example_array.com;
server s2.example_array.com;
server s3.example_array.com;
}
server {
listen 80;
location / {
proxy_pass http://example_array;
}
}
}
3. IP哈希
以客户端的IP地址作为hash的key, 使得某客户端的全部请求都能交给集群中某指定服务器, 便于服务器的session效果最大化.
http {
upstream example_array {
ip_hash;
server s1.example_array.com weight=3 mail_fails=2 fail_timeout=30s;
server s2.example_array.com;
server s3.example_array.com;
}
server {
listen 80;
location / {
proxy_pass http://example_array;
}
}
}
上面例子中列出了upstream的server命令三个常用参数:
1) weight参数
用以表示服务器承担请求的权重, 默认为1. 上例中, 平均每5个请求中, 有3个会分给s1, 其余s2与s3各分1个.
2) mail_fails与fail_timeout参数
Nginx反向代理包含被动的健康检查机制: 如果在fail_timeout时间内从某服务器上收到多于max_fails个异常响应, Nginx会将该服务器标记为"失败"状态, 并在其后fail_timeout时间内避免向该服务器发送后续请求. 经过这段时间后, Nginx会小心翼翼的对该"失败"服务器发送一个请求, 如果成功响应, 则将该服务器标记为"正常"状态.
max_fails参数默认为1, 当为0时, 被动的健康检查机制会被关闭. fail_timeout参数默认为10s.
文中如有不当之处, 还望包容和指出, 谢谢