Nginx管理(二)
一、Nginx虚拟主机
一个web服务器软件默认情况下只能发布一个web,因为一个web分享出去需要三个条件(IP、Port、Domain name)
Nginx虚拟主机实现一个web服务器软件发布多个web。
虚拟主机就是将一台物理服务器划分成多个“虚拟”的服务器,每个虚拟主机都可以有独立的域名和独立的目录。
现在很多公司出售的产品——“网站空间”,就是基于虚拟主机来卖的。价格和使用成本远远低于购买云服务器。
案例:同时发布两个网站
DocumentRoot /usr/local/nginx/html/web1
DocumentRoot /usr/local/nginx/html/web2
1、基于IP的虚拟主机
要测试基于IP的虚拟主机,必须要有两个IP的虚拟机、DocumentRoot存在、索引页index.html配置。
场景是:每个网站都需要一个IP。
缺点是:需要多个IP,如果是公网IP,每个IP都需要付费。
(1) 配置文件快速重置
在这里需要知道nginx.conf文件是有一个默认备份文件的:nginx.conf.default,使用它可以迅速完成配置重置。
$ pwd
/usr/local/nginx/conf
$ cp nginx.conf nginx.conf.bak
$ cp nginx.conf.default nginx.conf
# 仅保留有用的配置
sed -i "/#/d" nginx.conf # 有#的都删除
sed -i "/^$/d" nginx.conf # 有空行的都删除
(2)nginx.conf配置
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 192.168.31.42:80;
server_name localhost;
location / {
root html/web1;
index index.html index.htm;
}
}
server {
listen 192.168.31.52:80;
server_name localhost;
location / {
root html/web2;
index index.html index.htm;
}
}
}
(3)准备环境配置验证
两个IP、DocumentRoot存在、索引页index.html配置
# 两个ip除了创建虚机等方式外,还可以配置虚拟ip
$ ifconfig eno16777736:1 192.168.31.52/24 up
# 创建DR目录
$ mkdir /usr/local/nginx/html/web1
$ mkdir /usr/local/nginx/html/web2
# 索引页配置
$ echo web01 > /usr/local/nginx/html/web1/index.html
$ echo web02 > /usr/local/nginx/html/web2/index.html
# 启动nginx并查看端口
$ /usr/local/nginx/sbin/nginx
$ netstat -ntpl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1317/master
tcp 0 0 192.168.31.52:80 0.0.0.0:* LISTEN 12422/nginx: master
tcp 0 0 192.168.31.42:80 0.0.0.0:* LISTEN 12422/nginx: master
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1095/sshd
tcp6 0 0 ::1:25 :::* LISTEN 1317/master
tcp6 0 0 :::22 :::* LISTEN 1095/sshd
# 访问验证
$ elinks http://192.168.31.42 --dump
web01
$ elinks http://192.168.31.52 --dump
web02
# 关闭子网卡方法
$ ifconfig eno16777736:1 down
2、基于端口的虚拟主机
基于端口的虚拟主机只需要一个IP,但只适合内部用户,端口变化内部通知即可。(各种不良网站会需要改变IP和端口来逃避封锁)
缺点:端口无法告诉公网用户,无法适用于公网用户。
(1)nginx.conf配置
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
#server_name localhost;
location / {
root html/web1;
index index.html index.htm;
}
}
server {
listen 8080;
#server_name localhost;
location / {
root html/web2;
index index.html index.htm;
}
}
}
(2)测试验证
$ /usr/local/nginx/sbin/nginx -g nginx.conf # 验证前面修改的nginx配置
nginx: [emerg] unexpected end of parameter, expecting ";" in command line
$ killall nginx
$ /usr/local/nginx/sbin/nginx # 启动服务
$ netstat -ntpl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1317/master
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 12543/nginx: master
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 12543/nginx: master
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1095/sshd
tcp6 0 0 ::1:25 :::* LISTEN 1317/master
tcp6 0 0 :::22 :::* LISTEN 1095/sshd
$ elinks http://192.168.31.42 --dump # 未加端口默认是80端口
web01
$ elinks http://192.168.31.42:8080 --dump
web02
3、基于域名的虚拟主机
一个网站必然有一个域名,可以ip和端口相同,但域名不同。基于域名的虚拟主机主要用来处理线上问题。
基于域名的虚拟主机,完美解决了基于IP和基于端口虚拟主机的问题。
(1)配置/etc/hosts和nginx.cnnf
# /etc/hosts
...... 原始的保留
192.168.31.42 www.abc.com
192.168.31.42 www.cbd.com
# nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name www.abc.com;
location / {
root html/web1;
index index.html index.htm;
}
}
server {
listen 80;
server_name www.cbd.com;
location / {
root html/web2;
index index.html index.htm;
}
}
}
(2)测试验证
$ /usr/local/nginx/sbin/nginx -g nginx.conf
$ killall nginx
$ /usr/local/nginx/sbin/nginx
$ netstat -ntpl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1317/master
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 12676/nginx: master
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1095/sshd
tcp6 0 0 ::1:25 :::* LISTEN 1317/master
tcp6 0 0 :::22 :::* LISTEN 1095/sshd
$ elinks http://www.abc.com -dump
web01
$ elinks http://www.cbd.com -dump
web02
二、反向代理
- 正向代理:
正向代理是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端必须要进行一些特别的设置才能使用正向代理。
正向代理的用途:访问原本无法访问的资源、做缓存加速访问资源、对客户端访问授权上网认证、代理可以记录用户访问记录(上网行为管理。)。 - 反向代理(Reverse Proxy):
代理服务器,客户机在发送请求时,不会直接发送给目的主机,而是先发送给代理服务器,代理服务接受客户机请求之后,再向主机发出,并接收目的主机返回的数据,存放在代理服务器的硬盘中,再发送给客户机中。此时代理服务器对外就表现为一个服务器。
反向代理的作用:保证内网的安全,可以使用反向代理提供WAF功能,阻止web攻击;负载均衡,通过反向代理来优化网站的负载。
反向代理图示如下:
1、反向代理应用场景
(1)堡垒机场景
业务服务器安全配置只接受来自源IP为堡垒机的链接访问,其他的都拒绝。黑客攻击的只是一台暴露在外网的反向代理服务器,服务器上其实什么都没有,不用担心数据丢失。
(2)内网服务器发布场景
适用于公网IP地址不足的场景。
在业务服务器前面做一个反向代理服务器,以虚拟主机的方式配置三个虚拟机主机,并配置三个代理。访问不同的虚拟主机找不同的业务服务器获取数据,再将数据提供给用户。
(3)缓存场景
常见缓存场景应用:CDN。
网站具有动态、静态两种数据。自行配置缓存服务器时,在缓存服务器上保存静态数据。客户访问时,缓存服务器将静态数据发给客户端。动态数据则是由缓存服务器向业务服务器发送请求获取后发给客户端。往往静态页面还在渲染,动态数据已经获取并逐渐加载。
好处是:加载速度较快,用户体验提升;降低业务服务器压力。
2、反向代理原理
1)客户端通过浏览器发起请求,请求发送给代理服务器;
2)代理服务器接收请求;
3)代理服务器发送请求给业务服务器;
4)业务服务器接受请求、处理请求;
5)业务服务器发送响应请求把数据交给代理服务器;
6)代理服务器再发送响应请求将数据交给客户端;
7)客户端通过浏览器将数据渲染出来并展示给用户。
3、反向代理实现
client用mac电脑代替,反向代理用之前的Nginx,业务机器用book.ayitula.com(http://118.190.209.153:4000)。期望实现在mac上访问http://192.168.31.42访问到该服务页面。
(1)备份重启操作
$ cp nginx.conf nginx.conf.bak_2
$ cp nginx.conf.default nginx.conf
$ killall nginx
$ /usr/local/nginx/sbin/nginx
(2)nginx.conf配置修改内容
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
# root html; # 这个机器不再是web服务器,而是反向代理,因此没用了
proxy_pass http://118.190.209.153:4000; # 请求转向指定地址
index index.html index.htm;
}
(3)反向代理效果
4、反向代理优化参数(性能优化)
location / {
index index.php index.html index.htm; #定义首页索引文件的名称
proxy_pass http://mysvr ; #请求转向mysvr 定义的服务器列表
# 设置请求头——给请求头加字段
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; # 告诉业务服务器是代替哪个客户来拿数据
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 常用缓存和超时的设置
client_max_body_size 10m; # 允许客户端请求的最大单文件字节数
client_body_buffer_size 128k; # 缓冲区代理缓冲用户端请求的最大字节数,
proxy_connect_timeout 90; # nginx跟后端服务器连接超时时间(代理连接超时)
proxy_send_timeout 90; # 后端服务器数据回传时间(代理发送超时)
proxy_read_timeout 90; # 连接成功后,后端服务器响应时间(代理接收超时)
proxy_buffer_size 4k; # 设置代理服务器(nginx)保存用户头信息的缓冲区大小
proxy_buffers 4 32k; # proxy_buffers缓冲区,网页平均在32k以下的话,这样的设置
proxy_busy_buffers_size 64k; # 高负荷下缓冲大小(proxy_buffers*2)
proxy_temp_file_write_size 64k; # 设定缓存文件夹大小,大于这个值,将从upstream服务器传
}
三、Nginx限速
限流(rate limiting)是NGINX众多特性中最有用的,也是经常容易被误解和错误配置的特性之一。
限速该特性可以限制某个用户在一个给定时间段内能够产生的HTTP请求数。请求可以简单到就是一个对于主页的GET请求或者一个登陆表格的POST请求。
限流也可以用于安全目的上,比如减慢暴力密码破解攻击。通过限制进来的请求速率,并且(结合日志)标记出目标URLs来帮助防范DDoS攻击。一般地说,限流是用在保护上游应用服务器不被在同一时刻的大量用户请求湮没。另外还可以保护磁盘IO。
1、应用场景
- DDOS防御
DDOS的特点是分布式,针对带宽和服务攻击,也就是四层流量攻击和七层应用攻击,相应的防御瓶颈四层在带宽,七层的多在架构的吞吐量。对于七层的应用攻击,我们还是可以做一些配置来防御的,例如前端是 Nginx,主要使用nginx的http_limit_conn和http_limit_req模块来防御。 ngx_http_limit_conn_module 可以限制单个IP的连接数,ngx_http_limit_req_module 可以限制单个IP每秒请求数,通过限制连接数和请求数能相对有效的防御CC攻击。 - 下载场景保护IO
很多人一起下载,硬盘IO负荷过高,硬盘会扛不住,导致硬盘故障或服务器宕机。
2、限速原理(漏桶原理)
算法思想是:
水(请求)从上方倒入水桶,从水桶下方流出(被处理);
来不及流出的水存在水桶中(缓冲),以固定速率流出;
水桶满后水溢出(丢弃)。
这个算法的核心是:缓存请求、匀速处理、多余的请求直接丢弃。
相比漏桶算法,令牌桶算法不同之处在于它不但有一只“桶”,还有个队列,这个桶是用来存放令牌的,队列才是用来存放请求的。
3、实现方式
Nginx官方版本限制IP的连接和并发分别有两个模块:
- limit_req_zone 用来限制单位时间内的请求数,即速率限制,采用的漏桶算法 "leaky bucket"。
- limit_req_conn 用来限制同一时间连接数,即并发限制。
(1)limit_req_zone参数配置:
Syntax: limit_req zone=name [burst=number] [nodelay]; Default: —
Context: http, server, location
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
(2)基于请求数限速案例
基于IP对下载速率做限制,限制每秒处理1次请求,对突发超过5个以后的请求放 入缓存区
http {
limit_req_zone $binary_remote_addr zone=baism:10m rate=1r/s;
server {
location /abc {
limit_req zone=baism burst=5 nodelay;
}
}
}
1)limit_req_zone $binary_remote_addr zone=baism:10m rate=1r/s; 设置缓存区(设置一个漏桶)
- 第一个参数:$binary_remote_addr 表示通过remote_addr这个标识来做限制, “binary_”的目的是缩写内存占用量,是限制同一客户端ip地址。
- 第二个参数:zone=baism:10m表示生成一个大小为10M,名字为one的内存区域, 用来存储访问的频次信息。
- 第三个参数:rate=1r/s表示允许相同标识的客户端的访问频次,这里限制的是每秒 1次,还可以有比如30r/m的。
2)limit_req zone=baism burst=5 nodelay; 应用缓存区
- 第一个参数:zone=baism 设置使用哪个配置区域来做限制,与上面 limit_req_zone 里的name对应。
- 第二个参数:burst=5,重点说明一下这个配置,burst爆发的意思,这个配置的意 思是设置一个大小为5的缓冲区当有大量请求(爆发)过来时,超过了访问频次限 制的请求可以先放到这个缓冲区内。
- 第三个参数:nodelay,如果设置,超过访问频次而且缓冲区也满了的时候就会直 接返回503,如果没有设置,则所有请求会等待排队。
(3)基于连接数、下载做限速
http {
#基于IP做连接限制 限制同一IP并发为1 下载速度为100K
limit_conn_zone $binary_remote_addr zone=addr:10m;
#基于IP对下载速率做限制 限制每秒处理1次请求,对突发超过5个以后的请求放 入缓存区
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
location /abc {
limit_req zone=one burst=5 nodelay;
limit_conn addr 1; # 并发限制,同一时间能下几个资源
limit_rate 100k; # 下载最高速率限制
#limit_rate_after 250m; # 下载到250M限速(不太常用)
}
}
}
(4)测试验证
# 案例一:请求数限速
$ elinks http://192.168.31.42 -dump # 连续发起5次,第五次将得到404页面,返回页面也可以自行定义
# 案例二:下载限速
#在服务器端生成一个300M的文件
$ dd if=/dev/zero of=../html/abc/bigfile bs=1M count=300
#从mac上访问下载
$ wget http://192.168.31.42/abc/bigfile
#启动下载限速最高100kB/s
limit_rate 100k;
#启动同时连接数限制,最多一个
limit_conn addr 1;
四、URL重写(URL rewrite)
URL重写是基于ngx_http_rewrite_module这个rewrite模块。
Rewrite功能是Nginx服务器提供的一个重要功能,也几乎是所有web产品必备技能,用于实现URL重写。
URL重写是非常有用的功能,比如它可以在我们改变网站结构后,不需要客户端修改原来的书签,也不需要其他网站修改对我们网站的友情链接,还可以在一定程度上提高网站的安全性,能够让我们的网站显得更加专业。
Nginx服务器Rewrite功能的实现是依赖于PCRE(Perl Compatible Regular Expression,Perl兼容的正则表达式)的支持,所以在编译安装Nginx之前,需要安装PCRE库。
1、应用场景
- 域名变更
比如:京东之前的老域名是www.360buy.com,但是现在访问这个域名,它会自动跳到www.jd.com。 - 用户跳转
比如老链接不用了,但是要引导客户去访问新链接,可以从老链接跳到新链接。用户不会因为链接修改而无法访问。 - 伪静态场景
CDN只能缓存静态页面数据,但是如果能缓存动态数据会更完美好用,将动态页面做成静态页面,变成一个伪静态,便于CDN缓存动态页面数据。
2、URL重写原理
上述图片过程:用户通过浏览器向nginx发起请求,nginx接收请求后,url重写将新的url告诉用户浏览器,用户浏览器再用新的url去访问业务服务器,业务服务器将数据发给用户浏览器。
3、URL模块语法
(1)常用关键字(指令)
(1) set:设置变量
(2) if:负责语句中的判断
(3) return:返回返回值或URL
(4) break:终止后续的rewrite规则
(5) rewrite:重定向URL
(2)常用正则匹配:
模糊匹配:~匹配 !~不匹配 ~* 不区分大小写的匹配
精确匹配:=匹配 !=不匹配
(3)URL rewrite指令语法
rewrite <regex> <replacement> [flag];
关键字 正则 替代内容 flag标记
常用flag:
last —— 本条规则匹配完成后,继续向下匹配新的location URL规则
break —— 本条规则匹配完成即终止,不再匹配后面的任何规则
redirect —— 返回302临时重定向,浏览器地址会显示跳转后的URL地址
permanent —— 返回301永久重定向,浏览器地址栏会显示跳转后的URL地址
4、Rewrite规则相关指令
示例:将http://www.ayitula.com重写为http://www.ayitula.com/baism
(1)set指令——自定义变量
语法:set $variable value;
作用域:server,location,if
location / {
#root html;
#index index.html index.htm;
set $name baism;
rewrite ^(.*)$ http://www.ayitula.com/$name; # 调用了变量$name
}
(2)if指令——负责判断
语法:if (condition) {......}
作用域:server和location。
location / {
root html;
index index.html index.htm;
if ($http_user_agent ~* 'Chrome') { # 不区分大小写匹配chrome
return 403; # 如果浏览器是chrome,直接返回403
#return http://www.jd.com;
}
}
需要注意:$http_user_agent是Nginx内部变量。
(3)return指令——定义返回数据
语法:
return code [text]; # 返回代码和文本
return code URL;
return URL; # 返回url
作用域:server,location,if
(4)break指令——停止执行当前虚拟主机后续rewrite指令集
语法:break;
作用域:server,location,if
location / {
root html;
index index.html index.htm;
if ($http_user_agent ~* 'Chrome') {
break;
return 403;
}
}
break代表本条规则匹配完成即终止,不再匹配后面的任何规则。
server {
listen 80;
server_name www.ayitula.com;
location / {
rewrite ^/$ http://www.jd.com break;
# rewrite ^/$ http://www.jd.com redirect; # redirect:临时重定向
}
}
直接将重写的域名发给客户端后结束。类似临时重定向效果,返回客户端302。
(5)rewrite指令
域名跳转:www.ayitula.com 重写为 www.jd.com
server {
listen 80;
server_name www.ayitula.com;
location / {
rewrite ^/$ http://www.jd.com permanent; # ^/$ 指定根目录 permanent:永久重定向
# rewrite ^/$ http://www.jd.com redirect; # redirect:临时重定向
}
}
Nginx配置完后,还需要配置/etc/hosts,将域名解析到本地nginx服务器地址:
192.168.31.42 www.ayitula.com
注意:
- 重定向就是将网页自动转向重定向。
- 301永久性重定向:新网址完全继承旧网址,旧网址的排名等完全清零。301重定向是网页更改地址后对搜索引擎友好的最好方法,只要不是暂时搬移 的情况,都建议使用301来做转址。
- 302临时性重定向:对旧网址没有影响,但新网址不会有排名。
- 搜索引擎会抓取新的内容而保留旧的网址。(重定向主要影响在搜索引擎、推广)
(6)last指令
last指令在url重写后,并不会结束而是马上发起一个新的请求,再次进入server块,重试location匹配,超过十次匹配不到报500错误,地址栏url不变。
示例:根据用户浏览器重写访问目录
如果是chrome浏览器 就将 http://192.168.10.42/\(URI 重写为 http://http://192.168.10.42/chrome/\)URI
实现步骤:1)URL重写;2)请求转给本机location。
location / {
.....
if ($http_user_agent ~* 'chrome'){
rewrite ^(.*)$ /chrome/$1 last; # 第一步重写url
}
location /chrome { # 第二步用新的url(http://192.168.31.42/chorm/$uri)来匹配规则
root html ;
index index.html;
}
}
注意正则使用:
- "^" 以什么开头 ^a
- "\(" 以什么结尾 c\)
- "." 除了回车以外的任意一个字符
- "*" 前面的字符可以出现多次或者不出现 #更多内容看正则表达式 re