编译自:
nginx-web-server
目录:
- 建立虚拟服务器
- 配置 location
- 使用变量
- 返回指定的状态码
- URI 重写
- 对 HTTP Response 进行重写
- 处理错误
这里有一个视频,有兴趣可以看看:nginx 安装与调优,其中讲述了以下主题:
- nginx 怎样使你的应用能更快响应、具有更好的伸缩性、更快、更安全?
- 如何安装 nginx
- 为 nginx 调整操作系统参数
从高层次来说,配置 nginx 为一个 web 服务器,主要是定义:
- 对哪些 URL 进行处理
- 如何处理对于这些 URL 的 HTTP 请求
从较低层次来说,主要是定义一组 虚拟服务器 ,让这些 虚拟服务器 去处理对于 特定域名 或 IP地址 的请求。
更多关于如何配置 nginx 的信息,可参考 Creating NGINX Plus Configuration Files。
每个 虚拟服务器 都定义了 location 区块,location 区块定义了对于指定的一组 URI 是如何进行处理的。
在 location 中可作如下定义:
- 转发请求到后端服务器(也就是将此 nginx 服务器作为代理),或者返回一个文件;
- 对 URI 进行重写,将请求重定向至其它的 location 或者其它虚拟服务器;
- 返回指定的 error code,并且可以为每个 error code 配置一个指定的 error page。
建立虚拟服务器
在 nginx 配置文件中,必须包含至少一个 server 指令,server 指令定义了一个虚拟服务器。当一个请求到来时,nginx 首先要决定选择哪一个虚拟服务器处理该请求。
server 指令在 http context 中进行定义,例如:
http {
server {
# Server configuration
}
}
在 http context 中,可添加多个 server 指令以定义多个虚拟服务器。
在 server 区块中,一般会包含一个 listen 指令。listen 指令是用于定义该虚拟服务器监听于哪个 IP地址 和 端口(或者定义一个 Unix socket 文件及路径)。IP地址可为 IPv4 或 IPv6 地址;IPv6 地址应放入方括号中。
以下是一个例子,该服务器监听于 127.0.0.1 和 8080 端口:
server {
listen 127.0.0.1:8080;
# The rest of server configuration
}
如果不指定端口地址,将使用标准的端口地址,即 80 端口。如果不指定 IP 地址,将监听于所有 IP 地址之上。如果 server 区块中没有包含 listen 指令,根据超级用户的权限,将使用 标准的 80/tcp 端口或者 默认的 8000/tcp 端口。
如果同时有多个 虚拟主机 匹配了请求的IP地址和端口,nginx 将测试请求的 Host 首部字段,将它与 server 区块中的 server_name 指令的配置进行对比。server_name 指令的值有三种:准确的主机名、通配主机名、正则表达式主机名。通配主机名在其起始、或末尾有一个 * 符号,或者起始和末尾都有一个 * 符号,* 可匹配任意长度的字符串;nginx 的正则表达式兼容 Perl 的正则语法,在正则表达式之前需有~
前缀。
以下是关于 准确的主机名 的例子:
server {
listen 80;
server_name example.org www.example.org;
...
}
如果有多个 server_name 指定的主机名与请求首部的 Host 字段匹配,nginx 按如下的优先次序选择,当找到第一个能匹配的 server name 就终止查找:
- 准确的主机名
- 以 “*” 起始的最长的通配主机名,比如 *.example.org
- 以 “*” 结尾的最长的通配主机名,比如 mail.*
- 第一个匹配的正则表达式(按照配置文件中的顺序)
如果没有找到与 Host 字段匹配的 server name,nginx 将把请求路由到该端口地址的 默认的虚拟主机。 如果没有特别指定,默认的虚拟主机 就是 nginx.conf 文件中的第一个定义的 虚拟主机。也可以使用 listen 指令的 default_server 参数显式地指定一个虚拟主机为 默认的虚拟主机 :
server {
listen 80 default_server;
...
}
配置 location
nginx 可基于请求的 URI,将访问流量转发给不同的后端服务器,或者将不同的文件提供给客户端。这个功能由 location 指令定义,location 指令在 server 区块中定义。
举个例子,你可以定义三个 location 区块,将一些请求转发给一个后端服务器,将另一些请求转发给另一个不同的后端服务器,余下的请求从本地的文件系统中提供客户端所请求的文件。
当一个请求交给了某个虚拟主机之后,nginx 将请求的 URI 与该虚拟主机内所有的 location 指令的定义进行对比,然后将请求映射到匹配的 location 之中。
在每个 location 区块中,一般可以放置更多的 location 指令(有少数例外),用于进一步对请求进行分组处理。
Note: 在本文中,location 这个词只表示一个单独的 location 上下文。
location 指令可定义两种参数:
- 前缀字符串(路径名)
- 正则表达式
如果一个请求的 URI 以某个 前缀字符串 为起始,则与该 location 匹配。
下面举一个 前缀字符串 的例子,在下面的例子中,该 location 的参数为 /some/path/ ,它能匹配类似于 URI 为 /some/path/document.html 的请求:
location /some/path/ {
...
}
正则表达式必须带有前缀 ~
或 ~*
(忽略大小写)。在下面的例子中,该 location 可匹配包含 .html 或者 .htm 的请求:
location ~ \.html? {
...
}
为了找到某个 URI 的最佳匹配,nginx 首先比较 URI 和 前缀字符串,然后比较 URI 和 正则表达式。
正则表达式拥有更高的优先级,除非正则表达式使用了 ^~ 修饰符。
在所有匹配的 前缀字符串 中,nginx 选择其中最长及最完整的前缀字符串所对应的 location。
下面是准确的查找 loction 的过程:
- 将 URI 与所有的 前缀字符串 进行比较
- 修饰符 = 表示 URI 与 前缀字符串 必须精确匹配。如果能够精确匹配,则结束查找
- 如果在匹配的最长的 前缀字符串 前添加了 ^~ 修饰符,则不会再检查正则表达式
- 保存匹配的最长的 前缀字符串
- 测试 URI 和 正则表达式的匹配情况
- 一旦找到匹配的正则表达式,则终止查找,并使用对应的 location
- 如果没有匹配的正则表达式,使用保存匹配的最长的 前缀字符串
如果对于 / 的请求很频繁,可为 location / 添加 = 修饰符,这样可以加速处理过程,因为一次匹配查找即可结束:
location = / {
...
}
在 location 区块中,可匹配将请求转发给后端服务器。在下面的例子中,对于匹配第二个 location 的请求,将被转发给 www.example.com:
server {
location /images/ {
root /data;
}
location / {
proxy_pass http://www.example.com;
}
}
root 指令指定了提供静态文件的本地路径。如果请求的 URI 匹配第一个 location,将 URI 追加到 /data 之后即可得到文件的访问路径:/data/URI。比如请求的 URI 为 /images/example.png,nginx 将 /data/images/example.png 文件返回给客户端。
proxy_pass 指令用于将请求转发给后端服务器,参数值即为后端服务器的访问路径 URL。从后端服务器取回响应之后,nginx 再转发给客户端。在上面的例子中,所有不以 /images/ 起始的 URI,对应的请求将被转发给后端服务器。
使用变量
在 nginx.conf 中可使用变量。变量的值在运行时进行计算,可作为指令的参数使用。引用变量,使用 $
符号,比如 $remote_addr
。变量的定义信息依赖于 nginx 当前的状态,比如当前被处理的请求的属性等。
有许多变量是预定义的,比如 core HTTP 定义的变量;另外你也可以自定义变量,使用 set,map,或 geo 指令进行自定义。
大多数变量的值是在运行时计算出来的,其中包含特定请求的信息。比如 $remote_addr
包含客户端的 IP地址 信息,而 $uri
包含当前的 URI 值。
返回指定的状态码
在有些情况下,比如当一个页面已经被临时或永久地移动到其他位置,访问这种 web 站点的 URI 时需要立即返回一个错误码或者重定向码。最容易的方法是使用 return 指令:
location /wrong/url {
return 404;
}
return 指令的第一个参数是响应状态码。第二参数是可选的,可以是一个重定向的 URL(for codes 301, 302, 303, and 307),或者是放入响应 body 的一段文本。比如:
location /permanently/moved/url {
return 301 http://www.example.com/moved/here;
}
return 指令可放入 location 和 server 上下文中。
URI 重写
在处理请求的过程中,使用 rewrite 指令可对 URI 进行多次修改。
rewrite 指令的语法为:
rewrite regex replacement [flag]
regex 是用于匹配 URI 的正则表达式,replacement 参数用于替换匹配的 URI。flag 参数是可选的,可用于终止进一步的 rewrite 指令操作,或者发送重定向(301 或 302)给客户端,例如:
location /users/ {
rewrite ^/users/(.*)$ /show?user=$1 break;
}
在 server 上下文和 location 上下文中,都可包含多个 rewrite 指令。nginx 按照 rewrite 指令出现的顺序依次进行处理。当一个 server 上下文被选择用于处理请求时,在 server 上下文中的 rewirte 指令被执行一次。
当 nginx 对一组 rewrite 指令进行处理之后,它根据新的 URI 选择匹配的 location 上下文。如果在选择的 location 中也包含 rewrite 指令,它们将被依次执行。如果 URI 匹配其中任意一个,当所有定义的 rewrite 指令被处理之后,开始对新的 URI 进行查找。
如下例子中,rewrite 指令和 return 指令联合使用:
server {
...
rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;
rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra last;
return 403;
...
}
上例中,对两组 URI 进行了区分。
类似于 /download/some/media/file 的 URI 请求被替换为 /download/some/mp3/file.mp3。因为该 rewrite 指令添加了 last flag,它将跳过后面的指令(第二个 rewrite 指令和 return 指令)。然后 nginx 开始处理新的 URI。
类似于 /download/some/audio/file 的 URI 请求被替换为 /download/some/mp3/file.ra。因为该 rewrite 指令添加了 last flag,它将跳过后面的指令(return 指令)。
如果 URI 不匹配 location 中的任何一个 rewrite 指令,nginx 返回 403 状态码给客户端。
rewrite 指令有两个参数可以终止 rewrite 指令集的处理:
last - 停止当前 server 或 location 上下文中的 rewrite 指令集的执行,nginx 对修改后的 URI 进行匹配查找。如果新匹配的 location 中包含 rewrite 指令,URI 有可能被再次修改。
break - 如同 break 指令,终止当前上下文中的 rewrite 指令集的执行,nginx 对修改后的 URI 进行匹配查找,在新匹配的 location 中如果包含 rewrite 指令,它们不会被执行。
对 HTTP Response 进行重写
有时你需要对 HTTP 响应报文的内容进行重写或修改。你可以使用 sub_filter 指令来定义重写操作。该指令支持变量和链式替换,可作复杂的修改:
举个例子,你可以对指向一个服务器的绝对链接进行修改:
location / {
sub_filter /blog/ /blog-staging/;
sub_filter_once off;
}
另一个例子,修改 http:// 为 https:// ,并且将 localhost 地址修改为请求首部中的 host 字段的值。sub_filter_once 指令告诉 nginx 是否对所有匹配的字符串重复地执行替换操作,还是只在第一次遇到匹配的字符串时,执行一次替换操作(只替换一次)。sub_filter_once 默认为 on,表示只在第一次遇到匹配的字符串时,替换一次:
location / {
sub_filter 'href="http://127.0.0.1:8080/' 'href="https://$host/';
sub_filter 'img src="http://127.0.0.1:8080/' 'img src="https://$host/';
sub_filter_once on;
}
注意,如果响应报文的一部分已经被一个 sub_filter 指令所修改,当另一个 sub_filter 也匹配该部分时,不会再进行修改。
处理错误
使用 error_page 指令,你可以配置 nginx :
- 返回一个 error code 以及一个自定制的页面;
- 在响应报文中,替换一个不同的 error code
- 发送重定向指令给浏览器,指向不同的 URI
在下面的例子中,error_page 指令指定了 /404.html 页面,这个页面在返回 404 code 时会一并返回给客户端:
error_page 404 /404.html;
要注意的是,这个指令不是立即返回该错误给客户端(这是 return 指令做的事),这只是定义了如果处理该错误。该 error code 可来自于一个后端服务器,或者在 nginx 做一些处理时出现(例如,当 nginx 不能找到请求的文件时,将返回 404 错误)。
下面的例子中,当 nginx 找不到请求的页面时,它将 code 404 替换为了 code 301,并将返回一个重定向给客户端:http:/example.com/new/path.html。
这个配置是很有用的,当客户端尝试以一个老旧的 URI 请求页面时,可返回重定向指令,令其访问在新路径下的文件。
code 301 告诉浏览器,该页面已经被永久地转移到了其他地方,它需要将返回的新的地址替换原来的老的地址:
location /old/path.html {
error_page 404 =301 http:/example.com/new/path.html;
}
下面的例子中,当请求 /images/ 路径下的文件发生文件未找到的错误时,通过内部重定向转发到后端服务器。因为在 error_page 指令中,在 = 后面没有定义替换的状态码,所以返回给客户端的状态码由后端服务器指定(不一定是 404):
server {
...
location /images/ {
# Set the root directory to search for the file
root /data/www;
# Disable logging of errors related to file existence
open_file_cache_errors off;
# Make an internal redirect if the file is not found
error_page 404 = /fetch$uri;
}
location /fetch/ {
proxy_pass http://backend/;
}
}
error_page 指令告诉 nginx ,当发生 file not found 错误时,做一个内部的重定向。$uri 变量的值为当前请求的 URI,在重定向中被转发给了后端服务器。
例如,如果 /images/some/file 未找到,它被替换为 /fetch/images/some/file,对这个新 URI,nginx 会查找与其匹配的 location,这里就是 location /fetch/,然后就被转发给后端服务器了。
(可参考 反向代理)
当发送 file not found 错误时,open_file_cache_errors 指令在这里用于防止记录错误日志。因为请求已经被转发给后端,所以不应该记录错误日志。
版权信息:
*本文编译自 nginx.com