nginx常用设置及实践

# 简介

nginx是一个高性能的HTTP和反向代理服务器,也是一个通用的TCP/UDP代理服务器,最初由俄罗斯人Igor Sysoev编写。

Nginx以事件驱动的方式编写,所以有非常好的性能,同时也是一个非常高效的反向代理、负载平衡服务器。

  • 在性能上,Nginx占用很少的系统资源,能支持更多的并发连接,达到更高的访问效率;
  • 在功能上,Nginx是优秀的代理服务器和负载均衡服务器;在安装配置上,Nginx安装简单、配置灵活;
  • 支持热部署,启动速度特别快,还可以在不间断服务的情况下对软件版本或配置进行升级,即使运行数月也无需重新启动。

# 优势

  • 高并发高性能
  • 可扩展性好
  • 高可靠性
  • 热部署
  • 开源许可证

# 应用场景

  • http服务器,静态资源服务,通过本地文件系统提供服务;
  • 虚拟主机,反向代理服务、负载均衡;
  • API服务、权限控制,减少应用服务器压力;

# 常用配置

# 配置结构

下面是一个nginx配置文件的基本结构:

模块 功能
main nginx的全局配置,对全局生效。
events 配置影响nginx服务器或与用户的网络连接。
http 可以嵌套多个server,配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置。
server 配置虚拟主机的相关参数,一个http中可以有多个server。
location 配置请求的路由,以及各种页面的处理情况。
upstream 配置后端服务器具体地址,负载均衡配置不可或缺的部分。

简化版配置:

