地址

视频__Nginx应用指南

  1. Nginx优秀特性
  2. Nginx配置⽂件
  3. Nginx⽇志配置
  4. Nginx状态监控
  5. Nginx下载站点
  6. Nginx访问限制
  7. Nginx访问控制
  8. Nginx虚拟主机

Nginx特性

Nginx基于IO多路复用

Nginx基于IO多路复用 , 解决的是并发性的问题,Socket作为复用,

1575217815292

串行,产⽣阻塞

1575217920909

多线程, 消耗大

1575217958119

IO多路复用(主动上报)

1575217987588

  • 多个描述符的I/O操作都能在一个线程内并发交替地顺序完成,这就叫I/O多路复用
  • 复用指的是复用同一个线程。
  • 在同一个线程里面, 通过拨开关的方式,来同时传输多个I/O流,
  • ngnix会有很多链接进来, epoll会把他们都监视起来,然后像拨开关一样,谁有数据就拨向谁,然后调用相应的代码处理

img

CUP亲和

将CPU核⼼和Nginx⼯作进程绑定⽅式,把每个worker进程固定在一个cpu上执⾏,减少切换cpu的 cache miss ,获得更好的性能。

1575265844729

文件传输

传统文件传输, 在实现上其实是比较复杂的, 其具体流程细节如下:

1575266017213

  1. 调用read函数,文件数据被复制到内核缓冲

  2. read函数返回,文件数据从内核缓冲区复制到用户缓冲区

  3. write函数调用,将文件数据从用户缓冲区复制到内核与socket相关的缓冲区。

  4. 数据从socket缓冲区复制到相关协议引擎。

传统文件传输数据实际上是经过了四次复制操作:

硬盘—>内核buf—>用户buf—>socket缓冲区(内核)—>协议引擎

也就是说传统的文件传输需要经过多次上下文的切换才能完成拷贝或读取, 效率不⾼。

sendfile文件传输是在内核中操作完成的, 函数直接在两个文件描述符之间传递数据, 从而避免了
内核缓冲区数据和用户缓冲区数据之间的拷⻉, 操作效率很高, 被称之为零拷贝

1.系统调用sendfile函数通过 DMA 把硬盘数据拷⻉到 kernel buffer,
2.数据被 kernel 直接拷贝到另外一个与 socket 相关的 kernel buffer。
3.DMA把数据从kernel buffer直接拷贝给协议栈。

1575266199876

这⾥没有用户空间和内核空间之间的切换,在内核中直接完成了从一个buffer到另一个buffer的拷贝。

Nginx配置

  1. server 用于对不同的域名做不同的配置
  2. Location 用于对不同的路径做不同的配置

这就是为什么 HTTP层下允许有不同的server , server下允许有不同的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
//nginx默认配置语法
user //设置nginx服务的系统使用用户
worker_processes //⼯作进程,配置和CPU个数保持一致
error_log //错误⽇志, 后面接入的是路径
pid //Nginx服务启动时的pid

//events事件模块
events {
worker_connections //每个worker进程⽀持的最大连接数
use epoll //内核模型,可以是select,poll,epoll
}

//⾮虚拟主机的配置或公共配置定义在http{}段内, server{}段外
http {
...
//必须使用虚拟机配置站点, 每个虚拟机使用一个server{}段
'server' {
listen 80; //监听端⼝, 默认80
server_name localhost; //提供服务的域名或主机名

//控制网站访问路径
'location' / {
root /usr/share/nginx/html; //存放⽹站路径
index index.html index.htm; //默认访问⾸⻚文件
}

//指定错误代码,统一定义错误页面,错误代码重定向到新的Locaiton
error_page 500 502 503 504 /50x.html;
'location' = /50x.html {
root html;
}
}
...
//第⼆个虚拟主机配置
'server'{
...
}
}

测试配置 : nginx -t

Nginx字符编码

1
charset utf-8,gbk;

用于server或者http

注意 : charset utf-8,gbk;charset gbk,utf-8;是不一样的

Nginx日志配置

1
2
//Nginx默认配置
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"';

Nginx日志变量

  1. $remote_addr //表示客户端地址
  2. $remote_user //http客户端请求nginx认证用户名
  3. $time_local //Nginx的时间
  4. $request //Request请求⾏, GET等⽅法、http协议版本
  5. $status //respoence返回状态码
  6. $body_bytes_sent //从服务端响应给客户端body信息⼤⼩
  7. $http_referer //http上一级⻚⾯, 防盗链、用户⾏为分析
  8. $http_user_agent //http头部信息, 客户端访问设备
  9. $http_x_forwarded_for //http请求携带的http信息

Nginx状态监控

--with-http_stub_status_module 记录 Nginx 客户端基本访问状态信息

