大家好,欢迎来到IT知识分享网。
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; } }
try_files
说明:
try_files 作用是 检查文件是否存在,就是指 在每次匹配URL路径的时候,找不到 对应的 静态资源 的 时候 自动跳转 到index.html文件。
- 不加 try_files 会出现的问题:
nginx部署完项目后,正常访问是没有问题的, 但是 只要在 非根目录 下的页面 只要 一刷新 就报
Nginx404页面
- 原因解释:
因为web
单页面
开发模式,只有一个index.html入口,其他路径 都是 前端路由 去跳转的,nginx 是不知道对应这个路径。
举例说明:如:http://127.0.0.1/user ,此时 刷新页面 之后,会 根据浏览器的url, 访问nginx上 对应的 静态资源,而nginx会根据localhost / 的 匹配规则 在 dist文件夹 中 查找 对应的静态文件user,肯定是找不到的,所以就会报错404。
- 解决办法:
# 无 子目录 情况
location / {
root /home/tom/vue/dist/;
index index.html;
try_files $uri $uri/ /index.html;
}
# 有子目录 的情况
server {
listen 80;
server_name 127.0.0.1;
index index.html;
root /www/h5;
try_files $uri $uri/ /index.html;
......
}
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' ; add_header 'Content-Type' 'text/plain; charset=utf-8'; add_header 'Content-Length' 0; return 204; } # 配置跨域 <=============== location / {
proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header proxyhost $proxy_host; 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' ; 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' ; add_header 'Content-Type' 'text/plain; charset=utf-8'; add_header 'Content-Length' 0; return 204; } default_type text/plain; root /data/static/; } }
3、重定向处理跨域问题
# 前端 通过重定向 处理 前端 获取动态数据 的请求跨域 # /wtt/aaa/bbb ====> /aaa/bbb ====> http://localhost:8082/aaa/bbb location /wtt{
proxy_set_header Host $proxy_host; proxy_set_header Real-IP $remote_addr; proxy_set_header name bbb; rewrite ^/wtt/(.*)$ /$1 break; proxy_pass http://localhost:8082; }
4、负载均衡
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
- -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进行 启动、停止、重载、开启自启等管理
安装好的各文件位置:
配置文件(/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 "<h1> hello </h1>"; # 普通字符串处理
}
location /get_html {
include mime.types;
default_type text/html;
return 200 "<h1> hello </h1>"; # 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.静态资源部署
Nginx处理静态资源的内容,要考虑一下几个方面:
- 配置命令
- 配置优化
- 压缩配置指令
- 缓存处理
- 访问控制,包括跨域 和 防盗链问题
一、配置指令
1. listen
listen 配置比较灵活,常用方式如下:
- listen 120.0.0.1:8000; // 监听指定的IP和端口
- listen 120.0.0.1; // 不加端口,默认监听 80端口
- listen 8000; // 监听指定端口上的连接
- listen *:8000; // 监听指定端口上的连接
listen 的 default_server
配置参数项 是 标识符,用来将此虚拟机设置成为默认主机 。
所谓的默认主机: 如果所有的server都没有匹配到对应的 address:port(实际过程中,先匹配port,再匹配 address), 则默认执行该 server。
如果不手动指定,则默认第一个server 是 默认主机。
2. server_name
关于server_name 的配置方式有三种:
- 精确匹配
server {
listen 80; server_name www.baidu.com www.kaixin.com; }
- 通配符匹配
通配符 * 只能出现在域名的
首 和 尾
, 不能出现在中间
位置!!!
server_name *.baidu.com; # 以下情况 为 语法错误 server_name www.*.com; server_name www.baidu.c*; # 正确为: www.baidu.*;
- 正则匹配
若使用正则表达式,必须 使用
~
作为正则表达式 字符串 开始的标记。
强调: ~ 后面不能有空格,要紧挨着后面的 正则表达式 字符串。
server_name ~^www\.(/w+)\.com$; # 正则拆分: ~: 正则表达式 字符串 开始的标记 ^www : 以三w开头 \. : 之后必须有个 点 (/w+): 至少得有一个字符,去掉括号也可以 com$ : 以com结尾
匹配优先级 (重点)
- 精确匹配 的优先级最高
- 通配符 在 开始位置 的情况 次之
- 通配符 在 结尾位置 的情况 再次之
- 正则匹配 的优先级 再靠后
- 最后 被 默认的虚拟机 (default_server)处理
- 如果没有明确指定虚拟机,则被第一台 虚拟机 处理
3. location
location:
头指定模式
: 不带上述符号,则必须 以 指定模式 开始
location /abc {
default_type text/plain; return 200 "===> see you"; }
说明:
location / {
default_type text/plain; return 200 "===> see you"; }
=
: 精准匹配
location =/abc {
default_type text/plain; return 200 "===> see you"; }
~
: 正则匹配
location ~^/abc\w$ {
default_type text/plain; return 200 "===> see you"; }
- 例 图片的静态目录
location ~ .*\.(gif|jpg|jpeg|png)$ {
# default_type text/plain; root /root/test/static/; }
~*
: 正则无大小匹配
location ~*^/abc\w$ {
default_type text/plain; return 200 "===> see you"; }
^~
: 一见钟情匹配
location /abcd {
default_type text/plain; return 200 "===> 指定模式"; } location ~/abc\w$ {
default_type text/plain; return 200 "===> 正则匹配"; }
location ^~/abcd {
default_type text/plain; return 200 "===> 一见钟情匹配"; } location ~/abc\w$ {
default_type text/plain; return 200 "===> 正则匹配"; }
4. 请求资源的目录 root/alias
root
和alias
都可以定义在location模块
中,都是用来指定请求静态资源
的文件路径
的。
但在使用过程中要注意两者的区别:
比如要 访问:
/root/wtt/static/imgs/01.png
文件
- root 的方式访问
location /imgs { root /root/wtt/static; }
root的处理结果是: root路径 + location路径
所以图片文件的访问路径:/imgs/01.png
- 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
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"; } }
二、静态资源优化指令
1. sendfile on;
底层原理解释:
为了保证操作安全,操作系统分为
用户区
和内核区
,
当用户区 需要 操作本地资源数据 or 对底层硬件进行操作时 都需要 向 内核区 申请(即 调用内核区的方法), 由 内核区 来完成。
nginx 运行在 用户区,当客户端过来一个请求客户端本地 aaa.png图片的请求时:不启用sendfile的处理过程:
- nginx 通过调用 系统的read()方法,向系统传递 要读取本地 aaa.png文件到 用户区(即 nginx应用程序缓冲区)
- 第一次复制操作:内核区 将
硬盘
上的 aaa.png 复制 到内核缓冲区
- 第二次复制操作:内核缓存区 将 aaa.png 复制到 用户区的 nginx应用程序缓冲区
- nginx 通过调用 系统的write()方法,向系统传递 要将用户区的 aaa.png文件 写入到 内核区(具体为
socket 缓冲区
)通过网卡
将文件发送到客户端。- 第三次复制操作: 用户区的nginx应用程序缓冲区 向 内核区的socket缓冲区 进行文件复制
- 第四次复制操作: 内核区的socket缓冲区 将文件 复制到 网卡 上,进行文件发送。
启用sendfile的处理过程:
- nginx 通过调用 系统的 sendfile()方法,向系统表明要 发送 aaa.png文件的操作
- 第一次复制操作:内核区 将
硬盘
上的 aaa.png 复制 到 内核缓冲区- 内核缓冲区 将aaa.png文件 直接
移动
到 socket缓冲区,(因为都在内核区)- 第二次复制操作:内核区的socket缓冲区 将文件 复制到 网卡 上,进行文件发送。
2. tcp_nopush on;
该指令必须在sendfile打开的状态下才会生效,主要用来提升网络包的传输
效率
。
语法: tcp_nopush on|off;
默认值: off
位置: http、server、location
底层原理解释:
3. tcp_nodelay on;
该指令必须在keep-alive(长连接)开启的时候才会生效,主要来提高网络包传输的
实时性
。
语法: tcp_nodelay on|off;
默认值: on
位置: http、server、location
底层原理解释:
上面三个指令的配置建议
三、静态资源压缩
1 gzip off;
2 gzip_typys text/html;
http{
gzip on; gzip_typys application/javascript; # 此时只有返回给前端js文件时,才对js文件启用压缩功能, }
3 gzip_comp_level 1;
http{
gzip on; gzip_typys application/javascript; # 此时只有返回给前端js文件时,才对js文件启用压缩功能, gzip_comp_level 6;# 一般建议在6就可以了。级别再高,可以压缩的空间就很小了,反而会浪费很多CPU资源 }
4 gzip_vary off;
5 gzip_disable
6 gzip_http_version 1.1;
7 gzip_min_length 20;
8 gzip_proxied off;
配置值说明:
- 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 的共存问题
- gzip_static on|off|always;
四、静态资源缓存
相关说明
http协议中缓存相关的字段:
Header | 说明 |
---|---|
Expires | 缓存过期的时间 |
Cache-Control | 设置缓存相关的配置信息 |
Last-Modified | 请求资源最后修改的时间 |
Etag | 请求变量的实体标签的当前值,比如文件的MD5值 |
浏览器使用缓存文件流程说明:
- 浏览器发送请求前, 先判断是否有缓存
- 如果没有 请求服务器
- 如果有,判断缓存是否已过期
- 如果没过期,则使用本地缓存的资源
- 如果过期,则将请求发送到服务器,验证Etag和Last-Modified
- 通过验证,决定 继续使用本地缓存 or 请求服务器资源
1 expires off;
参数说明:
- time:
location ~ .*\.(html|js|css|png)$ {
expires 10d; #expires 3600; #3600s }
- epoch
- max
location ~ .*\.(html|js|css|png)$ {
expires max; }
- off: 默认值,告诉浏览器不要缓存
2 add_header
add_header Token ;
- 此配置可用来解决跨域问题:
- 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' ; 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防盗链的实现原理:
具体实现
valid_referers none|blocked|server_names|string…
- 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中 重定向 有两个 指令 :
return
和rewrite
return 一般用于 域名 重写,rewrite 一般用于 路径 重写。
- 转发 和 重定向 的区别
转发 是 服务端 的 行为, 重定向 是 客户端 的 行为
- 后面要讲的 proxy_pass 代理 属于 转发,转发 是 服务端 的 行为,所以 浏览器是无感知的,因此 浏览器的 访问输入的 地址 是不会发生变化的。
- 重定向是 浏览器的 行为,所以 浏览器的 访问输入的 地址 是会发生变化的。
return:
服务端 停止处理 并 将状态码 status code 返回给客户端
语法 | 默认值 | 位置 |
---|---|---|
return code [text]; return code URL; return URL | — | server、location、if |
说明:
- 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 |
说明:
- 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 |
说明:
Rewrite应用场景:
Rewrite 的相关指令
set:定义一个新的变量
语法 | 默认值 | 位置 |
---|---|---|
set $key val; | — | server、location、if |
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 作为判定条件,支持以下写法:
- 变量名: 如果变量名的值是 空字符串 or 0,都会被判定为 false
- 条件: 使用 = 和 != 进行条件判断:
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 "; }
注意:
- 正则: 变量 和 正则表达式 之间 用 、、!、! 来连接
if ($http_user_agent ~ MSIE){
# 若 $http_user_agent 的值中 包含 MSIE 字符串,则为true }
注意:
- 文件存在:
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 "<h1 style=\"color:red\">nihao </h1>"; } 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 找不到阿"; } }
说明:
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: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
语法 | 默认值 | 位置 |
---|---|---|
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 功能。
具体用途说明
举例说明:
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") }
说明:
- 在 不使用 proxy_redirect 的情况下:
如果 被代理服务器 没有发生重定向,那么客户端 看到的地址是 代理服务器的 地址
如果 被代理服务器 发生重定向,那么客户端 看到的地址是 被代理服务器的 地址
.- 在 使用 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轮询
3. 四/七层负载均衡
- 七层:
- 应用层: 为应用程序提供网络服务
- 表示层: 对数据进行格式化、编码、加密、压缩等操作
- 会话层: 建立、维护、管理会话链接。
- 传输层: 建立、维护、管理 端到端 的连接,常见的有TCP、UDP。
- 网络层: IP寻址和路由选择
- 数据链路层: 控制网络层 和 物理层 之间的通信
- 物理层: 比特流传输
- 四层:
- 传输层: 建立、维护、管理 端到端 的连接,常见的有TCP、UDP。
- 网络层: IP寻址和路由选择
- 数据链路层: 控制网络层 和 物理层 之间的通信
- 物理层: 比特流传输
- 实现四层负载均衡的方式:
- 实现七层负载均衡的方式:
软件: Nginx Hayproxy等
- 区别:
四层的数据包是在底就进行了分发,而七层则是在最顶端进行分发,所以
四层 比 七层 负载均衡的效率要高
。
四层不识别 域名,而 七层 要识别域名。
Nginx七层负载均衡
nginx 要实现七层负载均衡 需要用到 proxy_pass代理模块,nginx默认就支持这个模块。
upstream
upstream 负载均衡, 可以理解为 反向代理的 一对多 的一种扩展模式,所以反向代理 又得一些配置, 负载均衡 也可以 使用。
语法 | 默认值 | 位置 |
---|---|---|
upstream name {…}; | — | http |
server
语法 | 默认值 | 位置 |
---|---|---|
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添加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
- flush
- gzip
- 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; # 说明 错误日志 本质上说是 不能关闭的, 但是错误日志的输出 我们不去记录, 就如同 关闭了一样,其实输出还是在一直进行着。
文件描述符缓存
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
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
- 每个 连接 的大小
连接占用的存储空间大小是不固定的,通常情况下,每个连接占用的存储空间可以粗略地估计为以下几个部分的总和:
- 连接相关的元数据:包括连接的IP地址、端口号、协议等信息。
- 连接状态相关的数据:例如连接的建立时间、最近活动时间、当前状态等。
- 请求 和 响应相关的数据:这取决于您是否需要记录请求和响应的详细信息。如果记录了请求和响应的内容,那么存储空间将更大。
基于 请求数 的限流(推荐):
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:
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/121605.html