Nginx基础学习

522 阅读10分钟

Nginx简介

Nginx 是一款轻量级的HTTP服务器,采用事件驱动的异步非阻塞处理方式框架,这让其具有极好的IO性能,时常用于服务端的反向代理和负载均衡

Nginx 对于我们前端工作人员的日常普通开发而言,不仅可以通过它的正向代理和反向代理功能,实现跨域、接口代理等需求,更可以帮助我们将自己不同的项目部署到同一台服务器(为什么一台服务器,因为没钱😄)上面。

Nginx安装

本节以阿里云上的学生机服务器为例,安装ubuntu16.04系统,来讲解如何安装nginx服务器。

  • sudo apt-get update && sudo apt-get upgrade

    apt-get 是一款适用于 ubuntu 系统的应用程序管理器, 主要用于从互联网的软件仓库中搜索、安装、升级、卸载软件或操作系统。

  • sudo apt-get install nginx

    安装nginx

  • nginx -v

    查看安装的 nginx 版本,whereis nginx 命令可以查看 nginx 二进制启动文件的位置,一般 nginx 的安装位置在 /etc/nginx文件夹里面

Nginx配置文件

nginx.conf 是 nginx 的总配置文件,位于/etc/nginx/ 文件夹中,查看该文件 sudo vim nginx.conf