1
2
3
Syntax:	stub_status;
Default: —
Context: server, location
1
2
3
4
location /mystatus	{
stub_status on;
access_log off;
}
1
2
3
4
Active	connections:2
server accepts handled requests
16 16 19
Reading:0 Writing:1 Waiting:18
  1. Active connections:2 Nginx当前活跃连接数

  2. server表示Nginx处理接收握手总次数。

  3. accepts表示Nginx处理接收总连接数。

    请求丢失数=(握⼿数-连接数)可以看出,本次状态显示没有丢失请求。

  4. handled requests,表示总共处理了19次请求。

  5. Reading : Nginx读取数据 , Nginx读取到客户端的 Header信息数

  6. Writing : Nginx写的情况 , Nginx返回给客户端的 Header信息数。

  7. Waiting : Nginx开启keep-alive⻓连接情况下,既没有读也没有写,建⽴连接情况

Nginx下载站点

1
2
3
4
Syntax:	autoindex   on|off;
Default:
autoindex off;
Context: http,server,location

autoindex常用参数

  1. autoindex_exact_size off;
    默认为on, 显示出文件的确切大小,单位是bytes。
    修改为off,显示出文件的大概大小,单位是kB或者MB或者GB。
  2. autoindex_localtime on;
    默认为off,显示的文件时间为GMT时间。
    修改为on, 显示的文件时间为文件的服务器时间。
  3. charset utf-8,gbk;
    默认中文⽬录乱码,添加上解决乱码。

eg

1
2
3
4
5
6
7
//开启⽬录浏览
location / {
root html;
autoindex on;
autoindex_localtime on;
autoindex_exact_size off;
}

Nginx访问限制

  • 连接频率限制 limit_conn_module
  • 请求频率限制 limit_req_module

HTTP是建⽴在TCP, 在完成HTTP请求需要先建⽴TCP三次握⼿(称为TCP连接),在连接的基础
上在HTTP请求。

1575467434021

Nginx连接限制配置

limit_conn_zone必须自HTTP块中

1
2
3
4
5
6
7
//Nginx连接限制语法
Syntax: limit_conn_zone key zone=name:size;
Default: —
Context: http
Syntax: limit_conn zone number;
Default: —
Context: http, server, location

具体配置如下:

