Nginx配置文件
本部分参考了文章
建议参考 nginx 官网文档
nginx.conf 结构
nginx.conf 的结构
{
main
events : {}
http : {
main
server : {
main
location : {}
}
}
}
最外面的块是 main,main 包含 Events 和 HTTP,HTTP 包含 upstream 和多个 Server,Server 又包含多个 location;
- main 块设置的指令将影响其他所有设置,相当于全局设置;
- event 主要设置连接相关的配置。
- http 设定http服务
- upstream 指令主要用于设置负载均衡。
- server 块的指令主要用于指定主机和端口,设置网站,例如虚拟主机;
- location 块用于匹配网页位置,就是匹配网页的路径,匹配到的路径可以做一些事情,例如反向代理(服务器端)。
以下转载了 Nginx配置文件详细说明 中的内容
main 配置
基础配置。
daemon:不要在生产环境使用 daemon 和 master_process 配置,应该直接使用默认的值。
#运行用户, 默认值 nobody
user www-data;
#启动进程数,通常设置成和cpu的数量相等
worker_processes 1;
#全局错误日志及PID文件,可以设置成根目录开始。
#${prefix}/logs/error.log
error_log logs/error.log;
#pid 文件在不同应用中有不同的作用
#普通应用的pid文件只有一行,记录该进程的PID,防止进程启动多个副本
#由于nginx会启动多个进程,其pid文件会有多行,里面记录着nginx启动的进程,
#这样在重新加载nginx 的配置时,只要kill -HUP 'cat /path/nginx.pid'就可以
pid /var/run/nginx.pid;
event 配置
#工作模式及连接数上限
events {
#epoll是多路复用IO(I/O Multiplexing)中的一种方式,但是仅用于linux2.6以上内核,
#可以大大提高nginx的性能
use epoll;
#单个后台worker process进程的最大并发链接数
worker_connections 1024;
}
http 配置
设定http服务器。参考 OpenResty最佳实践
主配置
基础配置,传输数据的类型,日志,如何发送数据,超时,压缩等。
#以设定http服务器,利用它的反向代理功能提供负载均衡支持 为例
http {
#设定mime类型,类型由mime.type文件定义
#MIME多用途邮件扩展,实际并不仅仅和邮件相关。在http中用于标识传输数据的类型)
include /etc/nginx/mime.types;
# default_type 属于HTTP核心模块指令,这里设定默认类型为二进制流,
# 也就是当文件类型未定义时使用这种方式,例如在没有配置PHP环境时,
# Nginx是不予解析的,此时,用浏览器访问PHP文件就会出现下载窗口。
default_type application/octet-stream;
# 设定日志格式,详细介绍参加下面 ngix log
#(main 为当前日志格式的名称,在下面 access_log 可以直接使用这个名称指定日志格式)
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'
'$upstream_addr $upstream_response_time $request_time ';
access_log logs/access.log main;
# sendfile 指令指定 nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件,
# 对于普通应用,必须设为 on
# 如果用来进行下载等应用磁盘IO重负载应用,可设置为 off,
# 以平衡磁盘与网络I/O处理速度,降低系统的uptime.
# 关于sendfile的原理参见下面
sendfile on;
#tcp_nopush会设置调用tcp_cork方法,而tcp_cork方法和tcp_nodelay方法是互斥的。tcp_cork的意思是当有一个数据包时不会马上传输出去,而是会等到数据包最大时,一起传输。而tcp_nodelay收到包后马上传输。前者的好处是可以提高一个数据报中有效信息的比例。而后者延迟小。
#tcp_nopush on;
#连接超时时间
#keepalive_timeout 0;
keepalive_timeout 65;
tcp_nodelay on;
#gzip模块设置。gzip 压缩响应数据,减少传输数据量
gzip on; #开启gzip压缩输出
gzip_min_length 1k; #响应头的"Content-Length"的值大于gzip_min_length的响应才会进行压缩
gzip_buffers 4 16k; #压缩缓冲区,按照原始数据大小以4k为单位的32倍申请内存。
gzip_http_version 1.0; #压缩版本(默认1.1,前端如果是squid2.5请使用1.0)
gzip_comp_level 5; #压缩等级,通常合理取值是4-6。
gzip_types application/x-www-form-urlencoded; #指定需要压缩的响应内容类型,text/html类型总会被压缩,不需要显式的指定
#设定请求缓冲,有关请求缓冲的解释参见下面
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
# 如果收到的请求大于指定的大小,那么Nginx会回复HTTP 413错误(Request Entity too large)
client_max_body_size 8m;
# 设定了request body的缓冲大小。如果body超过了缓冲的大小,那么整个body或者部分body将被写入一个临时文件。
# 如果Nginx被设置成使用文件缓冲而不使用内存缓冲,那么这个dirctive就无效
client_body_buffer_size 1024k;
# nginx隐藏版本号server_tokens
server_tokens = off
# 设置 http 头的值(文档 https://github.com/openresty/headers-more-nginx-module#readme)
# 对于状态码为 404 且 类型为 text/plain 的设置 Foo 的值为 bar
more_set_headers -s 404 -t 'text/plain' 'Foo: bar';
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
# lua 相关的配置,在使用 lua 相关库前,要在 nginx.conf 中引入
lua_package_path "/usr/example/lualib/?.lua;;"; #lua 模块
lua_package_cpath "/usr/example/lualib/?.so;;"; #c模块
upstream 配置
设置负载均衡,可以使用lua文件,进行负载均衡。和server里面的location定义配合使用。
#设定负载均衡的服务器列表, mysvr替换为你的域名
upstream mysvr {
#weigth参数表示权值,权值越高被分配到的几率越大
#本机上的Squid开启3128端口
server 192.168.8.1:3128 weight=5;
server 192.168.8.2:80 weight=1;
server 192.168.8.3:80 weight=6;
}
upstream mysvr1 {
0.0.0.1; # just an invalid address as a place holder
balancer_by_lua_file /work/lua/xx.lua; # 这里可以指定一个文件,也可以使用 {//你的 lua 代码}
keeplive 1024; //连接池
}
server 配置
配置具体提供服务的部分。
server {
#侦听80端口
listen 80;
#域名可以有多个,用空格隔开。
#请求中的 host 会与 server_name 做匹配,使用最先匹配的 server 配置
server_name www.ospring.pw ospring.pw;
#设定本虚拟主机的访问日志
access_log logs/www.xx.com.access.log main;
#关于location参见下面的详细说明
# 图片缓存时间设置。
# ~表示使用正则,区分大小写。
# 正则 . 表示匹配除换行符 \n 之外的任何单字符,* 表示0或多个字符 $表示以前面的为结尾
location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$ {
expires 10d;
}
# JS和CSS缓存时间设置
location ~ .*.(js|css)?$ {
expires 1h;
}
#默认请求
location / {
root /root; #定义服务器的默认网站根目录位置
index index.php index.html index.htm; #定义首页索引文件的名称
fastcgi_pass www.xx.com;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
include /etc/nginx/fastcgi_params; //我们可以把一些通用配置写到文件中,通过 include 实现复用
}
# 定义错误提示页面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /root;
}
#静态文件,nginx自己处理
# / 表示正则开始和结束
location ~ ^/(images|javascript|js|css|flash|media|static)/ {
root /var/www/virtual/htdocs;
#过期30天,静态文件不怎么更新,过期可以设大一点,如果频繁更新,则可以设置得小一点。
expires 30d;
}
#PHP 脚本请求全部转发到 FastCGI处理. 使用FastCGI默认配置.
# 正则使用 \ 转义
location ~ \.php$ {
root /root;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/www/www$fastcgi_script_name;
include fastcgi_params;
}
#对aspx后缀的进行负载均衡请求
location ~ .*\.aspx$ {
root /root; #定义服务器的默认网站根目录位置
index index.php index.html index.htm; #设置默认首页
proxy_pass http://mysvr ;#请求转向 mysvr (上面定义的 upstream )定义的服务器列表。也可以是别人的服务器
}
#设定查看Nginx状态的地址
location /NginxStatus {
stub_status on; //输出当前服务器的状态,如已接受的客户端连接总数,已处理的客户端连接总是
access_log on;
auth_basic "NginxStatus"; #是否启用密码认证,string | off
auth_basic_user_file conf/htpasswd; #指定密码认证的配置文件路径,只有在auth_basic启用时有效。是存储用户名,密码对的文件,提前使用 httpd 的指令生成
}
# 定义错误页
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
#禁止访问 .htxxx 文件
location ~ /\.ht {
deny all;
}
以上为一个http服务器的基础配置。
location
error_page
error_page code … [=[response]]uri;
- code
要处理的HTTP错误代码 - response
将code指定的错误代码转换为新的错误代码 - uri
错误页面的路径或者网站地址,这个uri是相对于root设置的根路径而言的。 - 示例:
error_page 404 /404.html;
allow
allow address | CIDR | unix |all;
- 示例
allow 172.16.100.120;
rewrite
Nginx中的Rewrite的重定向配置与实践
该指令是通过正则表达式的使用来改变URI。可以同时存在一个或多个指令。需要按照顺序依次对URL进行匹配和处理。
该指令可以在server块或location块中配置,其基本语法结构如下:
rewrite regex replacement [flag];
regex:用于匹配URI的正则表达式。
replacement:将regex正则匹配到的内容替换成 replacement。
flag: flag标记,有如下值:
- last:
本条规则匹配完成后,继续向下匹配新的* location URI 规则。(不常用) - break
本条规则匹配完成即终止,不再匹配后面的任何规则(不常用)。 - redirect
返回302临时重定向,浏览器地址会显示跳转新的URL地址。 - permanent
返回301永久重定向。浏览器地址会显示跳转新的URL地址。
变量
分成两种类型:用户自定义变量,内建变量。
用户自定义变量
Nginx 变量定义是全局的,而值的生命期和作用范围与当前请求绑定。
# 变量定义
set $variableName variableValue
# 变量引用
$variableName
内建变量
if
在 nginx 中还可以使用 if 指令,决定不同的配置,搭配 rewrite 等,能实现较为复杂的配置
Nginx中的Rewrite的重定向配置与实践
if 使用的匹配规则与 location相同,如:
set $cors_origin "";
if ($http_origin ~* 'https?://(www\.ospring\.pw|.*\.ospring\.pw)') {
set $cors_origin $http_origin;
}
附录(术语)
MIME(Multipurpose interent mail extensions)
MIME并不是专用于邮件的一种格式,而是通用的用来表示传输内容的标准协定。
在HTTP中,MIME类型被定义在header中的Content-Type 字段。在ngingx的配置文件中有指令
include /etc/nginx/mime.types;
当web服务器收到静态的资源文件请求时,依据请求文件的后缀名在服务器的MIME配置文件中找到对应的 MIME Type,再根据 MIME Type 设置 HTTP Response 的 Content-Type,然后浏览器根据 Content-Type 的值处理文件
/etc/nginx/mime.types;文件类似下面(裁剪了一部分内容)
types {
text/html html htm shtml;
text/css css;
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
application/javascript js;
application/atom+xml atom;
application/rss+xml rss;
text/mathml mml;
text/plain txt;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/x-component htc;
image/png png;
image/svg+xml svg svgz;
image/tiff tif tiff;
font/woff woff;
font/woff2 woff2;
application/java-archive jar war ear;
application/json json;
application/mac-binhex40 hqx;
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
xlsx;
application/vnd.openxmlformats-officedocument.wordprocessingml.document
docx;
application/octet-stream bin exe dll;
application/octet-stream deb;
application/octet-stream dmg;
audio/midi mid midi kar;
audio/mpeg mp3;
video/3gpp 3gpp 3gp;
video/mp2t ts;
video/mp4 mp4;
}
其中:形如text/html格式的字符串就是用来说明数据类型的,/ 前的是主类型,/ 之后的是该主类型下的子类型。详细的类型定义在RFC2046中。Nginx通过服务器端文件的后缀名来判断这个文件属于什么类型,再将该数据类型写入HTTP头部的Content-Type字段中,发送给客户端。
比如,当我们打开OSC(Open Source Commerce)的一个页面,看到一个PNG格式的图片的时候,Nginx是这样发送格式信息的:
- 服务器上有enter_narrow.png这个文件,后缀名是png;
- 根据mime.types,这个文件的数据类型应该是image/png;
- 将Content-Type的值设置为image/png,然后发送给客户端
nginx log
access log
nginx的log日志分为access log 和 error log参考博文
- access log 记录了哪些用户,哪些页面以及用户浏览器、ip和其他的访问信息;
- error log 则是记录服务器错误日志
1.$remote_addr 与$http_x_forwarded_for 用以记录客户端的ip地址;
2.$remote_user :用来记录客户端用户名称;
3.$time_local : 用来记录访问时间与时区;
4.$request : 用来记录请求的url与http协议;
5.$status : 用来记录请求状态;成功是200,
6.$body_bytes_s ent :记录发送给客户端文件主体内容大小;
7.$http_referer :用来记录从那个页面链接访问过来的;
8.$http_user_agent :记录客户端浏览器的相关信息;
error log
NGINX error log format documentation
通过阅读src / core / ngx_log.c我猜一般的错误日志格式似乎是:
YYYY/MM/DD HH:MM:SS [LEVEL] PID#TID: *CID MESSAGE
PID是日志进程 ID, TID 是线程Id。CID标识一个(可能是代理的)连接的数字,可能是一个计数器。 *CID部分是可选的。
sendfile
参考博客
sendfile实际上是 Linux2.0+以后的推出的一个系统调用,web服务器可以通过调整自身的配置来决定是否利用 sendfile这个系统调用。
传统网络传输过程
先来看一下不用 sendfile的传统网络传输过程:
read(file,tmp_buf, len);
write(socket,tmp_buf, len);
硬盘 >> kernel buffer >> user buffer>> kernel socket buffer >>协议栈
一个基于socket的服务,首先读硬盘数据,然后写数据到socket 来完成网络传输的。上面2行用代码解释了这一点,不过上面2行简单的代码掩盖了底层的很多操作。来看看底层是怎么执行上面2行代码的:
1、系统调用 read()产生一个上下文切换:从 user mode 切换到 kernel mode,然后 DMA 执行拷贝,把文件数据从硬盘读到一个 kernel buffer 里。
2、数据从 kernel buffer拷贝到 user buffer,然后系统调用 read() 返回,这时又产生一个上下文切换:从kernel mode 切换到 user mode。
3、 系统调用write()产生一个上下文切换:从 user mode切换到 kernel mode,然后把步骤2读到 user buffer的数据拷贝到 kernel buffer(数据第2次拷贝到 kernel buffer),不过这次是个不同的 kernel buffer,这个 buffer和 socket相关联。
4、系统调用 write()返回,产生一个上下文切换:从 kernel mode 切换到 user mode ,然后 DMA 从 kernel buffer拷贝数据到协议栈。
上面4个步骤有4次上下文切换,有4次拷贝,我们发现如果能减少切换次数和拷贝次数将会有效提升性能。在kernel2.0+ 版本中,系统调用 sendfile() 就是用来简化上面步骤提升性能的。sendfile() 不但能减少切换次数而且还能减少拷贝次数。
使用sendfile的网络传输过程
再来看一下用 sendfile()来进行网络传输的过程:
sendfile(socket,file, len);
硬盘 >> kernel buffer (快速拷贝到kernelsocket buffer) >>协议栈
1、 系统调用sendfile()通过 DMA把硬盘数据拷贝到 kernel buffer,然后数据被 kernel直接拷贝到另外一个与 socket相关的 kernel buffer。这里没有 user mode和 kernel mode之间的切换,在 kernel中直接完成了从一个 buffer到另一个 buffer的拷贝。
2、DMA 把数据从 kernelbuffer 直接拷贝给协议栈,没有切换,也不需要数据从 user mode 拷贝到 kernel mode,因为数据就在 kernel 里。
简单说,sendfile是个比 read 和 write 更高性能的系统接口, 不过需要注意的是,sendfile 是将 in_fd 的内容发送到 out_fd 。而 in_fd 不能是 socket , 也就是只能文件句柄。 所以当 Nginx 是一个静态文件服务器的时候,开启 SENDFILE 配置项能大大提高 Nginx 的性能。 但是当 Nginx 是作为一个反向代理来使用的时候,SENDFILE 则没什么用了,因为 Nginx 是反向代理的时候。 in_fd 就不是文件句柄而是 socket,此时就不符合 sendfile 函数的参数要求了。
请求缓冲
client_header_buffer_size
large_client_header_buffers
先根据client_header_buffer_size配置的值分配一个buffer,如果分配的buffer无法容纳 request_line/request_header,那么就会再次根据large_client_header_buffers配置的参数分配large_buffer,如果large_buffer还是无法容纳,那么就会返回414(处理request_line)/400(处理request_header)错误
vhost
虚拟 http 服务器。,每一个 nginx.conf 中的每一个 server 项都配置一个虚拟的 http 服务器。
同一 ip:port 上的不同 vhost 通过域名相互区分。Nginx 收到请求后会根据域名定位到对应的 vhost 的 server 配置。但是,Nginx从请求中解析域名(header 解析阶段)的时候就要用到 client_header_buffer_size 这个配置,但是由于请求没有解析,拿不到 IP 和 Port,所以没办法,只能设置一个默认的服务器(default_server)。
最终结论是所有在 header 解析阶段用到的配置都只能从 default_server 读取,因为这个时候无法确定要用哪个具体的 server。
可以通过指定default参数设置默认default_server(如果不指定,默认第一个server)
server {
listen 80;
server_name db.job360.com;
......
}
server {
listen 80 default;
server_name www.job360.com;
large_client_header_buffers 1m;
......
}
location
语法规则:
location [=|~|~*|^~] /uri/ { … }
- = 表示精确匹配。只有请求的url路径与后面的字符串完全相等时,才会命中。
- ^~ 表示如果该符号后面的字符是最佳匹配,采用该规则,不再进行后续的查找。
- ~ 开头表示区分大小写的正则匹配,
- ~* 开头表示不区分大小写的正则匹配
- !~和!~*分别为区分大小写不匹配及不区分大小写不匹配 的正则
- / 通用匹配,任何请求都会匹配到。
匹配规则
location的配置有两种形式,前缀字符和正则。查找匹配的流程为:
- 先查找前缀字符,保存最长匹配项,再查找正则。
- 正则的查找是按照在配置文件中的顺序进行的,找到的第一个作为匹配即返回,因此正则的优先级是优于前缀字符的。因此正则的顺序很重要,建议越精细的放的越靠前。如果正则没有匹配到,则使用最长匹配项。
例子可以参考1 参考2
URL尾部的 / 需不需要
关于URL尾部的/有三点也需要说明一下。第一点与location配置有关,其他两点无关。
- location 中的字符有没有 / 都没有影响。也就是说 /user/ 和 /user 是一样的。
- 如果 URL 结构是 https://domain.com/ 的形式,尾部有没有 / 都不会造成重定向。因为浏览器在发起请求的时候,默认加上了 /。虽然很多浏览器在地址栏里也不会显示 / 。这一点,可以访问 baidu 验证一下。
- 如果 URL 的结构是 https://domain.com/some-dir/ 。尾部如果缺少 / 将导致重定向。因为根据约定,URL 尾部的 / 表示目录,没有 / 表示文件。所以访问 /some-dir/ 时,服务器会自动去该目录下找对应的默认文件。如果访问 /some-dir 的话,服务器会先去找 some-dir文 件,找不到的话会将 some-dir 当成目录,重定向到 /some-dir/ ,去该目录下找默认文件。可以去测试一下你的网站是不是这样的。
nginx 和 lua
参考
各种lua文件存在于nginx.conf文件中, ngx 和 ndk 软件包位于ngx_lua中的默认全局范围内,可以不用包含就在对应的lua文件中使用, 也可以通过包含使用,包含方法为
local ngx = require“ngx”
local ndk = require“ndk”
ngx.log(ngx.err, "remind info ", $YouNeedToShowVariable)
在 nginx 运行的各个阶段,都可以通过 init_by_lua_block, body_filter_by_lua_block 设置相应到的 lua 指令,从而对 nginx 网关工作,http 请求的过程进行干预,可以说非常灵活,因此网关完全不仅仅只做转发请求,完全可以做一些逻辑处理。
init_by_lua_block
Nginx Lua的执行阶段
init_by_lua_block是init_by_lua的替代版本。
在OpenResty 1.9.3.1 或 Lua-Nginx-Modulev 0.9.17 之前使用的都是init_by_lua。
init_by_lua_block比init_by_lua更灵活,所以建议优先选用init_by_lua_block。
语法
init_by_lua_block {luaCode}
含义
配置环境:http
阶段:loading-config
当Nginx的master进程加载Nginx配置文件(加载或重启Nginx进程)时,会在全局的Lua VM(Virtual Machine,虚拟机)层上运行 luaCode (lua 代码),每次当Nginx获得HUP(即Hangup)重载信号加载进程时,代码都会被重新执行。
init_by_lua_file
init_by_lua_file和init_by_lua_block的作用一样,主要用于将init_by_lua_block的内容转存到指定的文件中,这样Lua代码就不必全部写在Nginx配置里了,易读性更强。
init_worker_by_lua_block
语法:
init_worker_by_lua_block {lua-script-str}
含义:
配置环境:http
阶段:starting-worker
当master进程被启动后,每个worker进程都会执行Lua代码。如果Nginx禁用了master进程,init_by_lua*将会直接运行。
作用
常用来启动定时任务