# 全局区   有一个工作子进程,一般设置为CPU数 * 核数
worker_processes  1;
events {
    # 一般是配置nginx进程与连接的特性
    # 如1个work能同时允许多少连接,一个子进程最大允许连接1024个连接
    worker_connections  1024;
}
# 配置HTTP服务器配置段
http {
    # 配置虚拟主机段
    server {
        # 定位,把特殊的路径或文件再次定位。
        location  {
 			...
        }
    }
    server {
        ...
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

基本示例及说明:

# 定义Nginx运行的用户和用户组
user  nginx;
# nginx进程数,建议设置为等于CPU总核心数
worker_processes  1;   
# 错误日志存放目录和类型
error_log  /var/log/nginx/error.log warn;
# 进程文件
pid        /var/run/nginx.pid;

events {
    worker_connections  1024; # 单个进程最大连接数(最大连接数=连接数*进程数)
}

# 设定http服务器
http {
    include       /etc/nginx/mime.types;   # 文件扩展名与类型映射表
    default_type  application/octet-stream;  # 默认文件类型
    #设置日志的格式
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;   # nginx访问日志存放位置
    # 开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on。
    # 如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。
    # 注意:如果图片显示不正常把这个改成off。
    sendfile        on;   
    tcp_nopush     on;    # 防止网络阻塞
    keepalive_timeout  65;  # 长连接超时时间,单位是秒
    gzip  on;  # 开启gzip压缩
    include /etc/nginx/conf.d/*.conf; # 包含的子配置项位置和文件,表示conf.d文件夹下.conf后缀的文件都会归入nginx配置中
    # 服务配置
    server{
        listen 80;# 监听端口
        # 根目录下
        location / {
            proxy_pass http://myproject; # 选择哪个服务器列表
        }
    }
}
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

# 内置变量

下面是 nginx一些配置中常用的内置全局变量,你可以在配置的任何位置使用它们。

变量名 功能
$host 请求信息中的 Host,如果请求中没有 Host行,则等于设置的服务器名
$request_method 客户端请求类型,如 GETPOST
$remote_addr 客户端的 IP地址
$args 请求中的参数
$content_length 请求头中的 Content-length字段
$http_user_agent 客户端agent信息
$http_cookie 客户端cookie信息
$remote_addr 客户端的IP地址
$remote_port 客户端的端口
$server_protocol 请求使用的协议,如 HTTP/1.0、·HTTP/1.1`
$server_addr 服务器地址
$server_name 服务器名称
$server_port 服务器的端口号

# 其他操作

# 声明变量 & 变量赋值

# 声明变量,并为变量赋值
set $username "samy";
1
2

# 读取cookie

# 读取请求携带的cookie,其中keyName是cookie的key
$cookie_keyName;
1
2

# if 判断语句

set $env $cookie_ENV;
# if 判断 ==  !=
if ($cookie_ENV == "dev") {
    rewrite ^/website/blog/index.dev.html;
}
1
2
3
4
5

# 文件|目录 判断

语句 功能
-f 文件存在
-d 目录存在
!-d 目录不存在
-e 文件或目录存在
!-e 文件或目录都不存在
-x 文件可执行
!-x 文件不可执行
# 如果文件或者目录不存在则返回html
if (!-e $request_filename) {
    rewrite ^/website/blog/index.html;
}
location /blog {
    root /data/sites/;
    autoindex on;
    expires 30d; # 缓存30天
    if (!-e $request_filename) {
        rewrite ^/(.*) /blog/index.html;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 设置响应头,状态码

# 在server里设置响应头 add_header
add_header Access-Control-Allow-Origin *;

location / {
    # 通常在代理情况下使用 proxy_set_header:
    proxy_set_header Host 127.0.0.1;
    # 设置剔除的头部字段
    proxy_hide_header Expires; 
    # 设置状态码直接return即可
    return 200;
}
1
2
3
4
5
6
7
8
9
10
11

# 常用命令

# 命令列表

sudo systemctl enable nginx # 设置开机启动 
sudo service nginx start # 启动 nginx 服务
sudo service nginx restart # 重启 nginx 服务
sudo service nginx stop # 停止 nginx 服务
sudo service nginx -t # 检查语法
sudo service nginx reload # 重新加载配置,一般是在修改过 nginx 配置文件时使用。
1
2
3
4
5
6
nginx -h 		#打开帮助信息
nginx -s reopen 	#重启Nginx
nginx -s reload 	#重新加载Nginx配置文件,然后以优雅的方式重启Nginx
nginx -s stop   	#强制停止Nginx服务
nginx -s quit   	#优雅地停止Nginx服务(即处理完所有请求后再停止服务)
nginx -v 		#显示版本信息并退出
nginx -V		#显示版本和配置选项信息,然后退出
nginx -t		#检测配置文件是否有语法错误,然后退出
nginx -T	 	#检测配置文件是否有语法错误,转储并退出
nginx -q 	  	#在检测配置文件期间屏蔽非错误信息
nginx -p prefix   	#设置前缀路径(默认是:/usr/share/nginx/)
nginx -c filename	#设置配置文件(默认是:/etc/nginx/nginx.conf)
nginx -g directives 	#设置配置文件外的全局指令
kill all nginx		#杀死所有nginx进程
kill -quit 进程编号
kill -9 进程编号 # 强制停止:这个得分别干掉master进程和worker进程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 命令详情

# 查看安装目录【要点】

ps -ef | grep nginx
# 查看服务是否启动成功
# root 4593 1  0 Jan23 ? 00:00:00 nginx: master process /usr/sbin/nginx
1
2
3

# 查看配置文件目录

通过检查配置是否正确的方式来查看配置文件目录

nginx -t

# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
1
2
3

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok

# 检查配置语法是否正确

nginx -t

# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful
1
2
3
4

其中:参数 -c 指定了配置文件的路径,如果不加 -c 参数,Nginx 会默认加载其安装目录的 conf 子目录中的 nginx.conf 文件。

# 启动/重启服务

# 通过软连接,这样就可以直接使用 nginx 执行
$ sudo ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx
#配置了全局软应用后,就直接使用nginx命令;

# 启动nginx服务,ps:如果nginx已经开启了,再次执行nginx -c 命令时,会报错
/usr/sbin/nginx -c /etc/nginx/nginx.conf
/usr/local/nginx/sbin/nginx -c conf/nginx.conf

# 在启动的时候也可以指定pid的存储位置
/usr/local/nginx/sbin/nginx -g "pid /usr/local/nginx/nginx.pid;"
/usr/local/nginx/sbin/nginx -g "pid /usr/local/nginx/nginx.pid;" -s stop

# 重启nginx服务
/usr/sbin/nginx -s reload
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 停止服务

# 快速强制停止Nginx服务
/usr/local/nginx/sbin/nginx -s stop

# 优雅停止nginx服务
/usr/local/nginx/sbin/nginx -s quit
1
2
3
4
5

quit 参数首先会关闭监听端口,停止接收新的连接,然后把当前正在处理的连接全部处理完,最后再退出进程。

# 查看nginx日志【要点】

nginx的log日志分为access log 和 error log

cat /etc/nginx/nginx.conf # 直接输出整个文件的内容
tail -f /usr/local/etc/nginx/logs/access.log # 实时输出日志
tail -n 100 -f ./logs/insure-adm/insure-adm-web.log

tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log
tail -n 100 -f ./logs/access.log
1
2
3
4
5
6
7

# 热加载命令

如果改变了Nginx的配置文件.nginx.conf,想要重启Nginx,首先需要验证nginx.conf的语法有没有问题

/usr/local/nginx/sbin/nginx -t
1

语法验证没有问题我们就可以通过 -s reload来重新加载配置文件了

/usr/local/nginx/sbin/nginx -s reload
1

获取通过发送信号量的方式来重新加载

kill -hup master进程编号
1

# 应用实践

# 跨域【要点】

同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。通常不允许不同源间的读操作。

# 同源策略

浏览器同源:如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的源。

image-20210220235532607

# 解决跨域

  • 前端server的域名为:fe.server.com
  • 后端服务的域名为:dev.server.com

现在在 fe.server.comdev.server.com发起请求一定会出现跨域。将 server_name设置为 fe.server.com, 然后设置相应的location以拦截前端需要跨域的请求,最后将请求代理回 dev.server.com。如下面的配置:

server {
    listen       80;
    server_name  fe.server.com;
    location /api {
        proxy_pass dev.server.com;
       # proxy_pass  http://127.0.0.1:3000;
        proxy_redirect     off;
        proxy_set_header   Host             $host;        # 传递域名
        proxy_set_header   X-Real-IP        $remote_addr; # 传递ip
        proxy_set_header   REMOTE-HOST      $remote_addr; # 传递远程host
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
       # proxy_set_header   X-Scheme         $scheme;      # 传递协议
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

实现原理:这样可以完美绕过浏览器的同源策略: dev.server.com访问 nginxfe.server.com属于同源访问,nginx对服务端转发的请求不会触发浏览器的同源策略;

# 管理虚拟主机

虚拟主机使用的是特殊的软硬件技术,它把一台运行在因特网上的服务器主机分成一台台“虚拟”的主机,每台虚拟主机都可以是一个独立的网站,可以具有独立的域名,具有完整的Intemet服务器功能(WWW、FTP、Email等),同一台主机上的虚拟主机之间是完全独立的。从网站访问者来看,每一台虚拟主机和一台独立的主机完全一样。

一般这种会单独配置一个.conf文件加端口命名;

# 分类

# 基于域名

1、在http大括号中添加如下代码段:

server {  
        listen 80;   
        server_name samy.cn;
        location / {              
            root    samy;  
            index index.html;                 
        }  
    }

server {  
  listen 80;
  #listen  2022; #基于端口
  server_name samyz.cn; #基于域名
  #server_name  192.168.197.142; #基于IP地址
  location / {              
    root    /home/samy/deploy/api-doc;  
    index index.html;                 
  }  
  #vue history模式
  location / {
    root /home/samy/deploy/avue/dist;
    try_files $uri $uri/ /index.html;
    index index.html;
  }
}
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

2、切换安装目录:cd/usr/local/software/nginx

3、创建目录:mkdir samy

4、新建index.html文件:vi /usr/local/software/nginx/samy/index.html,文件内容:

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    </head>
    <body>
        <h2>samy</h2>
    </body>
</html>
1
2
3
4
5
6
7
8

5、重新读取配置文件:

/usr/local/software/nginx/sbin/nginx-s reload

kill -HUP进程号

6、配置windows本机host:

192.168.197.142 samy.cn

7、访问:http://samy.cn:80/

# 基于端口
server {
        listen  2022;
        server_name     feng.com;
        location / {
           root    /home;
           index index.html;
        }
    }
1
2
3
4
5
6
7
8
# 基于IP地址
    server {
      listen  80;
      server_name  192.168.197.142;
      location / {
          root    ip;
          index index.html;
      }
    }
1
2
3
4
5
6
7
8

# 案例

# ubuntu上部署

sudo ln -s ,要点一定要记得配置软引用

cd /etc/nginx
sudo vim /sites-available/insure-8181.conf
sudo ln -s ../sites-available/insure-8181.conf insure-8181.conf

sudo nginx -t
sudo nginx -s reload
curl xxxx/api/xxx

sudo service nginx restart
1
2
3
4
5
6
7
8
9
# 静态网页配置doc&原型

image-20210220235532607image-20210220235532607

# 多域名及配置

由于多个项目的nginx配置和日志等最好分开维护和部署,所以利用nginx模块化功能,分为多个子配置文件。

  • nginx.conf:入口文件
http {
    # 加载其他子nginx配置
    include /etc/nginx/conf.d/*.conf;
}
1
2
3
4
  • 服务端渲染服务配置文件 /etc/nginx/conf.d/samy.ssr.com.conf
server {
    listen 80;
    server_name samy.ssr.com; # 域名
    access_log /data/web_deployment/log/nginx/samy.ssr.com.access.log;
    error_log /data/web_deployment/log/nginx/samy.ssr.com.error.log;
    
    location /ssr {
        root /data/sites/ssr/;
        proxy_pass http://127.0.0.1:3000; # 代理到服务器本地3000端口上
        proxy_set_header Host samyz.ssr.com;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header referer "http://$host";
        break;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  • 文档站点静态资源配置文件 /etc/nginx/conf.d/samy.docs.com.conf
server {
    listen 80;
    server_name samyz.docs.com; # 域名
    access_log /data/web_deployment/log/nginx/samy.docs.com.access.log;
    error_log /data/web_deployment/log/nginx/samy.docs.com.error.log;
    
    location /docs {
        root /data/sites/docs;
        if (!-e $request_filename) {
            rewrite ^/(.*) /docs/index.html;
        }
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 其他案例
http{
  server{
    listen 8081;
    server_name  test.com;
  }
}
1
2
3
4
5
6

重启Nginx,用浏览器访问 test.com:8081 (opens new window) ,会发现无法访问。这因为在Host文件中还没把 test.com 指向 127.0.0.1 。

这里推荐一个修改 Host 的工具(Switchhosts!),可以自行百度搜索下载安装,修改好Host文件后,重新用浏览器访问 test.com:8081 (opens new window) ,访问结果会和访问 http://localhost:80 的页面一样。

# 静态资源

server {
    location / {
        root /data/www; # 根目录
        autoindex on; # 自动显示目录下的index.html页面
        expires 30d; # 缓存30天
    }
    location ~* \.(png|gif|jpg|jpeg)$ {
        root    /root/static/;
        autoindex on;
        access_log  off;
        expires     10h;# 设置过期时间为10小时
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

匹配以 png|gif|jpg|jpeg为结尾的请求,并将请求转发到本地路径, root中指定的路径即nginx本地路径。同时也可以进行一些缓存的设置。

# 请求过滤

# 根据状态码过滤

error_page 500 501 502 503 504 506 /50x.html;
location = /50x.html {
    #将跟路径改编为存放html的路径。
    root /root/static/html;
}
1
2
3
4
5

# 根据URL名称过滤

根据URL名称过滤,精准匹配URL,不匹配的URL全部重定向到主页;

location / {
    rewrite  ^.*$ /index.html  redirect;
}
1
2
3

# 根据请求类型过滤

if ( $request_method !~ ^(GET|POST|HEAD)$ ) {
    return 403;
}
1
2
3

# 示范【推荐】

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    access_log  /usr/local/etc/nginx/logs/access.log;  #nginx请求日志地址
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }
        # 前端
        location /blog {
            root /data/sites/;
            autoindex on;
            expires 30d; # 缓存30天
            if (!-e $request_filename) {
                rewrite ^/(.*) /blog/index.html;
            }
        }
        # 后端,只转发 /blog/api 开头的请求
        location /blog/api {
            proxy_pass  http://127.0.0.1:3000;
            proxy_redirect     off;
            proxy_set_header   Host             $host;        # 传递域名
            proxy_set_header   X-Real-IP        $remote_addr; # 传递ip
            proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
            proxy_set_header   X-Scheme         $scheme;      # 传递协议
        }
        # redirect server error pages to the static page /50x.html
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}
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
41
42
server {
    listen       80;
    #静态文件及服务器
    root /home/samy/deploy/xx-web/vue/;
    server_name  web.xx.cn;
   #接口处理
    location /api/ {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_pass http://localhost:7002;
        proxy_redirect off;
    }
   #上传文件处理
    location /uploads/ {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_pass http://localhost:7002;
        proxy_redirect off;
    }
  #websocket处理
    location /socket.io/ {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_pass http://localhost:7002;
    }

    location / {
          # index  index.html;
          try_files $uri $uri/ /index.html;
       }
     location /api/1/statistics/person/ {
          return   500;
      }
    location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|js|pdf|txt){
      root /var/www/pro/mall/current/public
    }
    # 图片样式缓存1年
    location ~* /app.*\.(js|css|png|jpg)${
        access_log off;
        expires    365d;
    }
    # html/xml/json 文件不缓存
    location ~* /app.*\.(?:manifest|appcache|html?|xml|json)${
        expires    -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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

# 代理

代理是在服务器和客户端之间假设的一层服务器,代理将接收客户端的请求并将它转发给服务器,然后将服务端的响应转发给客户端。

不管是正向代理还是反向代理,实现的都是上面的功能。

代理有正向代理和反向代理两种,都是用proxy_pass指令来实现。

  • 一句话解释正向代理,正向代理的对象是用户,用户知道访问那个服务器,而服务器不知道是哪个用户访问它。
  • 一句话解释反向代理,反向代理的对象是服务器,用户不知道访问了哪个服务器,而服务器知道那个用户访问它。

image

正向代理是为我们服务的,即为客户端服务的,客户端可以根据正向代理访问到它本身无法访问到的服务器资源。

正向代理对我们是透明的,对服务端是非透明的,即服务端并不知道自己收到的是来自代理的访问还是来自真实客户端的访问。

相关设置

  • server_name指令主要用于配置基于名称虚拟主机
  • gzip的作用是是否需要开启压缩传输
  • location指令用于匹配 URL
  • proxy_pass指令用于设置被代理服务器的地址
  • proxy_set_header用来设定被代理服务器接收到的header信息(请求头)

# 正向代理

正向代理是为客户端服务的,通过代理客户端的请求,去访问客户端本身无法直接访问的服务器,翻墙工具就是最常见的正向代理。正向代理对于客户端透明,对于服务器端不透明。

正向代理

nginx配置示例:

server {
    resolver 8.8.8.8;       #指定DNS服务器IP地址 
    listen 80;
    location / {
        proxy_pass http://$host;     #设定代理服务器的协议和地址 
        proxy_set_header HOST $host;
        proxy_buffers 256 4k;
        proxy_max_temp_file_size 0k;
        proxy_connect_timeout 30;
        proxy_send_timeout 60;
        proxy_read_timeout 60;
        proxy_next_upstream error timeout invalid_header http_502;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
resolver 8.8.8.8 # 谷歌的域名解析地址
server { 
    location / {
        # 当客户端请求我的时候,我会把请求转发给它      
        # $http_host 要访问的主机名 $request_uri 请求路径      
        proxy_pass http://$http_host$request_uri;
    }
}
1
2
3
4
5
6
7
8

# 反向代理

反向代理是指为服务端服务的,反向代理接收来自客户端的请求,帮助服务器进行请求转发、负载均衡等。通常解决前端跨域问题也是通过反向代理实现的。反向代理对于服务端是透明的,对于客户端是不透明的。

反向代理

nginx配置示例:

server {
    listen       80;
    server_name  xx.a.com; // 监听地址
    location / {
        root html;
        proxy_pass xx.b.com; // 请求转向地址
        index index.html; // 设置默认页
    }
}
1
2
3
4
5
6
7
8
9

nginx 反向代理时丢失端口的解决方案

nginx没有正确的把端口信息传送到后端,没能正确的配置nginx,下面这行是关键

proxy_set_header Host $host:$server_port; 这一行是关键。

# the 90 port
server {
  listen 90;
  server_name xxxx.cn;
  proxy_set_header X-Forwarded-Host $host;
  proxy_set_header X-Forwarded-Server $host;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header Host $host:$server_port; #这里是重点,这样配置才不会丢失端口
  location / {
  proxy_pass http://127.0.0.1:9001;
  }
  location = /50x.html {
  root html;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 负载均衡

负载均衡是指nginx将大量客户端的请求合理地分配到各个服务器上,以达到资服务端资源的充分利用和更快的响应请求。

# 后端服务器状态

后端服务器支持以下的状态配置:

  • down:当前服务器不参与负载均衡
  • backup:当其他节点都无法使用时的备用服务器
  • max_fails:允许请求失败的次数,若到达就会休眠
  • fail_timeout:经过max_fails次失败后,服务器的暂停时间,默认为10s
  • max_conns:限制每个服务器的最大接收连接数
upstream samyz {
 server 127.0.0.1:66 down;
 server 127.0.0.1:77 backup;
 server 127.0.0.1:88  max_fails=3 fail_timeout=10s;
 server 127.0.0.1:99 max_conns=1000;
}
1
2
3
4
5
6

img

示范:

image-20210220235532607image-20210220235532607

# 负载策略

实现负载均衡有几种方案

  • 轮询(默认),每个请求按照时间顺序轮流分配到不同的后端服务器,如果某台后端服务器宕机,Nginx 轮询列表会自动将它去除掉。
  • weight(加权轮询),轮询的加强版,weight 和访问几率成正比,主要用于后端服务器性能不均的场景。
  • ip_hash,每个请求按照访问 IP 的 hash 结果分配,这样每个访问可以固定访问一个后端服务器。
  • url_hash,按照访问 URL 的 hash 结果来分配请求,使得每个URL定向到同一个后端服务器上,主要应用于后端服务器为缓存时的场景。
  • 自定义hash,基于任意关键字作为 hash key 实现 hash 算法的负载均衡
  • fair,按照后端服务器的响应时间来分配请求,响应时间短则优先分配。

示范:在需要使用负载均衡的server中增加

upstream backserver{ 
    ip_hash; 
    server 127.0.0.1:9090 down; (down 表示单前的server暂时不参与负载) 
    server 127.0.0.1:8080 weight=2; (weight 默认为1.weight越大,负载的权重就越大) 
    server 127.0.0.1:6060; 
    server 127.0.0.1:7070 backup; (其它所有的非backup机器down或者忙的时候,请求backup机器) 
} 

proxy_pass http://backserver/; 
1
2
3
4
5
6
7
8
9
  • max_fails :允许请求失败的次数默认为1.当超过最大次数时,返回proxy_next_upstream 模块定义的错误。
  • fail_timeout:max_fails次失败后,暂停的时间。
# 轮询 默认

默认策略,遍历服务器节点列表,逐一分配请求,如果服务器down掉,自动剔除。

轮询即Round Robin,根据Nginx配置文件中的顺序,依次把客户端的Web请求分发到不同的后端服务器。

upstream backserver {
    server 192.168.0.14;
    server 192.168.0.15;
}
1
2
3
4
# 加权轮询 weight

每台服务器有不同的权重,一般权重越大意味着该服务器的性能越好,可以承载更多的请求。

upstream balanceServer {
   server 192.168.0.14 weight=3;
   server 192.168.0.15 weight=7;
}
1
2
3
4

权重越高,在被访问的概率越大,如上例,分别是30%,70%。

# 客户端ip绑定 ip_hash

前述的两种负载均衡方案中,同一客户端连续的Web请求可能会被分发到不同的后端服务器进行处理,因此如果涉及到会话Session,那么会话会比较复杂。常见的是基于数据库的会话持久化。要克服上面的难题,可以使用基于IP地址哈希的负载均衡方案。这样的话,同一客户端连续的Web请求都会被分发到同一服务器进行处理。[将来自同一个ip的请求永远只分配给一台固定的服务器。]

upstream balanceServer {
    ip_hash;
    server 192.168.0.14:88;
    server 192.168.0.15:80;
}
1
2
3
4
5
# 最快响应时间 fair

按后端服务器的响应时间来分配请求,响应时间短的优先分配。

upstream balanceServer {
    fair;
    server 1.1.2.3:80;
    server 1.1.2.4:80;
    server server1;
    server server2;
}
1
2
3
4
5
6
7
# 最小连接 least_conn

将请求优先分配给压力较小的服务器,避免压力大的服务器添加更多的请求。

upstream balanceServer {
    least_conn;
    server 1.1.2.3:80;
    server 1.1.2.4:80;
    server 1.1.2.5:80;
}
1
2
3
4
5
6
# 访问 url_hash

按访问url的hash结果来分配请求,使每个url定向到同一个(对应的)后端服务器,后端服务器为缓存时比较有效。

upstream backserver {
    server squid1:3128;
    server squid2:3128;
    hash $request_uri;
    hash_method crc32;
}
1
2
3
4
5
6

# 配置示例

#user  nobody;
worker_processes  4;
events {
    worker_connections  1024;  # 最大并发数
}
http{
    # 待选服务器列表
    upstream balanceServer {
        server 1.1.2.3:80;
        server 1.1.2.4:80;
        server 1.1.2.5:80;
    }

    server {
        server_name  xx.a.com;
        listen 80;
        location /api {
            proxy_pass http://balanceServer;
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 配置gzip

    gzip                    on;
    gzip_http_version       1.1;
    gzip_comp_level         5;
    gzip_min_length         1000;
    gzip_types text/csv text/xml text/css text/plain text/javascript application/javascript application/x-javascript application/json application/xml;
    gzip_disable    "MSIE [1-6]\.";     # IE6无效
1
2
3
4
5
6
location ~ .*\. (jpg|png|gif)$ {    
    gzip off; #关闭压缩    
    root /data/www/images;
}
location ~ .*\. (html|js|css)$ {    
    gzip on; #启用压缩    
    gzip_min_length 1k; # 超过1K的文件才压缩    
    gzip_http_version 1.1; # 启用gzip压缩所需的HTTP最低版本    
    gzip_comp_level 9; # 压缩级别,压缩比率越高,文件被压缩的体积越小    
    gzip_types text/css application/javascript; # 进行压缩的文件类型   
    root /data/www/html;
}
1
2
3
4
5
6
7
8
9
10
11
12

并不是每个浏览器都支持 gzip的,如何知道客户端是否支持 gzip呢,请求头中的 Accept-Encoding来标识对压缩的支持

image-20210122001003105

启用 gzip同时需要客户端和服务端的支持,如果客户端支持 gzip的解析,那么只要服务端能够返回 gzip的文件就可以启用 gzip了,我们可以通过 nginx的配置来让服务端支持 gzip下面的 responecontent-encoding:gzip,指服务端开启了 gzip的压缩方式。

image-20210122001032928

# gzip

  • 开启或者关闭 gzip模块
  • 默认值为 off
  • 可配置为 on/off

# gziphttpversion

  • 启用 GZip 所需的 HTTP 最低版本
  • 默认值为 HTTP/1.1

HTTP/1.1默认支持 TCP持久连接, HTTP/1.0 也可以通过显式指定 Connection:keep-alive来启用持久连接。对于 TCP持久连接上的 HTTP 报文,客户端需要一种机制来准确判断结束位置,而在 HTTP/1.0中,这种机制只有 Content-Length。而在 HTTP/1.1中新增的 Transfer-Encoding:chunked 所对应的分块传输机制可以完美解决这类问题。

nginx同样有着配置 chunked的属性 chunked_transfer_encoding,这个属性是默认开启的。

Nginx在启用了 GZip的情况下,不会等文件 GZip 完成再返回响应,而是边压缩边响应,这样可以显著提高 TTFB( TimeToFirstByte,首字节时间,WEB 性能优化重要指标)。这样唯一的问题是, Nginx 开始返回响应时,它无法知道将要传输的文件最终有多大,也就是无法给出 Content-Length这个响应头部。

所以,在 HTTP1.0中如果利用 Nginx启用了 GZip,是无法获得 Content-Length的,这导致HTTP1.0中开启持久链接和使用 GZip只能二选一,所以在这里 gzip_http_version默认设置为 1.1

# gzipcomplevel

  • 压缩级别,级别越高压缩率越大,当然压缩时间也就越长(传输快但比较消耗cpu)。
  • 默认值为 1
  • 压缩级别取值为 1-9

# gzipminlength

  • 设置允许压缩的页面最小字节数, Content-Length小于该值的请求将不会被压缩
  • 默认值: 0
  • 当设置的值较小时,压缩后的长度可能比原文件大,建议设置 1000以上

# gzip_types

  • 要采用gzip压缩的文件类型( MIME类型)
  • 默认值: text/html(默认不压缩 js/ css)

# 请求限制

对于大流量恶意的访问,会造成带宽的浪费,给服务器增加压力。往往对于同一 IP 的连接数以及并发数进行限制。关于请求限制主要有两种类型:

  • limit_conn_module 连接频率限制
  • limit_req_module 请求频率限制
# $binary_remote_addr 远程IP地址 zone 区域名称 10m内存区域大小
limit_conn_zone $binary_remote_addr zone=coon_zone:10m;
server {
 limit_conn conn_zone 1;# conn_zone 设置对应的共享内存区域 1是限制的数量
}

# $binary_remote_addr 远程IP地址 zone 区域名称 10m内存区域大小 rate 为请求频率 1s 一次
limit_req_zone $binary_remote_addr zone=req_zone:10m rate=1r/s;
server {
    location / {
        # 设置对应的共享内存区域 burst最大请求数阈值 nodelay不希望超过的请求被延迟
        limit_req zone=req_zone burst=5 nodelay;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 访问控制

快速实现简单的访问限制

关于访问控制主要有两种类型:

  • -http_access_module 基于 IP 的访问控制
  • -http_auth_basic_module 基于用户的信任登陆

经常会遇到希望网站让某些特定用户的群体(比如只让公司内网)访问,或者控制某个uri不让人访问。

以下是基于 IP 的访问控制:

server {
 location ~ ^/index.html {
  # 匹配 index.html 页面 除了 127.0.0.1 以外都可以访问
  deny 127.0.0.1;
  allow all;
 }
}
1
2
3
4
5
6
7
location / {
    deny  192.168.1.100;
    allow 192.168.1.10/200;
    allow 10.110.50.16;
    deny  all;
}
1
2
3
4
5
6

# 配置socket/文件资源

image-20210122001032928image-20210122001032928

# 配置http/https

详细配置请参考下文的配置https/http

# 简单示例【推荐】

image-20210122001032928image-20210122001032928

# 适配PC与移动环境

现在很多网站都存在PC站和H5站两个站点,因此根据用户的浏览环境自动切换站点是很常见的需求。Nginx可以通过内置变量$http_user_agent,获取到请求客户端的userAgent,从而知道用户处于移动端还是PC,进而控制重定向到H5站还是PC站。

location / {
	# 移动端设备匹配
  if ($http_user_agent ~* '(Android|webOS|iPhone|iPad|BlackBerry)') {
    set $mobile_request '1';
  }
  if ($mobile_request = '1') {
    rewrite ^.+ https://mobile.com 
  }
}
1
2
3
4
5
6
7
8
9

# 合并请求

前端性能优化中重要一点就是尽量减少http资源请求的数量。通过nginx-http-concat (opens new window)模块(淘宝开发的第三方模块,需要单独安装)用一种特殊的请求url规则

# 图片处理

在前端开发中,经常需要不同尺寸的图片。现在的云储存基本对图片都提供有处理服务(一般是通过在图片链接上加参数);在前端开发中,我们有时会需要不同尺寸的图片,而一些云服务都提供有带链接上添加参数来获取不同大小图片的服务。我们可以通过使用一个非基本模块(需安装)ngx_http_image_filter_module来实现。

   # 图片缩放处理
    # 这里约定的图片处理url格式:以 mysite-base.com/img/路径访问
    location ~* /img/(.+)$ {
        alias /Users/cc/Desktop/server/static/image/$1; #图片服务端储存地址
        set $width -; #图片宽度默认值
        set $height -; #图片高度默认值
        if ($arg_width != "") {
            set $width $arg_width;
        }
        if ($arg_height != "") {
            set $height $arg_height;
        }
        image_filter resize $width $height; #设置图片宽高
        image_filter_buffer 10M;   #设置Nginx读取图片的最大buffer。
        image_filter_interlace on; #是否开启图片图像隔行扫描
        error_page 415 = 415.png; #图片处理错误提示图,例如缩放参数不是数字
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 防盗链处理

因为被大肆盗链使用图片而开启了防盗链处理**,防盗链处理是我们需要开启来保护服务器的一种方式**。

防盗链的原理就是根据请求头中 referer 得到网页来源,从而实现访问控制。这样可以防止网站资源被非法盗用,从而保证信息安全,减少带宽损耗,减轻服务器压力。

location ~ .*\.(jpg|png|gif)$ { # 匹配防盗链资源的文件类型
    # 通过 valid_referers 定义合法的地址白名单 $invalid_referer 不合法的返回403  
    valid_referers none blocked 127.0.0.1;
    if ($invalid_referer) {
        return 403;
    }
}
1
2
3
4
5
6
7
server {
  # 匹配所有图片
  location ~* \.(gif|jpg|png|bmp)$ {
    # 验证是否为没有来路,或者有来路与域名或白名单进行匹配,也可以写正则,若匹配到字段为0,否则为1
    valid_referers none blocked server_names www.ite.com;
    # 如果验证不通过则返回403错误
    if ($invalid_referer) {
      return 403; 
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11

# 页面内容修改

Nginx可以通过向页面底部或者顶部插入额外的css和js文件,从而实现修改页面内容。

# 性能测试

# ab命令

ab命令全称为:Apache bench,是 Apache 自带的压力测试工具,也可以测试 Nginx、IIS 等其他 Web 服务器。

  • -n 总共的请求数
  • -c 并发的请求数
ab -n 1000 -c 5000 http://127.0.0.1/
1

# 相关链接

https://juejin.cn/post/6844903684967825421

https://juejin.cn/post/6844903793918738440

https://www.kancloud.cn/wizardforcel/nginx-doc/92353

上次更新: 2022/04/15, 05:41:30
×