目录
日志管理
- access_log
- error_log
日志文件切割
自定义错误页
http 访问限流
限制请求数
语法
使用
限制连接数
语法
测试
补充:
https 配置
使用
生成证书
配置 nginx
测试
补充
HttpRewrite 模块
if
if 的语法:
全局变量
自定义变量:
重定向 rewrite
第三方模块
前置知识 (编译安装)
安装第三方模块
没有讲到的内容
前置知识章节:
1. 介绍, 安装, hello world,location 匹配
2. 反向代理, 负载均衡, 缓存服务, 静态资源访问
3. 当前章节: 日志管理, http 限流, https 配置, http_rewrite 模块, 第三方模块安装, 结语.
日志管理
nginx 里面有访问日志和错误日志, 访问日志记录记录客户端访问 nginx 的每一个请求; 错误日志记录发生错误的请求.
access_log
access_log 用于配置访问日志, 日志的格式可以根据 log_format 指令来进行自定义.
log_format 用于定义访问日志的格式. log_format 指令的第一个参数是格式名, 可以给当前格式定义一个名字, 第二个参数是格式字符串, 支持一些内部变量语法, 比如 $remote_addr 会获取到请求的客户端的 IP 地址. log_format 只可以配置在 http 块中.
log_format 示例:
- log_format main '$remote_addr - $remote_user [$time_local]"$request" '
- '$status $body_bytes_sent"$http_referer" '
- '"$http_user_agent" "$http_x_forwarded_for"';
- log_format mylog '[client_ip:] $remote_addr [time:] $time_local [user_agent:]"$http_user_agent"';
log_format 语法说明:
整个字符串使用''包裹, 内部可以使用 $ 开头的变量, 比如 $remote_addr 会获取到请求的客户端的 IP 地址, 其他字符都作为显示效果, 比如上面使用的"" 只是用于包裹数据而已.[],-,: 也是这样的.
access_log 指令可以用来指定访问日志的存储位置和日志格式. access_log 指令的第一个参数是访问日志的存储路径, 第二个参数是使用的格式的格式名. access_log 可以使用在 http, server, location, location 的 if, limit_except 等块中.
语法格式:
access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
* path 是日志存储路径
* format 用于定义格式, 是 log_formate 的名字,
* buffer=size 为存放日志的缓冲区大小
* flush=time 为将缓冲区的日志刷到磁盘的时间
* gzip[=level] 表示压缩级别
* if 一般不配置
access_log off; # 关闭访问日志记录
默认在 nginx.conf 中配置了 access_log 的默认配置:
nginx 日志常见可用变量:(更多变量可以参考: 英文文档, 某 CSDN 博客)
内置变量 | 说明 |
---|---|
$remote_addr | 客户端的 IP 地址 |
$remote_user | 客户端用户名,用于记录浏览者进行身份验证时提供的名称,如果没有登录则为空 |
$time_local | 访问的时间与时区 |
$request | 请求的 URI 和 HTTP 协议 |
$status | 记录请求返回的 HTTP 状态码 |
$body_bytes_sent | 发送给客户端的文件主体 |
$http_referer | 请求来源的 URL 地址 |
$http_user_agent | 客户端浏览器信息 |
$http_x_forwarded_for | 经过的客户端 IP 地址列表,如果请求是代理转发的,那么原始的客户端 IP 应该在这个字段里面 |
error_log
error_log 是错误日志, 只有访问错误的时候才会记录下来. 不支持格式定义.
error_log 的语法是:
error_log file [level];
error_log 指令的第一个参数是错误日志存储路径, 第二个参数是日志级别.
日志级别有 debug,info,notice,warn,error,crit 几个等级. debug 的日志记录是最完善的, crit 只记录 "致命" 级别的错误.
error_log 可以设置在 http,server,location,location 的 if 块中配置.
指令
error_log /dev/null
用于关闭错误日志./dev/null 在 Linux 中可以认为是一个无底洞, 可以把它当作垃圾桶.
日志文件切割
对于日志文件有些版本会自动切割, 有些版本不会, 也就是说, 如果你的服务端跑了一年, 那么一年的访问日志都存储在 access.log 中, 很明显, 这不是一个好的处理, 这样不方便我们在发生错误时分析日志. 所以通常都会对日志文件进行切割, 根据业务需求可能按天, 按周来进行切割.
自动切割: 如果你的 nginx 能够自动切割日志, 那么你就不需要看了, 怎么判断有没有自动切割功能呢, 查看一下 / etc/logrotate.d 下是否有 nginx 文件, logrotate 用于日志切割, Linux 自带的, 但内置的除了切割还有一些其他的操作, 比如定时清除, 有需要的可以自行看一下 VIM /etc/logrotate.d/nginx
下面教的是使用定时任务自动切割日志文件, 当然如果你喜欢手动也没问题.
我们只需要定义一个定时任务即可.
1. 先提一下 crontab 的语法, 用示例来简单讲解语法:
示例: 0 * * * */root/nginx-cut-log.sh>/dev/null 2>&1
crontab 语法:
第一个参数: 分 (取值 0-59,* 代表每一个), 对应上面第一个 0
第二个参数: 时 (取值 0-23), 对应上面第二个 0
第三个参数: 日 (取值 1-31)
第四个参数: 月 (取值 1-12)
第五个参数: 星期 (取值 0-6,0 代表星期日)
第六个参数: 要运行的命令
额外的说明:
上面的命令中 `>/dev/null 2>&1` 用于把定时任务的标准输出和错误输出都重定向到 "垃圾桶 / 黑洞" 中.
2. 然后编写一个切割日志文件的脚本文件 nginx-cut-log.sh(命名随意):
- #!/bin/bash
- # 定义日志目录变量
- logs_path="/var/log/nginx/"
- # 切割日志, 其实就是拷贝与新建而已.
- #`date -d yes +"%Y%m%d"` 中 `` 可以用来获取 Linux 命令的执行结果, 可以参考 https://www.cnblogs.com/asxe/p/9317811.html
- mv $logs_path/access.log $logs_path/access-`date +"%Y-%m-%d-%H-%M"`.log # 测试的时候请打开这一个关闭下面的, 这个用于每分钟执行一次.
- # 下面的这个应该用于每天执行的情况, 因为以日期命名了文件
- #mv $logs_path/access.log $logs_path/access-`date -d "1 day ago" +"%Y-%m-%d"`.log
- # 上面的操作类似于重命名, 所以原本的 access.log 会没了, 使用下面的命令让 nginx 重新生成一个 access.log.
- /nginx -s reopen;
3. 记得给脚本文件增加执行权限:
chmod +x nginx-cut-log.sh
4. 然后定义一个定时任务:
执行命令 crontab -e, 并在那里附加下述命令:
* * * * */root/nginx-cut-log.sh>/dev/null 2>&1
上面的用于每分钟都创建新的日志文件的测试, 正式使用应该前面两个是一个准确的值, 比如 0 0 * * */root/nginx-cut-log.sh>/dev/null 2>&1 代表每天零点零分执行.
5. 然后重启 crond: 执行命令 crond restart
6. 然后你在 / var/log/nginx / 目录下等一分钟看是否会创建新的 access.log 文件. 如果创建了, 就说明我们的日志切割成功运行了. 当然, 记得测试完后清除我们上面在 crontab -e 中输入的命令, 因为那个代表了每分钟都运行.
自定义错误页
自定义错误页其实是一个非常小的内容. 用于定义 nginx 的 http 请求发生错误的时候显示的页面
语法:
error_page code ... [=[response]] uri;
示例:
error_page 500 502 503 504 /50x.HTML;
: 代表 http 响应码为 500,502,503,504 时, 返回各自 location 的 root 下的 / 50x.HTML
error_page 400 http://xxxx.html
: 代表 http 响应码为 400 时, 返回 http://xxxx.html
error_page 404 = @fallback;
还支持内部重定向,@fallback 是自定义的一个内部重定向 location.
error_page 400=200 http://xxxx.html
: 发生 400 错误时, 返回 http://xxxx.html, 并修改返回的响应码为 200.
http 访问限流
访问限流依靠模块, 模块. ngx_http_limit_conn_module 用来限制连接数. ngx_http_limit_req_module 用来限制请求数.
为什么需要限流呢? 那是为了防止过量的请求给服务端带来过大的压力.
连接跟请求的区别:
http 也是应用层协议, 也是 tcp 的一种, http 请求其实是使用 tcp 来连接请求的. 在 HTTP/1.0 中, 大多是一次连接, 一次请求的. 但它其实也支持
Connection: keep-alive
, 如果在响应的 Header 中有这
Connection: keep-alive
, 那么就会维持连接, 直到响应 / 请求的 Header 中有 Connection: close 才断开连接 (超时也会, keep-alive 也是有时效的). 在
Connection: keep-alive
的时候一个连接可以发起多个请求.
如下图, 我连续请求一张图片, 第一次的时候 initial connection 初始化了 tcp 连接, 而第二次请求的时候没 initial connection, 这代表连接没用端口:
百度的请求是支持
Connection: keep-alive
的, 你可以尝试在谷歌浏览器中打开百度的一张图 https://hmcdn.baidu.com/static/hmt/icon/21.gif , 并打开它的请求 Timing 来查看是否每一次都 initial connection(初始化连接, 这代表建立新的 tcp 连接, 而 stalled 代表检测是否有旧的可用的 tcp 连接, 所以上面的第二种图中没用 initial, 只有 stalled,stalled 使用了没断开的 tcp 连接) 中测试.
限制请求数
语法
limit_req_zone: 用来设置请求限制规则,
语法
limit_req_zone key zone=name:size rate=rate;
key 用于定义请求限制的对象, 比如为 $server_name 的时候, 代表限制虚拟主机的请求次数, 为
$binary_remote_addr
或 $remote_addr 时代表限制同一个 IP 的客户端的请求次数.
zone=name:size 中, name 是当前这个请求限制规则空间的名字, size 是这个空间的大小.
使用位置 : limit_req_zone 只能配置在 Http 块.
示例:
limit_req_zone $binary_remote_addr zone=req_zone:10m rate=1r/s;
limit_req: 与 limit_req_zone 配合, 用来定义限制请求次数.
语法:
limit_req zone=name [burst=number] [nodelay | delay=number];
zone=name 中 name 式 limit_req_zone 的名字
burst 用来定义突发大小, 例如在
limit_req zone=req_zone burst=3
中, 限制请求次数是 1, 那么突发的 2 个请求会放到下一秒再执行.
使用位置 :limit_req 可以用在 http, server, location
超出请求限制的请求, 会返回 503.
示例:
limit_req zone=req_zone burst=3 nodelay;
使用
1. 配置 nginx:
2. 重启之后测试: 你可以在一秒内连续在浏览器中刷新, 如果刷新多次之后突然响应 503, 那说明请求被限制了. 或者你可以在
/var/log/nginx/error.log
中看到 limiting requests
限制连接数
语法
limit_conn_zone: 用来设置连接限制规则, 语法 limit_conn_zone key zone=name:size;
key 用于定义连接限制的对象, 比如为 $server_name 的时候, 代表限制虚拟主机的连接次数, 为
$binary_remote_addr
或 $remote_addr 时代表限制同一个 IP 的客户端的连接次数.
zone=name:size 中, name 是当前这个连接限制规则空间的名字, size 是这个空间的大小.
limit_conn_zone 只能配置在 Http 块.
例如:
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn: 与 limit_conn_zone 配合, 用来定义限制连接次数. 语法 limit_conn zone number;
number 是限制的次数.
limit_conn 可以用在 http, server, location.
例如: limit_conn addr 1;, 假如 addr 是一个限制同一个 IP 的客户端的连接次数的规则, 代表同一个 IP 的客户端的并发连接为 1.
补充: 并不是所有的连接都会被计算, 只有并发压力的连接才计算, 比如上面的 limit_conn addr 1; 代表每个 IP 只能有一个连接, 但如果你给不了 nginx 请求压力的话, 那么假设你发起两个连接, nginx 马上处理完第一连接之后, 后面来的第二个连接此时并不算并发连接 (这时候就限制失败了), 所以如果你下面测试的话, 可以访问处理比较慢的资源, 让 nginx 持续地持有这个连接, 然后我们再发起另外一个连接, 这样才能测试成功. 下面是官网文档的一段话:
Not all connections are counted. A connection is counted only if it has a request being processed by the server and the whole request header has already been read.
测试
上面说了, 要使用一个响应比较慢的资源, 所以我们这里使用反向代理来作为响应.
1. 新建一个后端服务端接口:(下面示例基于 spring boot, 我让它 sleep 了 10 秒, 也就相当于要处理十秒才能响应数据. 此时有充足的时间来让我们发起第二次数据)
2. 配置 default.conf:
3. 测试访问:
首先访问一下
http://192.168.31.128/user/info
, 这个是我的代理后的请求接口, 响应时间至少需要十秒
在上面响应的十秒内, 用另外一个窗口访问一下
http://192.168.31.128/user/info
, 这个会直接得到 503, 而不是等待十秒的响应.
补充:
limit_rate 可以用来限制响应的传输速度, 这里没讲.
https 配置
注意, 此时的 https 配置并没有太多实战意义, 因为证书都是正规机构发的话, 浏览器才能够识别成安全的. 这里的教学只是做个认知, 就是知道怎么配置, 证书什么的是都是应该从正规机构申请的.
使用 nginx -V 查看编译参数, 如果有
--with-http_ssl_module
, 那么就代表启用了模块. 默认的 YUM 方式安装是携带这个模块的. 如果你是使用了编译安装的, 那么自行去加上吧.
Https 有什么好处, 处理什么情况, 这些自己查吧.
Https 会使用几种加密方式, 非对称加密用于身份验证和密钥协商, 对称加密用于采用协商的密钥来对数据进行加密. 另外散列算法用于检验数据完整性.
对称加密使用同一个密钥.
非对称加密, 公钥用于加密, 私钥用于解密
Https 简单流程: 首先发起非对称加密, 服务端将公钥发送给客户端 (此时发送的是证书, 证书客户端是需要校验的), 如果证书合法, 那么客户端使用伪随机数来生成一个会话密钥, 使用证书加密会话密钥并传输给服务端. 服务端使用私钥来解密得到会话密钥. 然后后面传输的数据使用此时两端都知道的会话密钥来加密数据.从这个简单流程, 应该我们只需要关心两条, 一个是证书, 一个是私钥.
使用
生成证书
1. 生成证书私钥: 此处生成的私钥用于提交给 CA 来生成证书认证签名文件.
openssl genrsa -out server.key 2048 用于生成密钥 Key, 执行这个命令后需要输入一个密码, 会基于这个密码来生成私钥.
genrsa 代表使用 RSA 来生成私钥, openssl rsa 代表从私钥中获取公钥.
可选的 - des3: 指定生成的密钥使用 des3 方式进行加密, 这样的话每次使用都需要输出密码来解密.
- out 文件路径: 用于指定生成的 key 的位置.
2048
是密钥的长度, 长度越长, 安全性越强, 一般推荐使用 2048.
2. 创建服务器证书的申请文件 server.csr.CSR 文件是您的公钥证书原始文件, 包含了您的服务器信息和您的单位信息, 需要提交给 CA 认证中心审核.
openssl req -new -key server.key -out server.csr
会提示输入几个内容:
如果你上面使用了 - des3 来生成证书私钥, 那么第一行会是要求你输入私钥的解密密码 server.key: 生成密钥时输入的密码
Country Name (2 letter code) [XX]
: 国家代码, 如 CN, 可以不填, 直接回车跳过即可.
State or Province Name (full name) []
: 省份名称, 可以不填, 直接回车跳过即可.
Locality Name (eg, city) [Default City]
: 城市名称, 可以不填, 直接回车跳过即可.
Organization Name (eg, company) [Default Company Ltd]
: 机构名称, 可以不填, 直接回车跳过即可.
Organizational Unit Name (eg, section) []
: 组织单位名称, 可以不填, 直接回车跳过即可.
Common Name (eg, your name or your server's hostname) []
: 使用 SSL 加密的域名. 注意这里要配成你的网站的域名, 不然在访问的时候会说 "这个证书不属于这个网站 (英文我忘记是什么了)", 如果你看到这样的错误的话, 你就应该知道是你的证书绑定错了域名. 比如可以输入 www.123.com.
Email Address []: 邮件地址, 可以省略
A challenge password []
: 有些认证机构需要这个密码, 一般为空
An optional company name []
: 可选的公司名称, 省略即可.
其实上面这个创建证书文件也就是自己用用而已, 正式的时候都会去证书机构中申请, 比如在阿里云或者腾讯云中申请一个免费的证书, 个人用的话申请一个免费的就可以了.[PS: 证书也是有区别的, 一些证书只会加密数据, 不能用于认证, 比如说有些网站访问的时候就会显示 XXX 公司, 其实这就是在证书中做了企业认证.]
3. 生成 CRT 证书认证文件:
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
* X509 用于自签名
* -req:x509 工具默认以证书文件做为 inputfile(-in file), 指定该选项将使得 input file 的 file 为证书请求文件.
* -days 30 用于设置证书的有效期
* -in: 用于指定 CSR 证书申请文件
* -signkey: 用于指定签名的私钥
* -out: 用于指定输出的 CRT 证书认证文件的路径.
4. 完成:
那么此时生成了一个. crt 文件和. key 文件.
配置 nginx
简单配置一个新的 server:
- server {
- server_name www.123.com;
- listen 443 ssl;
- ssl_certificate /etc/nginx/ssl_key/server.crt;
- ssl_certificate_key /etc/nginx/ssl_key/server.key;
- location / {
- root /usr/share/nginx/HTML;
- }
- }
ssl_certificate 用于配置服务端上 CA 证书的位置
ssl_certificate_key 用于配置服务端上 CA 私钥的位置
在旧版本中 ssl on 用来开启 ssl, 现在可以使用 listen 443 ssl 来代替.
更多配置可以自行参考
测试
为了尽量达到仿真, 所以我们手动配置一个 dns, 这样的话我们就相当于有一个虚假的域名了.
访问我们的虚假网站 www.123.com:
但由于我们是本地环境, 它始终会报错, 它还是会在浏览器中显示不安全, 但 https 是已经配置成功了的. 我们选择强行访问的话, 链接栏仍热会报红:
只是因为我们是自己生成证书, 导致证书颁发机构不可信而已, 如果我们是从网上申请的证书, 那么此时证书颁发机构应该是可信的.
补充
正规域名的 https 配置可以稍微参考阿里云 nginx 配置 https 文档
HttpRewrite 模块
if
if 在 nginx 文档中
if 属于 ngx_http_rewrite_module 模块.
if 可以做一些的判断, 根据条件来进行不同的处理, 可以使用在 server 和 location 中.
if 的使用场景:
场景一: 假如你想让没有携带指定 header 的请求返回 403 的话, 这样的请求判断需要借助 if.
场景二: 如果浏览器是 IE 浏览器, 返回指定数据
...
下面是一个例子, 就是如果浏览器是谷歌浏览器, 就返回 503.
- # 禁止 Chrome 访问: 如果 $http_user_agent` 如果包含 Chrome, 就禁止访问.
- if ($http_user_agent ~ Chrome) {
- return 503;
- }
if 的语法:
判断条件:
= 用于判断两个值是否相等, 例如
if ($request_method = POST)
!= 用于判断两个值是否不相等
~: 大小写敏感的正则匹配, 与后面的正则搭配使用, 例如:
if ($http_user_agent ~ MSIE)
代表 $http_user_agent 如果包含 MSIE, 就为 true.
~*: 对大小写不敏感的正则匹配, 与后面的正则搭配使用.
!~: 如果~ 结果为 true, 则!~ 为 false
!~*: 如果~* 结果为 true, 则!~* 为 false
-f: 如果文件存在, 为 true. 例如:
if (-f $request_filename)
!-f: 如果目录存在, 文件不存在, 为 ture; 目录和文件都不存在, 为 false. 例如:
if (!-f $request_filename)
-d: 如果请求的目录存在, 则为 true
!-d: 如果请求目录的上级目录存在, 目录不存在, 为 true; 如果上级目录和目录都不存在, 为 false.
if 可以使用变量来判断, 可用变量有全局变量和自定义变量.
下面是可以用作 if 判断的全局变量
全局变量
参数名 | 说明 |
---|---|
`$arg_PARAMETER | PARAMETER 是变量名,可以根据不同的 PARAMETER 获取请求行中的指定参数,也就是 URL 中的参数。 |
$args | URL 中的查询参数。,比如 https://www.baidu.com/baidu?wd=nginx&tn=monline_4_dg&ie=utf-8 中的 wd=nginx&tn=monline_4_dg&ie=utf-8 |
$binary_remote_addr | 二进制的客户端 IP 地址。 |
$content_type | 请求头中的 Content-Type 字段。 |
$cookie_COOKIE | 客户端 cookie 信息 |
$document_root | 当前请求在 root 指令中指定的值。 |
$document_uri | 包含请求参数的原始 URI |
$host | 请求头中的 Host 字段 |
$http_HEADER | HEADER 是一个变量,可以用于获取请求头中的参数值。 |
$http_user_agent | 客户端 agent 信息,客户端浏览器信息 |
$http_cookie | 客户端 cookie 信息 |
$is_args | 如果有 url 参数,则为?;无则为空。 |
$limit_rate | nginx 配置的 limit_conn 的数值。 |
$query_string | 与 $args 功能一致 |
$remote_addr | 客户端的 IP 地址 |
$remote_port | 客户端的端口 |
$request_filename | 当前请求的资源文件的路径名 |
$request_method | 请求的方法,GET、POST 之类的。 |
$request_uri | 包含请求参数的原始 URI,不包含主机名 |
$scheme | http 还是 https |
$server_addr | 服务端地址 |
$server_name | 服务端名称(域名) |
$server_port | 服务端接收请求的端口 |
$server_protocol | http 协议版本,1.0,1.1,HTTP/2? |
$uri | 与 $document_uri 相同 |
自定义变量:
除了使用全局变量来判断, 还可以自己通过 set $ 变量名 值设置变量, 例如:
- location / {
- root /usr/share/nginx/HTML;
- default_type text/HTML;
- set $flag "";
- if ($http_user_agent ~ Chrome) {
- set $flag "Chrome";
- }
- # 这里绕了一圈只是为了说明, 可以使用我们自己设置的变量
- if ($flag = 'Chrome') {
- return 200 "hello";
- }
- }
set 的值除了是一个字面值, 还可以是一个全局变量, 比如 set $web_agent "${http_user_agent}";.set 的使用应该是面向场景的, 所以这里只做个开头, 当你想要某个值来做判断的时候, 你可以自己去探究一下这个值该怎么设置.
重定向 rewrite
rewrite 属于 ngx_http_rewrite_module 模块.
rewrite 用于重写 url 和重定向, 一个比较常见的用途是, 比如用于 http 重定向 https, 你原本访问 http://example.com, 我帮你强制跳转到 https://example.com; 比如某文件位置迁移了, 访问旧的位置, 重写成迁移后的位置; 比如根据不同浏览器重定向到不同页面你是 IE 浏览器, 我就帮你转到一个特定的页面; 这就是 rewrite 干的活, 做一些重定向的活.
语法是: rewrite regex replacement [flag], 可以使用在 server, location, if 中.
regex 是正则, 注意传入的数据是 uri, 不包括域名, 只包含访问的资源路径.
replacement 是重定向的路径. 可以使用 ($1,$2) 来获取正则中的匹配结果或使用全局变量来拼接 URL.
flag 可以是以下几个:
last: 会内部重新发起一个重定向目录的请求, 可以匹配到 nginx 的 location.
beak: 匹配后, 会内部从 root 目录查找重定向的目录, 不会匹配 location.
redirect: 会返回 302 给浏览器, 让浏览器发起新的请求, 代表临时重定向, 浏览器不会缓存.
permanent: 会返回 301 给浏览器, 让浏览器发起新的请求, 代表永久重定向, 浏览器会进行缓存, 下次访问这个地址的时候, 浏览器直接重定向, 不需要访问 nginx 再重定向.
实验一: 测试 regex 匹配对象的是什么:
- server {
- listen 80;
- server_name 127.0.0.1;
- location / {
- rewrite (.*) http://192.168.48.129$1 redirect;
- }
- }
当访问 nginx 所在机器
192.168.31.128/aaa/bbb
的时候, 由于上面的规则是重定向到
http://192.168.48.129$1
, 所以得出结论, regex 对应的部分就是有 / 开头的 uri 部分.
实验二: 重定向到指定的页面:
- server {
- listen 80;
- server_name 127.0.0.1;
- location / {
- #只有匹配成功的时候才重定向, 访问 / rewrite/aaa 时重定向, 访问 / aaa 时不重定向
- rewrite ^/rewrite/(.*) http://192.168.48.129/$1 redirect;
- #访问 http://192.168.31.128/rewrite 时, 重定向到 http://192.168.48.129
- #访问 http://192.168.31.128/rewriteaaa, 重定向到 http://192.168.48.129
- #rewrite ^/rewrite http://192.168.48.129 redirect;
- #访问 http://192.168.31.128/rewrite, 内部重定向到 http://192.168.31.128/hello
- #root /usr/share/nginx/HTML;
- #rewrite ^/rewrite /hello last;
- #访问 http://192.168.31.128/rewrite, 返回 "root"+/hello.HTML 资源
- #root /usr/share/nginx/HTML;
- #rewrite ^/rewrite /hello.HTML break;
- }
- location /hello{
- default_type text/HTML;
- return 200 "hello";
- }
- }
实验三: 与 if 配合重定向, 假如浏览器是 IE 的, 跳转到指定页面:
- server {
- listen 80;
- server_name 127.0.0.1;
- location / {
- #访问 http://192.168.31.128/rewrite, 返回 "root"+/hello.HTML 资源
- root /usr/share/nginx/HTML;
- # 如果 http_user_agent 中包含了 Chrome, 那么就重定向
- if ($http_user_agent ~ Chrome) {
- rewrite ^(.*)$ /Chrome/$1 break;
- }
- rewrite ^/rewrite /hello.HTML break;
- }
- }
第三方模块
上面的例子中都是内置模块的内容, 但也稍微提了一下第三方模块, 比如在负载均衡中提到了 fair 和 url_hash. 对于需要使用第三方模块的, 还是建议使用编译安装的方式, 那样添加第三方模块比较方便.
前置知识 (编译安装)
1. 先到官网下载编译安装用的 tar 包, 或者 wget http://nginx.org/download/nginx-1.12.1.tar.gz[因为下面的演示的 echo 模块最高兼容 1.16, 所以这里安装 1.16]
2. 解压 tar 包: tar -zxvf nginx-1.12.1.tar.gz
3.cd nginx-1.12.1/
4../configure --prefix=/etc/nginx, 注意, 编译方式安装, 文件目录布局与 yum 安装方式的不太一样.
5.make && make install
6. 进入 / etc/nginx/sbin 目录下执行./nginx -v, 如果能够正常输出 nginx 版本, 那么就代表编译安装成功了.
--prefix 用于指定 nginx 编译后的安装目录
[docker 内部的 nginx 也是编译安装的, 如果你懂 docker, 那么你可以通过修改 docker 的 dockerfile 来添加第三方模块]
[如果你是覆盖安装的, 注意保存之前的配置信息.]
安装第三方模块
安装第三方模块需要我们重新编译安装, 所以下面的过程是以编译安装为基础的.
下面的安装模块我们以 echo 模块为例. echo 模块可以返回变量, 比如 echo $remote_addr; 代表把客户端的 IP 作为响应数据.
1. 从 GitHub 上下载 echo 模块的源代码: echo-nginx-module
或者直接在 nginx 所在的机器上 wget https://github.com/openresty/echo-nginx-module/archive/v0.61.tar.gz
2. 上传到 nginx 所在的机器上.
3. 解压第三方模块 echo 模块: tar -zxvf v0.61.tar.gz
4. 我们进入到之前的 nginx 源代码目录: cd nginx-1.12.1/
5. 重新编译安装:./configure --prefix=/etc/nginx --add-module=/root/temp/echo-nginx-module-0.61
6.make && make install
7. 进入 / etc/nginx/sbin 目录下执行./nginx -V, 如果能看到 configure arguments: --prefix=/etc/nginx --add-module=/root/temp/echo-nginx-module-0.61, 那么就代表编译安装成功了. 除了这样, 你还可以尝试在代码中添加 echo 指令来测试.
在还没安装之前: 如果你在代码中使用 echo 的话, 重启 nginx 会报如下的错误: ![20200629210011](https://progor.oss-cn-shenzhen.aliyuncs.com/img/20200629210011.png)
- nginx: [emerg] unknown directive "echo" in /etc/nginx/conf.d/default.conf:5
- nginx: configuration file /etc/nginx/nginx.conf test failed
那么如果我们安装了之后, 不报错, 并且访问 nginx 服务端之后, 返回的是客户端的 IP 地址的话, 那么就说明第三方模块安装成功了.
知识补充:
--add-module = 第三方模块源代码路径
用于添加第三方模块,
--add-module=/usr/local/nginx/third_module/echo-nginx-module-0.60
代表添加了 echo 模块.
--with - 模块名 表示启用的 nginx 模块, 如
--with-http_ssl_module
代表启用了 http_ssl_module 模块
没有讲到的内容
没有讲到的内容其实挺多的, 但上面的应该是常见的内容了, 学会了应该就够日常使用了, 后面有需要你自己去百度的时候应该就能看懂别人的配置了.
其他的内容由于优先级不是很高, 而且考虑篇幅问题, 所以这里没有讲解, 下面列举一下我觉得可能
nginx 还支持邮件服务, 但可能比较少用.
nginx 与 Keepalived 搭配的高可用.[其实挺重要, 大家可以自己搜索学习一下]
nginx 也支持 NFS(网络文件系统), 但有一些替代方案, 比如对于 Java 来说的话, 比较常见的是 FastDFS(也依托 nginx) 了.
网页压缩, 可以使用 GZIP 来进行网页压缩, 来减少传输的数据, 但压缩是需要系统去处理的, 所以可能需要消耗一些 CPU 资源. 自己有需求就去找找看吧.
nginx 与其他服务器的比较, 因为这篇文章重点不是这个, 所以不讲.
如果你关心文件传输方面的知识, 那么可以了解下 send_file 和 tcp_nopush 对于数据传输的处理.
sub_status 模块, 用来查看 nginx 自上次启动以来的工作状态. 包括处理的连接数, 请求数等.
geoip 可以用于地区识别, 比如基于 IP 判断用户的地区.
http_slice_module 模块可以用于大文件分片的处理.
如果你想拿来当面试谈资, 那么 IO 多路复用模型可以了解一下, nginx.conf 的 events 块中其实可以修改 nginx 对于请求处理的 IO 模型, 当问 nginx 为什么那么厉害的时候, IO 多路复用模型也可以谈一下.
我这篇文章讲了一些例如负载均衡的内容, 但这并不代表你不需要额外学习 nginx 的内容了, 因为我只是讲了普通情况, 如果你的业务复杂的话, 那么你最好仔细的看一下官方文档了.
请认清, 这只是一篇用于基础理论了解的文章而已.
来源: https://www.cnblogs.com/progor/p/13338485.html