如果不进行动静分离用户访问业务服务器集群的时候, 每一个请求都将通过Nginx服务器从集群内的服务器拿静态资源拿到之后再由Nginx转发给用户
这个过程看起来很简单,但是使用Nginx进行转发静态资源的意义不是很大,影响服务器的性能。于是可以将业务处理服务器内的静态资源放在Nginx服务器
内,在使用的时候直接在Nginx服务器上拿走,省去了Nginx与业务处理服务器的交互,只有一些关键的页面才由Nginx访问业务服务器拿取。
这样做彻底减小了业务处理服务器的压力,Nginx服务器的压力减小了一半(因为客户端还需要直接从Nginx服务器上拿静态资源)
将静态文件放在Nginx服务器上,这样在进行请求的时候客户端可以直接从Nginx服务器上拿到想要的,根据Nginx配置文件中的location字段进行路径匹配
如果可以匹配到静态路径就会去指定的路径下找资源,如果没有匹配到就去被代理的服务器上找资源。
以下代码将指定的端口代理到127.0.0.1:8080端口监听的应用下,并指定被代理主机端口根路径做为Nginx服务器的根路径
location / {
proxy_pass http://127.0.0.1:8080;
}
不使用正则表达式:
location /css {
root /usr/local/nginx/static;
index index.html index.htm;
}
location /images {
root /usr/local/nginx/static;
index index.html index.htm;
}
location /js {
root /usr/local/nginx/static;
# 从root对应的路径下找js目录
index index.html index.htm;
}
使用正则表达式:
location ~*/(css|img|js) {
root /usr/local/nginx/static;
index index.html index.htm;
}
正则匹配:
/ 通用匹配,任何请求都会匹配到。
= 精准匹配,不是以指定模式开头
~ 正则匹配,区分大小写
~* 正则匹配,不区分大小写^~ 非正则匹配,匹配以指定模式开头的location
^~ 非正则匹配,匹配以指定模式开头的location
正则匹配规则:
多个正则location直接按书写顺序匹配,成功后就不会继续往后面匹配
普通(非正则)location会一直往下,直到找到匹配度最高的(最大前缀匹配)
当普通location与正则location同时存在,如果正则匹配成功,则不会再执行普通匹配
所有类型location存在时,“=”匹配 > “^~”匹配 > 正则匹配 > 普通(最大前缀匹配)
我这里使用的是一个Go语言项目,最初的界面是下面这样的:
失去资源的界面:
获取不到js、css、images所在的位置
失去css后的界面只剩了骨架
失去js后的页面没办法进行登录
此时登录注册增删改查都已经失效了!
配置Nginx配置文件
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream httpd {
server 192.168.31.253:8081 weight=1 down;
server 192.168.31.253:8080 weight=1;
#server 192.168.31.253:8082 weight=2;
}
#第一个主机
server {
listen 80;
server_name *.aiecp.com;
location / {
proxy_pass http://httpd;
proxy_set_header Host $host:$server_port;
}
location ~*/resource/(css|images|js) {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
报错及解决方案:
# 控制台报错(找不到相应的资源)
# 解决方法:配置Nginx的配置文件,将路径映射进去
GET http://aiecp.com/resource/css/index.css net::ERR_ABORTED 404 (Not Found)
GET http://aiecp.com/resource/js/index.js net::ERR_ABORTED 404 (Not Found)
GET http://aiecp.com/resource/images/logo.png 404 (Not Found)
# 控制台报错(因为路径原因,没有映射成功)
# 解决方案:检查路径细节上错误,可能有一段路由不存在,但是映射上去了(映射到了跟路径也就是index.html上)
# 在js文件中是不被认识的
index.js:1 Uncaught SyntaxError: Unexpected token '<' (at index.js:1:1)
# 控制台报错
# 解决方案:由于项目进行了URL路径静态资源的映射(将其关掉就好了)
# http.Handle("/resource/", http.StripPrefix("/resource/", http.FileServer(http.Dir("public/resource/"))))
Refused to apply style from 'http://aiecp.com/resource/css/index.css' because its MIME type ('text/plain') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
GET http://aiecp.com/resource/js/index.js net::ERR_ABORTED 404 (Not Found)
GET http://aiecp.com/resource/images/logo.png 404 (Not Found)
Refused to execute script from 'http://aiecp.com/resource/js/index.js' because its MIME type ('text/plain') is not executable, and strict MIME type checking is enabled.
favicon.png:1 GET http://aiecp.com/resource/images/favicon.png 404 (Not Found)
# 控制台报错 URL映射到了Nginx的配置内,但是在Nginx配置内没有找到相应的路径
# 解决方案:将root目录修改为正确的
GET http://aiecp.com/resource/css/index.css net::ERR_ABORTED 404 (Not Found)
GET http://aiecp.com/resource/js/index.js net::ERR_ABORTED 404 (Not Found)
成功配置
# root 请求的路径部分/resource/...将会变成请求html目录下的/resource/...
location ~*/resource/(css|images|js) {
root html;
index index.html index.htm;
}
# alias 直接就是将请求/resource/css下的东西变成请求html目录下的东西
location ~*/resource/css {
alias html/;
index index.html index.htm;
}
root用来设置根目录,而alias在接受请求的时候在路径上不会加上location。
1)alias指定的目录是准确的,即location匹配访问的path目录下的文件直接是在alias目录下查找的;
2)root指定的目录是location匹配访问的path目录的上一级目录,这个path目录一定要是真实存在root指定目录下的;
3)使用alias标签的目录块中不能使用rewrite的break(具体原因不明);另外,alias指定的目录后面必须要加上"/"符号!!
4)alias虚拟目录配置中,location匹配的path目录如果后面不带"/“,那么访问的url地址中这个path目录后面加不加”/“不影响访问,访问时它会自动加上”/“; 但是如果location匹配的path目录后面加上”/“,那么访问的url地址中这个path目录必须要加上”/“,访问时它不会自动加上”/“。如果不加上”/",访问就会失败!
5)root目录配置中,location匹配的path目录后面带不带"/",都不会影响访问。
场景复现:
想要访问的路径:http://www.aiecp.com/xxx/sss/aaa/getInfo?page=1
不使用rewrite访问的路径:http://www.aiecp.com/xxx/sss/aaa/getInfo?page=1
经过rewrite可以直接访问的路径:http://www.aiecp.com/1.html
可以将实现细节进行隐藏,可以简化网址的长度。语义化更强更便于用户与浏览器理解
rewrite是实现URL重写的关键指令,根据regex (正则表达式)部分内容,重定向到replacement,结尾是flag标记。
rewrite [flag]; #分别为:关键字 正则规则 替代内容 flag标记
关键字:其中关键字不能改变
效果
配置文件:
#第一个主机
server {
listen 80;
server_name *.aiecp.com;
rewrite ^/([0-9]+).html$ /?page=$1 break;
location / {
proxy_pass http://httpd;
proxy_set_header Host $host:$server_port;
}
location ~*/resource/(css|images|js) {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
#第一个主机
server {
listen 80;
server_name *.aiecp.com;
rewrite ^/([0-9]+).html$ /?page=$1 redirect;
location / {
proxy_pass http://httpd;
proxy_set_header Host $host:$server_port;
}
location ~*/resource/(css|images|js) {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
什么是网关呢?网关所在的网段所有流量都会经过网关,Nginx在进行代理的时候控制着路由的转发与响应,所以对于一个被Nginx代理的集群来说
Nginx服务器就是一个网关。
应用服务器开关防火墙
重启防火墙:systemctl restart firewalld
重载规则:firewall-cmd --reload
配置指定端口和ip访问(指定端口开放并不靠谱,如果仅仅是为了实验一下效果,暂时关闭防火墙)
指定以ipv4协议开放192.168.44.101的8080端口
指定端口和ip访问
firewall-cmd --permanent --add-rich-rule="rule family=“ipv4” source address=“192.168.44.101"port protocol=“tcp” port=“8080” accept”
移除规则
firewall-cmd --permanent --remove-rich-rule=“rule family=“ipv4” source address=“192.168.44.101” port port=“8080” protocol=“tcp” accept”
配置文件:
upstream httpd {
# 这两台主机上跑的分页代码一样(为了效果明显只是修改了一下首页的导航栏的信息)
server 192.168.31.253:8081 weight=1;
server 192.168.31.253:8080 weight=1;
#server 192.168.31.253:8082 weight=2;
}
#第一个主机
server {
listen 80;
server_name *.aiecp.com;
rewrite ^/([0-9]+).html$ /?page=$1 break;
location / {
proxy_pass http://httpd;
proxy_set_header Host $host:$server_port;
}
location ~*/resource/(css|images|js) {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
配置完进行启动然后刷新浏览器页面会发现,页面的信息会不停的变换。
主机1
主机2
防盗链顾名思义,就是为了防止别人盗用自己的资源而做的一些操作。
用户初次访问网站的时候并不会加上防盗链,如果加载如一个站点,再去请求其余的资源时会在请求头加上自己的原链接
而Nginx可以根据用户的原链接看看是否对其进行放行。
配置关键字:valid_referers none | blocked | server_names | strings …;
none, 检测 Referer 头域不存在的情况。
blocked,检测 Referer 头域的值被防火墙或者代理服务器删除或伪装的情况。这种情况该头域的值不以“http://” 或 “https://” 开头。
server_names ,设置一个或多个 URL ,检测 Referer 头域的值是否是这些 URL 中的某一个。在需要防盗链的location中配置
实战演练配置文件:
#第一个主机
server {
listen 80;
server_name *.aiecp.com;
rewrite ^/([0-9]+).html$ /?page=$1 break;
location / {
proxy_pass http://httpd;
proxy_set_header Host $host:$server_port;
}
# 给静态资源配置防盗链
location ~*/resource/(css|images|js) {
# 只允许192.168.200.128拿资源
valid_referers 192.168.200.128;
if ($invalid_referer) {
# 返回错误状态
return 403;
}
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
安装curl:
yum install curl
使用curl发送请求
没有源
curl -I http://192.168.200.128/resource/images/logo.png
有源
curl -e "http://www.baidu.com" -I http://192.168.200.128/resource/images/logo.png
正常页面:
被限制到的页面:
在接下来的三种应用场景中,都将防盗链设为了192.168.200.129,实际Nginx部署的机器ip是192.168.200.128,
所以在访问192.168.200.128的时候一定会因为防盗链影响。
#第一个主机
server {
listen 80;
server_name *.aiecp.com;
rewrite ^/([0-9]+).html$ /?page=$1 break;
location / {
proxy_pass http://httpd;
proxy_set_header Host $host:$server_port;
}
location ~*/resource/(css|images|js) {
valid_referers 192.168.200.129;
if ($invalid_referer) {
# 返回错误状态
return 403;
}
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
#第一个主机
server {
listen 80;
server_name *.aiecp.com;
# 这里重定向URl要注释掉,否则会混乱匹配
#rewrite ^/([0-9]+).html$ /?page=$1 break;
location / {
proxy_pass http://httpd;
proxy_set_header Host $host:$server_port;
}
location /resource/images {
valid_referers 192.168.200.129;
if ($invalid_referer) {
return 401;
}
root html;
index index.html index.htm;
}
location ~*/resource/(css|js) {
root html;
index index.html index.htm;
}
error_page 401 /401.html;
location = /401.html {
root html;
}
}
#第一个主机
server {
listen 80;
server_name *.aiecp.com;
rewrite ^/([0-9]+).html$ /?page=$1 break;
location / {
proxy_pass http://httpd;
proxy_set_header Host $host:$server_port;
}
location /resource/images {
valid_referers 192.168.200.129;
if ($invalid_referer) {
rewrite ^/ /resource/images/loading.gif break;
# return 403;
}
root html;
index index.html index.htm;
}
location ~*/resource/(css|js) {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
为了保障集群的健壮性,一台Nginx服务器可能没有办法稳定的代理集群内的所有机器(万一Nginx挂掉全部玩完),为了
解决这一窘迫的景象可以安装一些高可用保活应用,例如Keepalived,kafaka等。通过这些应用可以使多态Nginx之间平行通信。
下载地址
https://www.keepalived.org/download.html#
使用 ./configure 编译安装
如遇报错提示
configure: error:
!!! OpenSSL is not properly installed on your system. !!!
!!! Can not include OpenSSL headers files. !!!
安装依赖
yum install openssl-devel
yum install keepalived
配置
使用yum安装后配置文件在
/etc/keepalived/keepalived.conf
最小配置
第一台机器
! Configuration File for keepalived
global_defs {
router_id lb111
}
vrrp_instance atguigu {
state MASTER
interface ens33
virtual_router_id 51priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.44.200
}
}
第二台机器
! Configuration File for keepalived
global_defs {
router_id lb110
}
vrrp_instance atguigu {
state BACKUP
interface ens33
virtual_router_id 51
priority 50
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.44.200
}
}
启动服务
systemctl start keepalived
根据配置文件内的权重进行配置,权重高的优先得到地址。
当地址所在的机器挂掉之后,配置的地址会自动飘到活跃的主机上。
https证书配置文件
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
# 配置https的安全证书
server {
listen 443 ssl;
server_name www.aiecp.cn;
ssl_certificate aiecp.cn_bundle.crt;
ssl_certificate_key aiecp.cn.key;
ssl_session_timeout 5m;
#请按照以下协议配置
ssl_protocols TLSv1.2 TLSv1.3;
#请按照以下套件配置,配置加密套件,写法遵循 openssl 标准。
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location / {
root html;
index index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
server{
listen 80;
server_name aiecp.cn;
rewrite ^/(.*)$ https://aiecp.cn:443/$1 permanent;
}
}
这里要吐槽一下防火墙问题,因为开放指定端口在我这里不知道为什么不行。最后还是关闭了linux系统的整个防火墙才可以了。
最后的效果图
如果服务起来了,但是因为防火墙无法访问最后结果应该是这样的。(响应时间过长)
如果服务没起来,访问还会被直接拒绝,最后应该长这样。(直接拒绝)
配置报错:
nginx: [emerg] the "ssl" parameter requires ngx_http_ssl_module in /usr/local/nginx/conf/nginx
# 原因分析:
# 因为在安装nginx的时候没有安装openssl这个模块
解决方案:
具体操作:
# 进入解压的目录
cd /usr/local/nginx/nginx-1.23.2/
# 检查nginx是不是因为模块缺失
/usr/local/nginx/sbin/nginx -V
# 编译预检验
./configure --prefix=/usr/local/nginx --with-http_ssl_module=path path是你安装openssl的路径
# 编译
make(这个make要在nginx解压的路径内执行,make没有报错再往下执行)
# 将原来的可执行文件备份(以防万一)
cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak
# 将生成的可执行文件覆盖原有的
cp ./objs/nginx /usr/local/nginx/sbin/
# 再次检查,看是不是安装上了
/usr/local/nginx/sbin/nginx -V
进入解压的目录 cd /usr/local/nginx/nginx-1.23.2/
检查nginx是不是因为模块缺失 /usr/local/nginx/sbin/nginx -V
编译预检验 ./configure --prefix=/usr/local/nginx --with-http_ssl_module
编译 make(这个make要在nginx解压的路径内执行,make没有报错再往下执行)
将原来的可执行文件备份(以防万一)cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak
将生成的可执行文件覆盖原有的 cp ./objs/nginx /usr/local/nginx/sbin/
再次检查,看是不是安装上了 /usr/local/nginx/sbin/nginx -V