#运行用户,默认即是nginx,可以不进行设置
user  nginx;
#nginx进程,一般设置为和CPU核数一样
worker_processes  1;   
#进程pid存放位置
pid        /run/nginx.pid;
events {
    worker_connections  1024; #单个后台进程的最大并发数
  	# multi_accept on/off;  # 一个工作进程可以同时接受 所有的新连接/一个新连接
}
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访问日志存放位置
    error_log  /var/log/nginx/error.log warn;  #错误日志存放目录
    tcp_nodelay on;  #禁用Nagle算法,即数据包立即发送出去,小的数据包不等待直接传输
    sendfile        on;   #开启高效传输模式
    tcp_nopush     on;    #sendfile为on时这里也应该设为on,数据包会累积一下再一起传输,可以提高一些传输效率
    types_hash_max_size 2048;  #影响散列表的冲突率。types_hash_max_size越大,就会消耗更多的内存,但散列key的冲突率会降低,检索速度就更快。types_hash_max_size越小,消耗的内存就越小,但散列key的冲突率可能上升
    server_tokens off;  #nginx版本是否在浏览器请求中显示
    keepalive_timeout  65;  #保持连接的时间,也叫超时时间
    gzip  on;  #开启gzip压缩
    client_max_body_size 100M; #客户端上传的body的最大值。超过最大值就会发生413(Request Entity Too Large)错误
    include /etc/nginx/conf.d/*.conf; #包含的子配置项位置和文件
    include /etc/nginx/sites-enabled/*;  #默认首页显示的文件储存位置, 里面的default文件是一个指向/etc/nginx/sites-available/default的软链接

/etc/nginx/conf.d/*.conf 为子配置文件,默认第一次安装后会有一个默认的子配置文件 default.conf 具体如下

server {
    listen       80;   #配置监听端口
    server_name  localhost;  //配置域名

    #charset koi8-r;     
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;     #服务默认启动目录
        index  index.html index.htm;    #默认访问文件
    }

    #error_page  404              /404.html;   # 配置404页面

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;   #错误状态码的显示页面,配置后需要重启
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

服务器上的 /usr/share/nginx/html/index.html文件即是首页默认显示的网页;此时,访问你的本机公网ip地址,即可看到该网页。

Nginx服务器的操作

# nginx 启动/重启/停止
sudo service nginx start/restart/stop
# 重新加载配置|重启|停止|退出 nginx
sudo nginx -s reload|reopen|stop|quit 
# nginx 配置文件检查
sudo nginx -t

Nginx的正向代理与反向代理

  • 正向代理

    正向代理-客户端的请求发送到目标服务器的中间要经过一层/几层代理服务器,代理服务器转发请求至目标服务器,拿到目标服务器的响应后再返回给客户端,典型的应用-VPN && 抓包工具(charles)

    A机器在墙外,不能访问C墙外机器,但是A机器能访问B机器(代理服务器),B机器能访问C机器,这个时候A机器可以发送请求B机器,B机器去访问C机器,拿到响应后再返回给A机器,这就达到了A机器访问C机器的需求;

    A1机器在墙外,可以直接访问墙外C机器,无需B机器作为中间人;

    缺陷: 这种情况下,B机器通过代理人的身份,能够拿到A所有的请求信息,此时A的一些隐私也随之暴露,这就带来了安全隐患。

正向代理示意图

  • 反向代理

    反向代理-代理服务器接收局内网外的客户端请求,根据不同的请求转发到不同的内网服务器上,拿到响应后再返回给客户端。代理服务器和真正server服务器可以直接互相访问,属于一个LAN(服务器内网);代理对用户是透明的,即无感知。

    内网服务器不对外暴露服务,仅允许代理服务器访问,客户端要想访问内网服务器只能通过代理服务器

    优点:

    • 安全。保证内网服务器不对外暴露信息,代理服务器起到中间人作用。即客户端将无法直接通过请求访问真正的内容服务器,必须首先通过Nginx。Nginx层可以配置将危险或者没有权限的请求内容过滤掉,保证服务器的安全。
    • 负载均衡。例如一个网站的内容被部署在若干台服务器上(集群服务器),Nginx内部模块提供的多种负载均衡算法可以将接收到的客户端请求“均匀地”分配到这个集群中所有的服务器上,从而实现服务器压力的负载均衡。此外,nginx还带有健康检查功能(服务器心跳检查),会定期轮询向集群里的所有服务器发送健康检查请求,来检查集群中是否有服务器处于异常状态,一旦发现某台服务器异常,那么在以后代理进来的客户端请求都不会被发送到该服务器上(直到后面的健康检查发现该服务器恢复正常),从而保证客户端访问的稳定性。

反向代理示意图

一般使用了Nginx的大型网站都是使用了Nginx的反向代理功能。

Nginx部署静态项目

假如你想把自己的文章博客或者利用 webpack 打包后生成的静态资源项目放置到自己的服务器上,并且别人可以通过访问域名(域名访问的话涉及到域名绑定ip并且要进行域名备案,详情戳如何将自己的网站部署到阿里云的服务器)或者ip访问你的博客

Nginx的路径匹配规则

location [=|~|~*|^~] /uri/ { … }

符号 说明
= 表示精确匹配。只有请求的 url 路径与后面的字符串完全相等时,才会命中
~ 表示该规则是使用正则定义的,区分大小写
~* 表示该规则是使用正则定义的,不区分大小写
^~ 表示如果该符号后面的字符是最佳匹配,采用该规则,不再进行后续的查找

匹配任意请求

location / { 
}

精确匹配, 如 /index.html

location = /index {
    
}

匹配所有以/a/b/开头的路径, 如 /a/b/test.html

location /a/b/ {
    
}

匹配 /images/ 路径,匹配后不再进行后续查找

location ^~ /images/ {
    
}

匹配所有以 png|jpg|jpeg (不区分大小写)结尾的后缀文件

location ~* \.(png|jpg|jpeg)$ {
    
}

更多匹配规则,参考文章一文弄懂Nginx的location匹配

访问静态文件

  • /etc/nginx/conf.d 文件夹中配置相应的配置文件,如 static-example.conf
server {
    listen 80;
    server_name ip;
    locaton / {
        root /home/test;
        index index.htm index.html;
    }
}
  • 保存后执行 sudo nginx -t && sudo nginx -s reload && sudo service nginx restart, 检查配置文件,重新载入配置文件,重启 nginx 服务
  • 如配置文件所述,在你的服务器的文件夹 /home/test/ 下面创建 index.html后,访问ip地址,就可以看到你部署的网站了
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>我的博客</title>
</head>
<body>
  我的第一篇博客😝
</body>
</html>


自定义错误页

假如你想让你的网站更为友好,你可以定义自己的错误页面,就比如 github 的访问错误提示页

当你输入 github 网站上不存在的路由时,便会展示该页面。我们在 nginx 中定义错误页很简单

  • 自定义错误页指向网页文件
server {
    listen 80;
    server_name ip;
    error_page 404 /404.html;  # 单独为404错误指定网页文件
    locaton / {
        root /home/test;  # 网站目录文件夹
        index index.htm index.html;
    }
}

当然,你需要在网站目录文件夹下创建响应的 404.html 文件。

当然,你可以为多个错误码指向同一个页面: error_page 403 404 /404.html

  • 自定义错误网页指向某个地址
server {
    listen 80;
    server_name ip;
    error_page 404 http://www.baidu.com;  # 错误页指向百度首页网址😁
    locaton / {
        root /home/test;  # 网站目录文件夹
        index index.htm index.html;
    }
}

自定义访问权限

  • 屏蔽某个地址过来的请求
server {
    listen 80;
    server_name ip;
    error_page 404 http://www.baidu.com;  # 错误页指向百度首页网址😁
    deny 10.0.1.0;  # 禁止该ip访问
    locaton / {
        root /home/test;  # 网站目录文件夹
        index index.htm index.html;
    }
}
  • 屏蔽某个地址段的访问

deny 10.0.1.0/24;

  • 单独允许某个ip访问
allow 10.0.1.25; 
deny all;
  • 网站目录的访问控制
location = /test {
    allow 202.202.12.145; # nginx采用先声明先生效的原则,如果先声明deny all; 再 allow 某个ip,这个时候将拒绝所有地址段的访问
    deny all; #只允许某个ip访问 /test 路径
}
  • 网站文件的访问控制
location = ~* \.(png|jpg|pdf) {
    allow 202.202.12.145;
    deny all; #只允许某个ip访问网站目录下的后缀名为png|jpg|pdf文件,不区分大小写
}

关于更多权限的配置 => nginx_http_access_module

Nginx 部署 Nodejs 项目

无论你是想部署自己的 API 服务到自己的服务器,还是想将自己的服务端项目(Nodejs + express/koa + ejs/pug)部署到自己的服务器,又或者是将好几个这样的项目运行在不同的端口,Nginx 都可以很好地解决这些问题。

  • 部署单个 Nodejs 服务端项目

    当我们使用 node server.js 来启动自己项目的入口文件时,如果碰到一些意外错误时,Nodejs都会自动退出,我们可以借助 PM2 来守护 Nodejs 进程,当意外退出时能自动重启,使 Nodejs 进程永驻。

    直接ip访问/域名访问

    为了不暴露项目在服务器实际运行的端口,nginx 一般采用端口反向代理的方式访问实际的应用程序

    server {
      listen 80;
      server_name ip || www.fizz.com;
      location / {
          proxy_set_header X-Real-IP $remote_addr; # 将实际客户端的ip传递给实际服务端
      	proxy_set_header X-Forward-For $proxy_add_x_forwarded_for; # 记录客户端到达nginx代理服务器的代理服务器的ip过程
    
      	proxy_set_header Host $http_host; # nginx代理服务器传递给实际服务器的主机名
      	proxy_set_header X-Nginx-Proxy true; # 告诉实际服务器是否使用了nginx代理
    
      	proxy_redirect off; # 是否启动修改实际服务器的地址,即实际响应服务器的响应url信息
          proxy_pass http://127.0.0.1:8080; # 直接访问ip就可以访问到服务器本地跑在8080端口的项目
      }
    }
    
  • 多端口代理多个应用程序

    • 如果你的 ip 绑定了域名,你可以将不同的应用程序跑在服务器的不同端口,使用 nginx 反向代理功能,将来自该域名下的不同子域名代理到不同端口上,实现多个应用程序部署到同一台服务器上
    • 如果没绑定域名,那就使用 ip:port 的方式访问不同的应用程序

fizz-8080.conf

  server {
    listen 80;
    server_name a.fizz.com;
    location / {
        proxy_set_header X-Real-IP $remote_addr; # 将实际客户端的ip传递给实际服务端
		proxy_set_header X-Forward-For $proxy_add_x_forwarded_for; # 记录客户端到达nginx代理服务器的代理服务器的ip过程

		proxy_set_header Host $http_host; # nginx代理服务器传递给实际服务器的主机名
		proxy_set_header X-Nginx-Proxy true; # 告诉实际服务器是否使用了nginx代理

		proxy_redirect off; # 是否启动修改实际服务器的地址,即实际响应服务器的响应url信息
        proxy_pass http://127.0.0.1:8080; # 直接访问ip就可以访问到服务器本地跑在8080端口的项目
    }
  }

fizz-8081.conffizz-8082.conf 文件类似,都位于 conf.d 文件夹下面。

  • 负载均衡

    当你的网站流量非常大的时候,除了优化本身应用程序的高并发性能,一般会采用多台服务器同时部署同一个应用程序,来达到分流的作用;同时,当一台服务器宕机时,别的服务器依然能够访问到应用程序,提高了网站的健壮性。不同的服务器如果性能不一样,我们可以根据其承载能力适配其相应的分流权重系数。

    负载均衡策略主要有轮询,加权轮询,最少连接数以及源地址哈希法(IP Hash):

    • 轮询:将请求按顺序轮流地分配到后端服务器上,它均衡地对待后端的每一台服务器,而不关心服务器实际的连接数和当前的系统负载。

    访问 http://a.fizz.com,Nginx 服务器会将请求按顺序分发到 a1.fizz.coma2.fizz.coma3.fizz.com 所在的服务器上, 最终负载比例为 1 : 1 : 1

    http {
        upstream backend {
            server a1.fizz.com;
            server a2.fizz.com;
            server a3.fizz.com;
        }
        server {
            listen 80;
            server_name a.fizz.com;
            location / {
                proxy_pass http://backend;
            }
        }
    }
    

    轮询只是简单实现请求的顺序转发,并没有考虑不同服务器的性能差异

    • 加权轮询:不同的后端服务器可能机器的配置和当前系统的负载并不相同,因此它们的抗压能力也不相同。给配置高、负载低的机器配置更高的权重,让其处理更多的请;而配置低、负载高的机器,给其分配较低的权重,降低其系统负载,加权轮询能很好地处理这一问题,并将请求顺序且按照权重分配到后端。

    访问 http://a.fizz.com,Nginx 服务器会将请求按顺序和权重分发到 a1.fizz.coma2.fizz.coma3.fizz.com 所在的服务器上,最终负载比例为 3 : 2 : 1

    http {
        upstream backend {
            server a1.fizz.com weight=3;
            server a2.fizz.com weight=2;
            server a3.fizz.com;
        }
        server {
            listen 80;
            server_name a.fizz.com;
            location / {
                proxy_pass http://backend;
            }
        }
    }
    

    加权轮询设置了初始时服务器的权重,该权重在服务器运行过程中是固定的,没有考虑运行过程中的服务器状态

    • 最小连接数:由于后端服务器的配置不尽相同,对于请求的处理有快有慢,最小连接数法根据后端服务器当前的连接情况,动态地选取其中当前积压连接数最少的一台服务器来处理当前的请求,尽可能地提高后端服务的利用效率,将负责合理地分流到每一台服务器。

    访问 http://a.fizz.com,Nginx 服务器会将请求转发到a1.fizz.coma2.fizz.coma3.fizz.com 中连接数较少的服务器上,最终负载比例为非固定

    http {
        upstream backend {
            least_conn;
            server a1.fizz.com;
            server a2.fizz.com;
            server a3.fizz.com;
        }
        server {
            listen 80;
            server_name a.fizz.com;
            location / {
                proxy_pass http://backend;
            }
        }
    }
    

    考虑了后端服务器的连接数情况,并没有完全考虑服务器的整体性能

    • 源地址哈希(IP Hash):根据获取客户端的IP地址,通过哈希函数计算得到一个数值,用该数值对服务器列表的大小进行取模运算,得到的结果便是客服端要访问服务器的序号。采用源地址哈希法进行负载均衡,同一IP地址的客户端,当后端服务器列表不变时,它每次都会映射到同一台后端服务器进行访问。

    访问 http://a.fizz.com,由于a1.fizz.coma2.fizz.coma3.fizz.com 三个服务需要共享 session,使用该策略可以实现某一客户端的请求固定转发至某一服务器

    http {
        upstream backend {
            ip_hash;
            server a1.fizz.com;
            server a2.fizz.com;
            server a3.fizz.com;
        }
        server {
            listen 80;
            server_name a.fizz.com;
            location / {
                proxy_pass http://backend;
            }
        }
    }
    

    保证同一个客户端请求转发到同一个后台服务器实现了session保存,然而当该后台服务器发生故障时,访问该服务器的客户端将访问失败

    • 动态负载均衡策略

      类似于加权轮询策略,可以通过对于后端服务器集群的状态监测,量化不同服务器的性能差异,来周期性调整服务器的比重来实现权重的动态调整。这个一般通过 Nginx 的第三方模块来实现

Nginx官方文档