写给大忙人的nginx核心配置详解(匹配&重写、集群、环境变量&上下文)

因为当前不少应该都是先后端分离了,同时大量的基于http的分布式和微服务架构,使得不少时候应用和不一样项目组之间的系统相互来回调用,关系复杂。若是使用传统的作法,都在应用中进行各类处理和判断,不只维护复杂、容易出错,还大大增长开发、调试的工做量,在nginx中,有很多的非功能类实际上是能够帮咱们处理掉的,因此,对于现代开发人员来讲,有必要对nginx的location比较熟悉,以便达到事半功倍的效果,好比说,平常的图片上传就是个例子,咱们能够将图片上传到特定的目录,而后配置nginx对于用户上传的图片,都转发到特定的目录,该目录不必定是nginx的html目录,甚至是挂载的盘,这样对于通常的应用来讲,既能够按应用规划设置文件服务器,也避免了须要安装和维护ftp服务器软件的工做。php

 nginx配置

由于Nginx是模块化架构,每一个模块都会有一系列本身引入的指令,这些指令一般包含在指令块中,好比events模块,就有一个events块。以下所示:html

events {
	worker_connections 1024;
}

对于最经常使用的部分,指令块一般层层嵌套。例如:linux

http {
	server {
		listen 80;
		server_name example.com;
		access_log /var/log/nginx/example.com.log;
		location ^~ /admin/ {
			index index.php;
		}
	}
}

默认状况下,之块会继承父块中声明的设置,除非明确覆盖。nginx

在nginx的配置中,语法比较复杂,并且不一样的指令,可能规则彻底不一样。git

好比root仅接受一个字符,声明服务于网站的文件的根路径。github

模块中一般定义了能够用于指令中的变量,变量以$开头。某些指令中不容许使用变量,好比error_log,此时它会被当作字面量处理。web

指令的值能够带双引号、带单引号、不带引号,除非使用了特殊符号,此时须要用引号括起来以免nginx解析误解,对于特殊符号须要当作字面量使用的,须要用\,好比$。正则表达式

 

nginx的基本模块包括Core、Events(主要是声明网络机制,某些参数对系统的性能影响较大)、Configuration,这三个模块提供了整个基础架构。spring

nginx使用多进程架构。sql

核心模块的主要指令:

  • error_log:声明日志文件的位置,error_log /file/path level;格式,默认是logs/error.log error。main,http, server,location级别均可以自定义。
  • thread_pool:声明一个可供aio指令使用的线程池。主要用于服务于异步较大的文件请求时提升性能,thread_pool name threads=number [max_
  • queue=number];默认为thread_pool default threads=32 max_queue=65536;。
  • worker_processes:声明实际工做进程数,默认状况下,nginx会使用检测到的cpu数量而不是1,这一点现代系统基本上都是动态判断,不像早期同样默认为单核,甚至内存都是动态本身判断和设置。
  • worker_cpu_affinity:声明进程跟cpu的亲和关系,通常仅在多核下使用,格式worker_cpu_affinity 1000 0100 0010 0001;每组表明一个进程,每组中的1表明第几个核心。

 

events模块的主要指令包括(这些指令必须声明在events块中):

  • use:声明使用的事件模型,现代linux通常都应该使用epoll。
  • worker_connections:声明工做进程能够同时处理的并发链接数。

 

配置模块的主要指令包括:

  • include指令,在声明的位置插入指定文件的内容,跟spring的import/mybatis的sql同样。nginx内置模块化的文件包括nginx.conf、mime.types、fastcgi_params、proxy.conf、sites.conf,include的值支持通配符。

HTTP Core模块

HTTP Core模块包含了HTTP服务器的全部基础块、指令以及变量,其默认启用,实际上它也是最重要的一个模块。它包含三个主要的块:http,server,location。

  • http块位于最高层,定义了全部和http相关的指令和块。
  • server块声明一个网站,必须声明在http块内。
  • location块声明应用于网站内特定路径的一组设置,能够声明在server块内,或者嵌套在其余location内。

一个典型的http配置结构以下:

主要指令包括:

  • listen:声明监听的地址,listen [address][:port] [additional options];应用于server块。
  • server_name:为server定义一个或多个主机名,server_name hostname1 [hostname2…];若是一个nginx服务提供多个网站时,该值能够用来进行区分。应用于server块。
  • tcp_nopush:启用或者禁用TCP_NOPUSH (FreeBSD)/TCP_CORK(Linux) socket选项,仅在sendfile启用时有效,其做用是nginx尽可能在一个tcp包中传输全部HTTP响应头。应用于全部块。
  • sendfile:若是启用,nginx会使用sendfile内核调用处理文件传输,不然nginx会本身传输。应用于全部块。

