Nginx 核心知识 100 讲学习笔记
初识 nginx
nginx 适用场景
静态资源服务:通过本地文件系统提供服务。
反向代理服务:nginx 的强大性能,缓存,负载均衡。
API 服务:OpenResty
Nginx 的优点
高并发,高性能
可扩展性好
高可靠性
热部署
BSD 许可证(开源免费)
Nginx 的组成
Nginx 的版本发布
nginx 编译
- vim 语法支持
cp -r contrib/vim/* ~/.vim/
查看帮助文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18[root@ecs nginx-1.18.0]# ./configure --help|more
......
第一类
--prefix=PATH
第二类:使用哪些和不使用哪些模块
--with-http_ssl_module #默认是不编译进nginx的
--without-http_charset_module #默认是编译进nginx,加这个参数就是卸载这个模块
第三类:特殊优化参数
--with-cc=PATH set C compiler pathname
--with-cpp=PATH set C preprocessor pathname
--with-cc-opt=OPTIONS set additional C compiler options
--with-ld-opt=OPTIONS set additional linker options
--with-cpu-opt=CPU中间文件介绍
生成中间文件在什么地方?
1
2
3
4
5
6
7
8
9
10
11
12[root@ecs nginx-1.18.0]# cd objs/
[root@ecs objs]# ll
total 5148
-rw-r--r-- 1 root root 17457 Feb 16 09:53 autoconf.err
-rw-r--r-- 1 root root 40144 Feb 16 09:53 Makefile
-rwxr-xr-x 1 root root 5130480 Feb 16 09:55 nginx
-rw-r--r-- 1 root root 5375 Feb 16 09:55 nginx.8
-rw-r--r-- 1 root root 7037 Feb 16 09:53 ngx_auto_config.h
-rw-r--r-- 1 root root 657 Feb 16 09:53 ngx_auto_headers.h
-rw-r--r-- 1 root root 5856 Feb 16 09:53 ngx_modules.c #所有的模块都放在 ngx_modules.c
-rw-r--r-- 1 root root 45232 Feb 16 09:55 ngx_modules.o
drwxr-xr-x 9 root root 91 Feb 16 09:53 src为什么要知道 nginx 编译中间文件是放在这里呢?
在进行 nginx 版本升级的时候不能执行 make instal 需要把中间文件拷贝到安装目录下
c 语言编辑生成的所有中间目录都会放在 src 目录中
1
2
3
4
5
6
7
8
9
10/[root@ecs objs]# cd src
[root@ecs src]# ll
total 8
drwxr-xr-x 2 root root 4096 Feb 16 09:55 core
drwxr-xr-x 3 root root 191 Feb 16 09:55 event
drwxr-xr-x 4 root root 4096 Feb 16 09:55 http
drwxr-xr-x 2 root root 6 Feb 16 09:53 mail
drwxr-xr-x 2 root root 6 Feb 16 09:53 misc
drwxr-xr-x 4 root root 31 Feb 16 09:53 os
drwxr-xr-x 2 root root 6 Feb 16 09:53 stream如果使用了动态模块、生成的 so 文件也会放在这个目录下
编译安装
1
2
3./configure --prefix=/usr/local/nginx
make
make install1
2
3
4
5
6
7
8
9
10编译安装nginx需要pcre包,未安装会有如下提示:
./configure: error: the HTTP rewrite module requires the PCRE library.
You can either disable the module by using --without-http_rewrite_module
option, or install the PCRE library into the system, or build the PCRE library
statically from the source with nginx by using --with-pcre=<path> option.
需要安装pcre的devel包,pcre-devel。使用yum安装即可:(以下命令还带有ssl、zlib等依赖的安装)
yum -y install zlib zlib-devel openssl openssl-devel pcre pcre-devel
再重新编译安装
- vim 语法支持
nginx 配置语法
配置文件由指令与指令块构成
每条指令以;分号结尾,指令与参数间以空格符号分隔
指令块以{}大括号将多条指令组织在一起
include 语句允许组合多个配置文件以提升可维护性
使用 #符号添加注释,提高可读性
使用 $ 符号使用变量
部分指令的参数支持正则表达式
nginx 的命令行
重载配置文件
1
2
3
4
5
6
7
8
9
10
11
12[root@ecs sbin]# ./nginx
[root@ecs sbin]# ps -ef|grep nginx
root 254641 1 0 10:21 ? 00:00:00 nginx: master process ./nginx
nobody 254642 254641 0 10:21 ? 00:00:00 nginx: worker process
root 254644 221527 0 10:21 pts/0 00:00:00 grep --color=auto nginx
[root@ecs sbin]# vim ../conf/nginx.conf
[root@ecs sbin]# ./nginx -s reload
[root@ecs sbin]# ps -ef|grep nginx
root 254641 1 0 10:21 ? 00:00:00 nginx: master process ./nginx
nobody 254682 254641 0 10:22 ? 00:00:00 nginx: worker process
root 254694 221527 0 10:23 pts/0 00:00:00 grep --color=auto nginx热部署
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39[root@ecs sbin]# pwd
/usr/local/nginx/sbin
[root@ecs sbin]# cp nginx nginx.old
[root@ecs sbin]# cd /data/soft/nginx/nginx-1.18.0/objs/
[root@ecs objs]# ll
total 5148
-rw-r--r-- 1 root root 17457 Feb 16 09:53 autoconf.err
-rw-r--r-- 1 root root 40144 Feb 16 09:53 Makefile
-rwxr-xr-x 1 root root 5130480 Feb 16 09:55 nginx
-rw-r--r-- 1 root root 5375 Feb 16 09:55 nginx.8
-rw-r--r-- 1 root root 7037 Feb 16 09:53 ngx_auto_config.h
-rw-r--r-- 1 root root 657 Feb 16 09:53 ngx_auto_headers.h
-rw-r--r-- 1 root root 5856 Feb 16 09:53 ngx_modules.c
-rw-r--r-- 1 root root 45232 Feb 16 09:55 ngx_modules.o
drwxr-xr-x 9 root root 91 Feb 16 09:53 src
[root@ecs objs]# cp -r nginx /usr/local/nginx/sbin/ -f
cp: overwrite '/usr/local/nginx/sbin/nginx'? y
#给master进程发送一个信号,用新的nginx启动
[root@ecs objs]# kill -USR2 254641
# 可以看到新旧进程都在运行
# 新的master会生成新的work,老的master和work也在运行,他们会平滑的把所有的请求过度到新的二进制文件启的进程中
# 老的master和work已经不再监听80和443端口 所以新的请求,新的连接会进入新的nginx
[root@ecs objs]# ps -ef|grep nginx
root 254641 1 0 10:21 ? 00:00:00 nginx: master process ./nginx
nobody 254682 254641 0 10:22 ? 00:00:00 nginx: worker process
root 254778 254641 0 10:35 ? 00:00:00 nginx: master process ./nginx
nobody 254779 254778 0 10:35 ? 00:00:00 nginx: worker process
root 254789 221527 0 10:36 pts/0 00:00:00 grep --color=auto nginx
# 优雅的关闭所有work进程
[root@ecs objs]# kill -WINCH 254641
[root@ecs objs]# ps -ef|grep nginx
root 254641 1 0 10:21 ? 00:00:00 nginx: master process ./nginx
root 254778 254641 0 10:35 ? 00:00:00 nginx: master process ./nginx
nobody 254779 254778 0 10:35 ? 00:00:00 nginx: worker process
root 254800 221527 0 10:40 pts/0 00:00:00 grep --color=auto nginx
# 老的master进程还在运行、所有的请求已经转接到新的nginx上了 但是我们又可能会发生一些问题
# 新版本退回到老版本,所以我们还可以给老的master发送信号重新把老的work拉起来
# 老的master是不会自动退出 允许我们做版本回退切割日志
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28[root@ecs logs]# mv access.log bak.log
[root@ecs logs]# ll
total 12
-rw-r--r-- 1 nobody root 0 Feb 16 10:21 bak.log
-rw-r--r-- 1 nobody root 438 Feb 16 10:49 error.log
-rw-r--r-- 1 root root 7 Feb 16 10:35 nginx.pid
-rw-r--r-- 1 root root 7 Feb 16 10:21 nginx.pid.oldbin
重新启动之后会重新生成access.log
[root@ecs logs]# ../sbin/nginx -s reopen
[root@ecs logs]# ll
total 12
-rw-r--r-- 1 nobody root 0 Feb 16 10:50 access.log
-rw-r--r-- 1 nobody root 0 Feb 16 10:21 bak.log
-rw-r--r-- 1 nobody root 500 Feb 16 10:50 error.log
-rw-r--r-- 1 root root 7 Feb 16 10:35 nginx.pid
-rw-r--r-- 1 root root 7 Feb 16 10:21 nginx.pid.oldbin
定时切割日志
[root@ecs logs]# crontab -l
0 0 1 * * root /usr/local/nginx/logs/rotate.sh
[root@ecs logs]# cat rotate.sh
!/bin/bash
LOGS_PATH=/usr/local/nginx/logs/history
CUR_LOGS_PATH=/usr/local/nginx/logs
YESTERDAY=$(date -d "yesterday" +%Y-%m-%d)
mv ${CUR_LOGS_PATH}/access.log ${LOGS_PATH}/access_${YESTERDAY}.log
mv ${CUR_LOGS_PATH}/error.log ${LOGS_PATH}/error_${YESTERDAY}.log
向nginx主进程发送USR1信号。USR1信号是重新打开日志文件
kill -USR1 $(cat /usr/local/nginx/logs/nginx.pid)
搭建静态资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21[root@ecs nginx]# vi conf/nginx.conf
server {
listen 8080;
server_name www.test.com;
#charset koi8-r;
access_log logs/test.access.log main;
location / {
alis dlib/;
# 打开目录
#autoindex on;
# 限制访问速度
#set $limit_rate 1k;
#index index.html index.htm;
}
#error_page 404 /404.html;
}打开 gzip
1
2
3
4gzip on;
gzip_min_length 1;
gzip_comp_level 2;
gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;搭建具备缓存功能的反向代理服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65nginx.conf
proxy_cache_path /tmp/nginxcache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m;
upstream local {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name www.test.com;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cache my_cache;
proxy_cache_key $host$uri$is_args$args;
proxy_cache_valid 200 304 302 1d;
proxy_pass http://local;
}
error_page 404 /404.html;
}
server {
listen 127.0.0.1:8080;
#server_name www.test.com;
#charset koi8-r;
access_log logs/test.access.log main;
location / {
alias dlib/;
autoindex on;
set $limit_rate 1k;
index index.html index.htm;
}
#error_page 404 /404.html;
}
upstream local {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name www.test.com;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cache my_cache;
proxy_cache_key $host$uri$is_args$args;
proxy_cache_valid 200 304 302 1d;
proxy_pass http://local;
}
error_page 404 /404.html;
}用 GoAccess 实现可视化并实时监控 access 日志
安装 GoAccess
https://www.goaccess.cc/?mod=download
说明:
GoAccess 在使用源码安装时,依赖下列组件。
为方便最终日志统计时显示 IP 地理位置,需要安装依赖项 GeoIP-devel:
执行命令:yum install GeoIP-devel.x86_64
安装 ncurses-devel 开发库:
执行命令:yum install ncurses-devel
安装 openssl-devel 开发库:
执行命令:yum install openssl-devel
执行报错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15[root@ecs logs]# goaccess test.access.log -o ../html/report.html --real-time-html --time-format='%H:%M:%S'--date-format='%d/%b/%Y' --log-format=COMBINE
GoAccess - version 1.2 - Feb 16 2021 17:14:24
Config file: /usr/local/etc/goaccess.conf
Fatal error has occurred
Error occured at: src/parser.c - parse_log - 2705
No date format was found on your conf file.
# 生成报告
[root@ecs logs]# goaccess test.access.log -a -o ../html/report.html
# 配置nginx,访问查看
location /report.html {
alias /usr/local/nginx/html/report.html;
}
从网络协议来看 SSL 安全协议
- TLS 安全密码套件解读
对称加密与非对称加密各自的应用场景
- 对称加密
- 非对称加密
SSL 证书的公信力是如何保证的?
- PKI 公钥基础设施
- 证书类型
SSL 协议握手时 Nginx 的性能瓶颈在哪里?
用免费 SSL 证书实现一个 HTTPS 站点
安装
yum install certbot python2-certbot-nginx -y
配置
certbot --nginx --nginx-server-root=/usr/local/nginx/conf/ -d www.test.com
nginx 配置
1
2
3
4
5listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/pazzn.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/pazzn.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot基于 OpenResty 用 Lua 语言实现简单服务
- 下载安装 openresty
1
2[root@ecs soft]# wget https://openresty.org/download/openresty-1.19.3.1.tar.gz
[root@ecs openresty-1.19.3.1]# ./configure添加 Lua 代码
1
2
3
4location /lua {
default_type text/html;
content_by_lua 'ngx.say("User-Agent: ", ngx.req.get_headers()["User-Agent"])';
}
Nginx 架构基础 (一)
Nginx 请求处理流程
Nginx 进程结构
进程说明
Master 进程
1、是进行 work 进程的监控管理的
2、看看 work 进程是否正常工作需不需要进行热部署、需不需要重新载入配置文件Cache manager 缓存的管理
1、缓存为反向代理后端发来的动态请求做缓存使用2、缓存在不光是在 work 进程间使用、还要被 Cache manager 和 Cache loader 使用
Cache loader 载入缓存
实例演示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17[root@ecs conf]# ps -ef|grep nginx
root 262788 1 0 18:09 ? 00:00:00 nginx: master process ../sbin/nginx
root 262789 262788 0 18:09 ? 00:00:00 nginx: worker process
root 262790 262788 0 18:09 ? 00:00:00 nginx: cache manager process
root 274250 221527 0 19:54 pts/0 00:00:00 grep --color=auto nginx
[root@ecs conf]# ../sbin/nginx -s reload
[root@ecs conf]# ps -ef|grep nginx
root 262788 1 0 18:09 ? 00:00:00 nginx: master process ../sbin/nginx
root 274252 262788 0 19:54 ? 00:00:00 nginx: worker process
root 274253 262788 0 19:54 ? 00:00:00 nginx: cache manager process
root 274255 221527 0 19:54 pts/0 00:00:00 grep --color=auto nginx
[root@ecs conf]# kill -SIGHUP 262788
[root@ecs conf]# ps -ef|grep nginx
root 262788 1 0 18:09 ? 00:00:00 nginx: master process ../sbin/nginx
root 274267 262788 0 19:55 ? 00:00:00 nginx: worker process
root 274268 262788 0 19:55 ? 00:00:00 nginx: cache manager process
root 274270 221527 0 19:55 pts/0 00:00:00 grep --color=auto nginx
使用信号管理 Nginx 的父子进程
CHLD:终止进程信号。
TERM,INT: 立刻停止进程
QUIT: 优雅停止进程
HUP: 重载配置文件
USR1: 重新打开日志文件
USR2、WINCH: 需要通过命令行结合 kill 命令使用
reload 重载配置文件真相
热升级的完整流程
Nginx 架构基础 (二)
网络收发与 Nginx 事件间的对应关系
Nginx 网络事件实例演示
抓包工具:https://www.wireshark.org/#download
TCP 层:本地打开了 54756,Nginx 打开的是 8080 端口 进程与进程通信
IP 层:本机 IP 地址:192.168.1.196 nginx 服务器的 IP 地址:127.0.0.1
三次握手
windows 先向 nginx 发送一个 SYN
相反的 nginx 所在的 linux 也会向 windos 发送一个 SYN,这个时候 nginx 是没有感知到的、因为这是一个半打开的状态
直到 widows 再向 nginx 所在的 linux 服务器发送一个 ACK 时,linux 操作系统才会通知 nginx 这时有一个读事件需要处理
epoll 的优劣及原理
详解 HTTP 模块
冲突的配置指令以谁为准?
配置块的嵌套
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19main
http {
upstream { … }
split_clients {…}
map {…}
geo {…}
server {
if () {…}
location {
limit_except {…}
}
location {
location {
}
}
}
server {
}
}指令的 Context
1
2
3
4
5
6
7
8
9Syntax: log_format name [escape=default|json|none] string ...;
Default: log_format combined "...";
Context: http
Syntax:
access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off;
Default: access_log logs/access.log combined;
Context: http, server, location, if in location, limit_excep指令的合并
存储值的指令集成规则:向上覆盖
子配置不存在时,直接使用父配置块;
子配置存在时,直接覆盖父配置块。
1
2
3
4
5
6
7
8
9
10
11
12
13
14server {
listen 8080;
root /home/geek/nginx/html;
access_log logs/geek.access.log main;
location /test {
root /home/geek/nginx/test;
access_log logs/access.test.log main;
}
location /dlib {
alias dlib/;
}
location / {
}
}HTTP 模块合并配置的实现
- 指令在哪个块下生效?11 个阶段
- 指令允许出现在那些块下?
1
2
3{ ngx_string("valid_referers"),
NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
......- 在 server 块内生效、从 http 向 server 合并指令:
char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);
- 配置缓存在内存
char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
Listen 指令
1
2
3
4
5
6
7
8listen unix:/var/run/nginx.sock;
listen 127.0.0.1:8000;
listen 127.0.0.1;
listen 8000;
listen *:8000;
listen localhost:8000 bind;
listen [::]:8000 ipv6only=on;
listen [::1];处理 HTTP 请求头部的流程
- 接收请求事件模块
接收请求 HTTP 模块
如何找到处理请求的 server 指令块
server 匹配顺序
1、精确匹配
2、* 在前的泛域名
3、* 在后的泛域名
4、按文件中的顺序匹配正则表达式域名
5、default server
第 1 个
listen 指定 default
详解 HTTP 请求的 11 个阶段
参考地址:https://www.cnblogs.com/luoahong/p/13542203.html
11 个阶段的顺序处理
阶段 使用的模块 备注 POST_READ realip 刚读完 http 请求头、没有经过任何加工过、获取到一些原始的值 SERVER_REWRITE rewrite 它和下面 REWRITE 的只有一个模块 FIND_CONFIG 这个只有 nginx 框架会做 所以没有任何的模块、就是在做 location 的一个匹配 REWRITE rewrite 一般第三方模块没有一个处理 REWRITE POST_REWRITE 刚刚 REWRITE 之后要做的一些事情 PREACCESS limt_conn, limit_req 在 access 之前要不要做一些工作、 限制速度、 限制连接数 ACCESS auth_basic| access|auth_request 确认访问权限的 能不能访问 | 根据访问的 ip | 根据第三方的服务 POST_ACCESS PRECONFTENT try_files mirrors 处理 CONTENT 之前 会把这个服务发送给第三方服务、一个请求产生多个请求值 CONTENT index| autoindex|concat 反向代理 LOG access_log 打印 access 日志的 postread 阶段:获取真实客户端地址的 realip 模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22[root@ecs conf.d]# cat realip.conf
server {
server_name realip.test.com;
error_log logs/myerror.log debug;
set_real_ip_from 127.0.0.1;
real_ip_header X-Real-IP;
real_ip_recursive off;
real_ip_recursive on;
real_ip_header X-Forwarded-For;
location /{
return 200 "Client real ip: $remote_addr\n";
}
}
测试
[root@ecs conf.d]# curl -H 'X-Forwarded-For: 1.1.1.1,127.0.0.1' realip.test.com
Client real ip: 127.0.0.1
开启 real_ip_recursive on;
[root@ecs conf.d]# curl -H 'X-Forwarded-For: 1.1.1.1,127.0.0.1' realip.test.com
Client real ip: 1.1.1.1rewrite 阶段的 rewrite 模块:return 指令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45[root@ecs conf.d]# cat return.conf
server {
server_name return.test.com;
listen 8080;
root html/;
error_page 404 /403.html;
return 405;
location /{
return 404 "find nothing!\n";
}
}
[root@ecs conf.d]# curl return.test.com:8080/aaa.html
<!DOCTYPE html>
<html>
<head>
<title>Error</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>403 forbidden.</h1>
</body>
</html>
去掉 return 404 "find nothing!\n"; 注释
[root@ecs conf.d]# curl return.test.com:8080/aaa.html
find nothing!
去掉 return 405注释
说明 return 405是在SERVER_REWRITE 阶段,而return 404 "find nothing!\n"处于REWRITE,优先处理SERVER_REWRITE
[root@ecs conf.d]# curl return.test.com:8080/aaa.html
<html>
<head><title>405 Not Allowed</title></head>
<body>
<center><h1>405 Not Allowed</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>rewrite 阶段的 rewrite 模块:重写 URL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97[root@ecs conf.d]# cat rewrite.conf
server {
server_name rewrite.test.com;
rewrite_log on;
error_log logs/rewrite_error.log notice;
root html/;
location /first {
rewrite /first(.*) /second$1 last;
return 200 'first!\n';
}
location /second {
rewrite /second(.*) /third$1 break;
rewrite /second(.*) /third$1;
return 200 'second!\n';
}
location /third {
return 200 'third!\n';
}
location /redirect1 {
rewrite /redirect1(.*) $1 permanent;
}
location /redirect2 {
rewrite /redirect2(.*) $1 redirect;
}
location /redirect3 {
rewrite /redirect3(.*) http://rewrite.test.com$1;
}
location /redirect4 {
rewrite /redirect4(.*) http://rewrite.test.com$1 permanent;
}
}
从/first 重定向到 /second rewrite后面没有break,依次向下执行
[root@ecs conf.d]# curl rewrite.test.com/first/3.txt
second!
打开rewrite /second(.*) /third$1 break;
[root@ecs conf.d]# curl rewrite.test.com/first/3.txt
test3
实际访问目录是
[root@ecs conf.d]# cat /usr/local/nginx/html/third/3.txt
test3
[root@ecs conf.d]# curl rewrite.test.com/redirect1/ -I
HTTP/1.1 301 Moved Permanently
Server: nginx/1.18.0
Date: Sat, 20 Feb 2021 03:06:51 GMT
Content-Type: text/html
Content-Length: 169
Location: http://rewrite.test.com/
Connection: keep-alive
[root@ecs conf.d]# curl rewrite.test.com/redirect2/ -I
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.18.0
Date: Sat, 20 Feb 2021 03:06:57 GMT
Content-Type: text/html
Content-Length: 145
Location: http://rewrite.test.com/
Connection: keep-alive
[root@ecs conf.d]# curl rewrite.test.com/redirect3/ -I
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.18.0
Date: Sat, 20 Feb 2021 03:07:25 GMT
Content-Type: text/html
Content-Length: 145
Connection: keep-alive
Location: http://rewrite.test.com/
[root@ecs conf.d]# curl rewrite.test.com/redirect4/ -I
HTTP/1.1 301 Moved Permanently
Server: nginx/1.18.0
Date: Sat, 20 Feb 2021 03:07:44 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: http://rewrite.test.com/
通过打开的rewrite_log on; 查看日志
[root@ecs logs]# cat rewrite_error.log
2021/02/20 11:06:51 [notice] 295965#0: *12 "/redirect1(.*)" matches "/redirect1/", client: 127.0.0.1, server: rewrite.test.com, request: "HEAD /redirect1/ HTTP/1.1", host: "rewrite.test.com"
2021/02/20 11:06:51 [notice] 295965#0: *12 rewritten redirect: "/", client: 127.0.0.1, server: rewrite.test.com, request: "HEAD /redirect1/ HTTP/1.1", host: "rewrite.test.com"
2021/02/20 11:06:57 [notice] 295965#0: *13 "/redirect2(.*)" matches "/redirect2/", client: 127.0.0.1, server: rewrite.test.com, request: "HEAD /redirect2/ HTTP/1.1", host: "rewrite.test.com"
2021/02/20 11:06:57 [notice] 295965#0: *13 rewritten redirect: "/", client: 127.0.0.1, server: rewrite.test.com, request: "HEAD /redirect2/ HTTP/1.1", host: "rewrite.test.com"
2021/02/20 11:07:25 [notice] 295965#0: *14 "/redirect3(.*)" matches "/redirect3/", client: 127.0.0.1, server: rewrite.test.com, request: "HEAD /redirect3/ HTTP/1.1", host: "rewrite.test.com"
2021/02/20 11:07:25 [notice] 295965#0: *14 rewritten redirect: "http://rewrite.test.com/", client: 127.0.0.1, server: rewrite.test.com, request: "HEAD /redirect3/ HTTP/1.1", host: "rewrite.test.com"
2021/02/20 11:07:44 [notice] 295965#0: *15 "/redirect4(.*)" matches "/redirect4/", client: 127.0.0.1, server: rewrite.test.com, request: "HEAD /redirect4/ HTTP/1.1", host: "rewrite.test.com"
2021/02/20 11:07:44 [notice] 295965#0: *15 rewritten redirect: "http://rewrite.test.com/", client: 127.0.0.1, server: rewrite.test.com, request: "HEAD /redirect4/ HTTP/1.1", host: "rewrite.test.com"rewrite 阶段的 rewrite 模块:条件判断
find_config 阶段:找到处理请求的 location 指令块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43[root@ecs conf.d]# cat locations.conf
server {
server_name location.test.com;
error_log logs/error.log debug;
root html/;
default_type text/plain;
merge_slashes off;
location ~ /Test1/$ {
return 200 'first regular expressions match!\n';
}
location ~* /Test1/(\w+)$ {
return 200 'longest regular expressions match!\n';
}
location ^~ /Test1/ {
return 200 'stop regular expressions match!\n';
}
location /Test1/Test2 {
return 200 'longest prefix string match!\n';
}
location /Test1 {
return 200 'prefix string match!\n';
}
location = /Test1 {
return 200 'exact match!\n';
}
}
[root@ecs conf.d]# curl location.test.com/Test1
exact match!
[root@ecs conf.d]# curl location.test.com/Test1/
stop regular expressions match!
[root@ecs conf.d]# curl location.test.com/Test1/Test2
longest regular expressions match!
[root@ecs conf.d]# curl location.test.com/Test1/Test2/
longest prefix string match!preaccess 阶段:对连接做限制的 limit_conn 模块
限制发生时的日志级别
1
2
3Syntax: limit_conn_log_level info | notice | warn | error;
Default: limit_conn_log_level error;
Context: http, server, location限制发生时向客户端返回的错误码
1
2
3Syntax: limit_conn_status code;
Default: limit_conn_status 503;
Context: http, server, location1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24[root@ecs conf.d]# cat limit_conn.conf
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_req_zone $binary_remote_addr zone=one:10m rate=2r/m;
server {
server_name limit.test.com;
root html/;
error_log logs/myerror.log info;
location /{
limit_conn_status 500; #返回错误码500
limit_conn_log_level warn;
limit_rate 50; #限制每秒钟向用户返回50Byte
limit_conn addr 1; #限制并发连接数1
limit_req zone=one burst=3 nodelay;
limit_req zone=one;
}
}
打印错误日志
2021/02/20 13:40:08 [info] 296750#0: *45 client 127.0.0.1 closed keepalive connection
2021/02/20 13:40:13 [warn] 296750#0: *47 limiting connections by zone "addr", client: 127.0.0.1, server: limit.test.com, request: "GET / HTTP/1.1", host: "limit.test.com"
2021/02/20 13:40:17 [info] 296750#0: *46 client prematurely closed connection while sending response to client, client: 127.0.0.1, server: limit.test.com, request: "GET / HTTP/1.1", host: "limit.test.com"
2021/02/20 13:40:26 [warn] 296750#0: *49 limiting connections by zone "addr", client: 127.0.0.1, server: limit.test.com, request: "GET / HTTP/1.1", host: "limit.test.com"
2021/02/20 13:40:34 [info] 296750#0: *48 client 127.0.0.1 closed keepalive connectionpreaccess 阶段:对请求做限制的 limit_req 模块
限制发生时的日志级别
1
2
3Syntax: limit_req_log_level info | notice | warn | error;
Default: limit_req_log_level error;
Context: http, server, location限制发生时向客户端返回的错误码
1
2
3Syntax: limit_req_status code;
Default: limit_req_status 503;
Context: http, server, location1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57[root@ecs conf.d]# cat limit_conn.conf
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_req_zone $binary_remote_addr zone=one:10m rate=2r/m;
server {
server_name limit.test.com;
root html/;
error_log logs/myerror.log info;
location /{
limit_conn_status 500;
limit_conn_log_level warn;
limit_rate 50;
limit_conn addr 1;
limit_req zone=one burst=3 nodelay;
limit_req zone=one;
}
}
[root@ecs conf.d]# ../../sbin/nginx -s reload
第一次访问正常
[root@ecs conf.d]# curl limit.test.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
第二次返回503
[root@ecs conf.d]# curl limit.test.com
<html>
<head><title>503 Service Temporarily Unavailable</title></head>
<body>
<center><h1>503 Service Temporarily Unavailable</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>
打开 limit_req zone=one burst=3 nodelay; 之后,访问3次正常,第四次返回503
同时打开limit_conn 和 limit_req,返回503,limit_req访问在前。access 阶段:对 ip 做限制的 access 模块
如何限制某些 IP 地址的访问权限。
access 阶段:对用户名密码做限制的 auth_basic 模块
auth_basic 模块指令:
1
2
3
4
5
6
7# 安装工具包
[root@ecs ~]# yum install httpd-tools -y
# 生成文件
[root@ecs conf.d]# htpasswd -c auth.pass temp
New password:
Re-type new password:
Adding password for user tempaccess 阶段:使用第三方做权限控制的 auth_request 模块
重新编译安装
1
2
3
4
5
6
7
8
9
10
11
12
13
14[root@ecs nginx]# cd sbin/
[root@ecs sbin]# ll
total 15724
-rwxr-xr-x 1 root root 5833272 Feb 20 09:43 nginx
-rwxr-xr-x 1 root root 5130480 Feb 16 10:32 nginx.2.old
-rwxr-xr-x 1 root root 5130480 Feb 16 10:26 nginx.old
[root@ecs sbin]# mv nginx nginx.3.old
[root@ecs nginx-1.18.0]# ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_realip_module --with-http_auth_request_module
[root@ecs nginx-1.18.0]# make #切勿执行make install
#将objs下的nginx复制到安装目录
[root@ecs objs]# cp nginx /usr/local/nginx/sbin/
#热部署
[root@ecs nginx-1.18.0]# kill -USR2 3001751
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23server {
server_name access.test.com;
error_log logs/error.log debug;
root html/;
default_type text/plain;
location /auth_basic {
satisfy any;
auth_basic "test auth_basic";
auth_basic_user_file conf.d/auth.pass;
deny all;
}
location / {
auth_request /test_auth;
}
location = /test_auth {
proxy_pass http://127.0.0.1:8090/auth_upstream;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
}access 阶段的 satisfy 指令
如果有 return 指令,access 阶段会生效吗?
不会生效,因为 return 指令在 SERVER_REWRITE 和 REWRITE 阶段,领先于 access。
多个 access 模块的顺序有影响吗?
查看 ngx-modules.c
&ngx_http_auth_request_module,
&ngx_http_auth_basic_module
&ngx_http_access_module
有影响
输对密码,下面可以访问到文件吗?可以
1
2
3
4
5
6location/{
satisfy any;
auth_basic "test auth basic"
auth_basic_user_file examples/auth.pass;
deny all:
}如果把 deny all 提到 auth basic 之前呢?
可以,和指令顺序无关,主要取决于模块顺序。
如果改为 allow all, 有机会输入密码吗?
没有,因为配置的 satisfy any; 只要有一个模块放行即可。而且 allow 属于 access, 先于 auth_basic 执行。
precontent 阶段:按序访问资源的 try_files 模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32[root@ecs conf.d]# cat tryfiles.conf
server {
server_name tryfiles.test.com;
error_log logs/myerror.log info;
root html/;
default_type text/plain;
location /first {
try_files /system/maintenance.html
$uri $uri/index.html $uri.html
@lasturl;
}
location @lasturl {
return 200 'lasturl!\n';
}
location /second {
try_files $uri $uri/index.html $uri.html =404;
}
}
[root@ecs conf.d]# curl tryfiles.test.com/first
lasturl!
[root@ecs conf.d]# curl tryfiles.test.com/second
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>实时拷贝流量:precontent 阶段的 mirror 模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27# 本地服务
[root@ecs conf.d]# cat mirror.conf
server {
listen 10020;
location / {
return 200 'mirror response!';
}
}
#上游服务
[root@ecs conf]# vim mirror.conf
server{
listen 8001;
error_log Logs/error. log debug;
location / {
mirror /mirror;
mirror request _body off;
}
location =/mirror {
internal;
proxy_pass http://127.0.0.1:10020$request_uri;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Oriqinal-URI $request_uri;
}
}content 阶段:详解 root 和 alias 指令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68[root@ecs conf.d]# cat static.conf
server {
server_name static.test.com;
error_log logs/myerror.log info;
location /root {
root html;
}
location /alias {
alias html;
}
location ~ /root/(\w+\.txt) {
root html/first/$1;
}
location ~ /alias/(\w+\.txt) {
alias html/first/$1;
}
location /RealPath/ {
alias html/realpath/;
return 200 '$request_filename:$document_root:$realpath_root\n';
}
}
[root@ecs conf.d]# curl static.test.com/root/
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>
# 日志信息
2021/02/20 15:13:46 [error] 300277#0: *5 "/usr/local/nginx/html/root/index.html" is not found (2: No such file or directory), client: 127.0.0.1, server: static.test.com, request: "GET /root/ HTTP/1.1", host: "static.test.com"
[root@ecs conf.d]# curl static.test.com/root/1.txt
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>
# 日志信息
2021/02/20 15:15:09 [error] 300277#0: *7 open() "/usr/local/nginx/html/first/1.txt/root/1.txt" failed (20: Not a directory), client: 127.0.0.1, server: static.test.com, request: "GET /root/1.txt HTTP/1.1", host: "static.test.com"
[root@ecs conf.d]# curl static.test.com/alias/
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
[root@ecs conf.d]# curl static.test.com/alias/1.txt
test1static 模块提供的 3 个变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23# 建立软连接
[root@ecs html]# ln -s first realpath
[root@ecs html]# ll
total 352
-rw-r--r-- 1 root root 242 Feb 20 10:05 403.html
-rw-r--r-- 1 root root 494 Feb 16 09:55 50x.html
drwxr-xr-x 2 root root 32 Feb 20 15:23 first
-rw-r--r-- 1 root root 612 Feb 16 09:55 index.html
lrwxrwxrwx 1 root root 5 Feb 20 15:23 realpath -> first
-rw-r--r-- 1 root root 344328 Feb 16 17:55 report.html
drwxr-xr-x 2 root root 19 Feb 20 10:59 second
drwxr-xr-x 2 root root 19 Feb 20 10:59 third
[root@ecs html]# pwd
/usr/local/nginx/html
location /RealPath/ {
alias html/realpath/;
return 200 '$request_filename:$document_root:$realpath_root\n';
}
[root@ecs conf.d]# curl static.test.com/RealPath/1.txt
/usr/local/nginx/html/realpath/1.txt:/usr/local/nginx/html/realpath/:/usr/local/nginx/html/first静态文件返回时的 content-type
未找到文件时的错误日志
static 模块对 url 不以斜杠结尾却访问目录的做法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48[root@ecs conf.d]# cat dirredirect.conf
server {
server_name return.test.com dir.test.com;
server_name_in_redirect off;
listen 8088;
port_in_redirect on;
absolute_redirect off;
root html/;
}
[root@ecs conf.d]# curl localhost:8088/first -I
HTTP/1.1 301 Moved Permanently
Server: nginx/1.18.0
Date: Sat, 20 Feb 2021 07:31:28 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: /first/
# 添加注释 absolute_redirect off
[root@ecs conf.d]# curl localhost:8088/first -I
HTTP/1.1 301 Moved Permanently
Server: nginx/1.18.0
Date: Sat, 20 Feb 2021 07:40:40 GMT
Content-Type: text/html
Content-Length: 169
Location: http://localhost:8088/first/
Connection: keep-alive
[root@ecs conf.d]# curl -H 'Host:aaa' localhost:8088/first -I
HTTP/1.1 301 Moved Permanently
Server: nginx/1.18.0
Date: Sat, 20 Feb 2021 07:41:24 GMT
Content-Type: text/html
Content-Length: 169
Location: http://aaa:8088/first/
Connection: keep-alive
# 修改 server_name_in_redirect on 返回server_name中的域名
[root@ecs conf.d]# curl -H 'Host:aaa' localhost:8088/first -I
HTTP/1.1 301 Moved Permanently
Server: nginx/1.18.0
Date: Sat, 20 Feb 2021 07:42:15 GMT
Content-Type: text/html
Content-Length: 169
Location: http://return.test.com:8088/first/
Connection: keep-aliveindex 和 autoindex 模块的用法
对访问 / 时的处理:content 阶段的 index 模块
随机 index.html 文件:content 阶段的 autoindex 模块
显示目录内容:content 阶段的 autoindex 模块
autoindex 模块的指令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44[root@ecs conf.d]# cat autoindex.conf
server {
server_name autoindex.test.com;
listen 8080;
location / {
alias html/;
autoindex on;
#index a.html;
autoindex_exact_size off;
autoindex_format html;
autoindex_localtime on;
}
}
[root@ecs conf.d]# curl autoindex.test.com:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
# ****** 以html的形式显示文件目录 ******
[root@ecs conf.d]# cat autoindex.conf
server {
server_name autoindex.test.com;
listen 8080;
location / {
alias html/;
autoindex on;
index a.html;
autoindex_exact_size off;
autoindex_format html;
autoindex_localtime on;
}
}
[root@ecs conf.d]# ../../sbin/nginx -s reload
[root@ecs conf.d]# curl autoindex.test.com:8080
<html>
<head><title>Index of /</title></head>
<body>
<h1>Index of /</h1><hr><pre><a href="../">../</a>
<a href="first/">first/</a> 20-Feb-2021 15:23 -
<a href="realpath/">realpath/</a> 20-Feb-2021 15:23 -
<a href="second/">second/</a> 20-Feb-2021 10:59 -
<a href="third/">third/</a> 20-Feb-2021 10:59 -
<a href="403.html">403.html</a>
提升多个小文件性能的 concat 模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24# 安装concat模块
git clone git://github.com/alibaba/nginx-http-concat.git
[root@ecs nginx]# ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_realip_module --with-http_auth_request_module --add-module=/data/soft/nginx/nginx-http-concat
[root@ecs conf.d]# cat concat.conf
server {
server_name concat.test.com;
error_log logs/myerror.log debug;
concat on;
root html;
location /concat {
concat_max_files 20;
concat_types text/plain;
concat_unique on;
concat_delimiter ':::';
concat_ignore_file_error on;
}
}
[root@ecs conf.d]# curl concat.test.com/concat/??1.txt,2.txt
test1
:::test2access 日志的详细用法
access 日志格式
配置日志文件路径
对日志文件名包含变量时的优化
HTTP 过滤模块的调用流程
用过滤模块更改响应中的字符串:sub 模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66# 添加模块
[root@ecs nginx]# ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_realip_module --with-http_auth_request_module --add-module=/data/soft/nginx/nginx-http-concat --with-http_sub_module
[root@ecs conf.d]# cat sub.conf
server {
server_name sub.test.com;
error_log logs/myerror.log info;
location / {
#sub_filter 'Nginx.oRg' '$host/nginx';
#sub_filter 'nginX.cOm' '$host/nginx';
#sub_filter_once on;
#sub_filter_once off;
#sub_filter_last_modified off;
#sub_filter_last_modified on;
}
}
[root@ecs conf.d]# curl sub.test.com
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
#进行替换
[root@ecs conf.d]# cat sub.conf
server {
server_name sub.test.com;
error_log logs/myerror.log info;
location / {
sub_filter 'Nginx.oRg' '$host/nginx';
sub_filter 'nginX.cOm' '$host/nginx';
sub_filter_once on;
#sub_filter_once off;
sub_filter_last_modified off;
#sub_filter_last_modified on;
}
}
[root@ecs conf.d]# curl sub.test.com
<a href="http://sub.test.com/nginx/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://sub.test.com/nginx/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
# 全部替换
location / {
sub_filter 'Nginx.oRg' '$host/nginx';
sub_filter 'nginX.cOm' '$host/nginx';
#sub_filter_once on;
sub_filter_once off;
#sub_filter_last_modified off;
sub_filter_last_modified on;
}
[root@ecs conf.d]# curl sub.test.com
<p>For online documentation and support please refer to
<a href="http://sub.test.com/nginx/">sub.test.com/nginx</a>.<br/>
Commercial support is available at
<a href="http://sub.test.com/nginx/">sub.test.com/nginx</a>.</p>用过滤模块在 http 响应的前后添加内容:addition 模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31# 添加模块
[root@ecs nginx]# ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_realip_module --with-http_auth_request_module --add-module=/data/soft/nginx/nginx-http-concat --with-http_sub_module --with-http_addition_module
[root@ecs conf.d]# cat addition.conf
server {
server_name addition.test.com;
error_log logs/myerror.log info;
location / {
add_before_body /before_action;
add_after_body /after_action;
addition_types *;
}
location /before_action {
return 200 'new content before\n';
}
location /after_action {
return 200 'new content after\n';
}
location /testhost {
uninitialized_variable_warn on;
set $foo 'testhost';
return 200 '$gzip_ratio\n';
}
}
[root@ecs conf.d]# curl addition.test.com/a.txt
new content before
aaa
new content afterNginx 变量的运行原理
变量的惰性求值
变量的特性
惰性求值
变量值可以时刻变化,其值为使用时的那一刻的值
HTTP 框架提供的请求相关的变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49[root@ecs conf.d]# cat var.conf
log_format vartest '$remote_addr - $remote_user [$time_local] "$request" '
'$status bytes_sent=$bytes_sent body_bytes_sent=$body_bytes_sent "$http_referer" '
'"$http_user_agent" "$sent_http_abc"';
server {
server_name var.test.com localhost;
#error_log logs/myerror.log debug;
access_log logs/vartest.log vartest;
listen 9090;
location / {
set $limit_rate 10k;
return 200 '
arg_a: $arg_a,arg_b: $arg_b,args: $args
connection: $connection,connection_requests: $connection_requests
cookie_a: $cookie_a
uri: $uri,document_uri: $document_uri, request_uri: $request_uri
request: $request
request_id: $request_id
server: $server_addr,$server_name,$server_port,$server_protocol
tcpinfo: $tcpinfo_rtt, $tcpinfo_rttvar, $tcpinfo_snd_cwnd, $tcpinfo_rcv_space
host: $host,server_name: $server_name,http_host: $http_host
limit_rate: $limit_rate
hostname: $hostname
content_length: $content_length
status: $status
body_bytes_sent: $body_bytes_sent,bytes_sent: $bytes_sent
time: $request_time,$msec,$time_iso8601,$time_local
';
}
}
[root@ecs conf.d]# curl -H 'Content-Length: 0' -H 'Cookie: a=c1' 'localhost:9090?a=1&b=22'
arg_a: 1,arg_b: 22,args: a=1&b=22
connection: 4,connection_requests: 1
cookie_a: c1
uri: /,document_uri: /, request_uri: /?a=1&b=22
request: GET /?a=1&b=22 HTTP/1.1
request_id: 00c17d3d3fe9a07a362e7709ef28aab9
server: 127.0.0.1,var.test.com,9090,HTTP/1.1
tcpinfo: 12, 6, 10, 43690
host: localhost,server_name: var.test.com,http_host: localhost:9090
limit_rate: 10240
hostname: ecs
content_length: 0
status: 200
body_bytes_sent: 0,bytes_sent: 0
time: 0.000,1613812049.725,2021-02-20T17:07:29+08:00,20/Feb/2021:17:07:29 +0800HTTP 框架提供的其他变量
使用变量防盗链的 referer 模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53[root@ecs conf.d]# cat referer.conf
server {
server_name referer.test.com;
error_log logs/myerror.log debug;
root html;
location /{
valid_referers none blocked server_names
*.test.pub www.test.org.cn/nginx/
~\.google\.;
if ($invalid_referer) {
return 403;
}
return 200 'valid\n';
}
}
[root@ecs conf.d]# curl -H 'referer: http://www.test.org.cn/ttt' referer.test.com/
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>
[root@ecs conf.d]# curl -H 'referer: http://www.test.pub/ttt' referer.test.com/
valid
[root@ecs conf.d]# curl -H 'referer: ' referer.test.com/
valid
[root@ecs conf.d]# curl referer.test.com/
valid
[root@ecs conf.d]# curl -H 'referer: http://www.test.com' referer.test.com/
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>
[root@ecs conf.d]# curl -H 'referer: http://referer.test.com' referer.test.com/
valid
[root@ecs conf.d]# curl -H 'referer: http://image.baidu.com/search/detail' referer.test.com/
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>
[root@ecs conf.d]# curl -H 'referer: http://image.google.com/search/detail' referer.test.com/
valid使用变量实现防盗链功能实践:secure_link 模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57# 添加模块
[root@ecs nginx]# ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_realip_module --with-http_auth_request_module --add-module=/data/soft/nginx/nginx-http-concat --with-http_sub_module --with-http_addition_module --with-http_secure_link_module
[root@ecs conf.d]# cat secure_link.conf
server {
server_name securelink.test.com;
error_log logs/myerror.log info;
default_type text/plain;
location /{
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$uri$remote_addr secret";
if ($secure_link = "") {
return 403;
}
if ($secure_link = "0") {
return 410;
}
return 200 '$secure_link:$secure_link_expires\n';
}
location /p/ {
secure_link_secret mysecret2;
if ($secure_link = "") {
return 403;
}
rewrite ^ /secure/$secure_link;
}
location /secure/ {
alias html/;
internal;
}
}
# 生成hash摘要
[root@ecs conf.d]# echo -n '52656565776/test1.txt127.0.0.1 secret' | openssl md5 -binary | openssl base64 | tr +/ - | tr -d =
FQuWy7wgjy9V8yLg7M7ZoA
[root@ecs conf.d]# curl 'securelink.test.com/test1.txt?md5=FQuWy7wgjy9V8yLg7M7Zo&expires=52656565776'
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>
[root@ecs conf.d]# curl 'securelink.test.com/test1.txt?md5=FQuWy7wgjy9V8yLg7M7ZoA&expires=52656565776'
1:52656565776
[root@ecs conf.d]# echo -n 'test1.txtmysecret2' | openssl md5 -hex
(stdin)= c3f9b32bf901b04c052ea9511e29a918
[root@ecs conf.d]# curl 'securelink.test.com/p/c3f9b32bf901b04c052ea9511e29a918/test1.txt'
1111为复杂的业务生成新的变量:map 模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22[root@ecs conf.d]# cat map.conf
map $http_host $name {
hostnames;
default 0;
~map\.test\w+\.org.cn 1;
*.test.org.cn 2;
map.test.com 3;
map.test.* 4;
}
map $http_user_agent $mobile {
default 0;
"~Opera Mini" 1;
}
[root@ecs conf.d]# curl -H 'Host: map.test.com' 127.0.0.1:10001
3:0
[root@ecs conf.d]# curl -H 'Host: map.test.org.cn' 127.0.0.1:10001
2:0
[root@ecs conf.d]# curl -H 'Host: map.test123.org.cn' 127.0.0.1:10001
1:0通过变量指定少量用户实现 AB 测试:split_client 模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29[root@ecs conf.d]# cat map.conf
server {
listen 10001;
default_type text/plain;
location /{
return 200 '$name:$mobile\n';
}
}
split_clients "${http_testcli}" $variant {
0.51% .one;
20.0% .two;
50.5% .three;
#40% .four;
* "";
}
server {
server_name split_clients.test.com;
error_log logs/error.log debug;
default_type text/plain;
location /{
return 200 'ABtestfile$variant\n';
}
}
[root@ecs conf.d]# curl -H 'testcli: 354165131351315aaaabb' split_clients.test.com/
ABtestfile
[root@ecs conf.d]# curl -H 'testcli: 354165131351315aaaabb&&&&ddddddd' split_clients.test.com/
ABtestfile.three根据 IP 地址范围的匹配生成新变量:geo 模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29[root@ecs conf.d]# cat geo.conf
geo $country {
default ZZ;
#include conf/geo.conf;
proxy 127.0.0.1;
127.0.0.0/24 US;
127.0.0.1/32 RU;
10.1.0.0/16 RU;
192.168.1.0/24 UK;
}
server {
server_name geo.test.com;
location /{
return 200 '$country\n';
}
}
[root@ecs conf.d]# ../../sbin/nginx -s reload
[root@ecs conf.d]# curl -H 'X-Forwarded-For: 10.1.0.0,127.0.0.1,172.27.57.6' geo.test.com
ZZ
[root@ecs conf.d]# curl -H 'X-Forwarded-For: 10.1.0.0,127.0.0.1,192.168.1.123' geo.test.com
UK
[root@ecs ~]# curl -H 'X-Forwarded-For: 10.1.0.0' geo.test.com
RU
[root@ecs ~]# curl -H 'X-Forwarded-For: 10.1.0.0,127.0.0.1' geo.test.com
RU使用变量获得用户的地理位置:geoip 模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40# 添加模块
[root@ecs nginx]# ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_realip_module --with-http_auth_request_module --add-module=/data/soft/nginx/nginx-http-concat --with-http_sub_module --with-http_addition_module --with-http_secure_link_module --with-http_geoip_module
# 下载安装GeoIp(nginx是C语言编写的)
# 访问地址:https://dev.maxmind.com/geoip/legacy/downloadable/
# 下载地址:https://github.com/maxmind/geoip-api-c/releases
# 安装编译
[root@ecs nginx]# tar -zxvf GeoIP-1.6.12.tar.gz
[root@ecs GeoIP-1.6.12]# ./configure
[root@ecs GeoIP-1.6.12]# make
[root@ecs GeoIP-1.6.12]# make install
[root@ecs share]# cd /usr/share/GeoIP
[root@ecs GeoIP]# ll
total 59784
lrwxrwxrwx 1 root root 18 Feb 16 17:12 GeoIP.dat -> GeoLiteCountry.dat
-rw-r--r--. 1 root root 56548946 Jun 8 2018 GeoLite2-City.mmdb
-rw-r--r--. 1 root root 3423846 Jun 8 2018 GeoLite2-Country.mmdb
-rw-r--r-- 1 root root 1242574 Apr 4 2018 GeoLiteCountry.dat
[root@ecs conf.d]# cat geoip.conf
geoip_country /usr/share/GeoIP/GeoIP.dat;
geoip_city /usr/share/GeoIP/GeoLiteCountry.dat;
geoip_proxy 127.0.0.1/32;
geoip_proxy_recursive on;
server {
server_name geoip.test.com;
error_log logs/myerror.log info;
keepalive_requests 2;
keepalive_timeout 75s 20;
location /{
return 200 'country:$geoip_country_code,$geoip_country_code3,$geoip_country_name
country from city:$geoip_city_country_code,$geoip_city_country_code3,$geoip_city_country_name
city:$geoip_area_code,$geoip_city_continent_code,$geoip_dma_code
$geoip_latitude,$geoip_longitude,$geoip_region,$geoip_region_name,$geoip_city,$geoip_postal_code
';
}
}
[root@ecs ~]# curl -H 'X-Forwarded-For: 124.205.155.154' geoip.test.com对客户端使用 keepalive 提升连接效率