最近在学习如何对 Nginx 进行配置,故而对 Nginx 的配置文件的结构功能有了一些新的认识。刚开始接触 Nginx 时,感觉它的配置十分高深、难以理解,需要配置什么功能都是网上搜索现成的代码,复制粘贴,重启服务器。虽然也能够按照预期来工作,但是这种做法只是知其然而不知其所以然,不可取。
俗话说,好记性不如烂笔头。现在虽然能力理解看懂,但是过短时间之后还能不能记得那就得两说了。
以下是笔记内容。
注意:这是针对 Linux 平台的笔记,有些内容可能对其他平台并不适用!
启动、停止、重载配置
在安装完 Nginx 程序之后,执行 nginx 可执行文件即可启动 Nginx 服务了。一旦启动了服务之后,我们就可以使用那可执行文件带 -s 参数来控制 Nginx 服务器了,它的语法如下:
nginx -s signal
signal 是以下的信号之一:
- stop 快速停止服务
- quit 优雅地停止服务
- reload 重新加载配置文件
- reopen 重新打开日记文件
例如,重新加载配置文件的命令如下:
nginx -s reload
Nginx 的主进程接收到重载配置文件的信号之后,它会对新配置文件进行语法检查并尝试应用所提供的配置文件。如果成功的话,主进程会启动新的工作者进程,并且发送信号给旧的工作者进程,要求他们关闭。否则的话,主进程会将更新回滚,然后继续以旧的配置文件运行。
配置文件的模块结构
根据使用的平台不同,你的配置文件的路径也会不同,大部分情况下它会在 /etc/nginx/nginx.conf 。如果不在这里,它还可能会在 /usr/local/nginx/conf/nginx.conf 或 /usr/local/etc/nginx/nginx.conf。
Nginx 的配置文件是按配置块来组织的,从结构看起来一目了然。最外一层是 main 配置块,它是一个全局配置的区域;main 配置块下面有 events 和 http 配置块;http 下面又有 upstream 和 server 配置块;server 里有 location 等配置块。
从整体结构上来看,它基本上是这个样子:
# main
....
events {
....
}
http {
....
upstream myproject {
.....
}
server {
....
location {
....
if (test_condition) {
......
}
}
}
server {
....
location {
....
}
}
....
}
常用的基本上就这七大块了:
- main 全局配置块
- events 可以配置 Nginx 的工作模式、工作者进程连接数
- http http 的相关配置块
- server 虚拟主机配置块
- upstream 负载均衡配置块
- location RUI 匹配快
- if 条件判断块
各个模块的功能、常用指令
main 配置块
在这里配置全局的配置信息,常用的有如下这些:
user nobody nobody;
worker_processes 2;
error_log /usr/local/var/log/nginx/error.log notice;
pid /usr/local/var/run/nginx/nginx.pid;
worker_rlimit_nofile 1024;
- user 配置 Nginx 工作者进程的运行用户,默认有 nobody 账号运行
- woker_process 工作者进程的数量
它的最优值取决于多种因素,比如 CPU 的核数,保存数据的硬盘驱动的个数等等。一般情况下,可以将它设置为 CPU 的核数。- error_log 错误日记文件配置
第一个参数是错误日记的文件,第二个参数决定了日记的级别,可选的值有 debug, info, notice, warn, error, crit, alert 或者 emerg- pid 定义一个保存主进程的进程 ID 的文件
- worker_rlimit_nofile 这是工作者进程的最大文件打开数目
events 配置块
用指定 Nginx 的工作模式和工作模式及连接数上限,
events {
use kqueue; #mac平台
worker_connections 1024;
}
- use 指定工作者进程的连接方法
一般情况下是不需要设置这个的,因为 Nginx 会默认会选择最高效的方法- worker_connections 设置每个工作进程能够同时打开的最大连接数
需要注意的是:这个连接数是指所有的连接数(包括与代理服务器的连接数,还有其它的连接数),还有一点就是,最大连接数(worker_connections)的值不能超过当前工作者进程能够打开的最大文件数目(worker_rlimit_nofile)的限制。还有一个关于最大客户端数目的计算问题,有些困扰这我。当作为 HTTP 服务器时,Max_clients=worker_processesworker_connections;当作为代理服务器是,Max_clients=worker_processesworker_connections/4,这个为什么是除以 4 ,而不是 2 呢?
http 配置块
Nginx 的主要功能模块都是在这里配置的,可以在这里配置 Nginx 作为 HTTP 服务器,可以在这里配置 Nginx 成为反向代理,也可以在这配置 Nginx 成为负载均衡器。可以说,这个配置块里的配置内容至关重要!
http{
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /usr/local/var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 10;
upstream myproject {
.....
}
server {
....
}
}
- include 将其它的文件包含到配置文件中
- default_type 定义一个相应的默认 MIME 类型
- log_format 定义日记的格式
- access_log 设置访问日记的路径、格式
- sendfile 启用或者禁用 sendfile()
- tcp_nopush 当 sendfile 启用时,该指令才会生效。
它的作用是启用或者关闭在 freeDSB 中使用 TCP_NOPUSH socket 选项,或者在 linux 中使用 TCP_CORK socket 选项- tcp_nodelay 启用或者禁用 TCP_NODELAY 选项
只有当一个连接是 keep-alive 状态时,该指令才会生效- keepalive_timeout 设置 keep-alive 连接在服务端保持打开的时间
第一个参数表示链接打开的时间,0 表示关闭 keep-alive 在客户端的链接;可选的第二个参数设置响应头部的 “Keep-Alive: timeout=time”。这两个参数可以不同
upstream 配置块
upstream 配置块用来定义一组服务,里面的服务可以监听不同的端口。另外,服务也可以将 TCP 和 UNIX-domain sockets 进行混合使用。
upstream backend {
server backend1.example.com weight=5;
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server unix:/tmp/backend3;
server backup1.example.com backup;
}
上面的代码中定义了一个名为 backend 的负载均衡器,里面有三个后端服务,他们是按 weight 的方式进行轮询的。在每七个请求中,其中的五个会分配到 backend1.example.com 服务器,另外的两个请求分别分配给另外两个服务器。
最后还定义了一个作为备份的服务器,只有当所有的非备份服务器都挂掉之后才会请求备份服务器,所以他的负载时最轻的。
在HTTP Upstream模块中,可以设置后端服务器的 socket 信息,同时还可以设定每个后端服务器在负载均衡调度中的状态。常用的状态有:
- down 表示当前的 server 暂时不参与负载均衡。
backup 预留的备份机器。
当其他所有的非 backup 机器出现故障或者忙的时候,才会请求 backup 机器,因此这台机器的压力最轻。
max_fails 允许请求失败的次数,默认为1。
当超过最大次数时,返回 proxy_next_upstream 模块定义的错误。
fail_timeout,在经历了 max_fails 次失败后,暂停服务的时间。
max_fails 可以和 fail_timeout 一起使用。
Nginx 支持四种负载均衡的方法,它们分别是 Round-robin 、least_conn、ip_hash 和 hash 。
- Round-robin 这是根据权重的轮询方式,Nginx 默认使用这种方法。
upstream backend {
server backend1.example.com weight=3;
server backend2.example.com;
}
- least_conn 具有最少活跃连接数的服务器将会被发送请求。
upstream backend {
least_conn;
server backend1.example.com;
server backend2.example.com;
}
- ip_hash 根据客户端的 ip 地址来决定将请求发送给哪个服务器。
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
}
- hash 根据用户自定义的 hash 值来决定将请求发送到哪个服务器
upstream backend {
hash $request_uri consistent;
server backend1.example.com;
server backend2.example.com;
}
server 配置块
server 配置块是用来配置虚拟主机的信息的,可以在这里配置虚拟主机监听的端口,域名,URL 重定向等。
server {
listen 8080;
server_name localhost 192.168.12.10 www.yangyi.com;
# 全局定义,如果都是这一个目录,这样定义最简单。
root /var/www;
index index.php index.html index.htm;
charset utf-8;
access_log usr/local/var/log/host.access.log main;
aerror_log usr/local/var/log/host.error.log error;
....
}
- listen 用来设置虚拟主机要监听的端口
- server_name 设置虚拟主机的域名,多个域名使用空格隔开
- root 设置虚拟主机目录
index 定义目录中没有指定文件时的默认访问的文件。
服务器会根据指定的顺序来检查所指定的文件,文件名可以包含变量,最好一个可以指定绝对路径,例如:index index.$geo.html index.0.html /index.html;
- charset 指定特定的字符集到响应头部的 “Content-Type” 首部。
- access_log 设置访问日记的路径及格式。
- error_log 设置错误日记的路径及格式。
location 配置块
在这里可以针对指定的请求 URI 来设置配置。
location / {
root /var/www/;
index index.php index.html index.htm;
}
root 和 index 指令的作用上面已经提到过了,写在这里和写在 server 里面的区别是,前者是针对指定的 URI 生效,后者是全局生效的。
一个 location 可以匹配字符串前缀,也可以匹配正则表达式。正则表达式会以 “~*”(大小写不敏感) 修饰符开始,或者以 “~”(大小写敏感) 修饰符开始。
为了寻找一个与当前请求匹配的 location,Nginx 首先检查那些以前缀字符串定义的 location,然后选中其中匹配的前缀最长的 location 并将其记住。
接着再按照配置文件中定义的顺序来检查那些以正则表达式定义的 location,一旦查找到匹配的正则表达式就马上停止查找,其相应的配置将会被使用。
如果没有找到与之对应的正则表达式,那么之前匹配的前缀字符串 location 里面的配置将会被使用。
当然,可以使用 “=” 修饰符来定义一个对 URI 或者 location 的精确的匹配,Nginx 一旦找到一个精确匹配,检查则立马结束。举个例子,假如 ‘/’ 经常被请求,那么定义一个 “location = /” 会加速这些请求的处理,因为在第一个比较之后就立马停止了搜索。
如果最长的前缀匹配包含有 “^~” 修饰符,那么 Nginx 将不会再检查正则表达式。
可以通过下面几个小例子来理解上面的内容:
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。
if 配置块
对特定的条件进行判断,如果条件为真则执行配置块里面的配置项。
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1 break;
}
如果该请求是来自 IE 浏览器的则进行重定向到指定的文件夹。
- rewrite 将 URI 重定向到另一个 URI
if 指令将会对特定的条件进行判断,如果条件为真,大括号里面的指令将会执行,if 指令里面的配置将会分配到请求中。if 指令里面的配置将会继承上一级的配置。
条件可以是以下列举的任意一项:
- 一个变量名,如果变量的值是空或者 “0” 则为假。
- 使用 “=” 或者 “!=” 进行比较的变量
- 使用 “~*”(大小写不敏感) 或者 “~”(大小写敏感)的正则表达式进行匹配的变量
- 使用 “-f” 和 “!-f” 运算符来检测文件是否存在
- 使用 “-d” 和 “!-d” 运算符来检测目录是否存在
- 使用 “-e” 和 “!-e” 运算符来检测文件、目录或者符号链接是否存在
- 使用 “-x” 和 “!-x” 运算符来检测文件是否可执行
例子:
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1 break;
}
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
set $id $1;
}
if ($request_method = POST) {
return 405;
}
if ($slow) {
limit_rate 10k;
}
if ($invalid_referer) {
return 403;
}
一些不常用的配置块
split_clients
该配置块可以将服务器接收到的请求根据百分比进行划分成几个类别。因此可以将不同的内容提供给不同的客户端来进行 A/B 测试。
map
该配置块可以根据一个变量的值来设置另一个变量的值。
geo
该配置快可以用来配置一个映射。
types
这也是用来配置映射的。
内嵌的变量
- $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 已经经过 Auth Basic Module 验证的用户名
- $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://nginx.org/en/docs/
https://www.zybuluo.com/phper/note/89391
https://www.digitalocean.com/community/tutorials/understanding-the-nginx-configuration-file-structure-and-configuration-contexts