路径相关指令包括:

  • root:定义服务客户端请求的根目录,默认为html。应用于全部块以及if。
  • alias:声明用来提取文件时的别名路径,根路径不变,应该主要是用于对外公共接口的内部地址变了。
  • error_page:声明特定HTTP返回码的替换页面。格式为error_page code1 [code2…] [=replacement code] [=@block | URI]。应用于全部块以及if。
  • index:定义nginx的默认页面,默认为index.html,能够声明多个。应用于全部块。

客户端请求相关的指令包括:

  • keepalive_requests:一个长链接最多能够请求的数量,默认100,可应用于http, server, location。
  • keepalive_timeout:定义长链接的超时时间,默认75,第二个参数的值会经过http包头传给客户端,格式:keepalive_timeout time1 [time2];应用于http, server, location。
  • send_timeout:声明nginx多久后关闭未活动链接,客户端中止传输数据开始计算未活动,默认60秒。
  • client_body_buffer_size:声明用于存放客户端请求体的缓存大小,默认8k或者16k,具体是系统架构而定。

限制相关的指令包括:

  • limit_except:设置仅支持哪些HTTP方法。应用于location。例如:
location /admin/ {
	limit_except GET {
		allow 192.168.1.0/24;
		deny all;
	}
}

格式为:

limit_except METHOD1 [METHOD2…] {
	allow | deny | auth_basic | auth_basic_user_file | proxy_pass | perl;
}
  • limit_rate:设置每连接每秒钟的流量,默认不限,应用于http, server, location, if。
  • internal:声明本location仅适用于内部访问,也就是必须经过rewrite才能访问。

文件和缓存相关的指令:

  • directio:当文件超过特定大小时,使用Direct I/O系统机制直接从存储设备读取。应用于http, server, location。

其余指令:

  • merge_slashes:是否合并连续的/为单个/,好比将http://website.com//documents/转换为http://website.com/documents/,默认状况下会报404。应用于http, server, location。
  • resolver:声明nginx使用的自定义的DNS服务器。
  • underscores_in_headers:声明自定义HTTP请求头中是否容许下划线名字,默认为不容许,http头中通常为-分隔。
  • post_action:声明请求执行完成后,nginx调用的uri,特殊状况下可用,好比PV统计。

模块变量

HTTP Core模块包含了不少的变量,分为三类:第一类是在Http请求头中传递的,第二类是http响应头中的,第三类是彻底nginx生成的。参考nginx http server第三版 90页。

nginx容许用户声明样式匹配指定的uri,location的语法为:
location [=|~|~*|^~|@] pattern { ... }
第一个可选的参数是修饰符,各修饰符详解以下:

  • =修饰符:彻底匹配,也就是直接常量比较。
  • 无修饰符:必须以声明的样式开头,也就是like 'pattern%',一般servlet上下文匹配就是无修饰符的模式。
  • ~修饰符:请求的URI必须大小写敏感的匹配声明样式的正则表达式。如:
server {
	server_name website.com;
	location ~ ^/abcd$ {
		[…]
	}
}
  • ~*修饰符:请求的URI必须大小写不敏感的匹配声明样式的正则表达式。
  • ^~修饰符:和无修饰符相似,区别在于若是当前location匹配请求,则不会继续搜索其余的location。
  • @修饰符:定义一个命名location块,这些块不对外开放访问,仅用于内部转发。

搜索顺序和location匹配优先级

不少时候,咱们定义的不止一个location,一般至少会有两个,一个是根自己,一个指向后端服务。因此咱们须要理解nginx接收到一个请求以后,它如何肯定匹配的location。定义在配置文件中的location顺序对于一个请求是否优先匹配没有关系,nginx搜索匹配的样式的顺序以下:

  1. =修饰符的location
  2. 无修饰符的location(若是精确匹配的话)
  3. ^~修饰符的location
  4. ~/~*修饰符的location
  5. 无修饰符的location(若是前缀匹配的话)

Rewrite模块

这个模块的目的就是为了URL重写,URL重写是SEO的关键元素之一。URL重写由rewrite指令执行,它接收一个样式和一个替换URI。

正则表达式规则参考nginx http server第三版P103。
注意,由于正则表达式的{}和nginx指令块冲突,因此若是要使用,必须放到引号中。
捕获,正则表达式中用()括起来的内容会被捕获到一个个内置变量中,$N,N为捕获的索引,从1开始。捕获的变量能够做为指令的值。()也一般和|一块儿使用,二选一。命名捕获使用?<name>语法设置,例如^/(?<folder>[^/]+)/(?<file>.*)$。
在nginx中,在正则表达式中捕获的值,能够在后续指令中使用,只要不被覆盖便可。

