牛逼的 NGINX

臭大佬 2021-01-17 19:37:00 2470
linux 
简介 它是一款免费开源的高性能 HTTP 代理服务器及反向代理服务器(Reverse Proxy)产品,同时它还可以提供 IMAP/POP3 邮件代理服务等功能。

简介

官方网站为:http://nginx.org/ 。它是一款免费开源的高性能 HTTP 代理服务器及反向代理服务器(Reverse Proxy)产品,同时它还可以提供 IMAP/POP3 邮件代理服务等功能。

Nginx 配置介绍

我从宝塔里面拿一个完整的网站配置出来。

#######   Nginx的main(全局配置)文件

# 指定nginx运行的用户及用户组,默认为www
user  www www;

# 开启的线程数,一般跟逻辑CPU核数一致
worker_processes auto;

# 定位全局错误日志文件,级别以notice显示,还有debug,info,warn,error,crit模式,debug输出最多,crir输出最少,根据实际环境而定
error_log  /www/wwwlogs/nginx_error.log  crit;
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

# 指定进程id的存储文件位置
pid        /www/server/nginx/logs/nginx.pid;

# 指定一个nginx进程打开的最多文件描述符数目,受系统进程的最大打开文件数量限制
worker_rlimit_nofile 51200;

# events 块涉及的指令主要影响 Nginx 服务器与用户的网络连接,常用的设置包括是否开启对多 work process 下的网络连接进行序列化,是否允许同时接收多个网络连接,选取哪种事件驱动模型来处理连接请求,每个 word process 可以同时支持的最大连接数等。
events
    {
        # 设置工作模式为epoll,除此之外还有select,poll,kqueue,rtsig和/dev/poll模式
        use epoll;    
        # 定义每个进程的最大连接数,受系统进程的最大打开文件数量限制。
        worker_connections 51200;
        # 打开同时接受多个新网络连接请求的功能。
        multi_accept on;
    }

