Nginx
环境准备
以下使用 docker 准备学习环境。
- 先拉取
centos的最新镜像:docker image pull centos - 创建一个数据卷用于存放容器中产生的文件:
docker volume create centos - 启动我们的容器:
docker run -d -it -v centos:/workdir --name centos centos /bin/bash - 进入我们的容器:
docker exec -it centos /bin/bash
Nginx 的主要应用场景
- 静态资源服务,即通过本地文件系统提供服务;
- 反向代理服务,提供缓存,负载均衡功能;
API服务,通过Openresty直接访问数据库;
Nginx 的组成部分
Nginx二进制可执行文件;Nginx.confNginx配置文件,控制Nginx的行文;access.log访问日志,记录一条http请求信息;error.log错误日志;
热部署
为了便于演示,在编译Nginx的时候添加echo-nginx-module模块,记录一次编译(我所有的操作都是在目录 /workdir下):
-
源代码下载页面:
http://nginx.org/en/download.html先下载1.14.1版本,然后升级到1.15.6最新版; -
下载源代码并且解压,
wget http://nginx.org/download/nginx-1.14.1.tar.gz,然后tar -xzvf nginx-1.14.1.tar.gz -
下载
nginx-echo-module,wget https://github.com/openresty/echo-nginx-module/archive/master.zip -O nginx-echo-module.zip,并且解压:unzip nginx-echo-module.zip -
我们开始编译,
./configure --prefix=/workdir/nginx --add-module=/workdir/echo-nginx-module-master -
结束之后,我们执行:
make,这时候nginx已经编译好,在objs目录下,例如:![compile.png]()
-
首次编译,我们执行
make install安装我们执行的目录:/workdir/nginx -
至此将看到如下的目录结构:
![directory.png]()
-
修改Nginx的配置文件让其输出版本号,便于以后升级比较,
vim nginx/cong/nginx.conf:![version]()
利用我们添加的
echo模块中包含的echo指令输出 Nginx的版本号。 -
启动 Nginx (执行命令
./nginx/sbin/nginx)之后,我们访问:http://localhost/version,将会看到:![visit version]()
-
我们下载
1.15.6版本,并且编译好,编译的时候依然带上echo模块,但不要执行make install,将会看到如下结构:![new-version]()
-
由于热更新只是替换二进制文件,但是我们在操作之前先备份旧的二进制文件:
cp ./nginx/sbin/nginx ./nginx/sbin/nginx.old -
使用新版的
Nginx二进制文件替换掉当前正在使用中的:cp -f nginx-1.15.6/objs/nginx ./nginx/sbin/nginx -
发送信号至正在运行的Nginx,告诉它我们要进行热部署,升级Nginx,
kill -USR2 MasterPID![查看正在运行的nginx进程]()
这个时候会使用新的二进制文件新起一个
master进程,并且将新的请求转到新的worker进程中处理,旧的master和worker虽然仍然存活,但已经不再监听相应的端口并且接受请求了,这个时候我们在查看版本号,就是升级之后的版本了:[root@5b4bb2c41637 sbin]# curl http://localhost/version 1.15.6 -
关闭老的
worker进程,发送信号给旧的MasterPID,kill -WINCH MasterPID:![close-worker]()
可以看到老的
worker进程已经关闭了,但是此时老的master进程依然存在,是因为如果升级有问题,我们还可回退。回滚的时候,向老的master进程发送HUP信号,向新的master发送QUIT信号。 -
如果正常升级之后,应该给老的
master进程发送QUIT信号,使其优雅退出。
nginx 命令行
nginx -s quit优雅退出进程nginx -s stop立即退出进程
nginx 常用配置学习
配置静态资源访问服务器
1 | server { |
记录 access 日志
使用 ngx_http_log_module 模块我们来配置记录访问日志:
1 | http { |
开启 gzip 压缩
使用 ngx_http_gzip_module 提供的功能,对静态文件进行压缩
1 | http { |
开启防盗链
使用 ngx_http_referer_module 提供的功能实现防盗链:
1 | location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ |
反向代理
使用 ngx_http_upstream_module 模块提供的 upstream 来配置上游服务器:
1 | upstream local { |
指定某些路径配置反向代理,使用ngx_http_proxy_module提供的指令:
proxy_cache_path 配置缓存存储路径:
1 | proxy_cache_path /tmp/nginxcache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off; |
1 | location / { |
配置指令
location
location 配置指令是由 ngx_http_core_module 模块提供,它的配置是下面这个样组的:
1 | 语法: location [ = | ~ | ~* | ^~ ] uri { ... } |
它主要是用于根据请求 URL 设置配置,在解码以 %XX 形式编码的文本,解析对相对路径组件 .和..的引用,并将两个或多个相邻斜杠/的可能压缩为单个斜杠之后,对规范化的URI执行匹配。
一个location 可以被一个前缀字符串定义或者一个正则表达式,正则表达式通过 ~*(大小写不敏感) 或者 ~(大小写敏感) 指定。为了找到与给定请求匹配的 location ,nginx 首先检查使用前缀字符串定义的 location,其中有最长匹配前缀的将被使用,然后按照他们在配置文件中出现的顺序检查正则表达式,正则表达式的搜索在第一个匹配时终止,并使用相应的配置。如果未找到与正则表达式的匹配,则使用先前记住的前缀位置的配置。
location 块是可以嵌套的,但是除了下面提到的。
对于不区分大小写的操作系统(如macOS和Cygwin),与前缀字符串匹配会忽略大小写(0.7.7)。
正则表达式可以包含捕获组,用于后续的其他指令。
如果最长匹配前缀位置具有“^〜”修饰符,则不检查正则表达式。
此外,使用=修饰符可以定义URI和位置的精确匹配。如果找到完全匹配,则搜索终止。例如,如果频繁发生/请求,则定义location = /将加速这些请求的处理,因为搜索在第一次比较之后立即终止。这样的 location 显然不能包含嵌套 location。
我们来通过一个例子说明情况:
1 | location = / { |
/ 请求将会匹配 A,/index.html 将会匹配 B,/documents/document.html 将会匹配 C,/images/1.gif 将会匹配 D,/documents/1.jpg 将会匹配 E。
@ 用于定义一个命名 location,这样的 location 不用于常规请求处理,而是用于请求重定向。它们不能嵌套,也不能包含嵌套 location。
匹配顺序是:先精确匹配,然后前缀匹配取最长匹配,然后是正则表达式;但是如果前缀匹配到 ^~ 则不会进行正则表达式匹配,如果匹配到的最长前缀前面没有 ^~ 则会继续按声明顺序进行正则表达式匹配,取匹配到的第一个正则表达式,否则匹配前缀匹配。
路由重写
NGINX 通过 ngx_http_rewrite_module 模块支持URL重写,支持 if 条件判断,但不支持 else。
NGINX rewrite 指令执行顺序:
- 执行
server快的rewrite指令; - 执行
location匹配; - 执行选定的
location中的rewrite指令;
如果其中某一步 URI 被重写,则重新执行循环 1-3,直到找到真实存在的文件,如果循环超过10次,则返回 500 错误。
break 指令
break 的作用域为 server, location, if,用于停止当前虚拟主机的后续 rewrite 指令集:
1 | if ($slow) { |
if 指令
语法:if(condition) {...}
默认值:无
作用域:server, location
对给定的条件 condition 进行判断。如果为真,大括号内的 rewrite 指令将被执行。if条件( condition )可以是如下任何内容:
- 一个变量名;
false如果这个变量是空字符串或者以0开始的字符串; - 使用
= ,!=比较的一个变量和字符串 - 是用
~, ~*与正则表达式匹配的变量,如果这个正则表达式中包含},;则整个表达式需要用" 或’ 包围 - 使用
-f ,!-f检查一个文件是否存在 - 使用
-d, !-d检查一个目录是否存在 - 使用
-e ,!-e检查一个文件、目录、符号链接是否存在 - 使用
-x , !-x检查一个文件是否可执行
1 | if ($http_user_agent ~ MSIE) { |
return 指令
语法:return code [text];
return code URL;
return URL;
默认值:无
作用域:server,location,if
停止处理并返回指定状态码(code)给客户端。非标准状态码 444 表示关闭连接且不给客户端发响应头。
从0.8.42版本起,return 支持响应URL重定向(对于301,302,303,307),或者文本响应。对于文本或者URL重定向可以包含变量。作为特殊情况,可以将重定向 URL 指定为此服务器的本地URI,在这种情况下,根据请求方案($scheme)以及 server_name_in_redirect 和 port_in_redirect 指令形成完整重定向URL。
rewrite 指令
语法: rewrite regex replacement [flag];
作用域:server, location, if
如果指定的正则表达式匹配请求的URL,URL 将被改变为 replacement 中声明的字符串。rewrite 按照他们在配置文件出现的顺序执行,并且可以使用 [flag] 终止进一步处理。如果 replacement 是以 http://, https://, 或者 $scheme 开始,将不再继续处理,这个重定向将返回给客户端。
flag 参数可以是下列值之一:
last : 停止处理后续 rewrite 指令集,然后对当前重写的新URI在 rewrite 指令集上重新查找;
break : 停止处理后续rewrite指令集,并不在重新查找,但是当前 location 内剩余非 rewrite 语句和 location 外的的非 rewrite 语句可以执行;
redirect : 如果 replacement 不是以 http:// 或 https:// 开始,返回302临时重定向;
permanent: 返回 301 永久重定向。
例子:
1 | server { |
如果这些 rewrite 放到 /download/ location,如下所示, 那么应使用 break 而不是 last, 使用 last 将循环10次匹配,然后返回 500错误:
1 | location /download/ { |
对于重写后的URL(replacement)包含原请求的请求参数,原URL的?后的内容。如果不想带原请求的参数 ,可以在replacement后加一个问号。如下,我们加了一个自定义的参数user=$1,然后在结尾处放了一个问号?,把原请的参数去掉。
1 | rewrite ^/users/(.*)$ /show?user=$1? last; |
rewrite_log 指令
语法:rewrite_log on | off;
作用域:http, server, location, if
开启或关闭以 notice 级别打印 rewrite 处理日志到 error_log 文件。例子:
1 | rewrite_log on; |
set 指令
语法:set $variable value;
作用域:server, location, if
定义一个变量并赋值,值可以是文本,变量或者文本变量混合体。
uninitialized_variable_warn 指令
语法:uninitialized_variable_warn on | off;
作用域:http, server, location, if
控制是否输出为初始化的变量到日志。
参考阅读
- nginx 平滑升级
- nginx rewrite指令
- [ngx_http_rewrite_module 官方模块](http://nginx.org/en/docs/htt