server {
	server_name website.com;
	location ~* ^/(downloads|files)/(.*)$ {
		add_header Capture1 $1;
		add_header Capture2 $2;
	}
}

nginx区份内外部请求,内部请求由error_page, index, rewrite,try_files, add_before_body, add_after_body生成。内部请求还分两类:

  • 内部重定向(Internal redirects):最多见的内部重定向是rewrite。
  • 子请求(Sub-requests):内部自动触发,通常用的少。

简单的重定向以下:

server {
	server_name website.com;
	root /var/www/vhosts/website.com/httpdocs/;
	location /storage/ {
		internal;
		alias /var/www/storage/;
	}
	location /documents/ {
		rewrite ^/documents/(.*)$ /storage/$1;
	}
}

Rewrite模块的指令包括:

  • rewrite:为当前请求重写URI,格式为rewrite regexp replacement [flag];flag的取值以及含义为:
    • last:当前的重写规则是最后一个,当前重写应用以后,就去寻找新匹配的location。
    • break:当前重写规则应用以后,再也不找新的location。
    • redirect:返回302以及新的URI地址。
    • permanent:返回301以及新的URI地址。

    若是声明的URI以http://开头,nginx自动使用redirect标志。

    可应用于server,location,if。

  • break:用来防止后续重写,后面的重写都会被忽略。
  • return:停止处理请求,返回声明的状态码或声明的文本。状态码为204, 400, 402 to 406, 408, 410, 411, 413, 416, and 500 to 504。
  • set:初始化或定义变量。
  • uninitialized_variable_warn:若是为on,nginx为每一个遇到的未初始化的变量记录日志。
  • rewrite_log:若是为on,Nginx为每一次重写记录notice级别的日志。

upstream模块

任何以_pass结尾的指令都接受到一组服务器的引用。声明一组服务器的第一步是在http的upstream块内声明一个或多个server指令,以下:

http {
	upstream MyUpstream {
		server 10.0.0.201;
		server 10.0.0.202;
		server 10.0.0.203;
	}
	[…]
}

而后在server块内引用声明的upstream,以下:

server {
	server_name example.com;
	listen 80;
	root /home/example.com/www;
	# Proxy all requests to the MyUpstream server group
	proxy_pass http://MyUpstream;
	[…]
}

nginx提供多种负载均衡机制,P248。从Nginx 1.9.0开始,新增的Stream模块支持TCP负载均衡,这意味原来必须使用LVS或者HAPROXY做为负载均衡机制的模式能够采用NGINX了。
要启用线程池,必须使用--withthreads参数编译nginx,对于常常文件下载的应用,应使用以下配置:

location /downloads/ {
	aio threads;
	directio 8k;
	sendfile on;
}

 

ngx_http_log_module模块负责以声明的格式记录请求日志。
其主要的两个指令是:

  • log_format:声明日志格式。格式为:log_format name [escape=default|json|none] string ...;默认为log_format combined "...";日志格式能够包含公用变量以及仅在日志写的时候存在的变量。配置老是包含预约义的“combined”格式,以下:
  • access_log:设置写日志的路径、格式以及额外配置。格式为:
access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off;

默认为access_log logs/access.log combined;

nginx获取环境变量的值

首先参考centos下nginx安装与配置安装所需模块。

With Lua

If you are using Openresty, or have the ngx_lua module and ngx_devel_kit module installed, you are in luck.

You first need to declare what variables you'll be needing somewhere in your nginx.conf file using the envdirective:

env API_KEY;

After that, when you want to access the environment variable, you can use a combination of set_by_lua and os.getenv, like this:

http {   ...   server {     location / {       set_by_lua $api_key 'return os.getenv("API_KEY")';       ...     }   } }

In this example we are assigning the environment variable to one of Nginx variables; we can use $api_key as a regular nginx.conf variable.

With Perl

Using Lua was our preferred approach, since we have OpenResty. If you can't use Lua, a second solution involves using Perl. The first part is similar; you must declare the variables he uses using env:

env API_KEY;

After that, you can combine perl_set and some Perl to do the same thing as before:

http {   ...   server {     location / {       perl_set $api_key 'sub { return $ENV{"API_KEY"}; }';       ...     }   } }

You will need to have the ngx_http_perl_module module enabled in order to be able to use this technique.

相关文章
相关标签/搜索