1
2
3
4
5
6
7
8
9
10
http	{
# http段配置连接限制, 同一时刻只允许一个客户端IP连接
limit_conn_zone $binary_remote_addr zone=conn_zone:10m;
...
server {
...
location / {
# 同一时刻只允许一个客户端IP连接
limit_conn conn_zone 1;
}
1
2
3
//压⼒测试
yum install -y httpd-tools
ab -n 50 -c 20 http://127.0.0.1/index.html

Nginx请求限制配置

1
2
3
4
5
6
7
# Nginx请求限制语法
Syntax: limit_req_zone key zone=name:size rate=rate;
Default: —
Context: http
Syntax: limit_conn zone number [burst=number] [nodelay];
Default: —
Context: http, server, location

具体配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
http	{
# http段配置请求限制, rate限制速率,限制一秒钟最多一个IP请求
limit_req_zone $binary_remote_addr zone=req_zone:10m rate=1r/s;
...
server {
...
location / {
# 1r/s只接收一个请求,其余请求拒绝处理并返回错误码给客户端
limit_req zone=req_zone;
# 请求超过1r/s,剩下的将被延迟处理,请求数超过burst定义的数量, 多余的请求返回503
#limit_req zone=req_zone burst=3 nodelay;
}

压⼒测试

1
2
yum	install	-y	httpd-tools
ab -n 50 -c 20 http://127.0.0.1/index.html

连接限制没有请求限制有效

  • 多个请求可以建立在一次的TCP连接之上, 那么我们对请求的精度限制,当然比对一个连接的限制会更加的有效。
  • 因为同一时刻只允许一个连接请求进入。但是同一时刻多个请求可以通过一个连接进入。所以请求限制才是比较优的解决⽅案。

Nginx访问控制

  • 基于IP的访问控制 http_access_module
  • 基于⽤户登陆认证 http_auth_basic_module

基于IP的访问控制

1
2
3
4
5
6
7
8
# 允许配置语法
Syntax: allow address | CIDR | unix: | all;
Default: —
Context: http, server, location, limit_except
# 拒绝配置语法
Syntax: deny address | CIDR | unix: | all;
Default: —
Context: http, server, location, limit_except
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 配置拒绝某⼀个IP, 其他全部允许
location ~ ^/1.html {
root /usr/share/nginx/html;
index index.html;
deny 192.168.56.1;
allow all;
}
# 只允许某⼀个⽹段访问,其它全部拒绝
location / {
root html;
index index.php index.html index.htm;
allow 192.168.56.0/24;
deny all;
}

注意 : 先允许 , 后拒绝

1
2
3
4
5
location / {
root html;
deny all;
allow 192.168.56.0/24;
}
  • 上面的配置 , 谁都拿不到 , 因为deny all;已经拒绝所有人了 , 下面的allow不起作用
  • 读配置文件的时候都是从上往下读的,读到deny就结束了
  • 所以必须调换deny和allow的位置

对于一些私有的路径 , 可以写成

1
2
3
4
location /secret_route {
allow 127.0.0.1;
deny all;
}

比如 , 对于Django , 就可以设置

1
2
3
4
location /admin {
allow 127.0.0.1;
deny all;
}

这样 , 就只允许127自己访问

http_access_module局限性

1575470270401

下图是使⽤ http_x_forwarded_for 记录真实客户端IP地址以及代理服务器IP

1575470342908

解决⽅式

  1. 采⽤HTTP头信息控制访问, 代理以及web服务开启 http_x_forwarded_for
  2. 结合geo模块作
  3. 通过HTTP⾃动以变量传递

基于⽤户登陆认证

1
2
3
4
5
6
7
8
# 配置语法
Syntax: auth_basic string | off;
Default: auth_basic off;
Context: http, server, location, limit_except
# ⽤户密码记录配置⽂件
Syntax: auth_basic_user_file file;
Default: -
Context: http, server, location, limit_except

⽤户登陆认证需要安装依赖

1
2
3
4
5
yum install httpd-tools
# 生成允许的用户何应良,该文件存储为/etc/nginx/auth_conf (-c是create)
htpasswd -c /etc/nginx/auth_conf heyingliang
# 追加用户user , 密码是password (-b是追加)
htpasswd -b /etc/nginx/auth_conf user password

可在http,server,location下添加如下信息

1
2
3
4
5
# 目录/下的文件必须用户登录后才能访问
location / {
auth_basic "Please enter your Username!";
auth_basic_user_file /etc/nginx/auth_conf;
}

⽤户认证局限性

  1. ⽤户信息依赖⽂件⽅式
  2. ⽤户管理⽂件过多, ⽆法联动
  3. 操作管理机械,效率低下

解决办法

  1. Nginx 结合 LUA 实现⾼效验证
  2. Nginx 结合 LDAP 利⽤ nginx-auth-ldap 模块

Nginx虚拟主机

  • 所谓虚拟主机,在web服务器⾥是⼀个独⽴的⽹站站点,这个站点对应独⽴的域名(也可能是IP或端⼝),具有独⽴的程序及资源⽬录,可以独⽴地对外提供服务供⽤户访问。
  • 虚拟主机功能: 一个nginx下运行多个网址(站点域名) ,
  • 虚拟主机就是在同一个Nginx服务器上运行多个网站

方式一:基于不同域名

nginx.conf中的http{}中的每一个server{}就是一个站点(相同端口)

  • 可多个网站通过不同的域名进行访问。
  • 原理是 : 监听相同端口通过域名分发到不同的服务器
  • 在服务器端首先会判断来访的域名(a.com或者b.com);由对应的虚拟主机处理后将请求转发到不同的server;
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
#虚拟主机1 
server {
listen 80;
server_name a.com;
location / {
#deny 192.168.160.0/24;
root /opt/nginxtest/html;
index index.html index.htm;
}
location /pic {
alias /opt/nginxtest/pic;
}
location /status{
stub_status on;
}
  error_page 404 /404.html;
}

#虚拟主机2
server {
listen 80;
server_name b.com;
location / {
root /opt/nginxtest/html2;
index index.html;
}
}

同一默认端口:需要客户端修改hosts文件

1
2
3
# C:\Windows\System32\drivers\etc\hosts
192.168.160.132 www.nginx1.com
192.168.160.132 www.nginx2.com

访问时直接输入域名,默认80

方式二:基于不同端口

nginx.conf中的http{}中的每一个server{}就是一个站点(不同端口指定访问)

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
#虚拟主机1
server {
listen 80;
server_name www.nginx1.com;
location / {
#deny 192.168.160.0/24;
root /opt/nginxtest/html;
index index.html index.htm;
}
location /pic {
alias /opt/nginxtest/pic;
}
location /status{
stub_status on;
}
error_page 404 /404.html;
}

#虚拟主机2
server {
listen 81;
server_name www.nginx1.com;
location / {
root /opt/nginxtest/html2;
index index.html;
}
}

不同端口:需要客户端修改hosts文件

1
2
192.168.160.132 www.nginx1.com:80
192.168.160.132 www.nginx1.com:81

访问时输入域名并指定端口

注意 : 相同的域名,相同的端口,谁的文件名在前,谁会被优先读取

配置虚拟主机别名

1
2
3
4
5
6
7
8
9
10
11
# 默认配置
server {
listen 80;
server_name www.xuliangwei.com;
}

# 别名配置
server {
listen 80;
server_name www.xuliangwei.com xuliangwei.com;
}