Nginx学习笔记

前言

Nginx版本:

一、安装Nginx原生版本

1.1、手动安装

  1. 下载Nginx: wget http://nginx.org/download/nginx-1.22.0.tar.gz
  2. 解压:tar -zxvf nginx-1.22.0.tar.gz
  3. 进入解压目录:cd nginx-1.22.0.tar.gz
  4. 运行configure文件执行安装
1
2
3
4
5
6
7
8
9
10
11
12
13
root@Test-Learn:~/learn/nginx-1.22.0# tree -L 1
.
├── CHANGES
├── CHANGES.ru
├── LICENSE
├── README
├── auto
├── conf
├── configure
├── contrib
├── html
├── man
└── src

错误参考:[[手动安装Nginx报错]]

注:指定安装位置

1
./configure --prefix=/usr/local/nginx
  1. 配置成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Configuration summary
+ using system PCRE library
+ OpenSSL library is not used
+ using system zlib library

nginx path prefix: "/usr/local/nginx"
nginx binary file: "/usr/local/nginx/sbin/nginx"
nginx modules path: "/usr/local/nginx/modules"
nginx configuration prefix: "/usr/local/nginx/conf"
nginx configuration file: "/usr/local/nginx/conf/nginx.conf"
nginx pid file: "/usr/local/nginx/logs/nginx.pid"
nginx error log file: "/usr/local/nginx/logs/error.log"
nginx http access log file: "/usr/local/nginx/logs/access.log"
nginx http client request body temporary files: "client_body_temp"
nginx http proxy temporary files: "proxy_temp"
nginx http fastcgi temporary files: "fastcgi_temp"
nginx http uwsgi temporary files: "uwsgi_temp"
nginx http scgi temporary files: "scgi_temp"

  1. 编译安装:
    • make
    • make install
1
2
3
4
5
6
7
8
9
10
11
12
13
14
make结果:
sed -e "s|%%PREFIX%%|/usr/local/nginx|" \
-e "s|%%PID_PATH%%|/usr/local/nginx/logs/nginx.pid|" \
-e "s|%%CONF_PATH%%|/usr/local/nginx/conf/nginx.conf|" \
-e "s|%%ERROR_LOG_PATH%%|/usr/local/nginx/logs/error.log|" \
< man/nginx.8 > objs/nginx.8
make[1]: Leaving directory '/root/learn/nginx-1.22.0'

make install 结果:
....
test -d '/usr/local/nginx/logs' \
|| mkdir -p '/usr/local/nginx/logs'
make[1]: Leaving directory '/root/learn/nginx-1.22.0'

  1. 检查是否安装到安装目录:cd /usr/local/nginx
1
2
3
4
5
6
7
8
9
root@Test-Learn:~/learn/nginx-1.22.0# cd /usr/local/nginx
root@Test-Learn:/usr/local/nginx# ll
total 24
drwxr-xr-x 6 root root 4096 Sep 23 00:16 ./
drwxr-xr-x 11 root root 4096 Sep 23 00:16 ../
drwxr-xr-x 2 root root 4096 Sep 23 00:16 conf/
drwxr-xr-x 2 root root 4096 Sep 23 00:16 html/
drwxr-xr-x 2 root root 4096 Sep 23 00:16 logs/
drwxr-xr-x 2 root root 4096 Sep 23 00:16 sbin/
  1. 启动目录:/usr/local/nginx/sbin/nginx

  2. 关闭防火墙

    • 查看防火墙状态: ufw status
    • 关闭防火墙:ufw disable
      1
      2
      root@Test-Learn:/usr/local/nginx/sbin# ufw disable
      Firewall stopped and disabled on system startup
  3. 安装为SystemCtl服务

注册system服务:vim /etc/systemd/system/nginx.service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Unit]
Description=nginx web server
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecStop=/usr/local/nginx/sbin/nginx -s stop
ExecQuit=/usr/local/nginx/sbin/nginx -s quit
ExecReload=/usr/local/nginx/sbin/nginx -s reload
PrivateTmp=true

[Install]
WantedBy=multi-user.target

注:Xshell粘贴会出现缺胳膊少腿,先进入Insert模式再粘贴即可

开启服务:

1
2
3
4
systemctl daemon-reload
systemctl start nginx.service
systemctl status nginx.service
systemctl enable nginx.service
  1. 开启Nginx:systemctl start nginx.service
  2. 检查是否成功,访问:Welcome to nginx!

二、常用启动命令

  1. 启动:./nginx
  2. 快速停止:./nginx -s stop
  3. 安全关闭:./nginx -s quit
  4. 重新加载配置:./nginx -s reload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
nginx version: nginx/1.18.0 (Ubuntu)
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]

Options:
-?,-h : this help
-v : show version and exit
-V : show version and configure options then exit
-t : test configuration and exit
-T : test configuration, dump it and exit
-q : suppress non-error messages during configuration testing
-s signal : send signal to a master process: stop, quit, reopen, reload
-p prefix : set prefix path (default: /usr/share/nginx/)
-c filename : set configuration file (default: /etc/nginx/nginx.conf)
-g directives : set global directives out of configuration file

