1. http 配置
main
http {
upstream { … }
split_clients {…}
map {…}
geo {…}
server {
if () {…}
location {
limit_except {…}
}
location {
location {
}
}
}
server {
}
}
指令合并
值指令: 存储配置项的值 (可以合并)
- root
- access_log
- gzip
动作类指令: 指定行为 (不可以合并)
- rewrite
- proxy_pass 生效阶段
- server_rewrite 阶段
- rewrite 阶段
- content 阶段
存储值的指令继承规则: 向上覆盖
- 子配置不存在时,直接使用父配置块
- 子配置存在时,直接覆盖父配置块
例子
server {
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 模块合并配置的实现
char *(*merge srv conf)(ngx conf t*cf, void *prev, void *conf); # 在 server 块内生效,从 http 向 server 合并指
char *(*merge loc conf)(ngx conf t *cf, void *prev, void *conf); # 配置缓存在内存
2.listen指令
Default: listen *:80 | *:8000;
例子
listen 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];
3.处理HTTP请求头部的流程
接收请求事件模块
操作系统内核 worker线程 -> 事件模块 (epoll wait 分配连接池) -> http模块 (设置回调方法与超时定时器)
->data ack 数据包 -> epoll wait -> 分配内存与 读写缓存区
接收请求 HTTP 模块
接收URI
- 分配请求内存池 request pool size:4k
- 状态机解析请求行
- 分配大内存 large client header buffers:4 8k
- 状态机解析请求行
- 标识URI
接收header
- 状态机解析header
- 分配大内存 large client header buffers:4 8k
- 标识header
- 移除超时定时器 client header timeout: 60s
- 开始11个阶段的http请求处理
请求限制
client_header_buffer_size 10m;
large_client_header_buffers 4 16k; # number size; 读取大型客户端请求头的缓冲区的最大数量和大小
4.正则表达式
元字符
. # 匹配除换行符以外的任意字符
\w # 匹配字母或数字或下划线或汉字
\s # 匹配任意的空白符
\d # 匹配数字
\b # 匹配单词的开始或结束
^ # 匹配字符串的开始
$ # 匹配字符串的结束
重复
* # 重复零次或更多次
+ # 重复一次或更多次
? # 重复零次或一次
{n} # 重复n次
{n,} # 重复n次或更多次n1
{n,m} # 重复n到m次
## 转义与分组
\ # 转义符号: 取消元字符的特殊含义
() # 分组与取值
# 范围
[] :定义匹配的字符范围
[c] :匹配单个字符 c
注意:在括号里面用-表示范围:
[a-z] :匹配 a-z 小写字母的任意一个
[a-zA-Z0-9] :匹配所有大小写字母或数字
() :表达式的开始和结束位置 例如:(jpg|gif|swf|)
安装
# 下载 pcretest
https://www.pcre.org/
#
tar -xzvf pcre2-10.42.tar.gz
# 进入该目录,运行configure
cd pcre2-10.42
./configure --enable-utf8
# 执行make命令
make && make install
# 使用pcre2test命令
pcre2test
# 输入正则
re> /^\/admin\/website\/article\/(\d+)\/change\/uploads\/(\w+)\/(\w+)\.(png|jpg|gif|jpeg|bmp)$/
# 输入验证的数据
data> /admin/website/article/35/change/uploads/party/5.jpg
# 输出结果
# 0: /admin/website/article/35/change/uploads/party/5.jpg
# 1: 35
# 2: party
# 3: 5
# 4: jpg
# 测试例子2 nginx中 url替换
# 原始
/admin/website/article/35/change/uploads/party/5.jpg
# 转化后
/static/uploads/party/5.jpg
#使用的正则
/^\/admin\/website\/article\/(\d+)\/change\/uploads\/(\w+)\/(\w+)\.(png|jpg|gif|jpeg|bmp)$/
# 通过rewrite重写
rewrite /^\/admin\/website\/article\/(\d+)\/change\/uploads\/(\w+)\/(\w+)\.(png|jpg|gif|jpeg|bmp)$
/static/uploads/$2/$3.$4 last;
#
5.server_name 指令
## 指令后可以跟多个域名,第1个是主域名
server_name_in_redirect on / off # 默认 off
Context: http, server, location
## 泛域名:仅支持在最前或者最后
server_name *test.com
## 正则表达式:加~前缀
server_name www.test.com ~^www\d+\.test\.com$
例子 用正则创建变量
server {
server_name ~^(www\.)?(.+)$;
location / {
root /sites/$2;
}
}
server {
server_name ~^(www\.)?(?<domain>.+)$;
location / {
root /sites/$domain;
}
}
# 其他匹配
.test.com 可以匹配 test.com* .test.com
_ 匹配所有
"" 匹配没有Host头部
例子
server {
server_name primary.test.com second.test.com; # 第一个为主域名
server_name_in_redirect on;
return 302 /redirect;
}
# 测试命令
curl second.test.com -I
# 当 server_name_in_redirect为 on 会重定向到主域名
# 输出
Location: http://primary.test.com/redirect
# 当 server_name_in_redirect为 off 还是当前请求的域名
Location: http://second.test.com/redirect
Server 匹配顺序
- 精确匹配
- *在前的泛域名
- *在后的泛域名
- 按文件中的顺序匹配正则表达式域名
- default server : 第一个 ,listen 指定 default
6. 11个阶段的顺序处理
- postread 阶段 realip
- server_rewrite 阶段 rewrite
- find_config 阶段
- rewrite 阶段 rewrite
- post_rewrite 阶段
- preaccess 阶段 limit_req limit_conn
- access 阶段 access autn_basic autn_request
- postaccess 阶段
- precontent 阶段 try_files
- content 阶段 concat index auto_index
- log阶段 access_log
关键的6个阶段
1.postread - post_rewrite 阶段
- realip
- server_rewrite
- find_config
- rewrite
2.preaccess 阶段
- limit_req
- limit_conn
3.access 阶段
- access
- autn_basic
- autn_request
4.precontent 阶段
- try_files
- mirrors
5.content 阶段
- concat
- random_index
- index
- auto_index
- static
6.log 阶段
- log
11个阶段源码对照
char *ngx_module_names[] = {
"ngx_http_static_module",
"ngx_http_autoindex_module",
"ngx_http_index_module",
"ngx_http_random_index_module",
"ngx_http_mirror_module",
"ngx_http_try_files_module",
"ngx_http_auth_request_module",
"ngx_http_auth_basic_module",
"ngx_http_access_module",
"ngx_http_limit_conn_module",
"ngx_http_limit_req_module",
"ngx_http_realip_module",
"ngx_http_referer_module",
"ngx_http_rewrite_module",
"ngx_http_concat_module",
}
7.realip
拿到真实的用户 IP 地址
前提
- TCP 连接四元组 (src ip,src port, dst ip,dst port) 源码ip和端口, 目标ip和端口
- HTTP头部X-Forwarded-For 用于传递IP
- HTTP头部X-Real-IP 用于传递用户IP
- 网络中存在许多反向代理
完整流程 例子
用户 -> ADSL -> CDN -> 某个方向代理 -> Nginx
192.168.0.x -> 115.204.33.1 -> 1.1.1.1 -> 2.2.2.2 -> Nginx 通过 X-Real-IP拿到 115.204.33.1
用户
内网IP:192.168.0.x
ADSL
运营商公网IP:115.204.33.1 # 这个才是用户真正的ip
CDN
IP地址: 1.1.1.1
X-Forwarded-For: 115.204.33.1
X-Real-IP: 115.204.33.1
某个方向代理
IP地址: 2.2.2.2
X-Forwarded-For: 115.204.33.1 , 1.1.1.1
X-Real-IP: 115.204.33.1
Nginx
用户地址: 115.204.33.1
remote_addr变量:2.2.2.2
通过 binary_remote_addr& remote_addr 拿到用户的真实ip, 再结合limit conn模块实现限制。
realip 模块
默认不会编译进Nginx ,编译 --with-http-realip 启用功能
指令
- set_real_ip_from
- real_ip_header
- real_ip_recursive
变量
- realip_remote_addr
- realip_remote_port
例子
# 编译
./configure --with-http_realip_module
server {
server_name localhost;
error_log logs/myerror.log debug;
set_real_ip_from 116.62.160.193; # 将会被替代为精确的IP地址。
#real_ip_header X-Real-IP; # 客户端真实的 IP
#real_ip_recursive off; # 是否递归解析,off表示默认从最后一个地址开始解析;
real_ip_recursive on; # on表示从前往后依次递归获取ip
real_ip_header X-Forwarded-For; # 设置使用哪个头来替换IP地址。该模块将会使用X-Forwarded-For头中的最后一个IP地址来替换前端代理的IP地址。
location /{
return 200 "Client real ip: $remote_addr\n";
}
}
# 测试命令
curl -H 'X-Forwarded-For:1.1.1.1,172.25.70.1' localhost:8890
# 设置real_ip_recursive on X-Forwarded-For显示 172.25.70.1
#Client real ip: 1.1.1.1
# 设置real_ip_recursive off X-Forwarded-For 显示 1.1.1.1
#Client real ip: 172.25.70.1
8.rewrite 模块
return 指令
返回状态码
1. Nginx自定义 :
- 444:关闭连接
2. HTTP 1.0标准
- 301: http1.0永久重定向
- 302:临时重定向,禁止被缓存
3. HTTP1.1标准
- 303:临时重定向,允许改变方法,禁止被缓存
- 307:临时重定向,不允许改变方法,禁止被缓存
- 308:永久重定向,不允许改变方法
server与location块下的return指令关系
优先执行server的return
server {
server_name localhost;
listen 8080;
root html/;
error_page 404 /403.html;
return 403;
location /{
return 404 "find nothing!";
}
}
curl localhost:8080/aaa.txt
# 默认优先输出 server上定义的 403
# 当注释 # return 403;
显示 find nothing!
return与error_page
error写法
1. error_page 404 /404.html;
2. error_page 500 502 503 504 /50x.html;
3. error_page 404 =200 /empty.gif;
4. error_page 404 = /404.php;
5. location / {
error_page 404 = @fallback;
}
location @fallback {
proxy_pass http://backend;
}
6. error_page 403 http://example.com/forbidden.html;
7. error_page 404 =301 http://example.com/notfound.html;
rewrite指令
Syntax: rewrite regex replacement [flag];
Context: server. location,if
功能
- 将regex指定的url替换成replacement这个新的url
- 可以使用正则表达式及变量提取
- --last:用replacement这个URI进行新的location匹配-break: break指令停止当前脚本指令的执行,等价于独立的break指令
- --redirect: 返回302重定向
- --permanent: 返回301重定向
例子
# 目录结构
html/first/
└── 1.txt
html/second/
└── 2.txt
html/third/
└── 3.txt
# conf配置
server {
listen 8891;
server_name localhost;
rewrite_log on; #默认关闭
error_log logs/rewrite_error.log notice; # 默认会把 重定向写入 到 error里面
root html/;
location /first {
rewrite /first(.*) /second$1 last; #当访问 /first/3.txt时候 (.*) 匹配 /3.txt 即重定向到 /second/3.txt
return 200 'first!\n';
}
location /second {
rewrite /second(.*) /third$1 break; # 当访问 /second/3.txt时候 (.*) 匹配 /3.txt, 即重定向到 /third/3.txt
#rewrite /second(.*) /third$1;
return 200 'second!\n';
}
location /third { # 当访问 /third/3.txt时候, 由于该路径确实存在,返回 内容333 , 不返回 third!
return 200 'third!\n';
}
location /redirect1 {
rewrite /redirect1(.*) $1 permanent; # 返回301 重定向到 /
}
location /redirect2 {
rewrite /redirect2(.*) $1 redirect; # 返回302 重定向到 /
}
location /redirect3 {
rewrite /redirect3(.*) http://localhost$1; # 不写 默认还是 302 ,重定向到 http://localhost
}
location /redirect4 {
rewrite /redirect4(.*) http://localhost$1 permanent; # 不写 默认还是 301 ,重定向到 http://localhost
}
}
# 测试wriite访问
curl localhost:8891/first/3.txt
# 返回 333
# 测试redirect 访问
curl localhost:8891/redirect1/ -I # 返回 301
curl localhost:8891/redirect2/ -I # 返回 302
curl localhost:8891/redirect3/ -I # 返回 302
curl localhost:8891/redirect4/ -I # 返回 301
# 日志输出内容 一次请求,一次重定向
2023/03/15 10:38:53 [notice] 56760#0: *44 "/redirect1(.*)" matches "/redirect1/", client: 127.0.0.1, server: localhost, request: "HEAD /redirect1/ HTTP/1.1", host: "localhost:8891"
2023/03/15 10:38:53 [notice] 56760#0: *44 rewritten redirect: "/", client: 127.0.0.1, server: localhost, request: "HEAD /redirect1/ HTTP/1.1", host: "localhost:8891"
条件判断 if
context: server , location
规则: 条件为真执行{}里面内容, 指令可以继承
if 指令的条件表达式
1. 检查变量为空或者值是否为0,直接使用
2. 将变量与字符串做匹配,使用 = 或者 !=
3. 将变量与正则表达式做匹配
大小写敏感,~或者!~
大小写不敏感,~*或者!~*
4. 检查文件是否存在,使用-f 或者 !-f
5. 检查目录是否存在,使用-d或者!-d
6. 检查文件、目录、软链接是否存在,使用-e或者!-e
7. 检查是否为可执行文件,使用-x或者!-x
例子
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1 break;
}
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
set $id $1;
}
if ($request_method = POST) {
return 405;
}
if ($slow) {
limit_rate 10k;
}
if ($invalid_referer) {
return 403;
}
9.find_config
location
只匹配URI 不匹配参数
location[=|~|~*|^~] uri { ... }
location @name { ...}
Context:server,location
merge_slashes on/off # 默认 on 合并连续的/符号
Context:http, server
分类
- 常规
- =:精确匹配
- ^~:匹配上后则不再进行正则表达式匹配
- 正则表达式
- ~ :大小写敏感
- ~* :忽略大小写
- @ : 用于内部跳转的命名location
location 匹配逻辑
依次优先顺序
- location =
- location 完整路径 (最长路径优先)
- location ^~ 否定正则
- location ~* 正则顺序,不区分大小写
- location ~ 区分大小写正则顺序
- location 部分起始路径
- /
例子
#1. = : 用于不包含正则表达式的uri前,必须与指定的模式精确匹配(区分大小写,并且后面带/是有区别的)
location = /bbb {
default_type text/plain;
return 200 "access success bbb \n\r";
}
# 能匹配到:
http://127.0.0.1:8081/bbb
http://127.0.0.1:8081/bbb?p1=TOM
# 不能匹配到(大小写区分):
http://127.0.0.1:8081/bbb/
http://127.0.0.1:8081/bbbcd
http://127.0.0.1:8081/Bbb
#2.location /完整路径
location /aaa/bbb/ccc/ddd {
default_type text/plain;
return 200 "access success aaa \n\r";
}
# 只能匹配到:
http://127.0.0.1:8081//aaa/bbb/ccc/ddd
#3. ^~: 用于不包含正则表达式的uri前,功能和不加符号的一致,唯一不同的是,如果模式匹配,那么就停止搜索其他模式了,可用于提升优先级。(区分大小写,并且后面带/是有区别的)
location ^~ /fff {
default_type text/plain;
return 200 "access success. Non Regular expression matched: fff \n\r";
}
# 能匹配到:
http://127.0.0.1:8081/fff
http://127.0.0.1:8081/fff/
http://127.0.0.1:8081/fffdef
http://127.0.0.1:8081/fff/def/
http://127.0.0.1:8081/fff?p1=TOM
# 不能匹配到(大小写区分):
http://127.0.0.1:8081/Fff
http://127.0.0.1:8081/pp/fff
# 如果规则(后面跟/目录符号) location /fff/ { 则只能匹配到下面两行:
http://127.0.0.1:8081/fff/
http://127.0.0.1:8081/fff/def/
#4. ~*: 用于表示当前uri中包含了正则表达式,并且不区分大小写
# 正则表达式:不区分大小写,以/abc开头,以字母或数字或下划线或汉字结束的
location ~*^/ddd\w$ {
default_type text/plain;
return 200 "access success. 111 Regular expression matched: ddd \n\r";
}
# 能匹配到:
http://127.0.0.1:8081/dddb
http://127.0.0.1:8081/dddB
http://127.0.0.1:8081/ddd2
http://127.0.0.1:8081/DddH
# 不能匹配到(大小写区分):
http://127.0.0.1:8081/ddd
http://127.0.0.1:8081/Ddd
http://127.0.0.1:8081/ddd/
http://127.0.0.1:8081/ddddef
http://127.0.0.1:8081/ddd/def/
http://127.0.0.1:8081/ddd?p1=TOM
#5. ~ : 用于表示当前uri中包含了正则表达式,并且区分大小写
# 正则表达式:区分大小写,以/abc开头,以1个字母或数字或下划线或汉字结束的
location ~^/eee\w$ {
default_type text/plain;
return 200 "access success. 000 Regular expression matched: eee \n\r";
}
# 能匹配到:
http://127.0.0.1:8081/eeeb
http://127.0.0.1:8081/eeeB
http://127.0.0.1:8081/eee2
# 不能匹配到(大小写区分):
http://127.0.0.1:8081/eee
http://127.0.0.1:8081/Eee
http://127.0.0.1:8081/eee/
http://127.0.0.1:8081/eeedef
http://127.0.0.1:8081/eee/def/
http://127.0.0.1:8081/eee?p1=TOM
#6. 不带符号,要求必须以指定模式开始(区分大小写,并且后面带/是有区别的)
location /aaa/ {
default_type text/plain;
return 200 "access success aaa \n\r";
}
# 能匹配到:
http://127.0.0.1:8081/aaa
http://127.0.0.1:8081/aaa/
http://127.0.0.1:8081/aaadef
http://127.0.0.1:8081/aaa/def/
http://127.0.0.1:8081/aaa?p1=TOM
# 不能匹配到(大小写区分):
http://127.0.0.1:8081/Aaa
# 如果规则(后面跟/目录符号) location /aaa/ { 则只能匹配到下面两行:
http://127.0.0.1:8081/aaa/
http://127.0.0.1:8081/aaa/def/
#7. /
# 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求
# 但是正则和最长字符串会优先匹配
location / {
default_type text/plain;
return 200 "access success root \n\r";
}
测试例子2
server {
listen 8892
server_name localhost;
error_log logs/error.log debug;
#root html/;
default_type text/plain;
merge_slashes off;
location = /Test1 {
return 200 'exact match!\n';
}
location ^~ /Test1/ {
return 200 'stop regular expressions match!\n';
}
location ~ /Test1/$ {
return 200 'first regular expressions match!\n';
}
location ~* /Test1/(\w+)$ {
return 200 'longest regular expressions match!\n';
}
location /Test1/Test2 {
return 200 'longest prefix string match!\n';
}
location /Test1 {
return 200 'prefix string match!\n';
}
}
# 测试代码
curl localhost:8892/Test1 # = 等号匹配
#exact match!
curl localhost:8892/Test1/ # ^~非正则匹配
# stop regular expressions match!
curl localhost:8892/Test1/Test2 # 最长正则匹配 不区分大小写 ~* /Test1/(\w+)$
# longest regular expressions match!
curl localhost:8892/test1/Test2 # 最长正则匹配 不区分大小写 ~* /Test1/(\w+)$
# longest regular expressions match!
curl localhost:8892/Test1/Test2/ # 最长匹配
# longest prefix string match
10.preaccess 阶段
1. 限制每个客户端的并发连接数
ngx_http_limit_conn_module模块
模块:http_limit_conn_module
默认编译进nginx,通过 --without-http_limit_req_module 禁用
生效范围:
- 全部worker进程(基于共享内存)0
- 进入preaccess阶段前不生效
- 限制的有效性取决于key的设计: 依赖postread阶段的realip模块取到真实ip
limit_conn 指令
限制发生时的日志级别
定义共享内存 (包括大小) ,以及key关键字
Syntax: limit_conn_zone key zone=name:size;
Context: http
限制并发连接数
Syntax: limit_conn zone number;
Context: http, server, location
限制发生时的日志级别
Default: limit_conn_log_level error; # info | notice | warn | error;
Context: http, server, location
限制发生时向客户端返回的错误码
limit_conn_status 503;
Context: http, server,location
限制每个客户端的每秒处理请求数
ngx_http_limit_req_zone_module 模块
默认编译进nginx,通过--without-http_limit_req_zone_module禁用功能
生效算法: leaky bucket 算法
生效范围 和 limit_conn 一致
流量分类
- 突发性 bursty flow 比喻水龙头打开 ,一次性接收很多请求,立马处理,导致中间的请求无法响应。
- 修复均匀流量 fixed flow 漏斗式水盆接收后,按固定流量输出。不是立马处理,按均匀分布后,有序执行。
limit_req 指令
# 定义共享内存 (包括大小),以及 key 关键字和限制速率
limit_req_zone key zone=name:size rate=rate ; # rate单位为r/s或者r/m
# 限制并发连接数
limit_req zone=name [burst-number] [nodelay]:
context:http, server, location
burst #默认为0
nodelay #对burst中的请求不再采用延时处理的做法,而是立刻处理
limit_req_log_level error; #限制发生时的日志级别
limit_req_status 503; #限制发生时向客户端返回的错误码
例子
limit_conn_zone $binary_remote_addr zone=addr:10m; # 定义 addr 指定空间大小为10m,超过后通过LRU算法调整
limit_req_zone $binary_remote_addr zone=one:10m rate=2r/m; # 定义 one ,指定空间大小为10m,每分钟处理两个请求
server {
listen 8893;
server_name localhost;
root html/;
error_log logs/myerror.log info; #
location /{
limit_conn_status 500; # 默认503
limit_conn_log_level warn; # info | notice | warn | error; # 默认error
limit_req_log_level error; # info | notice | warn | error; # 默认error
#limit_rate 50; # 限制50字节
#limit_conn addr 1; # 每次只能有一个同时并发
limit_req_status 503; # 默认503
#limit_req zone=one; # 直接引用上面定义个 one,每分钟处理两个请求。
limit_req zone=one burst=3; # 当一分钟内超过2个正在进行的请求,则会放入队列,等待正在运行的2个请求结束后,再统一执行队列的任务,队列长度为3
limit_req zone=one burst=3 nodelay; # 队列里面的内容不等待,跟正在运行的两个任务一起发给后台处理。
}
}
# 同一分钟 请求2以上次 则提示 503 错误 503 Service Temporarily Unavailable
curl localhost:8893/
curl localhost:8893/
curl localhost:8893/
11.access阶段
用户授权
模块: http_access_module,默认编译进nginx
限制ip访问权限
server {
listen 8894;
server_name localhost;
root html/;
location / {
deny 192.168.0.13; #限制不能访问ip
allow 192.168.0.0/24; # 允许的 ip段
deny all; # 剩余的都限制不能访问
}
}
# 注意本地测试 对应的localhost 和 127.0.0.1 都要配置上去才生效
curl 192.168.0.7:8894 # 允许访问
curl localhost:8894 # 被限制
curl 127.0.0.1:8894 # 被限制
HTTP Basic Authentication
auth basic 模块的指令
基于HTTP Basic Authutication 协议进行用户名密码的认证
生成密码文件
# 1.定义文件
vi myfile1
# 输入内容
# comment
namel:password1
name2:password2:comment
name3:password3
# 2. 生成工具:htpasswd
yum install httpd-tools
htpasswd -cb myfile1 jason 123456
auth_request
# 安装
./configure --with-http_auth_request_module
# 效果
向上游的服务转发请求,若上游服务返回的响应码是2xx,则续执行,若上游服务返回的是401或者403,则将响应返回给客户端
# 原理
收到请求后,生成子请求,通过反向代理技术把请求传递给上游服务
auth_request_set # 可以设置请求参数
satisfy 指令
- satisfy all 来控制多个条件是否必须完全满足才放行
- satisfy any 只要有一个满足就才放行
Syntax: satisfy all/any; # 默认 all;
例子
# 上游服务器
server {
listen 8090;
server_name localhost;
location /auth_upstream {
return 200 'auth sucess'
}
}
# 下游验证服务器
server {
listen 8895;
server_name localhost;
error_log logs/error.log debug;
root html/;
default_type text/plain;
location /auth_basic {
satisfy any; # 这里 有两个验证 一个是 auth_basic, 一个是 deny 默认拒绝 ,如果 auth_basic验证通过会忽略deny拒绝,进行放行。
auth_basic "test auth_basic";
auth_basic_user_file myfile1; # 这里配置刚刚生成的包含用户和密码文件
deny all; # deny 不一定生效
}
location / {
auth_request /test_auth; # 通过上游的200 和 其他状态区分
}
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;
}
}
# 测试auth_basic 使用浏览器
http://localhost:8895/auth_basic
# 输入用户名 jason
# 输入用户密码 123456
# 测试 上游验证
curl localhost:8895/
# 上游返回200 则成功
# 如果上游返回其他状态则失败
12.precontent
try_files 指令
按序访问资源的try_files模块
try_files file ... uri;
try_files file ... =code;
原理
依次试图访问多个url对应的文件,由root或者alias指令指定当文件存在时直接返回文件内容, 如果所有文件都不存在,则按最后一个URL结果或者code返回。
例子
server {
listen 8896;
server_name localhost;
error_log logs/myerror.log info;
root html/;
default_type text/plain;
location /first { # 尝试多个uri 都没有则返回最后一个
# $uri 为 /first
# $uri/index.html 为 /first/index.html
# $uri.html 为 /first.html
try_files /aa/bbb.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;
}
}
curl localhost:8896/first
# 返回 lasturl
curl localhost:8896/second
# 返回 404
mirror模块
实时拷贝流量,处理请求时,生成子请求访问其他服务,对子请求的返回值不做处理,默认在编译nginx
mirror uri/off; # 默认off
mirror_request_body on/off; # 默认on
例子
# 这是 复制主服务器的流量分发服务
server {
listen 10020;
location / {
return 200 'mirror response!';
}
}
# 主服务器 入口主服务器
server {
listen 8897;
server_name localhost;
location / {
mirror /mirror;
mirror_request_body off;
proxy_pass http://127.0.0.1 # # 指定处理主流量的后端Server 可以不设置
}
location = /mirror {
internal; # 标志该location只为内部的重定向服务, 外面来的返回404
proxy_pass http://127.0.0.1:10020/$request_uri; # 需要显示指明,因为流量复制过来之后会丢掉request_uri
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
}
#测试
curl 127.0.0.1:8897/index.html
# 输出 首页信息
tail -f 100 ./logs/access.log
#查看两台服务器都分别请求了 index.html 页面
13.content阶段
root和alias指令
### alias
将url映射为文件路径,以返回静态文件内容
Context: location
### root
root会将完整ur映射进文件路径中
alias只会将location后的URL映射到文件路径
Context: http, server, location, if in location
root 和 alias的区别
# 1. root 指的是 完整的路径
location /c/ {
root /a/
}
# 对应路径是绝对的 /a/c/
# 2. alias 指的是虚拟路径
location /c/ {
alias /a/
}
# 对应路径是 /c/ 是虚拟的,只访问/a/ 下面的文件
例子
server {
listen 8898
server_name localhost;
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';
# $request_filename 为当前请求的完整路径 /usr/local/nginx/html/realpath/RealPath/1.txt
# $document_root 为当前请求的alias或者 root的路径 /usr/local/nginx/html/realpath
# $realpath_root 将document_root中的软链接等换成真实路径 /usr/local/nginx/html/first
}
}
# 创建测试数据
echo 'test1' ./html/1.txt
curl 127.0.0.1:/root/ # 等价于 html/root/index.html 所以返回404
curl 127.0.0.1:/root/1.txt # 等价于 html/root/1.txt 所以返回404
curl 127.0.0.1:/alias/ # 等价于 html/index.html 所以返回首页
curl 127.0.0.1:/alias/1.txt # 等价于 html/1.txt 所以返回首页 test1
curl 127.0.0.1:8898/RealPath/1.txt
# 输出
#/usr/local/nginx/html/realpath/RealPath/1.txt:/usr/local/nginx/html/realpath:
content-type
Context: http, server, location
Syntax: types { ... }
Default: types { text/html html; image/gif gif; image/jpeg jpg; }
Syntax: default_type mime-type;
Default: default_type text/plain;
Syntax: types_hash_bucket_size size;
Default: types_hash_bucket_size 64;
Syntax: types_hash_max_size size;
Default: types_hash_max_size 1024;
未找到文件时的错误日志
log_not_found on/off ; # on
url结尾 自动加 / 访问
static 模块实现了 root/alias 功能时, 发现访问目标是目录,但 URL 末尾未加/时,会返回 301 重定向
重定向跳转的域名
Syntax: server_name_in_redirect on | off; # 默认 off
Context: http, server, location
Syntax: port_in_redirect on | off; # 默认on
Context: http, server, location
Syntax: absolute_redirect on | off; # 默认on
Context: http, server, location
例子
server {
listen 8300;
server_name test1.com test2.com;
server_name_in_redirect off; # 重定向是否带域名
port_in_redirect on; # 重定向是否带上端口的开关
absolute_redirect off; # 默认on ,off 时候返回相对地址
root html/;
}
curl localhost:8300/first2 -I
# 301 重定向到 absolute_redirect off 返回相对地址
# /first/
# 当 absolute_redirect on 设置为on, 返回绝对地址
# 301 重定向到
# http://localhost:8300/first/
# 当添加 Host 头部信息
curl -H 'Host:test111' localhost:8300/first -I
# 返回
http://test111:8300/first/
# 当 server_name_in_redirect on; 设置为on,则重定向 会重新向到第一个域名
curl localhost:8300/first2 -I
# 301 重定向到
# http://test1.com:8300/first/
# 指定host 也改变不了
curl -H 'Host:test111' localhost:8300/first -I
# http://test1.com:8300/first/
index/random_index/autoindex
## index
# 指定 / 访问时返回index文件内容
index index.html;
### random_index
# 默认不在Nginx
random_index off;
### autoindex
## 默认在nignx里
Syntax: autoindex off;
Syntax: autoindex_exact_size on;
Syntax: autoindex_format html ; # html | xml | json | jsonp;
Syntax: autoindex_localtime off ;
例子
server {
listen 8301;
server_name localhost;
location / {
alias html/;
autoindex on;
index a.html; # 注意如果当前文件夹有index.html, 这里必须指定index 并指定不存在的xx.html,不然 index 默认是 index.html 导致无法访问文件夹
autoindex_exact_size off; # 显示文件实际大小
autoindex_format html; # 按指定格式显示 文件列表信息
autoindex_localtime on; # on 显示的文件时间为文件的服务器时间 , off 为显示的文件时间为GMT时间
}
}
curl localhost:8301
# 显示文件列表
# 当 注释 index a.html,则 autoindex不会生效
curl localhost:8301
# 则显示a.html 页面
concat
功能 :当页面需要访问多个小文件时,把它们的内容合并到一次http响应中返回,提升性能
安装
wget https://codeload.github.com/alibaba/nginx-http-concat/zip/refs/heads/master
unzip nginx-http-concat-master.zip
mkdir -p /usr/local/download/nginx-1.15.8/module
mv nginx-http-concat-master /usr/local/download/nginx-1.15.8/module
#编译
./configure --add-module=./module/nginx-http-concat-master
使用
在URI 后加上??,后通过多个逗号分隔文件。如果还有参数,则在最后通过?添加参数
分析淘宝网
例子
server {
listen 8302
server_name localhost;
error_log logs/myerror.log debug;
concat on;
root html;
location /concat { #访问文件路径为 html/concat
concat_max_files 20; #设置合并的最大文件数为20
concat_types text/plain; #允许合并的文件类型
concat_unique on; #只允许同类文件合并
concat_delimiter ':::'; # 返回 分割的符号
concat_ignore_file_error on;
}
}
# 创建测试文件
cd html
mkdir concat
echo 'test1' > ./concat/1.txt;
echo 'test2' > ./concat/2.txt;
curl localhost:8302/concat/??1.txt,2.txt
# 输出内容
# test1:::test2
# js 分割实例
cd html
# 创建 index.html
echo '<html><script src="./??a.js,b.js"> </script></html>' > ./concat/index.html
# 创建js
echo 'document.write("aaaa")' > ./concat/a.js;
echo 'document.write("bbbb")' > ./concat/b.js;
# conf 配置
concat_delimiter ''; # 去除分割符
# 在浏览器访问
http://localhost:8302/concat/
# 输出
# aaaabbbb
14.log阶段
access.log
将HTTP请求相关信息记录到日志 ngx_http_log_module 无法禁用
Syntax: log_format name [escape=default|json|none] string ...;
Default: log_format combined "...";
Context: http
log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent ' '"$http_referer"
"$http_user_agent"';
日志格式
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_except
日志路径
注意点
- path 路径可以包含变量:不打开 cache 时每记录一条日志都需要打开、关闭日志文件
- if 通过变量值控制请求日志是否记录
日志缓存
- 功能:批量将内存中的日志写入磁盘
- 写入磁盘的条件
- 所有待写入磁盘的日志大小超出缓存大小
- 达到 fush 指定的过期时间
- worker 进程执行reopen 命令,或者正在关闭
日志压缩。
- 功能:批量压缩内存中的日志,再写入磁盘
- buffer 大小默认为64KB
- 压缩级别默认为 1 (1 最快压缩率最低,9 最慢压缩率最高)
日志文件名包含变量时的优化
Syntax: open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time];
open_log_file_cache off;
Default: open_log_file_cache off;
Context: http, server, location
- max : 缓存内的最大文件句柄数,超出后用 LRU 算法淘汰
- inactive : 文件访问完后在这段时间内不会被关闭。默认 10 秒
- min_uses : 在inactive 时间内使用次数超过 min uses 才会继续存在内存中。默认 1超出 valid 时间后,将对缓
- valid : 存的日志文件检查是否存在。默认 60 秒
- off : 关闭缓存功能