# http全局块配置的指令包括文件引入、MIME-TYPE 定义、日志自定义、连接超时时间、单链接请求数上限等。
http
    {
        # 主模块指令,实现对配置文件所包含的文件的设定,可以减少主配置文件的复杂度,DNS主配置文件中的zonerfc1912,acl基本上都是用include语句。
        include       mime.types;
        #include luawaf.conf;

        include proxy.conf;
        # 核心模块指令,指令默认设置为二进制流,也就是当文件类型未定义时使用这种方式
        default_type  application/octet-stream;


        # 下面代码为日志格式的设定,main为日志格式的名称,可自行设置,后面引用
        #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
        #                  '$status $body_bytes_sent "$http_referer" '
        #                  '"$http_user_agent" "$http_x_forwarded_for"';

        # 引用日志main
        #access_log  logs/access.log  main;

        # 设置允许客户端请求的最大的单个文件字节数
        #client_max_body_size 20M;
        # 指定来自客户端请求头的headebuffer大小
        #client_header_buffer_size  32k;
        # 指定连接请求试图写入缓存文件的目录路径
        #client_body_temp_path /dev/shm/client_body_temp;
        # 指定客户端请求中较大的消息头的缓存最大数量和大小,目前设置为4个32KB
        #large client_header_buffers 4 32k;

        #设定请求缓存  
        server_names_hash_bucket_size 512;
        client_header_buffer_size 32k;
        large_client_header_buffers 4 32k;
        client_max_body_size 50m;
        # 开启高效文件传输模式
        sendfile   on;
        # 开启防止网络阻塞
        tcp_nopush on;

        # 设置客户端连接保存活动的超时时间
        keepalive_timeout 60;
        # 开启防止网络阻塞
        tcp_nodelay on;

        # 设置客户端请求读取超时时间
        #client_header_timeout 10;
        # 设置客户端请求主体读取超时时间
        #client_body_timeout 10;
        # 用于设置相应客户端的超时时间
        #send_timeout

        #### fastcgi参数
        # 连接到后端fastcgi超时时间
        fastcgi_connect_timeout 300;
        # 向fastcgi请求超时时间(这个指定值已经完成两次握手后向fastcgi传送请求的超时时间)
        fastcgi_send_timeout 300;
        # 接收fastcgi应答超时时间,同理也是2次握手后
        fastcgi_read_timeout 300;# 读取fastcgi应答第一部分需要多大缓冲区,该值表示使用1个64kb的缓冲区读取应答第一部分(应答头),可以设置为fastcgi_buffers选项缓冲区大小
        fastcgi_buffer_size 64k;    
        # 指定本地需要多少和多大的缓冲区来缓冲fastcgi应答请求,假设一个php或java脚本所产生页面大小为256kb,那么会为其分配4个64kb的缓冲来缓存;若页面大于256kb,那么大于的256kb的部分会缓存到fastcgi_temp指定路径中,这并非是个好办法,内存数据处理快于硬盘,一般该值应该为站点中php/java脚本所产生页面大小中间值,如果站点大部分脚本所产生的页面大小为256kb,那么可把值设置为16 16k,4 64k等
        fastcgi_buffers 4 64k;
        # 默认值是fastcgi_buffer的2倍
        fastcgi_busy_buffers_size 128k;
        # 写入缓存文件使用多大的数据块,默认值是fastcgi_buffer的2倍
        fastcgi_temp_file_write_size 256k;
        # 是否传递4xx和5xx错误信息到客户端
        fastcgi_intercept_errors on;

        #### HttpGZip模块配置
        # 开启gzip压缩
        gzip on;
        # 设置允许压缩的页面最小字节数
        gzip_min_length  1k;
        # 申请4个单位为16K的内存作为压缩结果流缓存
        gzip_buffers     4 16k;
        # 设置识别http协议的版本,默认为1.1
        gzip_http_version 1.1;
        # 指定gzip压缩比,1-9数字越小,压缩比越小,速度越快
        gzip_comp_level 2;
        # 指定压缩的类型
        gzip_types     text/plain application/javascript application/x-javascript text/javascript text/css application/xml;
        #让前端的缓存服务器进过gzip压缩的页面
        gzip_vary on;
        # Nginx做为反向代理的时候启用
        gzip_proxied   expired no-cache no-store private auth;
        # 通过表达式,表明哪些UA头不使用gzip压缩
        gzip_disable   "MSIE [1-6]\.";

        # 对客户端访问目录和文件的访问频率和次数进行限制
        limit_conn_zone $binary_remote_addr zone=perip:10m;
        limit_conn_zone $server_name zone=perserver:10m;

        # 隐藏版本号开关
        server_tokens off;
        # 访问日志
        access_log off;

# 最常见的配置是本虚拟机主机的监听配置和本虚拟主机的名称或IP配置,宝塔等软件通过 include引入多个网站配置文件
server
    {
        # 设置网络监听
        # listen *:80 | *:8080 #监听所有80端口和8080端口
        # listen  IP_address:port   #监听指定的地址和端口号
        # listen  IP_address     #监听指定ip地址所有端口
        # listen port     #监听该端口的所有IP连接
        listen 888;
        # 设置主机域名
        # server_name choudalao.com www.choudalao.com #多个域名
        # server_name 192.168.1.1 #  IP 地址的虚拟主机配置
        server_name www.choudalao.com;

        # 设置访问的语言编码
        #charset koi8-r;

        # 设置虚拟主机访问日志的存放路径及日志的格式为main
        #access_log  logs/host.access.log  main;

        # 设置网站的默认首页。
        index index.html index.htm index.php;
        # 访问路径
        root  /www/server/phpmyadmin;
            location ~ /tmp/ {
                return 403;
            }

        #SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则
        #error_page 404/404.html;
        #SSL-END

        #ERROR-PAGE-START  错误页配置,可以注释、删除或修改
        #error_page 404 /404.html;
        #error_page 502 /502.html;
        #ERROR-PAGE-END

        #PHP-INFO-START  PHP引用配置,可以注释或修改
        include enable-php-74.conf;
        #PHP-INFO-END

        #禁止访问的文件或目录
        location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)
        {
            return 404;
        }

        #一键申请SSL证书验证目录相关设置
        location ~ \.well-known{
            allow all;
        }
    }
    # 引入其他网站配置
    include /www/server/panel/vhost/nginx/*.conf;
}

常用功能

反向代理

在说反向代理之前,先说说什么是代理以及正向代理。

代理

顾名思义,代理就是自己让别人帮忙做某事,举几个职业便于理解,代理律师、代理记账等职业在我们工作中是经常能听到的。他们就是代替我们去做我们想做的事的。

正向代理

最常见的就是我们翻墙的候使用的VPN,,VPN的中转服务,是把我们的IP地址转化成VPN服务器公网IP,我们请求或接受任何数据都会通过这个VPN 服务器然后传入到我们本机。连上VPN后输出我们的IP地址,变成代理ip了。

正向代理服务器位于客户端和服务器之间,为了向服务器获取数据,客户端要向代理服务器发送一个请求,并指定目标服务器,代理服务器将目标服务器返回的数据转交给客户端。这里客户端是要进行一些正向代理的设置的。

反向代理

客户端向服务器发送请求时,会首先经过 Nginx 服务器,由服务器将请求分发到相应的 WEB 服务器。正向代理是代理客户端,而反向代理则是代理服务器,Nginx 在提供反向代理服务方面,通过使用正则表达式进行相关配置,采取不同的转发策略,配置相当灵活,而且在配置后端转发请求时,完全不用关心网络环境如何,可以指定任意的IP地址和端口号,或其他类型的连接、请求等。

反向代理和正向代理的区别就是:正向代理代理客户端,反向代理代理服务器。

反向代理,其实客户端对代理是无感知的,因为客户端不需要任何配置就可以访问,我们只需要将请求发送到反向代理服务器,由反向代理服务器去选择目标服务器获取数据后,在返回给客户端,此时反向代理服务器和目标服务器对外就是一个服务器,暴露的是代理服务器地址,隐藏了真实服务器IP地址。

实例

来个反向代理的配置栗子:

server
{
    listen 80;
    server_name admin-api.choudalao.com;

    # 其他配置 ....

    # 反向代理配置
    location / {
         proxy_pass http://127.0.0.1:9777;# http://xxx.com;# 也可以是域名
         index  index.html index.htm index.php;
    }
}

当我们访问 admin-api.choudalao.com时,处理请求的是 http://127.0.0.1:9777,这样就实现了反向代理。

负载均衡

一方面是将单一的重负载分担到多个网络节点上做并行处理,每个节点处理结束后将结果汇总返回给用户,这样可以大幅度提高网络系统的处理能力;另一方面将大量的前端并发请求或数据流量分担到多个后端网络节点分别处理,这样可以有效减少前端用户等待相应的时间。而 Nginx 负载均衡都是属于后一方面,主要是对大量前端访问或流量进行分流,已保证前端用户访问效率,并可以减少后端服务器处理压力。

配置说明

# upstream将创建一个上游服务配置项,用于交给proxy_pass 转发ip.
upstream bb.com {
    server 127.0.0.1:1111;
    server 127.0.0.1:2222;
}

upstream cc.com {
    # weight表示权重,越大请求权重越大
    server 127.125.0.1:80 weight=5;
    server 123.123.123.123:8081 weight=2;

    # 该指令就是告诉 nginx 服务器,同一个 IP 地址客户端发送的请求都将分发到同一个服务器进行处理。
    # ip_hash;
    #根据服务器处理请求的时间来进行负载,处理请求越快,也就是响应时间越短的优先分配。
    # fair;
}

server {
    listen       80;
    server_name  dev.host.net;

    location / {
        proxy_pass http://bb.com;
        index index.php index.html;
        autoindex  off;
    }

    # 访问localhost的cc模块
    location /cc/ {
        # proxy_pass代理了http://cc.com,获取到upstream中cc.com的配置
        proxy_pass http://cc.com;
        index index.php index.html;
        autoindex  off

    }
}

实例

本案例是在win10phpstudy下实现的,配置三个站点,
dev.host.net(监听80端口)
dev.localhost.net(监听1111端口)
dev.localhost1.net(监听2222端口)

dev.localhost.netdev.localhost1.net根目录下分别有个index.php文件,内容分别如下,
dev.localhost.netindex.php

<?php  
echo 'dev.localhost.net';

dev.localhost1.netindex.php

<?php  
echo 'dev.localhost1.net';

nginx配置分别如下:

# dev.host.net配置文件
upstream bb.com {
    # weight表示权重,越大请求权重越大
    server 127.0.0.1:1111 weight=5;
    server 127.0.0.1:2222 weight=2;

    # 该指令就是告诉 nginx 服务器,同一个 IP 地址客户端发送的请求都将分发到同一个服务器进行处理。
    # ip_hash;
    #根据服务器处理请求的时间来进行负载,处理请求越快,也就是响应时间越短的优先分配。
    # fair;
}

server {
        listen        80;
        server_name  dev.host.net;
        root   "D:/phpstudy_pro/WWW/dev.host.net";
        location / {
             proxy_pass http://bb.com;
            index index.php index.html error/index.html;
            include D:/phpstudy_pro/WWW/dev.host.net/nginx.htaccess;
            autoindex  off;
        }
        location ~ \.php(.*)$ {
            fastcgi_pass   127.0.0.1:9003;
            fastcgi_index  index.php;
            fastcgi_split_path_info  ^((?U).+\.php)(/?.+)$;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            fastcgi_param  PATH_INFO  $fastcgi_path_info;
            fastcgi_param  PATH_TRANSLATED  $document_root$fastcgi_path_info;
            include        fastcgi_params;
        }
}
# dev.localhost.net配置文件
server {
        listen        1111;
        server_name  dev.localhost.net;
        root   "D:/phpstudy_pro/WWW/dev.localhost.net";
        location / {
            index index.php index.html error/index.html;
            include D:/phpstudy_pro/WWW/dev.localhost.net/nginx.htaccess;
            autoindex  off;
        }
        location ~ \.php(.*)$ {
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_split_path_info  ^((?U).+\.php)(/?.+)$;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            fastcgi_param  PATH_INFO  $fastcgi_path_info;
            fastcgi_param  PATH_TRANSLATED  $document_root$fastcgi_path_info;
            include        fastcgi_params;
        }
}
# dev.localhost1.net配置文件
server {
        listen        2222;
        server_name  dev.localhost1.net;
        root   "D:/phpstudy_pro/WWW/dev.localhost1.net";
        location / {
            index index.php index.html error/index.html;
            include D:/phpstudy_pro/WWW/dev.localhost1.net/nginx.htaccess;
            autoindex  off;
        }
        location ~ \.php(.*)$ {
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_split_path_info  ^((?U).+\.php)(/?.+)$;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            fastcgi_param  PATH_INFO  $fastcgi_path_info;
            fastcgi_param  PATH_TRANSLATED  $document_root$fastcgi_path_info;
            include        fastcgi_params;
        }
}

配置好后重启nginx,访问 http://dev.host.net/

刷新页面,可以看到出现的内容有变化,而且weight值大的出现的频率相对来说大,这样就实现了简单的负载均衡,

问题

集群环境下的 session 共享,如何解决这个问题?

我们知道一个请求在经过一个服务器处理时,服务器会保存相关的会话信息,比如session,但是该请求如果第一个服务器没处理完,通过nginx轮询到第二个服务器上,那么这个服务器是没有会话信息的。

  最典型的一个例子:用户第一次进入一个系统是需要进行登录身份验证的,首先将请求跳转到 服务器1 进行处理,登录信息是保存 在 服务器1 上的,这时候需要进行别的操作,那么可能会将请求轮询到 服务器2 上,那么由于 服务器2 没有保存会话信息,会以为该用户没有登录,然后继续登录一次,如果有多个服务器,每次第一次访问都要进行登录,这显然是很影响用户体验的。

方法一:中间件存储

选择一个中间件,将登录信息保存在一个中间件上,这个中间件可以为 Redis 这样的数据库。那么第一次登录,我们将session 信息保存在 Redis 中,跳转到第二个服务器时,我们可以先去Redis上查询是否有登录信息,如果有,就能直接进行登录之后的操作了,而不用进行重复登录。

方法二:ip hash取模分组

根据客户端的IP地址划分,每次都将同一个 IP地址发送的请求都分发到同一个服务器,那么也不会存在 session 共享的问题。

我们在 upstream 指令块中增加了 ip_hash 指令。该指令就是告诉 nginx 服务器,同一个 IP 地址客户端发送的请求都将分发到同一个服务器进行处理。

我们来实现ip hash取模分组,把上面的dev.host.net配置修改如下

upstream bb.com {
    # 该指令就是告诉 nginx 服务器,同一个 IP 地址客户端发送的请求都将分发到同一个服务器进行处理。
    ip_hash;
    # weight 将失效
    server 127.0.0.1:1111 weight=5;
    server 127.0.0.1:2222 weight=2;
}
server {
    listen       80;
    server_name  dev.host.net;

    location / {
        proxy_pass http://bb.com;
        index index.php index.html;
    }
    # 其他配置
}

重启nignx访问 dev.host.net

发现刷新n次输出的结果都是dev.localhost.net

Web 缓存

Nginx 可以作为前置缓存服务器,它被用于缓存前端请求,从而提高 Web服务器的性能。Nginx 会对用户已经访问过的内容在服务器本地建立副本,这样在一段时间内再次访问该数据,就不需要通过 Nginx 服务器向后端发出请求。减轻网络拥堵,减小数据传输延时,提高用户访问速度。

配置

#### http模块
http {

    ### 其他配置
    #.....
    #要想开启nginx的缓存功能,需要添加此处的两行内容!
    #设置Web缓存区名称为cache_one,内存缓存空间大小为500M,缓存的数据超过1天没有被访问就自动清除;访问的缓存数据,硬盘缓存空间大小为30G
    proxy_cache_path /usr/local/nginx/proxy_cache_path levels=1:2 keys_zone=cache_one:500m inactive=1d max_size=30g;

    #创建缓存的时候可能生成一些临时文件存放的位置
    proxy_temp_path /usr/local/nginx/proxy_temp_path;

}

### server块
server {
     listen 888;
     server_name www.choudalao.com;

     # 其他配置
     #....

    location / {
        # 其他配置
        #....
        #使用Web缓存区cache_one,已在nginx.conf的缓存配置中命名的。
        proxy_cache cache_one;
        #对不同HTTP状态码缓存设置不同的缓存时间
        proxy_cache_valid 200 206 304 301 302 10d;
        #设置Web缓存的Key值,Nginx根据Key值md5哈希存储缓存,这里根据"域名,URI,
        #参数"组合成Key
        proxy_cache_key $uri;

        proxy_set_header Host $host:$server_port;

        proxy_set_header X-Real-IP $remote_addr;

        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        #proxy_connect_timeout 300;             ##跟后端服务器连接超时时间,发起握手等候响应时间
        #proxy_send_timeout 300;                ##后端服务器回传时间,就是在规定时间内后端服务器必须传完所有数据
        #proxy_read_timeout 600;                ##连接成功后等待后端服务器的响应时间,已经进入后端的排队之中等候处理
        #proxy_buffer_size 256k;                ##代理请求缓冲区,会保存用户的头信息以供nginx进行处理
        #proxy_buffers 4 256k;                  ##同上,告诉nginx保存单个用几个buffer最大用多少空间
        #proxy_busy_buffers_size 256k;          ##如果系统很忙时候可以申请最大的proxy_buffers
        #proxy_temp_file_write_size 256k;       ##proxy缓存临时文件的大小
    }
}

实例,

本实例在win10phpstudy环境下测试,

新建如下两个目录
D:\phpstudy_pro\Extensions\Nginx1.15.11\weblog\proxy_cache_pathD:\phpstudy_pro\Extensions\Nginx1.15.11\weblog\proxy_temp_path

nginx.conf中添加如下配置

#### http模块
http {

    ### 其他配置
    #.....
    #要想开启nginx的缓存功能,需要添加此处的两行内容!
    #设置Web缓存区名称为cache_one,内存缓存空间大小为500M,缓存的数据超过1天没有被访问就自动清除;访问的缓存数据,硬盘缓存空间大小为30G
    proxy_cache_path D:/phpstudy_pro/Extensions/Nginx1.15.11/weblog/proxy_cache_path levels=1:2 keys_zone=cache_one:500m inactive=1d max_size=30g;

    #创建缓存的时候可能生成一些临时文件存放的位置
    proxy_temp_path D:/phpstudy_pro/Extensions/Nginx1.15.11/weblog/proxy_temp_path;

}

我们修改上面 dev.localhost.net 的配置

server {
    #其他配置
    #....
     location / {
            index index.php index.html error/index.html;
            include D:/phpstudy_pro/WWW/dev.localhost.net/nginx.htaccess;
            autoindex  off;
            #使用Web缓存区cache_one,已在nginx.conf的缓存配置中命名的。
            proxy_cache cache_one;
            #对不同HTTP状态码缓存设置不同的缓存时间
            proxy_cache_valid 200 206 304 301 302 10d;
            #设置Web缓存的Key值,Nginx根据Key值md5哈希存储缓存,这里根据"域名,URI,
            #参数"组合成Key
            proxy_cache_key $host$uri$is_args$args;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
        }
}

dev.localhost.net网站根目录下把index.php改成index.html.并在同级创建img目录,并放一张图片上去。

index.html里面代码如下:

<!DOCTYPE html>
<html>
<body>
<h1>测试</h1>
<img src="./img/QQ图片20201104180508.png">
</body>
</html>

重启nginx,访问 http://127.0.0.1:1111/

然后删除图片

再次访问

已经缓存起来了,至于删除缓存,需要用到 proxy_cache_purge模块,感兴趣的去研究一下。

nginx与php-fpm的结合

www.example.com||Nginx||路由到www.example.com/index.php||加载nginx的fast-cgi模块||fast-cgi监听127.0.0.1:9000地址||www.example.com/index.php请求到达127.0.0.1:9000||php-fpm 监听127.0.0.1:9000||php-fpm 接收到请求,启用worker进程处理请求||php-fpm 处理完请求,返回给nginx||nginx将结果通过http返回给浏览器

nginx 解决跨域

前端 http://localhost:3200
后端 http://localhost:32000

由于端口不一致,所以会有跨域问题,
解决方式:

server {
    listen       80;
    server_name  dev.im.net;
    location / {
     proxy_pass http://127.0.0.1:3200;
    }
    # 接口都是在api下
    location /api/ {
        proxy_pass http://127.0.0.1:32000;
        index index.php index.html;
        autoindex  off;
    }
}

这样,前端访问就是http://dev.im.net/,后端接口访问是http://dev.im.net/api/,就不会出现跨域问题了