三、基础知识

3.1、目录结构

1
2
3
4
├── conf
├── html
├── logs
├── sbin
  • conf:配置文件目录(主配置文件:nginx.conf会引用其他的)
  • logs:日志 需要注意日志大小,防止文件无限增大,配置文件种可配置
    • access.log:访问记录每次访问,每个记录
    • error.log:错误日志
    • nginx.pid:表示进程id号码
  • html:网页文件、静态资源目录(index.html默认页面)
  • sbin:主程序

3.2、基本运行原理

nginx开启主进程先进项校验配置文件,之后启动(Fork)子进程Worker,Worker进行根据配置文件进行解析用户请求,可以解析进行处理。当配置文件修改后Master会进行重载,之后当Worker处理完之后被杀掉,由Master再创建。

  • master:进程只加载不处理业务
  • worker:处理解析实际用户请求
    1
    2
    3
    4
    root@Test-Learn:/usr/local/nginx/logs# ps -ef|grep nginx
    root 8242 1 0 00:29 ? 00:00:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
    nobody 8243 8242 0 00:29 ? 00:00:00 nginx: worker process
    root 8265 959 0 00:42 pts/1 00:00:00 grep --color=auto nginx

客户端通过网路访问Nginx

3.2、Nginx配置文件

客户端相关配置都在HTTP下、服务端SERVER下

worker_processes

Nginx的实际工作进程数量,与主机CPU数量有关,超过最大核心数会进行时间片分片
例:表示当前工作进程是1个

1
worker_processes  1;

events

事件驱动配置

worker_connections

每个Worker处理多少HTTP连接

http

