Nginx

1.基本介绍

Nginx是由俄罗斯的设计师开发的。
Nginx不像Apache那样,不论功能是否常用,统统都给你 自带了,
虽然功能 很强大,但是也很消耗性能,而Nginx只是自带了常用的功能。

Nginx 是 开源、高性能、高可靠的 Web 和反向代理 服务器,
而且支持 热部署,几乎可以做到 7 * 24 小时不间断运行,即使运行几个月也不需要重新启动,还能在不间断服务的情况下对软件版本进行热更新。
性能 是 Nginx 最重要的考量,其占用内存少、并发能力强、能支持高达 5w 个并发连接数,最重要的是,Nginx 是免费的并可以商业化,配置使用也比较简单。

使用场景

  • 静态资源服务,通过本地文件系统提供服务;
  • 反向代理服务,延伸出包括缓存、负载均衡等;
  • API 服务,OpenResty ;

使用实例

1、vue 打包部署到 NGINX

server {
        listen 80;
        server_name localhost;

        sendfile on;
        tcp_nodelay on;

        error_log /root/nginx_error_log/app_error.log;

        location / {
                # allow 27.197.70.72;
                # allow 119.176.167.13;
                # allow 119.176.161.201;
                # deny all;
                root /home/tom/vue/dist/;
                index index.html;
                try_files $uri $uri/ /index.html;
        }

        location /test {
                default_type text/plain;
                return 200 "hahahaha";
        }

        # 前端 通过重定向 处理 前端 获取动态数据 的请求跨域
        location /api_defaul{
                 proxy_set_header Host $proxy_host;
                 proxy_set_header Real-IP $remote_addr;
                 proxy_set_header name bbb;
                 rewrite ^/api_default/(.*)$  /$1 break;
                 proxy_pass http://localhost:8033;
        }
}

2、服务 的反向代理

server {
        listen 80;
        server_name www.baidu.com;

        error_log /root/nginx_error_log/app_error.log;

        # 配置跨域 ===============>
        add_header 'Access-Control-Allow-Origin' $http_origin;
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT';
        add_header 'Access-Control-Allow-Headers' 'Origin, x-requested-with, Content-Type, Accept, Authorization';
        add_header 'Access-Control-Expose-Headers' 'Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma';
        if ($request_method = 'OPTIONS') {
                add_header 'Access-Control-Max-Age' 1728000;
                add_header 'Content-Type' 'text/plain; charset=utf-8';
                add_header 'Content-Length' 0;
                return 204;
        }
        # 配置跨域 <===============

        location / {
                proxy_set_header proxyhost $proxy_host;
                proxy_set_header remoteaddr $remote_addr;
                proxy_set_header veryimportant $host$request_uri;
                proxy_pass http://0.0.0.0:8033;
        }

        # 静态资源 的 访问服务
        location ~ .*\.(gif|jpg|jpeg|png|txt|html|ico|apk)$ {

                default_type text/plain;
                root /data/static/;
        }

}


server {
        listen 443 ssl;
        server_name www.baidu.com;

        ssl_certificate /root/nginx_cert/www.baidu.com_bundle.crt;
        ssl_certificate_key /root/nginx_cert/www.baidu.com.key;
        ssl_session_timeout 10m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
        ssl_prefer_server_ciphers on;
        add_header X-Frame-Options DENY;           # 减少点击劫持
        add_header X-Content-Type-Options nosniff; # 禁止服务器自动解析资源类型
        add_header X-Xss-Protection 1;             # 防XSS攻击

        # 配置跨域 ===============>
        add_header 'Access-Control-Allow-Origin' $http_origin;
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT';
        add_header 'Access-Control-Allow-Headers' 'Origin, x-requested-with, Content-Type, Accept, Authorization';
        add_header 'Access-Control-Expose-Headers' 'Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma';
        if ($request_method = 'OPTIONS') {
                add_header 'Access-Control-Max-Age' 1728000;
                add_header 'Content-Type' 'text/plain; charset=utf-8';
                add_header 'Content-Length' 0;
                return 204;
        }
        # 配置跨域 <===============

        location / {
                proxy_set_header veryimportant $host$request_uri;
                proxy_set_header Host $proxy_host;
                proxy_set_header Real-IP $remote_addr;
                proxy_pass http://localhost:8033;
        }

        location ~ .*\.(gif|jpg|jpeg|png|txt|html|ico|apk)$ {

                add_header 'Access-Control-Allow-Origin' $http_origin;
                add_header 'Access-Control-Allow-Credentials' 'true';
                add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT';
                add_header 'Access-Control-Allow-Headers' 'Origin, x-requested-with, Content-Type, Accept, Authorization';
                add_header 'Access-Control-Expose-Headers' 'Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma';
                if ($request_method = 'OPTIONS') {
                        add_header 'Access-Control-Max-Age' 1728000;
                        add_header 'Content-Type' 'text/plain; charset=utf-8';
                        add_header 'Content-Length' 0;
                        return 204;
                }

                default_type text/plain;
                root /data/static/;
        }
}

3、负载均衡


http {

    server {
        listen 1234;
    	server_name localhost;
            location /test {
                    default_type text/plain;
                    return 200 "===> the server is test 1234";
            }
    }

    server {
            listen 1235;
    	    server_name localhost;
            location /test {
    	            charset utf-8;
                    default_type text/plain;
                    return 200 "===> 哈哈哈哈";
            }
    }

    upstream wtt {
            server localhost:1234; # # 链接后面 一定不要带 请求路径
            server localhost:1235;
    }

    # 访问 http://localhost:80/test 体验负责均衡
    server {
            listen 80;
            server_name localhost;

            location / {
                proxy_pass http://wtt;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
            }
    }
}

安装

apt install nginx
yum install nginx

Nginx 操作常用命令

  • nginx -v

版本查看

  • nginx -s reload

重新加载配置文件,热重启

  • nginx -s reopen

重启nginx

  • nginx -s quit

等待工作进程处理完成后关闭

  • nginx -s stop

快速关闭

  • nginx -T

查看当前nginx最终的配置

  • nginx -t

检查 默认的配置文件 是否有问题,
在非root用户下,如果 nginx -t 出现一些 警告等,可以 前置 sudo

  • -c <配置路径>
    检查 指定路径的配置文件 是否有问题
  • -q
    屏蔽 非错误 信息
  • 查看 配置文件 nginx.conf 位置
way1: 既可以检查 配置文件 , 又能找到配置文件的位置
nginx -t

way2: 如果程序正在运行着
ps -ef | grep nginx
>>> master process /www/server/nginx/sbin/nginx -c /www/server/nginx/conf/nginx.conf
  • 通过 systemctl 命令 对 Nginx进行 启动、停止、重载、开启自启等管理

安装好的各文件位置:

/usr/sbin/nginx:nginx主程序
/etc/nginx/nginx.conf:存放 主配置文件
/etc/nginx/conf.d/ 存放 子配置的配置项
/usr/share/nginx:通常静态文件都放在这个文件夹,也可以根据你自己的习惯放其他地方;
/var/log/nginx:存放日志

配置文件(/etc/nginx/nginx.conf)

配置结构

#全局块

events {         
   #events块,此处配置 可影响 服务器 和 用户的网络链接
}

http {
	#http全局块,配置代理、缓存、日志等

	upstream # 配置后端服务器的具体地址,负载均衡相关配置

	server {
		#server块,配置虚拟主机相关参数,一个http可有多个server块

		location {
			#location块,配置url的匹配,一个server可有多个location块
		}
	}
}

配置文件的语法规则

  • 配置文件由指令与指令块构成;
  • 每条指令以;分号结尾,指令与参数间以空格符号分隔;
  • 指令块{}大括号将多条指令组织在一起;
  • include 语句允许组合多个配置文件以提升可维护性;
  • 使用 # 符号添加注释,提高可读性;
  • 使用$符号使用变量;
  • 部分指令的参数支持正则表达式

常见配置项说明

user nginx; # 用于配置worker进程的用户和用户组(如果指定的用户不存在,则报错),语法 user user[group], 默认值 nobody,位置 全局块。页面报403,往往是worker进程的用户 没有访问root用户文件的权限导致的。

master_process;	# 配置是否开启worker进程,on|off ,默认 on,位于 全局块。
worker_processes auto; # 配置 worker进程的个数,建议和 CPU 核数一样,默认1

daemon on; # 设定nginx是否已守卫进程的方式启动, on|off 默认on,位于 全局块。默认启动方式 相当于 用了screen命令,所以在开启的终端中 Ctrl + C 无法退出nginx服务,或者直接关闭开启的终端 也不会 终止退出 nginx服务。

pid /run/nginx.pid; # 配置 master进程 的 进程号 和 进程号ID的文件路径, 位于 全局块。

error_log  /var/log/nginx/error.log warn;   # 配置 错误日志 存放路径 [日志级别]。位于 全局块、http、server、location。