配置与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
[server {
listen 80;
server_name localhost;


location / {
root html;
index index.html index.htm;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}](<http {
include mime.types;
default_type application/octet-stream;

sendfile on;
keepalive_timeout 65;

server {
listen 80;
server_name localhost;


location / {
root html;
index index.html index.htm;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

}>)

include

包含外部配置文件
例:

1
include     xxx.conf;

default_type

默认通过流application/octet-stream方式传输
例:

1
default_type  application/octet-stream;

sendfile

[[Linux零拷贝]]
例:

1
sendfile        on;

keepalive_timeout

连接保持时间
例:

1
keepalive_timeout  65;

server

服务配置(一个虚拟主机V-Host)
例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
server {
listen 80;
server_name localhost;


location / {
root html;
index index.html index.htm;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
listen

监听端口
例:

1
listen       80;
server_name

配置及域名或者主机名(host文件中/etc/hosts
例:

1
server_name  localhost;

解析规则: 前面匹配上,后面不进行匹配
可配置多个域名指向同一个地址:宫格隔开

1
server_name  video.test.com www.test.comn;
  • 完整匹配:与主机名完全匹配
  • 通配符匹配(一般放到最后兜底)
    • server_name *.test.com*:匹配以test.com结尾的
  • 通配符结束匹配
    • server_name www.test.*:匹配所有以www.test开头的所有域名
  • 正则匹配:一般用于二级系统,进入一个Server进行不同转发
    • server_name ~^[0-9]+\.test\.com$:匹配任何以0~9开头并且后面是test.com的域名
location

资源定位符号,后面是URI(域名后半部分的)
例:

1
2
3
4
location / {
root html;
index index.html index.htm;
}
  • root:URI解析到哪个目录(根目录)
  • alias:解析时候不会拼接Location上的地址,是绝对目录
  • index:当前访问Location下的默认展示首页(index.html、index.htm)
  • proxy_pass:与root和index二选一,这个生效另外两个不生效,分号结束,不支持HTTPS
  • deny all:拒绝访问
    1
    proxy_pass http://www.test.com

示例:反向代理到百度

1
2
3
location / {
proxy_pass http://www.baidu.com;
}

访问:

检查请求:发现没有反向代理成功,直接进行了页面重定向 ,事实上是代理成功了,因为被代理的应用服务器可能配置了页面重定向功能。

示例:负载均衡 -> [[Nginx学习笔记#5 3、 负载均衡]]

error_page

错误页面([[Nginx 自定义错误页面]])
例:将500、502、503、504错误重定向到50x.html文件

1
error_page   500 502 503 504  /50x.html;

alias与root

1
2
3
4
location /css {
alias /usr/local/nginx/static/css;
index index.html index.htm;
}

root用来设置根目录,而alias在接受请求的时候在路径上不会加上location。

  1. alias指定的目录是准确的,即location匹配访问的path目录下的文件直接是在alias目录下查找的;
  2. root指定的目录是location匹配访问的path目录的上一级目录,这个path目录一定要是真实存在root指定目录下的;
  3. 使用alias标签的目录块中不能使用rewrite的break(具体原因不明);另外,alias指定的目录后面必须要加上”/“符号!!
  4. alias虚拟目录配置中,location匹配的path目录如果后面不带”/“,那么访问的url地址中这个path目录后面加不加”/“不影响访问,访问时它会自动加上”/“; 但是如果location匹配的path目录后面加上”/“,那么访问的url地址中这个path目录必须要加上”/“,访问时它不会自动加上”/“。如果不加上”/“,访问就会失败!
  5. root目录配置中,location匹配的path目录后面带不带”/“,都不会影响访问。

四、基本原理

  • tcp/ip:是一个基础协议,以流进行传输
  • Http:基于Tcp/ip,包含报文长度等….
  • Https:基于Http增加额外数据安全服务(公钥私钥进行验签)

4.1、虚拟主机

多个虚拟主机绑定到一个静态公网Ip上面,相当于多个网站部署一个站点(多域名 -> 多个ip,由Nginx进行解析站点目录即可)

  1. 创建虚拟主机:/test
1
2
3
4
root@Test-Learn:~/test# tree
.
├── video 为video站点
└── www 为www站点

创建文件:在两个虚拟主机目录下创建文件

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>www</title>
</head>
<body>
<h1>这是wwwo站点</h1>
</body>
</html>
  1. 修改后的目录结构:
1
2
3
4
5
6
7
root@Test-Learn:~/test# tree
.
├── video
│   └── index.html
└── www
└── index.html

4.1.1、创建不同端口号主机

  1. 修改配置文件:vim /usr/local/nginx/conf/nginx.conf
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
# www主机
server {
listen 88;
server_name localhost;


location / {
root /test/www;
index index.html index.htm;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

# video主机
server {
listen 888;
server_name localhost;


location / {
root /test/video;
index index.html index.htm;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
  1. 重载配置
1
2
systemctl reload nginx
systemctl status nginx
  1. 访问测试

4.1.2、创建不同域名主机

  1. 修改HOS或者使用域名解析
1
2
3
4
vim /etc/hosts
# 增加解析
127.0.0.1 video.test.com
127.0.0.1 www.test.com
  1. 修改配置文件
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
# www主机
server {
listen 80;
server_name video.test.com;


location / {
root /test/www;
index index.html index.htm;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

# video主机
server {
listen 80;
server_name www.test.com;


location / {
root /test/video;
index index.html index.htm;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
  1. 重启服务
1
2
systemctl reload nginx
systemctl status nginx
  1. 测试
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
# 测试video主机
root@Test-Learn:/test# curl http://video.test.com
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>www</title>
</head>
<body>

<h1>这是wwwo站点</h1>

</body>
</html>

# 测试www主机
root@Test-Learn:/test# curl http://www.test.com
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>video</title>
</head>
<body>

<h1>这是video站点</h1>

</body>
</html>

4.2、域名解析

4.2.1、基本介绍

  1. 修改本机Host文件实现本机域名解析(路由同理)。
  2. 使用第三方域名提供商解析(TTL为解析失效多久重试时间)
    • A:IPv4地址
    • AAAA:Ipv6地址
    • CNAME:解析到另一个域名
    • NS:解析到另一台DNS服务器
    • MX:解析到指定的邮件服务器
    • 显性URL:域名重定向到另一个(不隐藏地址)
    • 隐形URL:域名重定向到另一个(隐藏目标地址)

4.2.2、常用企业域名解析场景

  • 二级域名系统

  • 短网址
    用户请求的短网址,在用户访问之前被通过映射规则存储到相应的数据库中,之后当用户进行请求的时候,由Nginx进行域名服务转发,将相应的请求转发到短网址解析服务器,之后进行Redirect真实地址访问。

  • HTTP-DNS
    一般是C/S架构实现,因为对于浏览器来说访问域名的时候才会获取地址,所以传统浏览器不能做到这一点,所以多用于客户端。客户端再发起一个Http-Dns请求的时候,通过HTTP外挂参数形式进行传递到HTTP-DNS服务器,之后由服务器进行解析,域名解析目标地址回到Client。

五、反向代理

5.1、网关和反向代理

什么是反向代理?代理内部服务给外部(由服务提供方提供)
什么是正向代理?通过代理服务器访问外部(客户端主动访问)
什么是网关?所有请求打入通用网关(单个或者多个网关),进行转发下一跳(代理服务器约等于网关)也就是中转站,但是存在瓶颈,网关处理速度不够大,不能及时转发数据包

当一个请求打到网关上,通过网关打入到Nginx服务器上面,之后通过Nginx转发到应用服务器。(外网与应用服务器隔离,通过Nginx代理)
问题?(隧道模型) 数据量大时候Nginx负载会过大,因为相当于网关是一个隧道模型一进一出。
怎么避免瓶颈? (DR模型)实质上请求时候请求很小,主要返回数据量过大,因此通过Nginx进行数据转发到应用服务器,但是返回直接由应用服务器进行返回数据。减少返回数据量。这种模型可以使用[[IPVS(IP Virtual Server) && LVS (Linux Virtual Server)]]这个时候应用服务器只接受由Nginx转发的数据,但是发送其他数据给服务器网关(半内网半外网)。

5.2、反向代理在系统架构中的应用场景

省略…待补充

5.3、Nginx的反向代理配置

Server块中增加:

1
2
3
location / {
proxy_pass 需要代理的主机地址;
}

详细参照负载均衡配置

5.4、 负载均衡

负载均衡:指的是处理请求的时候,不至于所有请求都打到一台业务服务上面,而是将请求进行分发负载近似平均的分配到每台服务器进行处理。而这些处理业务的服务器就是集群 [^1]。而请求的分发负载是通过某些负载均衡算法实现的,比如轮询、Ip-hash等算法。而当这次负载均衡失效之后,会进行重试,通过重试正常处理这次业务请求数据。

5.3.1、负载均衡配置

首先配置代理地址proxy_pass之后配置upstream 端口号在proxy_pass后面不加,加在upstream中的server后面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
upstream httpds{
server 192.168.0.13:80;
server 192.168.0.14:80;
}

server {
listen 80;
server_name localhost;


location / {
proxy_pass http://httpds;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

测试结果:一个地址访问一次,轮询但是实际上不能保证会话,因为每次请求都会被负载均衡,因此不能记录会话信息。 可以使用JWT(专用权限校验)或者分布式Session保存状态。

5.3.2、负载均衡权重设置

  1. weight:权重
    upstream中增加:weight=数字 数字越大权重越高
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    upstream httpds{
    server 192.168.0.13:80 weight=8;
    server 192.168.0.14:80 weight=1;
    }

    server {
    listen 80;
    server_name localhost;


    location / {
    proxy_pass http://httpds;
    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    root html;
    }
    }

测试:基本按照权重来进行转发的

  1. down:不参加负载均衡
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
upstream httpds{
server 192.168.0.13:80 weight=8 down;
server 192.168.0.14:80 weight=1;
}

server {
listen 80;
server_name localhost;


location / {
proxy_pass http://httpds;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

测试:一直只有14

  1. backup:正常情况不会被负载到,当所有的都不能用的时候会使用备用!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
upstream httpds{
server 192.168.0.13:80 weight=8 down;
server 192.168.0.14:80 weight=1 down;
server 192.168.0.15:80 weight=1 backup;
}

server {
listen 80;
server_name localhost;


location / {
proxy_pass http://httpds;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

注意:实际上,这些配置在实际服务过程中由于需要修改后重启因此不能动态调节,不经常使用

5.3.3、其他负载策略(可以保持会话)

无法做到动态变化负载均衡和转发地址

5.3.3.1、IP_Hash

Nginx会判断来源IP地址,相同IP指向同一个服务器。但是实际上切换客户端或者基站的时候又会发生会话丢失的状态。也可能发生流量倾斜!

5.3.3.2、least_conn

通过最小连接数进行负载,但是可能会与配置的权重冲突,并且也不支持动态配置

5.3.3.3、url_hsah

需要第三方支持

同一个URl传递到一个机器,定向流量转发。对每一个URL进行HASH但是当URL发生变化就会切换IP服务器地址,这个时候依旧会丢失会话。适用于访问固定资源情况

5.3.3.4、fair

需要第三方支持

根据服务相应时间,但是实际上当后端应用A,B不同时接入一个交换机时候,其中一个发生交换机延迟,导致相应增大,但这个时候实际上A服务还是低负载,但是由于延迟,请求全部被转发到B导致数据过载干爆了。

六、动静分离

只适应于中小型系统,不论什么系统静态文件尽量放置接近于用户侧

缓存配置:

实际请求处理过程:当使用Nginx代理时候,将静态资源直接放到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
#静态文件 && 缓存配置
proxy_cache_path /home/nginx/cache levels=1:2 keys_zone=frp_cache:100m max_size=5g inactive=30d; # 缓存配置 路径 等级 key 最大大小 有效期
resolver 8.8.8.8; # 域名解析器
upstream tomcatserver1 {
server 172.0.0.49: 8081;
}
server {
listen 80;
server_name 8081.max.com;
access_log logs/8081.access.log main;
location / {
proxy_redirect off;
proxy_pass http://xxxxx:80;
}
location ~.*\.(gif|jpg|png|htm|html|css|js|flv|ico|swf)$ {
proxy_redirect off; #关闭跳转
proxy_cache nginx-cache; #缓存的空间 -- proxy_cache.conf 中定义的
proxy_cache_valid 200 302 1h; #不同http状态缓存时间不同
proxy_cache_valid 301 1d;
proxy_cache_valid any 1m;

### 强制缓存后端文件,忽略后端服务器的相关头信息
proxy_ignore_headers Set-Cookie Cache-Control;
proxy_hide_header Cache-Control;
proxy_hide_header Set-Cookie; #隐藏cookie,否则nginx会把响应页面的头信息也一起缓存,包括Set-cookie,导致后面访问页面的用户的cookie被设置成缓存的头。
###
expires 30d; #告诉浏览器缓存有效期-- 30天内可以直接访问浏览器缓存
proxy_pass http://xxxxx:80; # 你的代理路径
proxy_redirect http://$host/ http://$http_host/;
}
}
  1. 测试站点页面配置:引用一个图片文件
1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>www</title>
</head>
<body>
<h1>192.168.0.14</h1>
<img src="img/logo.jpg">
</body>
</html>

  1. Nginx配置:需要增加不同的Location,实际地址是root + location拼接而来的地址:/test/img

location匹配规则:[[Location匹配规则]]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
server {
listen 80;
server_name localhost;


location / {
proxy_pass http://httpds;
}

# 配置静态地址
location /img {
root /test;

}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

可以正常显示:

正则匹配设置:
匹配请求路径为

  • xxxx/js
  • xxxx/img
  • xxxx/css
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
server {
listen 80;
server_name localhost;


location / {
proxy_pass http://httpds;
}

# 配置静态地址
location ~*/(js|img|css){
root /test;

}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

nginx作为缓存代理不缓存任何内容 - 问答 - 腾讯云开发者社区-腾讯云 (tencent.com)

静态文件不缓存原因:
1. nginx不缓存原因
默认情况下,nginx是否缓存是由nginx缓存服务器与源服务器共同决定的, 缓存服务器需要严格遵守源服务器响应的header来决定是否缓存以及缓存的时常。header主要有如下:

1
Cache-control:no-cache、no-store

如果出现这两值,nginx缓存服务器是绝对不会缓存的

1
Expires:1980-01-01

如果出现日期比当前时间早,也不会缓存。
2. 解决不缓存方案
2.1 方法一:
修改程序或者源服务器web程序响应的header
2.2 方法二:
nginx代理直接加上如下一句:

1
proxy_ignore_headers X-Accel-Expires Expires Cache-Control Set-Cookie;

七、URL_Rewrite

URl资源路径重写rewrite,隐藏实际后端页面。使用正则匹配,^开启,$结束,参数括号括起来,重写原始地址使用 $表示 $后接数字表示第几个匹配规则
比如:

  • 原始:http://192.168.0.11/index.html?sku=10
  • 重写后:http://192.168.0.11/sku/10.html
1
2
3
4
5
6
7
8
9
10
# 写死
location / {
rewrite ^/10.html$ /index.html?sku=10;
proxy_pass http://httpds;
}
# 动态
location / {
rewrite ^/([0-9]+).html$ /index.html?sku=$1;
proxy_pass http://httpds;
}

rewrite是实现URL重写的关键指令,根据regex (正则表达式)部分内容,
重定向到replacement,结尾是flag标记。

1
2
关键字     正则      替代内容    flag标记
rewrite <regex> <replacement> [flag];
  • 关键字:其中关键字error_log不能改变
  • 正则:perl兼容正则表达式语句进行规则匹配
  • 替代内容:将正则匹配的内容替换成replacement
  • flag标记:rewrite支持的flag标记

rewrite参数的标签段位置:server,location,if
flag标记说明:

  • last 本条规则匹配完成后,继续向下匹配新的location URI规则
  • break 本条规则匹配完成即终止,不再匹配后面的任何规则
  • redirect 返回302临时重定向,浏览器地址会显示跳转后的URL地址(重定向后真实地址)
  • permanent 返回301永久重定向,浏览器地址栏会显示跳转后的URL地址(重定向后真实地址)

    302、301用户实际使用没区别,这个实际上是给网路爬虫或者其他使用的

八、使用网关 && 伪静态&& Url Rewrite

  1. 内部应用服务器与外部隔离
    1. 开启内部防火墙
    2. 指定网关ip可访问应用服务器
  2. 配置upstream服务器进行负载均衡
  3. 配置伪静态rewrite功能

九、防盗链

9.1、原理

第一次访问的时候不存在Refer,但是当第二次访问的时候就会带上这个(refer=来源的实际URl域名),表示从哪个浏览器地址来的。当A站点第一次访问自己资源时候是可以访问的,但是当B站点访问A的资源时候,由于A站点已经第一次访问了这个资源,因此B站点访问时候会自动加上refer请求头,那么就可以根据这个请求头来进行判断是否允许访问资源,达到放盗链的效果。

引用非法,或者直接窗口访问也会禁用

9.2、配置

修改Nginx:配置到Location下面(后面是来源的网址)

1
2

valid_referers none | blocked | server_names | strings ....;
  • none:检测 Referer 头域不存在的情况。
  • blocked:检测 Referer 头域的值被防火墙或者代理服务器删除或伪装的情况。这种情况该头域的值不以“http://” 或 “https://” 开头。
  • server_names :设置一个或多个 URL ,检测 Referer 头域的值是否是这些 URL 中的某一个。
    在需要防盗链的location中配置
1
2
3
4
valid_referers 允许的站点地址;
if ($invalid_referer) {
return 403;
}

return返回状态码

9.2.1、基础防盗链

9.2.1.1、禁止refer不正确或者没有都不能访问

示例:只想让通过网关服务器进行正常访问

  • 192.168.0.11为网关服务器,反向代理192.168.0.14应用服务器,192.168.0.13为别人的盗链服务器
    未开启防盗链,两个服务器均可以访问静态资源
    开启设置:修改192.168.0.11网关服务器
1
2
3
4
5
vim /usr/local/nginx/conf/nginx.conf
valid_referers 允许的站点地址;
if ($invalid_referer) {
return 403;
}

效果:盗链服务器无法访问显示403禁止,并且直接访问也不能打开

9.2.1.1、禁止refer不正确不允许访问或者允许没有都访问

开启不存在refer也可以访问(直接访问):在valid_referers后面加上none即可。

9.2.2、返回错误页面或者提示信息

错误页面

  1. 设置错误页面
1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>www</title>
</head>
<body>
<h1>192.168.0.14</h1>
<b>禁止防盗链!!!</b>
</body>
</html>
  1. 配置防盗链转发
    配置错误转发地址:
1
2
3
4
error_page   403  /error.html;
location = /error.html {
root /test;
}

配置盗链错误转发return:

1
2
3
4
valid_referers 192.168.0.11;
if ($invalid_referer) {
return 403;
}

结果:

错误图片
修改配置文件:转发匹配全部请求地址,转发到目标图片,并且隐藏目标地址

1
2
3
4
valid_referers 192.168.0.11;
if ($invalid_referer) {
rewrite ^/ /img/false.png break;
}

效果:

十、高可用配置

10.1、简介

  1. 后端服务挂掉
    解决: 采用多个后端服务

  1. 前面反向代理服务器挂掉
    解决:如果不增加机器情况下,进行机器之间的切换

一个网路中有多个Nginx,当一个Ip的Nginx挂掉,如果可以通过KeepAlive切换请求到第二个ip的Nginx就可以解决问题。

  • 交换Ip:交换Ip会导致,虚假宕机的时候Ip会冲突💢
  • 虚拟Ip:虚拟Ip进行切换,此时相当于主备机制,主机下线备用获得虚拟Ip成为Master,当旧的恢复根据权重重新竞争虚拟Ip变为Master😙

    虚拟Ip(Ip漂移)由KeepAlive进行管理

10.2、安装KeepAlive

服务结构如下:

  1. 使用包管理安装

    • apt install -y keepalived
    • yum install -y keepalived
  2. 修改配置文件:/etc/keepalived

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    ! Configuration File for keepalived

    global_defs {
    router_id loadbanlanced-11
    vrrp_skip_check_adv_addr
    vrrp_strict
    vrrp_garp_interval 0
    vrrp_gna_interval 0
    }

    vrrp_instance test-bl {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
    auth_type PASS
    auth_pass 1111
    }
    virtual_ipaddress {
    192.168.0.200
    }
    }
  • vrrp_instance:起一个名字
  • virtual_router_id:不需要修改
  • interface:绑定网卡
  • priority:优先级,竞选Master时候使用
  • advert_int:间隔检测时间
  • authentication:每组的认证,每组相同
  • virtual_ipaddress:虚拟Ip

修改上面网卡名称为实际的,每台跑keepAlive机器均需要按照自己机器修改配置 instance、vitrul-id、authentication需要一致

主机:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
! Configuration File for keepalived

global_defs {
router_id loadbanlanced-11
vrrp_skip_check_adv_addr
vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}

vrrp_instance test-bl {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.0.200
}
}

备用机:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
! Configuration File for keepalived

global_defs {
router_id loadbanlanced-13
vrrp_skip_check_adv_addr
vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}

vrrp_instance test-bl {
state BACKUP
interface eth0
virtual_router_id 51
priority 80
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.0.200
}
}

重启KeepAlived:ststemctl restart keepalived
验证:

此时已经可以访问,但是显示盗链是由于配置了防盗链refer检查来源地址,这里可以直接设置成为192.168.0.200漂移Ip地址。

当关闭192.168.0.11主机时,从机获得200的ip,还是可以正常访问

解决Ping不通:keepalived配置虚拟ip无法ping通解决方法_weixin_40561490的博客-CSDN博客_keepalived虚拟ip 不能访问

但是当没有配置监听进程,所以默认监听的是Keepalive的主机,所以当主机上的Nginx挂掉之后,无法进行Ip漂移,所以通过脚本监听检查Nginx存活状态,当死掉后Kill掉死掉的Nginx主机上的KeepAlive进程,此时从机上的KeepAlive无法获取主机上的KeepAlive的状态就会执行Ip漂移。

十一、HTTP && HTTPS

11.1、原理

实际上传递过程中都是采用二进制传输, 在访问目标服务器时候会通过很多的Server进行数据转发,但是在每一个中间节点都能获取到数据,只要猜到传输的协议是什么,就可以进行对应的解码,读取其中的明文信息。(HTTP透明传输的)

因此为了保证安全,需要在通讯客户端服务器两端都需要创建安全协议进行通讯。实际上就是需要对报文进行加密,服务器端需要进行相应的解密。

  1. 对称加密:
    客户端与服务器均需要遵循同一套加密算法 需要内置,不够灵活。那么如果需要灵活那么传输数据包前进行协商一次密码,但是密码实际上也需要想办法发送过去,这个时候就又回到了对称加密一开始的问题!
  2. 非对称加密:

一次请求的过程

问题?:公钥会在网路之间传递,而私钥不会,因为客户端发送数据时采用公钥加密,因此如果公钥被中间人拦截,并且公钥可以解开公钥那么就一样数据不安全。因此公钥不能解开公钥加密的数据。

解决:防止客户端被拦截:公钥加密,私钥解密 -> 私钥加密,公钥解密 -> 公钥加密,公钥解密不了

  • 服务器端:

    问题?:伪造假的公钥信息,中间人使用假的公钥处理,篡改数据在使用真的服务器公钥加密伪造请求数据。

解决:实际上需要解决,这个公钥是不是可信的!———> 中间官方进行认证

避免外部不可信证书的加载,其次不要使用不安全的浏览器等,防止假CA证书的信任!!
windows证书管理:certmgr.msc
Linux证书:``/etc/ssl/certs/

系统内嵌的CA机构的证书,操作系统安装完成之后就存在

银行等为了防止操作系统被入侵,这个时候采用安全键盘、验证码等….

11.2、证书创建申请

工具:openSSl、XCA(可视化)

11.2.1、证书自签名

使用不多,自己给自己签名,在互联网上也不是安全的

11.2.2、CA签名证书

  1. 购买域名
  2. 购买VPS
  3. 连接到VPS

  1. 配置域名解析 && 申请SSl证书
    域名解析:

申请证书:

下载证书:

配置证书:vim /usr/local/nginx/conf/nginx.conf 增加Https链接

1
2
3
4
5
6
7
8
9
10
11
12
13
  server{
listen 443;
server_name test.baiyz.top

#相对路径读取conf目录
ssl_certificate cert.pom;
ssl_sertificate_key cert.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM- SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
}

开启强制转向HTTPS链接:Nginx强制https跳转_KanaySir的博客-CSDN博客

1
if ($scheme = http ) {return 301 https://$host$request_uri;}

443与80是两个不相同的服务,因此让80转向443

1
2
3
4
5
6
server {
listen 80;
server_name test.baiyz.top;
rewrite ^(.*)$ https://www.test.com$1 permanent;

}

配置成功,可以直接通过域名访问HTTPS加密的网站

[[安装Discuz社区]]

十二、Nginx扩容

垂直扩容:扩展单一机器的性能
水平扩容:增加机器

12.1、单机扩容

实际上就是增加当前单机的核心硬件配置

  • 云服务资源购买
    • 增加CPU
    • 网卡性能:10G / 100G
    • 硬盘:多副本,冷热分离、数据库存储
      • SSD:热数据、多副本
      • HDD:冷数据

12.2、水平扩展 - 集群化

12.2.1、基本介绍

增加更多的机器,集群化主机(一模一样),之间通过KeepAlive保持连接信息,之后通过Nginx转发给上游服务器进行处理业务。

实现:

  • proxy_pass、upstream
  • ip_hash:保持会话,同一个来源Ip请求负载到一个机器,保证用户登陆状态
  • 中间件分布式Session:Redis + SpringSession 当集群数量增大后Redis负担加重

12.2.2、HASH

12.2.2、IP_HASH

解决的场景:中小型项目 — 快速扩容

会根据IP生成一个HASH值 % 后端服务器个数 = 实际服务器位置,之后将请求实际转向这台服务器。

问题?

  1. Ip集中
    由于静态Ip较少,很多都是二级或者三级IP这种情况下IP地址可能实际上就那几个很集中,会造成流量倾斜(分发到某一台服务器上)
  2. 后端某一个机器宕机
    导致当前机器用户会话丢失

使用:在http模块中增加upstream,并且设置相应的ip_hash;即可保证同一个Ip打到一个服务器上。

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
http {
include mime.types;
default_type application/octet-stream;

sendfile on;
keepalive_timeout 65;


upstream hhtplb{
ip_hash;
server 192.168.0.15;
server 192.168.0.16;
server 192.168.0.17;
server 192.168.0.18;
}

server {
listen 80;
server_name localhost;


location / {
proxy_pass http://httpd;

}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

12.2.3、$request_urI (LUa定向分发)

使用同一个URL会进行转发到一个服务器。
应用场景:

  • 客户端不支持Cookie:传递会话信息http://xxx.com?cookie=xxxx
  • 后端资源倾斜:每个机器上面数据不一样,访问A就去A服务器,访问B就去B服务器

使用:在http模块中增加upstream,并且设置相应的hash $request_uri;即可保证同一个URI打到一个服务器上。

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
worker_processes  1;
events {
# 每个Worker处理多少连接
worker_connections 1024;
}


http {
include mime.types;
default_type application/octet-stream;

sendfile on;
keepalive_timeout 65;


upstream hhtplb{
hash $request_uri;
server 192.168.0.15;
server 192.168.0.16;
server 192.168.0.17;
server 192.168.0.18;
}

server {
listen 80;
server_name localhost;


location / {
proxy_pass http://httpd;

}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

同一个cookie请求的时候打到一个服务器上,解决会话问题

  1. 第一次登陆应用服务器下发Cookie
  2. 第二次请求根据Cookie进行计算Hash

使用:在http模块中增加upstream,并且设置相应的hash $cookie_jsessionid;即可保证同一个cookie.key打到一个服务器上。这个会取Cookie中的jsssionid(cookie[jssionId]

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
worker_processes  1;
events {
# 每个Worker处理多少连接
worker_connections 1024;
}


http {
include mime.types;
default_type application/octet-stream;

sendfile on;
keepalive_timeout 65;


upstream hhtplb{
hash $cookie_jsessionid;
server 192.168.0.15;
server 192.168.0.16;
server 192.168.0.17;
server 192.168.0.18;
}

server {
listen 80;
server_name localhost;


location / {
proxy_pass http://httpd;

}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

12.2.3、使用第三方模块

使用sticky模块实现cookieHash(不依赖上游服务器下发的cookie进行定向流量转发)既可以应用于后端静态服务也可以动态服务

Apache、Nginx存储视频等静态文件,不希望用户 每次都建立连接(新建连接开销大)所以希望与后端服务器(静态文件服务器保持会话)但是这个静态服务器不会自己下发Cookie因此使用Sticky完成会话保持。

安装:[[Nginx安装sticky]]

使用:在配置文件中http.upstream中增加sticky

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
worker_processes  1;
events {
# 每个Worker处理多少连接
worker_connections 1024;
}


http {
include mime.types;
default_type application/octet-stream;

sendfile on;
keepalive_timeout 65;


upstream hhtplb{
sticky;
server 192.168.0.15;
server 192.168.0.16;
server 192.168.0.17;
server 192.168.0.18;
}

server {
listen 80;
server_name localhost;


location / {
proxy_pass http://httpd;

}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

原理:实际上sticky会下发一个Cookie route,每次通用这个来进行HASH路由,stick的下发cookie可以进行配置,配置如下

1
sticky name=cookie_key expires=6h;
  • name:cookie的key的名称,默认是route(不要与后端服务实际cookie名称重复,重复会导致后端cookie和sticky的cookie冲突)
  • expires:cookie过期时间(默认存在过期时间)

12.2.4、HTTP中的KeepAlive及其相关配置

KeepAlive就是浏览器和服务端之间保持长连接,这个连接是可以复用的。当客户端发送一次请求,收到相应以后,第二次就不需要再重新建立连接(慢启动的过程),就可以直接使用这次的连接来发送请求了。在HTTP1.0及各种加强版中,是默认关闭KeepAlive的,而在HTTP1.1中是默认打开的。

什么时候开启什么时候关闭?存在下一步操做的时候一般就需要开启KeepAlive,但是静态资源一般请求一次即可之后就会缓存到浏览器本地了。并且在短耗时并且不存在下一次操做的时候关闭KeepLive有助于提升性能。

详细介绍:![[HTTP请求特性#KeepAlive]]

12.2.4.1、简单配置

开启长连接超时配置:这里指的是重置时间,65秒内再次请求就会刷新(不应配置过大或者过小)

  • 0:关闭
  • 其余:重置时间
1
2
3
4
http {
    keepalive_timeout  65;
    # .....
}

请求头变化
开启:Connection: keep-alive
关闭:Connection: close

12.2.4.2、详细配置

官方文档:模块 ngx_http_core_module (nginx.org)

12.2.4.2.1、客户端配置
  1. keepalive_time:默认1h keepAlive最大连接时间(多个重置时间加起来总时间和),一段时间强制关闭
  2. keepalive_disable:对某些UA禁用KeepAlive
  3. keepalive_requests :默认1000个 指一个TCP复用最大能够同时能够处理多少个请求(并发承载多少请求)
  4. keepalive_timeout :默认75s 重置时间,65秒内再次请求(响应头中会多出Keep-Alive: 时间
  5. send_timeout :默认60s (有坑) 发送请求后,服务端处理准备返回给客户端的数据所消耗的时间(此时没有发送,在发送准备)(长处理业务时间大于这个时间就会强制关闭请求)
12.2.4.2.1、上游upstream配置

12.3、分布式

  1. 数据分区
  2. 上游服务SOA化(将大型服务进行拆分为微服务)对于Nginx代理而言,原先代理的是一个庞大的系统,这个时候实际上进行模块服务划分,每一个Nginx代理一个服务器上的部分服务。
  3. 入口细分
    • 浏览器
    • App
    • CLient
    • H5
  4. 数据异构化
    • 客户端缓存
    • CND缓存
    • 异地多活
    • Nginx缓存
      将不同的业务数据进行多层划分,异构存储。根据数据类型以及数据使用情况将其数据划分到多级进行缓存
  5. 服务异构化
    进行异步请求服务,拆分请求(将一个大的请求进行划分,按步进行请求)、使用消息中间件(MQ …)、异步回调等

扩容原则:无状态、弹性原则

附录

Tomcat处理静态资源速度,实际上得益于底层采用OS的部分网络模型,因此处理速度略低于Nginx,主要开销在会话层面。因为每次连接都需要创建会话,但是实际上会话只在每次连接简历时候创建,之后保持KeepAlive因此没有那么多的会话被同时创建出来。


[^1]: 集群中的所有机器都是复制而来,可以处理完全相同的业务