include /etc/nginx/modules-enabled/*.conf; # 引入 子配置文件 合并到此处, 使nginx的配置更加灵活,位置 any。

events {
	accept_mutex on; # 网络连接序列化,on|off, 默认on,位于 events块,该配置项主要解决“惊群”问题,比如:空闲状态下所有的worker进程都会休眠,当进来一个用户请求时,所有worker都会被惊醒(唤醒),抢着处理这个请求,最先抢到的进行处理,其他没抢到的继续休眠,一个请求唤醒全部worker进程明显是影响nginx性能的,所以开启此配置项后,worker进程就会被编号,一个一个来唤醒,一个请求 唤醒一个worker进程。
	multi_accept on; # 配置是否允许 一个worker进程用时接收多个网络请求,默认off,位于 events块,建议打开。如果为off,一个worker进程只能同时接收一个新的连接。
	
	worker_connections 768; # 每个worker进程允许最大并发数,默认512,位于 events块,注意:其值 不能大于操作系统支持打开的最大 文件句柄 的数量。

	use epoll; # 配置nginx服务器选择哪种 事件驱动 来处理网络消息。默认值:根据操作系统,位于 events块。此配置是nginx优化的重要内容,可选值: select/poll/epoll/kqueue等,linux 内核在2.6以上可以使用epoll函数来优化nginx。
}

# http服务器 的相关设置
http {

	##
	# -----------------------------Basic Settings (基础设置)-----------------------------
	##

	sendfile on; # 提高处理静态资源的性能,默认 off, 位于 http、server、location。 sendfile函数Linux系统内核中高效处理静态资源的函数,故Nginx作为静态资源服务器时,开启则能大大提高Nginx的性能,但作为反向代理来使用的时候,就没什么进益了。

	tcp_nopush on; # 减少网络报文段的数量,仅在使用sendfile的时候使用
	tcp_nodelay on;

	keepalive_timeout 65; # 配置 长连接超时时间,默认75s,位于 http、server、location
	keepalive_requests 120; # 配置 一个长连接 可以处理的请求的个数,超过这个个数就会断开该连接。默认100,位于 http、server、location

	types_hash_max_size 2048;
	# server_tokens off;

	# server_names_hash_bucket_size 64;
	# server_name_in_redirect off;

	include /etc/nginx/mime.types; # 设定mime类型,类型由mime.types文件定义
	default_type application/octet-stream;

	##
	# -----------------------------SSL Settings(安全设置)-----------------------------
	##

	ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
	ssl_prefer_server_ciphers on;

	##
	# -----------------------------Logging Settings (日志设置)-----------------------------
	##

	# nginx 中的日志分为 access.log (记录用户所有的请求) 和 error.log(记录nginx运行时的错误信息)
	# nginx支持对日志的格式、大小、输出等进行设置,需要用到一下两个命令:
	log_format wttformat 'this is my defined'; # 指定日志的输出格式,位于http, 凡是采用  wttformat 格式的日志,只会重复输出一句话:this is my defined

	access_log /var/log/nginx/access.log wttformat; # 指定access日志的文件路径等相关属性,语法:access_log path [formate [buffer=size]],位于http、server、location, 日志采用就近原则,location 先用自身块中的 日志路径下的文件,如果没有就到 server中找,如果还没有就到http中找配置信息。
	error_log /var/log/nginx/error.log; # 指定error日志的文件路径等相关属性,

	##
	# -----------------------------Gzip Settings(压缩设置)-----------------------------
	##

	gzip on;

	# gzip_vary on;
	# gzip_proxied any;
	# gzip_comp_level 6;
	# gzip_buffers 16 8k;
	# gzip_http_version 1.1;
	# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;


    ##
	# -----------------------------Server(配置 虚拟主机)-----------------------------
	##

    server {
      listen  80; #虚拟主机监听的端口
      server_name localhost;  #虚拟主机使用的域名
  
  	
      # 单独 为该虚拟机定义一个 日志路径,而不是使用全局的
      # access_log /home/hero/log/wtt.access.log;
  
      
      charset utf-8;# 该虚拟机使用的字符编码
  
 	  location /get_text {
 		include mime.types;
 		default_type text/plain; # 配置nginx响应前端请求的默认mime类型,默认 text/plain,位于 http、server、location;告诉 浏览器 返回的资源类型
 		return 200 "

hello

"; # 普通字符串处理 } location /get_html { include mime.types; default_type text/html; return 200 "

hello

"; # html文档处理 } # 定义web的根路径 location / { root /usr/share/nginx/html; # 网站根目录 index index.html; # 默认访问文件 deny 172.168.22.11; # 禁止访问的ip地址,可以为 all allow 172.168.33.44; # 允许访问的ip地址,可以为 all } error_page 500 502 503 /50x.html # 根据错误代码,返回对应页面 error_page 400 404 error.html; # 同上 # url 中可包含正则 location [=|~|~*|^~]url { ... } # 1. = 精确匹配路径,用于不含正则表达式的 uri 前,如果匹配成功,不再进行后续的查找; # 2. ^~ 用于不含正则表达式的 uri 前,表示如果该符号后面的字符是最佳匹配,采用该规则,不再进行后续的查找; # 3. ~ 表示用该符号后面的正则去匹配路径,区分大小写; # 4. ~* 表示用该符号后面的正则去匹配路径,不区分大小写。跟 ~ 优先级都比较低,如有多个location的正则能匹配的话,则使用正则表达式最长的那个; # 5. 如果 uri 包含正则表达式,则必须要有 ~ 或 ~* 标志。 # example: location ~ .*\.(gif|jpg|jpeg|png)$ { root /root/wtt/rxw/static; } } }

全局变量

Nginx 有一些常用的全局变量,你可以在配置的 任何位置 使用它们,如下表:

全局变量名称 功能
$host 请求头中的host的值,如果请求头中无该键值对,则为 设置的服务器域名
$request_method 客户端的请求方法
$remote_addr 客户端的IP地址
$args 这个变量等于GET请求中的参数。例如,foo=123&bar=blahblah;
$arg_PARAMETER GET请求中变量名为PARAMETER参数的值
$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 服务器端口号
$scheme HPPT方法(http,https)

还有更多的内置预定义变量,可以直接搜索关键字「nginx内置预定义变量」

自定义变量

可以在sever,http,location等标签中使用set命令(非唯一)声明变量,语法如下:

set $变量名 变量值

location b/ {
    set $a hello nginx
    return 200 $a
}

变量拼接

 server {
        listen 1234;
        location /aaa {
                default_type text/plain;
                set $name tom 
                return 200 "===> the host is $host , the name is $name";
                # 以上方式 变量 和  字符 必须要有 间隔, 像 $hostaaa 是不可以的,如果非要 没有间隔,则使用如下方式:
                return 200 "===> the host is ${host}aaa";
        }
}

案例代码(跨域): 反向代理 + 静态资源

server {
   listen 33333 ssl;
   server_name kaoji.cn;

   ssl_certificate /root/music_level/nginx/ssl/kaoji..cn.pem;   # 证书文件地址
   ssl_certificate_key /root/music_level/nginx/ssl/kaoji.cn.key;  # 私钥文件地址
   
   ssl_session_timeout 10m;

   ssl_protocols TLSv1 TLSv1.1 TLSv1.2;      #请按照以下协议配置
   ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
   ssl_prefer_server_ciphers on;

   ### 一般还可以加上下面几个增强安全性的命令:
   add_header X-Frame-Options DENY;           # 减少点击劫持
   add_header X-Content-Type-Options nosniff; # 禁止服务器自动解析资源类型
   add_header X-Xss-Protection 1;             # 防XSS攻击


   location / {
        proxy_pass http://0.0.0.0:33332;
        # proxy_set_header wttname WHO;
        proxy_set_header Host $proxy_host; # 修改转发请求头,让被代理的应用可以受到真实的请求
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   }

   location ~ .*\.(gif|jpg|jpeg|png|mp4|xls)$ {
           root /root/music_level/app/static/upload;
   }
   access_log  /root/music_level/nginx/logs/access.log;
   error_log  /root/music_level/nginx/logs/error_log.log;
}

server {
   listen 55555;
   server_name kaoji.cn;

   sendfile on;
   tcp_nodelay on;

   location / {
           root   /root/music_level/webpage/dist;
           index  index.html;
           try_files $uri $uri/ /index.html;
   }
   location ~ .*\.(gif|jpg|jpeg|png|mp4)$ {
   				# 允许跨域请求的“域” 这是 ==核心==
   				# 允许跨域的请求,可以自定义变量 $http_origin, *表示所有
                add_header 'Access-Control-Allow-Origin' *;
                # 允许携带Cookie请求
                add_header 'Access-Control-Allow-Credentials' 'true';
                # 允许跨域的请求方法
                add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT';
                # 允许请求时携带的头部信息,*表示所有
                add_header 'Access-Control-Allow-Headers' 'Origin, x-requested-with, Content-Type, Accept, Authorization';
                # 允许发送 按段获取资源的 请求
                add_header 'Access-Control-Expose-Headers' 'Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma';
                # 若没有下面的语句, 则 post方法 无法进行跨域,
                # 因为 在发送 post跨域请求之前,会以options方式发送 预检请求, 服务器 接受时 才会正式请求
                if ($request_method = 'OPTIONS') {
                        # 预检请求缓存时间
                        add_header 'Access-Control-Max-Age' 1728000;
                        add_header 'Content-Type' 'text/plain; charset=utf-8';
                        add_header 'Content-Length' 0;
                        return 204;
                }
           expires 1d;
           root /root/music_level/app/static/upload;
   }
}


2.静态资源部署

http请求的内容分为两种,静态资源 和 动态资源:
静态资源: 是指在服务器中真实存在 且 能直接拿过来展示的一些文件,比如 html文件、js文件、图片等;
动态资源: 是指在服务器中真实存在 但 要获取需经过一定的业务逻辑,比如 数据表中的数据。

Nginx处理静态资源的内容,要考虑一下几个方面:

  1. 配置命令
  2. 配置优化
  3. 压缩配置指令
  4. 缓存处理
  5. 访问控制,包括跨域 和 防盗链问题

一、配置指令

1. listen

用来配置监听端口。
默认值: listen *:80 | *:8000
位置: server 块

listen 配置比较灵活,常用方式如下:

  1. listen 120.0.0.1:8000; // 监听指定的IP和端口
  2. listen 120.0.0.1; // 不加端口,默认监听 80端口
  3. listen 8000; // 监听指定端口上的连接
  4. listen *:8000; // 监听指定端口上的连接

listen 的 default_server 配置参数项 是 标识符,用来将此虚拟机设置成为默认主机
所谓的默认主机: 如果所有的server都没有匹配到对应的 address:port(实际过程中,先匹配port,再匹配 address), 则默认执行该 server。
如果不手动指定,则默认第一个server 是 默认主机。

2. server_name

配置 虚拟主机 匹配 请求 的 域名名称
语法: server_name name1 name2 …; //name值可以是ip也可以是域名,多个name之间用 空格隔开
默认值 为空字符串;
位置: server块
.
作用说明:

用一个IP配置不同的域名aaa.com 和 bbb.com ,
虚拟主机1 的 server_name 是aaa.com,虚拟主机2 的 server_name 是bbb.com,
请求 aaa.com的 请求 就会 被 虚拟主机1 所匹配。

关于server_name 的配置方式有三种:

  1. 精确匹配
server {
	listen 80;
	server_name www.baidu.com www.kaixin.com;
}
  1. 通配符匹配

通配符 * 只能出现在域名的 首 和 尾, 不能出现在中间位置!!!

server_name *.baidu.com;

# 以下情况 为 语法错误
server_name www.*.com;
server_name www.baidu.c*; # 正确为: www.baidu.*;
  1. 正则匹配

若使用正则表达式,必须 使用 ~ 作为正则表达式 字符串 开始的标记。
强调: ~ 后面不能有空格,要紧挨着后面的 正则表达式 字符串。

server_name ~^www\.(/w+)\.com$;

# 正则拆分: 
## ~: 正则表达式 字符串 开始的标记
## ^www : 以三w开头
## \. : 之后必须有个 点
## (/w+): 至少得有一个字符,去掉括号也可以
## com$ : 以com结尾
匹配优先级 (重点)

由上可知,server_name 的配置方式有多种,如果多个 虚拟机的 server_name 都匹配到了一个请求,
那么这个请求该给谁处理呢?
所以要明确一下 各个配置方式 的 优先级:

  1. 精确匹配 的优先级最高
  2. 通配符 在 开始位置 的情况 次之
  3. 通配符 在 结尾位置 的情况 再次之
  4. 正则匹配 的优先级 再靠后
  5. 最后 被 默认的虚拟机 (default_server)处理
  6. 如果没有明确指定虚拟机,则被第一台 虚拟机 处理

3. location

用户的请求发送到 nginx,先通过 匹配 listen 和 server_name 确定相应的 虚拟机.
然后再 通过 location 匹配 该虚拟机 上的 哪一个请求路径。

location

语法: location [ = | ~ | ~* | ^~ | @ ] uri {}
默认值: ——
位置: server、location

  1. 头指定模式: 不带上述符号,则必须 以 指定模式 开始
location /abc {
	default_type text/plain;
	return 200 "===> see you";
}

以上配置,下面的情况都是可以匹配的:
http://localhost/abc
http://localhost/abc123
http://localhost/abc/
http://localhost/abc/ccc/eee

说明:

location / { 
	default_type text/plain;
	return 200 "===> see you";
}

由于头指定模式的特性: 只要满足开头一样就可以,
所以 以上的 / 可以匹配一切路由。
就不会存在 404 的情况。

  1. =: 精准匹配
location =/abc {
	default_type text/plain;
	return 200 "===> see you";
}

以上配置,下面的情况:
http://localhost/abc (可以匹配)
http://localhost/abc/ (不可以匹配)
http://localhost/abc123 (不可以匹配)

  1. ~: 正则匹配
location ~^/abc\w$ {
	default_type text/plain;
	return 200 "===> see you";
}

以上配置,下面的情况:
http://localhost/abc (不可以匹配)
http://localhost/abc/ (不可以匹配)
http://localhost/abc1 (可以匹配)

  • 例 图片的静态目录
location ~ .*\.(gif|jpg|jpeg|png)$ {
    # default_type text/plain;
    root /root/test/static/;
}
  1. ~*: 正则无大小匹配
location ~*^/abc\w$ {
	default_type text/plain;
	return 200 "===> see you";
}

以上配置,下面的情况都是可以匹配的:
http://localhost/Abcd
http://localhost/ABCD
http://localhost/abcd

  1. ^~: 一见钟情匹配
location /abcd {
	default_type text/plain;
	return 200 "===> 指定模式";
}

location ~/abc\w$ {
	default_type text/plain;
	return 200 "===> 正则匹配";
}

请求路径 http://localhost/abcd 得到的响应是: ===> 正则匹配
这是因为匹配到 第一个location 后 还会接着看后面 还有没有 再能 匹配上的,所以后面的优先级要大于前面的location。

location ^~/abcd {
	default_type text/plain;
	return 200 "===> 一见钟情匹配";
}

location ~/abc\w$ {
	default_type text/plain;
	return 200 "===> 正则匹配";
}

请求路径 http://localhost/abcd 得到的响应是: ===> 一见钟情匹配
这是因为匹配到 第一个location 后, 就一见钟情了,不会再想着看后面的还有能匹配上这回事了。

4. 请求资源的目录 root/alias

rootalias 都可以定义在location模块中,都是用来指定 请求静态资源文件路径 的。
但在使用过程中要注意两者的区别:

比如要 访问: /root/wtt/static/imgs/01.png 文件

  • root 的方式访问

语法: root path;
默认值: root html;
位置: http、server、location

location /imgs {
	root /root/wtt/static;
}

root的处理结果是: root路径 + location路径
所以图片文件的访问路径:/imgs/01.png

  • alias 的方式访问

语法: root path;
默认值: root ——;
位置: location
说明:
root的 location 的 请求路径 是 某一个文件夹的 名字,而 alias是可以 自定义 请求路径的。

location /imgs {
	alias /root/wtt/static;
}

alias的处理结果是: alias路径 替换 location路径
所以图片文件的访问路径:/imgs/imgs/01.png


还有一个小区别:
如果location路径是以 / 结尾,那么alias也必须以 / 结尾,如下:

location /imgs/ {
	alias /root/wtt/static/;
}

root则没有要求。

  • 该部分 常用语 静态资源 ,实例如下:
          location ~ .*\.(gif|jpg|jpeg|png|mp4)$ {
                root /home/hero/static;
          }

5.index

设置网站的 默认 首项(呵呵 谐音梗 首相)
语法: index file …;
默认值: index index.html;
位置; http、server、location

location /images/ {
	alias html/images/;

	# index 后面可以跟多个 静态文件0, 会从左到右依次进行访问,直到找到为止。
	# http://localhost/images 展示aaa.png图片,如果没有找到,则展示bbb.png
	index aaa.png bbb.png;
}

6.error_page

设置网站的 错误页面
语法; error_page code1 code2 … [ = [response]] uri;
默认值; ——
位置; http、server、location

server {
	# 当出现对应的 code 时:
	## case1:可以指定 具体的跳转地址
	error_page 404 https://www.baidu.com;

	## case2: 可以指定 重定向地址 (重定向到 http://localhost/50x.html, 展示50x.html文件)
	error_page 500 501 /50x.html;
	
	## case3: 通过@定向到 location上
	error_page 404 @wtt_say_hi;
	
	# 实例
    location /img {
		error_page 404 https://www.baidu.com; # 当找不到 对应的图片 就 跳到百度页面

        alias /home/hero/Desktop/other;
		index a.jpg avatar.jpg;
     } 
}
  • 说一下 可选性 [ = [response]] 的作用:
server {
	error_page 404 =200 /a.html;
	location =/a.html {
		default_type text/plain;
		return 404 "hi my friend";
	}
}

当返回404时,在浏览器看到的返回状态码是200.
需要注意空格的使用,404 之后有空格, 等号 和 200 之间不能有空格。

二、静态资源优化指令

1. sendfile on;

开启高效文件传输模式
语法: sendfile on|off;
默认值: off
位置: http、server、location

底层原理解释:

为了保证操作安全,操作系统分为 用户区内核区
当用户区 需要 操作本地资源数据 or 对底层硬件进行操作时 都需要 向 内核区 申请(即 调用内核区的方法), 由 内核区 来完成。
nginx 运行在 用户区,当客户端过来一个请求客户端本地 aaa.png图片的请求时:

不启用sendfile的处理过程

  1. nginx 通过调用 系统的read()方法,向系统传递 要读取本地 aaa.png文件到 用户区(即 nginx应用程序缓冲区)
  2. 第一次复制操作:内核区 将 硬盘 上的 aaa.png 复制 到 内核缓冲区
  3. 第二次复制操作:内核缓存区 将 aaa.png 复制到 用户区的 nginx应用程序缓冲区
  4. nginx 通过调用 系统的write()方法,向系统传递 要将用户区的 aaa.png文件 写入到 内核区(具体为 socket 缓冲区)通过网卡将文件发送到客户端。
  5. 第三次复制操作: 用户区的nginx应用程序缓冲区 向 内核区的socket缓冲区 进行文件复制
  6. 第四次复制操作: 内核区的socket缓冲区 将文件 复制到 网卡 上,进行文件发送。

启用sendfile的处理过程

  1. nginx 通过调用 系统的 sendfile()方法,向系统表明要 发送 aaa.png文件的操作
  2. 第一次复制操作:内核区 将 硬盘 上的 aaa.png 复制 到 内核缓冲区
  3. 内核缓冲区 将aaa.png文件 直接移动到 socket缓冲区,(因为都在内核区)
  4. 第二次复制操作:内核区的socket缓冲区 将文件 复制到 网卡 上,进行文件发送。

2. tcp_nopush on;

该指令必须在sendfile打开的状态下才会生效,主要用来提升网络包的传输效率
语法: tcp_nopush on|off;
默认值: off
位置: http、server、location

底层原理解释:

socket 缓冲区 将数据复制到 网卡,网卡就会直接将 数据发送出去。
这里的tcp_nopush 的指令意思是 no push,不要急着将 socket 缓冲区 的数据 推送到 网卡,
也就是说 等socket 缓冲区 的数据量 到达一定数目 后 再 将数据推给 显卡。
这样就能保证 每次的 传输效率问题。
可类比 长途客车,搭载客人,拉着一个乘客跑 和 拉着整车乘客跑,肯定是后者效率更高。

3. tcp_nodelay on;

该指令必须在keep-alive(长连接)开启的时候才会生效,主要来提高网络包传输的实时性
语法: tcp_nodelay on|off;
默认值: on
位置: http、server、location

底层原理解释:

socket 缓冲区 将数据复制到 网卡,网卡就会直接将 数据发送出去。
这里的 tcp_nodeplay 的指令意思是 no deplay,不要 有 拖延,
只要socket 缓冲区 中有数据 就推送到 网卡,
这样就能保证了 数据 传输的 实时性。
可类比 长途客车,搭载客人,只要有乘客来了就发车,这样就能保证 乘客 及时到达目的地。

上面三个指令的配置建议

经过上面的分析,tcp_nopush 和 tcp_nodeplay 看起来好像是 互斥的。
但是在Linux2.5.9以后的版本中,两个是可以兼容的。
在兼容策略下,nginx是这么做的: nginx先优先使用tcp_nopush,全包每次推给显卡的都是一个比较完整的数据,
如果 socket 缓冲区 的数据量超过一定的时间 还没有达到 “满”的状态,
nginx则会忽略 tcp_nopush,启用tcp_nodeplay,将还没有达到 “满”的状态的数据发送出去。
所以这里建议,作为静态资源服务器时 以上 三个 指令都打开。

三、静态资源压缩

我们在思考这么一个问题,在满足上述优化的前提下,传送一个1M的数据和10M的数据,哪个更快?
所以 资源的压缩指令 在优化这块也是很重要的。

1 gzip off;

语法: gzip on|off;
默认: off
位置: http、server、location 等
压缩开关, 只有这个指令打开,下面介绍的相关指令 才能生效

2 gzip_typys text/html;

语法: gzip_typys mime-typy1 mime-typy1 …;
默认值: text/html
位置: http、server、location
该指令可以根据 响应页面 的 静态资源 的 mime类型 选择性的开启gzip压缩功能。
通配符 * 也可以作为该指令的值,但是不建议。
压缩的过程是要消耗cpu资源的,所以图片 和 视频 尽量上传的时候就完成压缩。

http{
	gzip on;
	gzip_typys application/javascript; # 此时只有返回给前端js文件时,才对js文件启用压缩功能,
}

3 gzip_comp_level 1;

语法: gzip_comp_level 1~9;
默认值: 1
位置: http、server、location
该指令用于设置gzip的压缩程度,级别从1到9,压缩程度依次增大,消耗的cpu资源也依次增多。

http{
	gzip on;
	gzip_typys application/javascript; # 此时只有返回给前端js文件时,才对js文件启用压缩功能,
	gzip_comp_level 6# 一般建议在6就可以了。级别再高,可以压缩的空间就很小了,反而会浪费很多CPU资源
}

4 gzip_vary off;

语法: gzip_vary on|off;
默认值: off
位置: http、server、location
该指令用于设置 是否让响应头 携带 “Vary: Accept-Encoding” 头部信息,
作用是告诉 客户端 该数据经过了压缩处理。

5 gzip_disable

语法: gzip_disable regexp …;
默认值: ——
位置: http、server、location
针对不同的客户端发起的请求,选择性关闭gzip功能。
因为有些客户端(IE5 之前的大部分浏览器)是不支持压缩文件的解压的
regexp 是根据 浏览器的标志 user-agent 来设置的。
匹配上的浏览器 不给使用 gzip 功能。

6 gzip_http_version 1.1;

语法: gzip_http_version 1.0|1.1;
默认值: ——
位置: http、server、location
针对不同的客户端发起的请求,选择性关闭gzip功能。
因为有些客户端是不支持压缩文件的解压的
regexp 是根据 浏览器的标志 user-agent 来设置的。
匹配上的浏览器 不给使用 gzip 功能。

7 gzip_min_length 20;

语法: gzip_min_length length;
默认值: 20
位置: http、server、location
针对传输数据的大小,选择性的开启和关闭Gizp压缩。
默认单位是字节,如:1024, 还可以 10k 或者 10m
压缩对于大数据效果明显,对于小数据就不建议压缩了,
建议设置下 1k 以上。

8 gzip_proxied off;

语法: gzip_proxied off|expired|no-cache|no-store|private|no_last_modified|no_etag|auth|any;
默认值: off;
位置: http、server、location
对服务器返回的结果是否进行压缩(该配置用在反向代理的时候多一些)。

配置值说明:

  • off: 不压缩
  • expired:启用压缩,如果header中包含Expires的头信息
  • no-cache:启用压缩,如果header中包含 Cache-Control:no-cache 的头信息
  • no-store:启用压缩,如果header中包含 Cache-Control:no-store 的头信息
  • private:启用压缩,如果header中包含 Cache-Control:private 的头信息
  • no_last_modified:启用压缩,如果header中包含 Last-Modified 的头信息
  • no_tag:启用压缩,如果header中包含 Etag 的头信息
  • auth:启用压缩,如果header中包含 Authorization 的头信息
  • any:无条件启用压缩

思考: Gzip 和 sendfile 的共存问题

前面讲解sendfile的时候,说过 开启sendfile以后,在读取磁盘上的静态资源文件的时候,
为了增加传输效率,减少拷贝次数,可以不经过 用户进程 将 静态文件 通过 网络设备 发出去,
但是 Gzip 要对资源进行压缩, 是要经过 用户进程 操作的, 这就产生冲突了。
所以 我们使用 ngx_http_gzip_static_module 模块 来解决这个冲突,让静态资源文件在
系统进程中 就可以得到 压缩。

  • gzip_static on|off|always;

默认值: gzip_static off;
位置: http、server、location



四、静态资源缓存

相关说明

为了节约网络的资源,加速浏览效率,浏览器在用户磁盘上对最近请求过的文件进行存储,
当访问者再次请求这个页面时,浏览器就可以从使用 本地磁盘中缓存的文档。
降低的服务器的压力,减少网络宽带的消耗,减少了网络延迟。

http协议中缓存相关的字段:

Header 说明
Expires 缓存过期的时间
Cache-Control 设置缓存相关的配置信息
Last-Modified 请求资源最后修改的时间
Etag 请求变量的实体标签的当前值,比如文件的MD5值

浏览器使用缓存文件流程说明:

  1. 浏览器发送请求前, 先判断是否有缓存
  2. 如果没有 请求服务器
  3. 如果有,判断缓存是否已过期
  4. 如果没过期,则使用本地缓存的资源
  5. 如果过期,则将请求发送到服务器,验证Etag和Last-Modified
  6. 通过验证,决定 继续使用本地缓存 or 请求服务器资源

上述过程产生的两个重要的名词:
强缓存:未经发送请求到服务器,直接从浏览器本地缓存中读书数据的过程;
弱缓存:经过发送请求到服务器,返回304再从浏览器本地缓存中读书数据的过程。

1 expires off;

语法: expires off|max|epoch|[modified] time;
默认: off
位置: http、server、location
该指令用来控制 页面缓存 的作用,可以通过该指令控制HTTP应答中的Expires 和 Cache-Control

参数说明:

  • time:

可以正数也可以是负数,指定过期的时间,
如果是负数,Cache-Control 的值则为 no-cache(在你使用缓存的时候,不管你的缓存有没有过期,都需要发送请求到服务端确认(弱缓存));
如果是正数或0,则Cache-Control 的值则为 max-age=time
max-age:起的作用 和 Expires 是一样的, 之所这两个同时都在使用,
是因为 Expires这个头信息 是 http1.0的, 它反应的是和服务端相关的一些配置时间,
如果客户端的时间和服务端不一致的话,往往达不到预期的效果。
所以在http1.1 时使用 max-age来替换Expires的作用,
因此如果 这两个值都有, max-age说了算,
但是如果有些浏览器不支持max-age的话,就会以Expires 为准了。

location ~ .*\.(html|js|css|png)$ {
	expires 10d;
	#expires 3600; #3600s
}
  • epoch

让 Expires 的值为 1970-01-01
让 Cache-Control的值为 no-cache

  • max

让 Expires 的值为 2037-12-31
让 Cache-Control的值为 10年

location ~ .*\.(html|js|css|png)$ {
	expires max;
}
  • off: 默认值,告诉浏览器不要缓存

2 add_header

语法: add_header name value [always];
默认: ——
位置: http、server、location…
该指令用来添加指定的 响应头 和 响应值。

add_header Token 132456;
  • 此配置可用来解决跨域问题:

跨域de报错信息主要是说: 访问的服务器的响应头中 中没有允许跨域访问的字段,
说明人家 默认是拒绝 跨域访问的。
所以解决的方式 在服务端 加上 那两个字段 表明 可以被跨域访问即可

  • Access-Control-Allow-Orion

允许跨域访问该服务的 源地址,可以用逗号隔开配置多个,也可以使用 * 允许所有的请求地址 跨域访问该服务。

  • Access-Control-Allow-Methods

允许跨域访问的请求方法,可以用逗号隔开配置多个。

location /aaa {
		==================================== 跨域处理 ==========================================
        # 允许跨域请求的“域” 这是 ==核心==
		add_header 'Access-Control-Allow-Origin' $http_origin;
		# 允许客户端提交Cookie
		add_header 'Access-Control-Allow-Credentials' 'true';
		# 允许客户端的请求方法
		add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT';
		# 允许客户端提交的的请求头
		add_header 'Access-Control-Allow-Headers' 'Origin, x-requested-with, Content-Type, Accept, Authorization';
		# 允许客户端访问的响应头
		add_header 'Access-Control-Expose-Headers' 'Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma';
		# 处理 预检请求
		if ($request_method = 'OPTIONS') {
			# 预检请求缓存时间
			add_header 'Access-Control-Max-Age' 1728000;
			add_header 'Content-Type' 'text/plain; charset=utf-8';
			add_header 'Content-Length' 0;
			return 204;
		}
		=====================================================================================
	    default_type applicaton/json;
	    return 200 '{"code":0, "data":"请求成功"}';
}

五、静态资源防盗链

资源盗链: 将他人服务器上的图片展示在自己的网站中。

nginx防盗链的实现原理:

当web服务器发送请求的时候,一般在请求头上都会带上Refer信息,来告诉服务器 这个 请求
是从哪个页面链接过来的,进而后台可以判断是否为自己信任的网站地址,如果是则放行,
如果不是则可以返回403 拒绝服务。

具体实现

valid_referers none|blocked|server_names|string…

默认值: –
位置: server、location
说明: 通过查看referer 自动和 valid_referers 后面的内容进行匹配,如果匹配到了 就将 $invalid_referer 变量置0,否则 置为1, 匹配的过程中不区分大小写。

  • none: 如果Header中的Referer为空,允许访问。直接将图片链接 通过浏览器打开的时候,Referer便为空,也就是说允许浏览器直接打开。
  • blocked:如果Header中的Referer 不为空, 但是该值 被 防火墙 or 代理 进行伪装过,如不带 “http://”、“https://” 等协议头的资源 允许其进行访问。
  • server_names:指定具体的 域名 or IP
  • string:可以支持正则表达式 和 * 的字符串。 如果是正则表达式,需要以 ~ 开头进行标识。
location ~ .*\.(png|jpg|gif)$ {
	valid_referers	none blocked www.baidu.com 192.168.1.1 *.example.com ~\.google\.;
	if ($invalid_referer) {
		return 403;
	}
	root /home/wtt/static/images;
}

扩展:如果图片有很多,该如何进行批量处理,也就是针对目录进行防盗链处理

location /images {
	valid_referers	none blocked www.baidu.com 192.168.1.1 *.example.com ~\.google\.;
	if ($invalid_referer) {
		return 403;
	}
	root /home/wtt/static;
}



3.重定向(URL 重写)

在nginx中 重定向 有两个 指令 : returnrewrite
return 一般用于 域名 重写,rewrite 一般用于 路径 重写。

  • 转发重定向 的区别

转发 是 服务端 的 行为, 重定向 是 客户端 的 行为

  • 后面要讲的 proxy_pass 代理 属于 转发,转发 是 服务端 的 行为,所以 浏览器是无感知的,因此 浏览器的 访问输入的 地址 是不会发生变化的。
  • 重定向是 浏览器的 行为,所以 浏览器的 访问输入的 地址 是会发生变化的。

return:

服务端 停止处理 并 将状态码 status code 返回给客户端

语法 默认值 位置
return code [text]; return code URL; return URL server、location、if

说明:

该指令 用于 完成对请求的处理,直接向客户端 进行返回。
在return 之后的配置都是无效的。

  • code : 指定 返回给客户端的 HTTP状态码。可以返回的状态为0~999
  • text : 返回到客户端的内容信息
  • URL : url 的情况直接进行跳转(忽略此项)

例子

  • 域名迁移

从 aaa.com 和 bbb.com 迁移到 ccc.com

server {
	listen 80;
	listen 8080 ssl;
	server_name aaa.com bbb.com;
	return 301 $scheme://ccc.com$request_uri;
}
  • 添加 www
server {
	listen 80;
	server_name aaa.com;
	return 301 $scheme;//www.aaa.com$request_uri;
}

rewrite

语法 默认值 位置
rewrite regexp replacement [flag]; server、location、if

说明:

该指令 通过正则表达式 的使用来改变 URI,
可以同时存在一个or 多个 指令,按照顺序依次对URL进行匹配处理。

  • regexp : 用来匹配URI的正则表达式
  • replacement : 匹配成功后,用URI中被截取内容的字符串 对URI进行重写。
location /aaa {
	# $1 是 正则的第一个()匹配的内容
	rewrite ^/aaa/(bbb)\w*$ /$1; # 请求 /aaa/bbb 先被 /aaa 匹配,然后重定向 到 /bbb
	rewrite /aaa/ccc /ccc; # 请求 /aaa/ccc 先被 /aaa 匹配,然后重定向 到 /ccc
}

location /bbb {
	default_type text/plain;
	return 200 bbbbbb;
}

location /ccc {
	default_type text/plain;
	return 200 cccccc;
}

### 效果
> 访问 http://localhost:8889/aaa/bbb ===> bbbbbb
> 访问 http://localhost:8889/aaa/ccc ===> cccccc

最佳实践:前后分离 的 跨域解决

server {
        listen 80;
        server_name aaa.com;
        
        # 前端 vue静态服务
        location / {  
                root /home/meng/;
                index index.html;
                try_files $uri $uri/ /index.html;
        }

        # 代理的 后端服务, 
        # 前端 请求加前缀 /api/* 代理到 后端服务, 实现 跨域处理
        location /api{
                 proxy_set_header Host $proxy_host;
                 proxy_set_header Real-IP $remote_addr;
                 
                 rewrite ^/api_default/(.*)$  /$1 break; # /api/user/info ===url重写===> /user/info
                 # 重定向之后 的 反向代理 的地址 不要有 请求路径, 即使 加上也 无效,这一点和 纯粹的 反向代理 差别很大
                 proxy_pass http://bbb.com;
        }
}

重定向 flag :last break redirect permanent

这里重点说明 last 和 break

# 例子 last ======================================================
server {
        listen 80;
        location /ccc {
                default_type text/plain;
                return 200 "===> this is proxy pass"; 
        }
}

server {
        listen 1234;
        location /aaa {
                rewrite /aaa /ccc last;
                proxy_pass http://localhost;
        }

        location /ccc {
                default_type text/plain;
                return 200 "===> this is location ccc"; 
        }
}
访问 localhost:1234/aaa    返回  ===> this is location ccc

# 例子 break ======================================================
server {
        listen 80;
        location /ccc {
                default_type text/plain;
                return 200 "===> this is proxy pass"; 
        }
}

server {
        listen 1234;
        location /aaa {
                rewrite /aaa /ccc break;
                proxy_pass http://localhost;
        }

        location /ccc {
                default_type text/plain;
                return 200 "===> this is location ccc"; 
        }
}
访问 localhost:1234/aaa    返回  ===> this is proxy pass
  • last: 终止 在 本location块 中继续 处理接收到的URI,
    并将 重写后的URI作为一个新的URI, 在 同 server 下 使用 各location块 进行继续处理。
  • break:将此处重写的URI作为一个新的URI,在 本location 块中 继续进行处理。
注意:

如果replacement是以 http 或 https开头的,则不会向下对URI进行处理,而是直接返回重写的URI给客户端, 例如: rewrite /aaa https://www/baidu.com;

  • redirect: 将重写后端的URI返回给客户端,状态码302,指明是临时重定向URI,只要用在replacement变量不是以 http 或 https 开头的情况。
  • permanent: 将重写后的URI返回给客户端, 状态码301,指明是临时重定向URI,只要用在replacement变量不是以 http 或 https 开头的情况。

rewrite_log

语法 默认值 位置
rewrite_log on off; off

说明:

该指令 决定 是否开启 URL重写日志的输出功能,
开启后,URL重写的相关日志 将以 notice级别输出到 error_log中。
如果错误日志的 错误收录等级 在notice 之上,是无法收集 重写日志 相关的数据的。

注意: Nginx的Rewrite功能依赖于PCRE的支持,因此要保证金系统安装了PCRE库(sudo apt install libpcre3 libpcre3-dev)。
Nginx 使用的是 ngx_http_rewrite_module 模块来解析 和 处理 Rewrite功能的。

Rewrite应用场景:

重定向
域名镜像
独立域名
目录自动添加 “/”
合并目录
防盗链的实现

Rewrite 的相关指令

set:定义一个新的变量

语法 默认值 位置
set $key val; server、location、if

注意: key为变量名,以"$"作为标记,不要和Nginx预设变量重名;
val 为变量的值,可以是字符串、或其他变量的组合等。

location /aaa {
	set $name tom;
	set $age 12;
	default_type text/plain;
	return 200 'name is $name age is $age';
}

自定义的 变量 和预设变量一样 也可以用在 日志文件中。

if:条件判断

语法 默认值 位置
if (condition){…} server、location

condition 作为判定条件,支持以下写法:

  1. 变量名: 如果变量名的值是 空字符串 or 0,都会被判定为 false
  2. 条件: 使用 = 和 != 进行条件判断:
location /test/methed {
		if ($request_method = POST){
			return 200 'your request methods is $request_method';
		}
		if ($request_method = GET){
			return 200 'your request methods is $request_method';
		}

		if ($request_method = DELETE){
			return 200 'your request methods is $request_method';
		}
                
		return 200 "===> defaule ";
}

注意:

单个 等于号
字符串 POST 无需加引号
等号 和 不等号 前后 都要加一个 空格

  1. 正则: 变量 和 正则表达式 之间 用 、!、! 来连接
if ($http_user_agent ~ MSIE){
	# 若 $http_user_agent 的值中 包含 MSIE 字符串,则为true
}

注意:

~ : 代表 区分大小写
~* : 不区分大小写
!~ : 对 ~ 的结果进行 取反
!~* :对 ~* 的结果进行 取反
正则字符串 一般不需要加引号,除非 正则字符串中有 } 或 ; 字符。
正则标记号 前后 都要加一个 空格

  1. 文件存在:
if (-f $request_filename){
	# 判断请求的文件是否存在
}

小案例:

server {
     listen       8099;
     server_name  wtt;
     set $subject test_rewrite;
     set $age 10;
     location / {
                if ($age = 5) {
                     return 404;
                }
                if ($age = 6) {
                     return 405;
                }
                if ($age = 7) {
                     return 302 /abc;
                }
         
                default_type text/html;
		        return 200 "

\"color:red\">nihao

"
; } location /abc { default_type text/plain; return 200 $subject; } error_page 404 @wtt_say_hi; location @wtt_say_hi { default_type text/plain; return 404 "hi my friend 找不到阿"; } }

说明:

age == 5 返回: “hi my friend 找不到阿”
age == 6 返回:405状态
age == 7 返回:”test_rewrite“

4.反向代理

在客户端 和 服务端 交流的过程中,如果 代理服务器 充当的是 客户端的角色,则为 正向代理
若充当的是服务端 的角色,则为 反向代理
所以说 反向代理 是掩藏 真实 服务器地址 的好手段。

nginx 反向代理 模块的指令是由 ngx_http_proxy_module 模块进行解析的,该模块在安装nginx的时候已经自己加装到nginx中了。

1 相关指令介绍

proxy_pass

该指令用来设置 被代理服务器的地址,可以是主机名称、IP地址加端口的形式。

语法 默认值 位置
proxy_pass URL; location
proxy_pass http://www.baidu.com;
proxy_pass http://198.168.1.1/;
注意
  • 一个location 下 只能有一个 proxy_pass 多了就报错。
此节重点

代理地址 的端口之后 带不带 / 有很大的区别,
以下是 没带 的情况:

proxy_pass http://www.123.com;
proxy_pass http://www.123.com:1234;

以下是 的情况:

proxy_pass http://www.123.com/;
proxy_pass http://www.123.com:1234/;
proxy_pass http://www.123.com:1234/abc/def;

1、没带 /

请求的匹配的 路径 就是 反向代理 收到的路径。

location /api/ {
	proxy_pass http://localhost:8080;
}
匹配的路径 ===> 反向代理收到的路径
/api/user ===> /api/user

2、带 /

请求的匹配的 路径 后,以开头 第一个 / 基准,先将其后 匹配成功的 那部分 去除, 再将 剩余部分 直接 拼接到 反向代理 后的路径 之后 就是 反向代理 最终收到的 路径。

  • 举例说明
    location ^~ /api/ , 第一个 / 为基准, 其后 匹配的部分为 api/,如果请求的路径是 /api/user/info , 那么 去除 匹配部分之后 剩下的部分为: /user/info, 剩下的 这部分 会被 直接 拼接在 反向代理的 路径后面。
location / {                                                                                                                               
    proxy_pass http://localhost/;                                                                                                      
} 
/api/user  ==> /api/user



location /api {                                                                                                                               
    proxy_pass http://localhost/;                                                                                                      
} 
/api/user  ==> //user



location /api/ {                                                                                                                               
    proxy_pass http://localhost/;                                                                                                      
} 
/api/user  ==> /user



location / {                                                                                                                               
    proxy_pass http://localhost/haha;                                                                                                      
} 
/api/user  ==> /hahaapi/user



location / {                                                                                                                               
    proxy_pass http://localhost/haha/;                                                                                                      
} 
/api/user  ==> /haha/api/user



location /api {                                                                                                                               
    proxy_pass http://localhost/haha/;                                                                                                      
} 
/api/user  ==> /haha//user



# 以上都是 探索形态, 以下这个是 成果形态
location /api/ {                                                                                                                               
    proxy_pass http://localhost/haha/;                                                                                                      
} 
/api/user  ==> /haha/user

proxy_set_header

该指令用来 更改 or 添加一个请求头信息。
常用于 安全校验:

为了安全起见, 我们不会让 真实服务 的服务器地址 直接暴露给用户,而是使用反向代理,
这样一来 用户 仅仅知道我们 反向代理的服务器,
为了让 真实服务 的服务器 知道 请求 来自于 nginx的反向代理,在请求到达 nginx后,
nginx可以通过 proxy_set_header 在请求头上 加一些 密文信息
真实服务 的服务器 收到 请求后,首先 通过 请求头的密文 验证 该请求是否来自 nginx 反向代理,
如果是 则 正常提供服务, 如果不是 直接 拉黑 该请求IP。

语法 默认值 位置
proxy_set_header key val; Host $proxy_host http、server、location
proxy_set_header field value; Connection close http、server、location

代理服务器:

location /aaa {
	# 设置一些密文
	proxy_set_header wttname WHO;
    # 将 nginx 地址 赋值给 Host
	proxy_set_header Host $proxy_host; # 修改转发请求头,让被代理的应用可以受到真实的请求
	# 将 真正请求IP 赋值给 Real-IP
    proxy_set_header Real-IP $remote_addr;

	proxy_pass http://192.168.1.1:8080/ping;
}

proxy_redirect

该指令用来 重置头信息中的 Location 和 Refresh 的值。

语法 默认值 位置
proxy_redirect redirect replacement; proxy_redirect default; http、server、location
proxy_redirect default; proxy_redirect default; http、server、location
proxy_redirect off; proxy_redirect default; http、server、location

说明:

  • proxy_redirect redirect replacement;
    redirect:目标, Location 的值
    replacement: 要替换的值
  • proxy_redirect default;
    将Location 块的URI 变量作为 replacement,
    将proxy_pass 变量作为 redirect进行替换
  • proxy_redirect off;
    关闭 proxy_set_header 功能。
具体用途说明

在请求访问的过程中,我们只希望 将 代理服务器 的地址 暴露给客户端。
但是 如果 被代理的服务器 出现 重定向 的情况,尤其是 重定向到 自身的某个地址,
那么 重定向的 这个地址 是会被 返回给 客户端的,从而 被代理的服务器 地址也就暴露了。
而 proxy_redirect 作用是对发送给客户端的URL进行修改,从而保护了 被代理的服务器 的地址。

举例说明:

server {
	listen 222.22.2.222:8081;
	server_name localhost;
	location / {
		# 111.111.1.111 这个地址是不能暴露的
		proxy_pass http://111.111.1.111:8081/;
		# proxy_redirect   待替换的地址(被保护的地址)    拿来替换的内容(暴露给用户的地址);
		#                  真正服务器 的地址            代理服务器 的地址
		proxy_redirect     http://111.111.1.111      http://222.22.2.222;
	}
}

# 被nginx 所代理的服务 为 真实服务,以 gin框架举例:
case1:重定向到 一个 链接
func Ping(c *gin.Context) {
	c.Redirect(302, "http://www.baidu.com")
}


case2: 重定向到 一个 请求路径
func Ping(c *gin.Context) {
	c.Redirect(302, "aaa/bbb/ccc")
}

说明:

  1. 在 不使用 proxy_redirect 的情况下:
    如果 被代理服务器 没有发生重定向,那么客户端 看到的地址是 代理服务器的 地址
    如果 被代理服务器 发生重定向,那么客户端 看到的地址是 被代理服务器的 地址
    .
  2. 在 使用 proxy_redirect 的情况下:
  • 重定向到 一个 链接
    那么客户端 看到的地址都是 重定向 到的 链接地址:http://www.baidu.com
  • 重定向到 一个 请求路径 (这一种情况 属于 保护 真正服务地址 的情况)
    那么客户端 看到的地址都是 拼接地址:http://222.22.2.222/aaa/bbb/ccc

2 反向代理还有一些其他的指令,可以了解一下:

  • proxy_connect_timeout 1;
    nginx服务器 与 被代理的服务器 建立连接 的 超时时间,默认60秒

  • proxy_ignore_client_abort on;
    客户端断网时,nginx服务器 是否终断 对 被代理服务器的请求。默认为off。

  • proxy_read_timeout;
    配置 Nginx 向 后端服务器组 发出 read 请求后,等待相应的超时时间;

  • proxy_send_timeout
    配置 Nginx 向后端服务器组发出 write 请求后,等待相应的超时时间;

3 使用反向代理解决跨域

server {
        listen 80;
        server_name aaa.com;
        
        # 前端 vue静态服务
        location / {  
                root /home/meng/;
                index index.html;
                try_files $uri $uri/ /index.html;
        }

        # 代理的 后端服务, 
        # 前端 请求加前缀 /api/* 代理到 后端服务, 实现 跨域处理
        location /api{
                 proxy_set_header Host $proxy_host;
                 proxy_set_header Real-IP $remote_addr;
                 
                 rewrite ^/api_default/(.*)$  /$1 break; # /api/user/info ===url重写===> /user/info
                 proxy_pass http://bbb.com;
        }
}

这样就将对前一个域名 aaa.com; 的请求全都代理到了 bbb.com;,前端的请求都被我们用服务器代理到了后端地址下,绕过了跨域。

5 负载均衡

常用的处理方式

1. 用户手动选择

这种方式比较原始,通过提供不同的线路,让用户自己选择:
典型例子就是通用网络下载: 电信网络下载、联通网络下载、移动网络下载

2. DNS轮询

一个 域名 绑定 多个IP, 实现访问一个 域名 ,但实际请求多个服务器的效果。
缺点:电脑会进行DNS缓存(hosts文件), 这使得DNS轮训有了大漏洞

理论上 一个域名是可以对应多个IP的。
用户访问 多IP的域名时,指向某一个具体IP,并不会同时访问多个IP。

3. 四/七层负载均衡

  • 七层:
  • 应用层: 为应用程序提供网络服务
  • 表示层: 对数据进行格式化、编码、加密、压缩等操作
  • 会话层: 建立、维护、管理会话链接。
  • 传输层: 建立、维护、管理 端到端 的连接,常见的有TCP、UDP。
  • 网络层: IP寻址和路由选择
  • 数据链路层: 控制网络层 和 物理层 之间的通信
  • 物理层: 比特流传输
  • 四层:
  • 传输层: 建立、维护、管理 端到端 的连接,常见的有TCP、UDP。
  • 网络层: IP寻址和路由选择
  • 数据链路层: 控制网络层 和 物理层 之间的通信
  • 物理层: 比特流传输
  • 实现四层负载均衡的方式:

硬件: F5 BIG-IP Radware等
软件: LVS Nginx Hayproxy等

  • 实现七层负载均衡的方式:

软件: Nginx Hayproxy等

  • 区别:

四层的数据包是在底就进行了分发,而七层则是在最顶端进行分发,所以 四层 比 七层 负载均衡的效率要高
四层不识别 域名,而 七层 要识别域名。

Nginx七层负载均衡

nginx 要实现七层负载均衡 需要用到 proxy_pass代理模块,nginx默认就支持这个模块。

upstream

upstream 负载均衡, 可以理解为 反向代理的 一对多 的一种扩展模式,所以反向代理 又得一些配置, 负载均衡 也可以 使用。

upstream 虚拟服务池(集群), 用来定义一组服务器,他们可以是监听不同端口的服务器,
并且也可以用时是监听TCP和socket的服务器。

语法 默认值 位置
upstream name {…}; http

server

该指令用来指定后端服务器的名称和一些参数,
可以使用域名、IP、端口 或者 socket。

语法 默认值 位置
server name [paramerters]; upstream

注意: 这个server指令 和 http快中的 是不一样的。

# backend 是后端的意思,可以自定义
upstream backend {
	server 192.168.1.111:9001; # 链接后面 一定不要带 请求路径
	server 192.168.1.111:9002;
	server 192.168.1.222:9002;
}

server {
	listen 8088;
	server_name localhost;
	location / {
		proxy_pass http://backend;
	}
}

负载均衡状态

状态 概述
down 标记的server不再参与负载均衡
backup 预留的备份服务器
max_fails 允许请求失败的次数
fail_timeout 经过max_fails失败后,服务器暂时停用的时间
max_conns 限制最大的接收连接数
upstream backend {
	server 192.168.1.111:9001 down; # 标记为永久不可用,一般会需要停机维护的服务器进行设置
	server 192.168.1.111:9002;
	server 192.168.1.222:9002;
}


upstream backend {
	server 192.168.1.111:9001 down; 
	server 192.168.1.111:9002 backup;# 为备份服务器,当第三台也不可用时,将启用该第二台服务器。
	server 192.168.1.222:9002;
}

upstream backend {
	server 192.168.1.111:9001; 
	server 192.168.1.111:9002;
	server 192.168.1.222:9002 max_fails=3 fail_timeout=15; # 如果 访问 9003 失败的次数 超过3次,将在 15秒内 不再对会该服务器进行访问。
}

upstream backend {
	server 192.168.1.111:9001; 
	server 192.168.1.111:9002;
	server 192.168.1.222:9002 max_conns=10; # 设置该代理服务器同时活动连接的最大数量,默认为0,便是不限制,这个主要用来 保护 性能不好的服务器,以免被压垮。 
}

负载均衡策略

算法名称 概述
轮训 默认方式
weight 权重方式
ip_hash 根据ip分配方式
least_conn 根据最少连接方式
url_hash 根据URL分配方式
fair 根据响应时间方式
# 每个请求按照时间顺序,依次分配到不同的后端服务器。
upstream backend {
	server 192.168.1.111:9001;
	server 192.168.1.111:9002;
	server 192.168.1.222:9002;
}

# 权重默认为1, 权重越大 被分到请求的概率就越大。
# 此策略比较适合服务器硬件差别比较大的情况。
upstream backend {
	server 192.168.1.111:9001 weight=10; 
	server 192.168.1.111:9002 weight=3;
	server 192.168.1.222:9002;
}

# 保证 相同IP的请求 下一次 还能能到达 本次访问的服务器
# 该策略无法保证 服务器的 负载均衡,且权限此时也不会起作用。
upstream backend {
	ip_hash;
	server 192.168.1.111:9001; 
	server 192.168.1.111:9002;
	server 192.168.1.222:9002;
}

# 把请求转发给 连接数 比较少 的后端服务器,解决了 轮训算法的一个痛点,
# 轮训算法下,有些请求占用的时间很长,会导致其所在的后端负载堆积较高。
# least_conn就可以达到更好的效果。
upstream backend {
	least_conn;
	server 192.168.1.111:9001; 
	server 192.168.1.111:9002;
	server 192.168.1.222:9002;
}

# fair采用第三模块实现的负载均衡,需要添加 nginx-upstream-fail
# 可以根据页面大小、加载时间长短 智能 的进行负载均衡。
upstream backend {
	fail;
	server 192.168.1.111:9001; 
	server 192.168.1.111:9002;
	server 192.168.1.222:9002;
}

案例:对不同的域名实现负载均衡

upstream aaa {
	server 192.168.0.111:8080;
	server 192.168.0.222:8080;
}

upstream bbb {
	server 192.168.0.333:8080;
	server 192.168.0.444:8080;
}


# 因为多个域名 可以绑定 一个ip,所以 server_name 是不同的。
server {
	listen 8888;
	server_name www.aaa.com;
	location / {
		proxy_pass http://aaa;
	}
}

server {
	listen 8888;
	server_name www.bbb.com;
	location / {
		proxy_pass http://bbb;
	}
}

Nginx四层负载均衡

nginx在1.9之后,增加了一个stream模块,用来实现 四层协议的转发、代理、负载均衡等。
stream模块的用法和 http的用法类似,允许配置一组 TCP or UDP 等协议的监听。
然后通过 proxy_pass来转发我们的请求, 通过upstream添加多个后端服务,实现负载均衡。

四层协议负载均衡的实现,一般会用到 HAProxy、F5等,要么很贵,要么配置很麻烦,
而nginx配置相对比较简单。

nginx添加stream模块的支持,需要在编译的时候 加上 --with-stream

stream

该指令 提供 在其中指定 流服务器 指令的 配置文件上下文, 和 http指令 同级别。

语法 默认值 位置
stream {…}; main

upstream

该指令和 http 的 upstream 指令是类似的。

events {}

stream {
	upstream backend {
		server 192.168.1.111:8080;
		server 192.168.1.222:8080;
	}

	server {
		listen 81;
		proxy_pass backend; # 注意不是 http://backend;
	}
}

http {}

注意:如果4层负载均衡的 监听 端口 和 http中(当然也包括七层负载均衡)监听的端口 重复了,那么 由于 四层 更偏底层一些,所以 端口被4层占去了。

6.配置HTTPS

下载证书的压缩文件,里面有个 nginx 文件夹,把 xxx.crt 和 xxx.key 文件拷贝到服务器目录,再配置下:

server {
 listen 443 ssl;   # SSL 访问端口号为 443
 server_name sherlocked93.club;         # 填写绑定证书的域名

 ssl_certificate /etc/nginx/https/aaa.crt;   # 证书文件地址
 ssl_certificate_key /etc/nginx/https/aaaa.key;  # 私钥文件地址
 
 ssl_session_timeout 10m;

 ssl_protocols TLSv1 TLSv1.1 TLSv1.2;      #按照以下协议配置
 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
 ssl_prefer_server_ciphers on;

 ### 加上下面几个增强安全性的命令:
 add_header X-Frame-Options DENY;           # 减少点击劫持
 add_header X-Content-Type-Options nosniff; # 禁止服务器自动解析资源类型
 add_header X-Xss-Protection 1;             # 防XSS攻击
 
 location / {
   root         /usr/share/nginx/html;
   index        index.html index.htm;
 }
}

7.日志

Nginx日志主要分为两种:access_log(访问日志)error_log(错误日志)
访问日志主要记录客户端的请求。客户端向Nginx服务器发起的每一次请求都记录在这里。
错误日志记录了访问出错的信息,可以帮助我们定位错误的原因。

访问日志

(1)设置语法

access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];

# 作用域
http,server,location,limit_except

# 关闭 访问日志
access_log off;

说明:

  • path

指定日志的存放文件路径

  • format

指定日志的格式。默认使用预定义的combined
预定义的combined 如下:

log_format combined '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent"';
  • buffer

用来指定日志写入时的缓存大小。默认是64k。
输出内容先缓存到 内存中,等到 缓存内容 到了 64k
则打开日志文件, 将缓存内容输入进去,减少io。

  • flush

设置缓存的有效时间。如果超过flush指定的时间,缓存中的内容将被清空。
到了指定时间, 即使缓存 中的内容 大小 达不到 64k 也会被 写入到 日志中。

  • gzip

日志写入前先进行压缩。压缩率可以指定,
从1到9数值越大压缩比越高,同时压缩的速度也越慢。默认是1。

  • if

条件判断。如果指定的条件计算为0或空字符串,那么该请求不会写入日志。

栗子

access_log /var/logs/nginx-access.log
# 说明:
该例子指定日志的写入路径为/var/logs/nginx-access.log,
日志格式使用默认的combined。


access_log /var/logs/nginx-access.log buffer=32k gzip flush=1m;
# 说明:
该例子指定日志的写入路径为/var/logs/nginx-access.log,
日志格式使用默认的combined,
指定日志的缓存大小为32k,
日志写入前启用gzip进行压缩,压缩比使用默认值1,
缓存数据有效时间为1分钟。

(2)自定义日志格式

如果不想使用Nginx预定义的格式,可以通过log_format指令来自定义。

log_format name [escape=default|json] string ... ;
  • name

自定义格式的名称。在access_log指令中引用。

  • escape

设置变量中的字符编码方式是json还是default,默认是default。

  • string

要定义的日志格式内容。该参数可以有多个。参数中可以使用Nginx变量。

下面是log_format指令中常用的一些变量:

变量

含义

$bytes_sent

发送给客户端的总字节数

$body_bytes_sent

发送给客户端的字节数,不包括响应头的大小

$connection

连接序列号

$connection_requests

当前通过连接发出的请求数量

$msec

日志写入时间,单位为秒,精度是毫秒

$pipe

如果请求是通过http流水线发送,则其值为"p",否则为“."

$request_length

请求长度(包括请求行,请求头和请求体)

$request_time

请求处理时长,单位为秒,精度为毫秒,从读入客户端的第一个字节开始,直到把最后一个字符发送张客户端进行日志写入为止

$status

响应状态码

$time_iso8601

标准格式的本地时间,形如“2017-05-24T18:31:27+08:00”

$time_local

通用日志格式下的本地时间,如"24/May/2017:18:31:27 +0800"

$http_referer

请求的referer地址。

$http_user_agent

客户端浏览器信息。

$remote_addr

客户端IP

$http_x_forwarded_for

当前端有代理服务器时,设置web节点记录客户端地址的配置,此参数生效的前提是代理服务器也要进行相关的x_forwarded_for设置。

$request

完整的原始请求行,如 "GET / HTTP/1.1"

$remote_user

客户端用户名称,针对启用了用户认证的请求

$request_uri

完整的请求地址,如 "https://daojia.com/"

栗子

access_log /var/logs/nginx-access.log wtt

log_format wtt '$remote_addr - $remote_user [$time_local] "$request" '
               '$status $body_bytes_sent "$http_referer" '
               '"$http_user_agent" "$http_x_forwarded_for"';

注意: 如果某个变量的值为空,则在日志中输出为 -

错误日志

错误日志的格式是固定的, 不支持 用户自定义。

error_log   path(错误日志的目录路径)  level(日志等级默认为error);

# 作用域
main, http, mail, stream, server, location

# 关闭错误日志
error_log /dev/null;
# 说明
错误日志 本质上说是 不能关闭的, 但是错误日志的输出 我们不去记录,   
就如同 关闭了一样,其实输出还是在一直进行着。

文件描述符缓存

nginx还有一个很重要的缓存功能只针对于打开的文件句柄以及源信息叫做open_file_cache, open_file_cahce对我们优化nginx性能也是非常有帮助的。
NGINX缓存将最近使用的文件描述符和相关元数据(如修改时间,大小等)存储在缓存中。
缓存不会存储所请求文件的内容。
缓存了文件句柄fd,缓存了文件句柄就意味着不用每次都close一个文件再open一个文件,
减少了系统调用的操作。

open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time];
  • max

设置缓存中最多容纳的文件描述符数量,如果被占满,采用LRU算法将描述符关闭。

  • inactive

设置缓存存活时间,默认是10s。

  • min_uses

在inactive时间段内,日志文件最少使用几次,才会将该日志文件描述符记入缓存,默认是1次。

  • valid

设置多久对日志文件名进行检查,看是否发生变化,默认是60s。

  • off

不使用缓存。默认为off。

栗子

open_log_file_cache max=1000 inactive=20s min_uses=2 valid=1m;
# 说明:
设置缓存最多缓存1000个日志文件描述符,
20s内如果缓存中的日志文件描述符至少被被访问2次,才不会被缓存关闭。
每隔1分钟检查缓存中的文件描述符的文件名是否还存在。

8.访问控制

allow 和 deny

1、allow 和 deny 指令在 ngx_http_access_module 模块中。
2、两个指令分别表示允许或禁止源 IP 访问,用于对源 IP 做访问控制,all 表示所有IP;
3、nginx 是按照 自上而下 的顺序进行匹配,匹配到一个就不往下继续了
4、遇到 重写 指令, 类似于 rewritereturn 指令时 allow 和 deny 指令 就会 失效
5、作用域: http 、 server、location、limit_except ;
6、被禁止的IP进行访问时, 得到的回应是 403 ForBidden

server {
        listen 8088;
        location /ping {
                allow 60.213.44.66;
                deny all;
                proxy_pass http://localhost:8080;
       }
}

9.限流

限流方式

  • 1、基于 连接数 的限流:

通过 limit_conn_module 模块可以设置每个 IP 或地址的最大并发连接数。
例如,使用 limit_conn_zone 指令定义一个存储区域,然后在 http、server 或 location 块中使用 limit_conn 指令来限制连接数。

  • 2、基于 请求数 的限流:

通过 limit_req_module 模块可以控制每个 IP 或地址的请求速率。
这个模块使用令牌桶算法进行请求的限流。您可以使用 limit_req_zone 指令定义存储区域,然后在 http、server 或 location 块中使用 limit_req 指令来限制请求速率。

说明:连接数 和 请求数 的区别:
连接数: 每个客户端(通常是一个 IP 地址)与服务器建立连接时,都会占用一个连接, 可近似理解为 客户端的数量。
请求数: 客户端 对 服务端 发出的 请求数, 可以理解为 所有客户端发出请求的总和。

连接数限流主要关注于控制并发连接的数量,以保护服务器的网络资源
请求数限流主要关注于控制请求的速率,以保护服务器的计算资源和处理能力。

  • 3、基于 带宽 的限流:

通过 ngx_http_core_module 模块中的 limit_rate 指令,您可以限制整个服务器或指定位置的带宽。这可以确保服务器不会被某个客户端的高速请求耗尽带宽资源。

案例演示

基于 连接数 的限流:

http {
  # 定义连接数存储区域
  # $binary_remote_addr : 这是一个 Nginx 的变量,代表客户端的IP地址
  # zone=wtt:10m : 它指定了连接数 限制区域 的 名称为wtt 和 大小10m
  limit_conn_zone $binary_remote_addr zone=wtt:10m; #单位还可以是: k、m、g

  server {
    listen 80;
    
    # 针对某个 location 进行连接数限流
    location /api/ {
      # 使用名为 wtt的限制区域, 并限制了每个源 IP 地址最多允许有 10 个并发连接, 如果一个公司的员工 共用一个 IP 明显是不够用的
      limit_conn wtt 10;  # 最大连接数为 10
      
      # 处理请求的逻辑
      ...
    }
  }
}
  • limit_conn_zone 和 limit_conn 的关系

limit_conn_zone 指令中设置的大小和 limit_conn 指令中设置的数量是有关系的。它们共同作用于连接数限流。
如果将 limit_conn wtt 设置为 10000,即每个 IP 地址最大连接数为 10000,并且假设每个连接占用的存储空间为 2KB,那么您可以根据以下公式来计算合适的 limit_conn_zone 大小:

limit_conn_zone_size = 10000 * 2KB

根据上述计算,您可能需要设置 limit_conn_zone 的大小为至少 20000KB,或者更大一些以确保有足够的存储空间来跟踪连接信息。
如果 limit_conn_zone 被沾满,即连接数存储区域已经达到了容量上限,后面进来的 连接 会被拒绝。

  • 每个 连接 的大小

连接占用的存储空间大小是不固定的,通常情况下,每个连接占用的存储空间可以粗略地估计为以下几个部分的总和:

  1. 连接相关的元数据:包括连接的IP地址、端口号、协议等信息。
  2. 连接状态相关的数据:例如连接的建立时间、最近活动时间、当前状态等。
  3. 请求 和 响应相关的数据:这取决于您是否需要记录请求和响应的详细信息。如果记录了请求和响应的内容,那么存储空间将更大。

基于 请求数 的限流(推荐):

http {
    # limit_req_zone 指令来 定义 一个名为 "wtt" 的 限流区域
    # 限流区域 大小为 10m
    # 限制了每秒钟最多处理 10 个请求
    limit_req_zone $binary_remote_addr zone=wtt:10m rate=10r/s;

    server {
        listen 80;
        server_name example.com;

        location / {
            # zone 指的是 使用 名为 wtt 的 限流区域
            # burst=5 ==》 当请求超过正常的限流速率时,如果请求数量未超过该阈值,系统将继续处理这些请求;但一旦请求数量达到或超过该阈值,系统将立即拒绝额外的请求,并返回错误响应。
            # nodelay 表示超过限流速度的请求将立即返回 503 错误。
            limit_req zone=wtt burst=5 nodelay;

            proxy_pass http://your_backend_server;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

扩展: 同时使用 基于 请求数 and 连接数 的限流时

http {
    limit_req_zone $binary_remote_addr zone=req:10m rate=5r/s;
    limit_conn_zone $binary_remote_addr zone=conn:10m;

    server {
        listen 80;
        server_name example.com;

        location / {
            limit_req zone=req burst=10 nodelay;
            limit_conn conn 10;
            proxy_pass http://your_backend_server;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

基于 带宽 的限流

区别于 基于 请求数 的是 这里的 rate后面跟的是 带宽 的大小 而不是 速率。

http {
    limit_req_zone $binary_remote_addr zone=req:10m rate=1m;

    server {
        listen 80;
        server_name example.com;

        location / {
            limit_req zone=req;
            proxy_pass http://your_backend_server;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

建议规范

  • 为了使 Nginx 配置更易于维护,建议为每个服务创建一个单独的配置文件,存储在 /etc/nginx/conf.d 目录,根据需求可以创建任意多个独立的配置文件。

  • 独立的配置文件,建议遵循以下命名约定 <服务>.conf,比如域名是 sherlocked93.club,那么你的配置文件的应该是这样的 /etc/nginx/conf.d/sherlocked93.club.conf,如果部署多个服务,也可以在文件名中加上 Nginx 转发的端口号,比如 sherlocked93.club.8080.conf,如果是二级域名,建议也都加上 fe.sherlocked93.club.conf。

  • 常用的、复用频率比较高的配置可以放到 /etc/nginx/snippets 文件夹,在 Nginx 的配置文件中需要用到的位置 include 进去,以功能来命名,并在每个 snippet 配置文件的开头注释标明主要功能和引入位置,方便管理。比如之前的 gzip、cors 等常用配置,我都设置了 snippet。

  • Nginx 日志相关目录,内以 域名.type.log 命名(比如 be.sherlocked93.club.access.log 和 be.sherlocked93.club.error.log )位于 /var/log/nginx/目录中,为每个独立的服务配置不同的访问权限和错误日志文件,这样查找错误时,会更加方便快捷。

常见问题

启动异常

在启动 nginx 服务时 systemctl start nginx, 报错如下:
Job for nginx.service failed because the control process exited with error code. See “systemctl stat

  • 原因1:

nginx配置文件有错误, 通过 nginx -t 进行检查。

  • 原因2:

nginx 要使用的 端口 被 别的服务 占用,
通过 netstat -antp | grep 80 查询某些端口是否被监听占用了。

你可能感兴趣的:(nginx,linux)