Nginx配置,比如说跨域、缓存、配置SSL证书、高可用等,老规矩,还是挑几个平时比较常用的进行演示分享
跨域是因为浏览器同源策略的保护,不能直接执行或请求其他站点的脚本和数据;一般我们认为的同源就是指协议、域名、端口都相同,否则就不是同源。
现在前后端分离开发已经很普遍了,跨域问题肯定少不了,但解决的方式也很多,比如JsonP、后端添加相关请求头等;很多时候,不想改动代码,如果用到nginx做代理服务器,那就可以轻松配置解决跨域问题。
需要准备两个项目,一个前端项目发布在80端口上,一个API项目发布在5000端口上,这里需要在阿里云的安全组中将这两个端口开放;
API项目环境(对外是5000端口)
API接口还是使用上次演示的项目,很简单,过程我就不再重复上图啦,直接来两张重要的;
配置nginx反向代理,然后运行看效果:
前端环境(对外是80端口)
前端页面(kuayu.html)
<!DOCTYPE html> <html> <head> <title>跨域测试</title> <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script> <script type="text/javascript"> $(document).ready(function(){ // 点击按钮 请求数据, $("#b01").click(function(){ // 请求数据 htmlobj=$.ajax({url:"http://47.113.204.41:5000/weatherforecast/getport",async:false}); // 将请求的数据显示在div中 $("#myDiv").html(htmlobj.responseText); }); }); </script> </head> <body> <h2>获取结果</h2> <div id="myDiv">结果显示</div> <button id="b01" type="button">GetPort</button> </body> </html>
将kuayu.html通过xFtp拷贝到服务器上,对应的static目录是自己创建的,如下图:
nginx配置及运行测试
配置nginx,在原有配置文件中再新增一个server块,如下配置:
运行测试:
跨域问题出现了,现在前后端都不想改代码,要干架吗?nginx说:和谐,一定要和谐~~~
在API的server中进行跨域配置,如下:
重启nginx之后,再测试,看看搞定了没?
现在的站点几乎都是https了,所以这个功能必须要实操一把;为了更符合真实线上场景,我特意准备了域名和证书,真真实实在阿里云服务器上演示; 这里需要登录到阿里云上购买域名,然后根据域名申请免费的SSL证书,最后进行配置使用,详情如下:
这里我注册了一个域名为:codezyq.cn;下面先说说注册域名的流程:
登录阿里云,找到域名注册入口
进入到一个页面,然后输入需要注册的域名
然后就出现搜索结果,如果被注册就会提示,可以选择其他类型或更换域名
买了域名之后,需要进行实名认证,个人上传身份证就完事啦,一会就实名完成; 完成之后就需要配置域名解析,即解析到自己的云服务器上,后续通过域名才可以访问;
测试是否能解析成功,直接在自己电脑上ping一下域名,看看是否解析到指定IP即可,简单直接;这样域名就可以用啦~~~
免费证书这块的申请需要用到买的域名,大概步骤如下:
领取免费证书数量(20个)
进入SSL证书(应用安全页面)进行证书创建
进行证书申请,即绑定域名
填写申请信息,如下:
这里一般填完申请信息,后续验证那块直接过也能签发,列表状态如下:
签发完成之后,下载对应服务器的证书即可,点击下载选择
直接下载下来一会配置使用。
检查环境
检查端口是否可访问
https需要443端口,所以在阿里云中将443端口加入到安全组中,如下图:
另外还需要查看云服务器的防火墙有没有开放对应的端口,如下命令:
# 查看防火墙端口开放情况 firewall-cmd --list-all public target: default icmp-block-inversion: no interfaces: sources: services: dhcpv6-client ssh # 显示的结果没有开放443端口 ports: 80/tcp 22/tcp 5000/tcp 3306/tcp 6379/tcp # 将443端口加入到里面 firewall-cmd --zone=public --add-port=443/tcp --permanent # 重新加载 firewall-cmd --reload # 再看防火墙端口开放情况 firewall-cmd --list-all public target: default icmp-block-inversion: no interfaces: sources: services: dhcpv6-client ssh # 443端口加入进来了 ports: 80/tcp 22/tcp 5000/tcp 3306/tcp 6379/tcp 8080/tcp 443/tcp
检查nginx中是否包含http_ssl_module模块
在配置证书之前需要检查一下nginx中是否已经包含http_ssl_module:
如果没有就算配置了也不能用,如下:
为nginx加上http_ssl_module
需要下载一个源码进行引入,这里还是使用版本1.18.0,具体步骤如下:
第一步,先准备环境,比如支持编译、openssl等,执行以下命令:
# 安装对应的包 yum -y install gcc openssl openssl-devel pcre-devel zlib zlib-devel
第二步,下载对应版本源码到usr/local/src中,并进行解压,执行以下命令
# 下载指定版本nginx包 wget http://nginx.org/download/nginx-1.18.0.tar.gz # 解压 tar -zxvf nginx-1.18.0.tar.gz
第三步,进入解压目录中,配置http_ssl_module,命令如下:
# 进入解压目录 cd nginx-1.18.0 # 加入http_ssl_module ./configure --prefix=/usr/local/nginx --with-http_ssl_module
第四步,编译,在解压目录中直接执行make命令即可
# 执行make命令,在当前目录就会添加新目录objs make # 如果是新安装nginx,执行以下命令 # make&make install
如果没报错,就编译出最新的啦; 这里我在实操的时候,先执行的./configure 配置命令,然后再执行第一步的命令,所以导致make的时候老是不成功,这里解决方案是在添加http_ssl_module模块时,同时指定了openssl源码路径(直接下载即可),然后再执行make命令就成功了。命令如下:
# 指定openssl源码路径 需要下载 ./configure --prefix=/usr/local/nginx --with-openssl=/usr/src/openssl-1.1.1d --with-http_ssl_module # 再执行make命令编译 make
第五步,将编译出来新的nginx文件替换原有的nginx文件,操作如下:
在nginx配置SSL的支持
还记得获取下载证书的时候吗,下载界面那有一个帮助操作,点击就有nginx配置SSL证书的详细步骤,如下图:
这里演示配置的内容如下(新增一个server块,专门配置SSL的):
server { # https 监听的是443端口 listen 443 ssl; # 指定准备好的域名 server_name codezyq.cn; # 指定证书路径,这里需要把准备好的证书放到此目录 ssl_certificate /usr/local/nginx/myssl/codezyq.cn.pem; ssl_certificate_key /usr/local/nginx/myssl/codezyq.cn.key; ssl_session_cache shared:SSL:1m; # 超时时间 ssl_session_timeout 5m; # 表示使用的加密套件的类型 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; # 表示使用的TLS协议的类型 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; location /www/ { root static; index index.html index.htm; } }
重启nginx,然后进行https访问对应的连接就可以啦
注:网站如果没有备案,会被拦截,会导致不能访问,正规站点都是要备案的。
盗链通俗一点的理解就是别人的网站使用自己服务器的资源,比如常见的在一个网站引入其他站点服务器的图片等资源,这样被盗链的服务器带宽等资源就会额外被消耗,在一定程度上会损害被盗链方的利益,所以防盗链是必要的;这里通过nginx简单实现静态资源防盗链的案例,原理很简单,就是判断一下请求源是否被允许。
将准备的html和图片放在创建的static目录下,如下图:
anti-stealing-link.html内容如下
<!DOCTYPE html> <html> <head> <title>anti-stealing-link test</title> </head> <body> <h2>使用云服务器上的图片</h2> <!-- 访问服务器图片 --> <img src="http://47.113.204.41/img/test.jpg" alt=""> </body> </html>
server { listen 80; server_name 47.113.204.41; # 针对html访问的匹配规则 location /www/ { root static; index index.html index.htm; } # 针对图片访问的匹配规则 location /img/ { root static; } charset utf-8; }
运行起来看效果:
现在有个需求,只能是云服务器的html才能使用图片,其他引用源都认为是盗链,直接返回403或重写到固定图片。
针对img配置如下:
server { listen 80; server_name 47.113.204.41; # 针对html访问的匹配规则 location /www/ { root static; index index.html index.htm; } # 针对图片访问的匹配规则 location /img/ { root static; #对源站点的验证,验证IP是否是47.113.204.41 #可以输入域名,多个空格隔开 valid_referers 47.113.204.41; #非法引入会进入下方判断 if ($invalid_referer) { #这里返回403,也可以rewrite到其他图片 return 403; } } charset utf-8; }
重启nginx,清除缓存再试:
防盗链是不是很简单,也可以通过代码的形式,比如在过滤器或管道中也可以实现,如果没有特殊需求,nginx稍微一配置就能实现,岂不美哉~~~
之前在项目中做渗透测试时,其中有一项问题就是不希望在响应头中体现服务器相关版本,避免在某些版本出现漏洞时,攻击者可以特意针对此版本进行恶意攻击,从而影响系统服务可用性。
现有情况:
页面找不到时:
看看nginx是如何关闭,如下配置:
看效果:
正常访问
找不到报错,版本也没有啦
尽管nginx性能再强,但服务器和网络有很多因素是不可控的,如:网络抖动、网络不通、服务器宕机等情况,都会导致服务不可用(可理解为单点故障),这样的系统体验肯定得不到好评;如果当一个服务器宕机或服务挂掉时,另外一台服务器自动代替宕机服务器提供服务,保证系统的正常运行,这就实现了高可用;这里nginx实现高可用的方式和Redis的主从模式很相似,只是nginx使用的是keepalived来实现高可用集群。
keepalived实现高可用的关键思路还是主、备节点的来回切换;
由上可见,在keepalive实现高可用时,肯定要有机制选择主备节点,主备之间肯定要互相通知,不然咋知道节点之间的健康状态,所以就使用了VRRP协议,目的就是为了解决静态路由的单点故障。
VRRP协议,全称Virtual Router Redundancy Protocol(虚拟路由冗余协议),利用IP多播的方式实现通信;通过竞选协议机制(根据配置的优先级来竞选)来将路由任务交给某台VRRP路由器,保证服务的连续性;
理论先了解这么多,先来把keepalived安装上,
方式一
执行以下命令可直接安装:
# 安装,这种直接安装完成了,修改配置文件启动即可 yum install-y keepalived # 启动 systemctl start keepalived.service
这种方式可能会遇到启动keepalived的时候报错,原因可能是服务配置文件(/usr/lib/systemd/system/keepalived.service)指定的keepalived相关目录找不到; 如果文件目录都正常,还报错,我折腾了好久,后来用源码方式进行安装就正常啦~~~
方式二
建议使用源码的形式进行安装,大概步骤如下:
第一步,环境准备
# 安装对应的依赖包 yum -y install gcc openssl openssl-devel pcre-devel zlib zlib-devel
第二步,下载并解压源码包
# 在/usr/local/src目录下执行,下载到该目录 wget https://www.keepalived.org/software/keepalived-2.0.18.tar.gz # 解压 tar -zxvf keepalived-2.0.18.tar.gz
第三步,安装
# 进入到解压出来的目录 cd keepalived-2.0.18 # 编译并安装 ./configure && make && make install
第四步,创建启动文件,即将编译出来的文件拷贝到对应的目录下
cp -a /usr/local/etc/keepalived /etc/init.d/ cp -a /usr/local/etc/sysconfig/keepalived /etc/sysconfig/ cp -a /usr/local/sbin/keepalived /usr/sbin/
第五步,创建配置文件
# 先创建配置文件存放的目录 mkdir /etc/keepalived # 再将创建好的配置文件通过xFtp传到此目录,也可以直接在这里创建
配置文件名为keepalived.conf,内容如下:
! Configuration File for keepalived global_defs { # 每台机器的唯一标识 router_id 31 } # vrrp实例,可以配置多个 vrrp_instance VI_1 { # 标识为主节点,如果是被节点,就为BACKUP state MASTER # 网卡名称,通过ip addr 命令可以看到对应网卡,需要哪个就配置哪个就行 interface enp0s8 # 路由ID,主、备节点的id要一样 virtual_router_id 3 # 优先级,主节点的优先级要大于备节点的优先级 priority 200 # 主备心跳检测,间隔时间为1s advert_int 1 # 认证方式,主备节点要一致 authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { # 虚拟IP 192.168.30.108 } }
第六步,启动
# 启动 systemctl start keepalived.service # 查看虚拟IP情况 ip addr
查看效果如下,虚拟ip正常在master节点上:
安装完keepalived和nginx之后就可以进行主备演示啦~~~
这里用了两台虚拟机,结构如下:
第一步nginx配置准备
这里用到的就是nginx默认配置,基本没咋改,如果要了解配置文件详情,点击(Nginx超详细常用功能演示,够用啦~~~)有详细说明。两台虚拟机配置的nginx.conf内容如下:
#user nobody; worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; #gzip on; server { # 需要防火墙开放80端口 listen 80; server_name localhost; location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
第二步准备html
两台虚拟机中html,用的是nginx默认的index.html(路径:/usr/local/nginx/html),为了方便演示,在index.html中增加了个105和106的显示标注,105机器内容如下,106机器上的html只是把内容中的105改成106即可:
第三步准备两台虚拟机上keepalived配置文件(路径:/etc/keepalived)
105机器上keepalived.conf内容如下:
! Configuration File for keepalived global_defs { # 每台机器不一样 router_id 31 } #检测nginx服务是否在运行 vrrp_script chk_nginx { #使用脚本检测 script "/usr/local/src/chk_nginx.sh" #脚本执行间隔,每2s检测一次 interval 2 #脚本结果导致的优先级变更,检测失败(脚本返回非0)则优先级 -5 weight -5 #连续2次检测失败才确定是真失败 fall 2 #检测到1次成功就算成功 rise 1 } vrrp_instance VI_1 { # vrrp实例,可以配置多个 state MASTER # 网卡名称,通过ip addr 命令可以看到对应网卡,需要哪个就配置哪个就行 interface enp0s8 # 路由ID,主、备节点的id要一样 virtual_router_id 3 # 优先级,主节点的优先级要大于备节点的优先级 priority 200 # 主备心跳检测,间隔时间为1s advert_int 1 # 认证方式,主备节点要一致 authentication { auth_type PASS auth_pass 123456 } #执行监控的服务。 track_script { #引用VRRP脚本,即在 vrrp_script 部分指定的名字。 chk_nginx } virtual_ipaddress { # 虚拟IP 192.168.30.108 } }
在/usr/local/src/中准备chk_nginx.sh,keepalived和nginx没有直接关系的,只有通过检查nginx的运行状态来进行高可用服务切换,chk_nginx.sh内容如下:
然后给这个文件增加执行权限,命令如下:
chmod +x chk_nginx.sh
106虚拟机上的步骤和检测脚本chk_nginx.sh都一样,只是keepalived.conf内容稍微有点变动。
106机器上keepalived.conf内容如下:
! Configuration File for keepalived global_defs { # 每台机器上不一样 router_id 32 } #检测nginx服务是否在运行 vrrp_script chk_nginx { #使用脚本检测 script "/usr/local/src/chk_nginx.sh" #脚本执行间隔,每2s检测一次 interval 2 #脚本结果导致的优先级变更,检测失败(脚本返回非0)则优先级 -5 weight -5 #连续2次检测失败才确定是真失败 fall 2 #检测到1次成功就算成功 rise 1 } vrrp_instance VI_1 { # 配置为备节点 state BACKUP # ip addr 查看对应的网卡名称 interface enp0s8 virtual_router_id 3 # 优先级比主节点低 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 123456 } #执行监控的服务 track_script { #引用VRRP脚本,即在 vrrp_script 部分指定的名字。 chk_nginx } virtual_ipaddress { # 虚拟IP 192.168.30.108 } }
第四步分别启动两台虚拟机上的nginx和keepalived,命令如下:
# 启动nginx cd /usr/local/nginx/sbin/ ./nginx # 启动keepalived systemctl start keepalived.service # 查看keepalived状态,是否运行 systemctl status keepalived.service
两台虚拟机都要执行
第五步测试,效果如下:
直接访问虚拟IP就能访问到主节点的服务啦;现在测试当主节点挂掉时,还会不会正常访问服务,在105机器上执行如下命令:
# 模拟宕机,停止keepalived systemctl stop keepalived.service # ip addr 查看虚拟IP已经漂移到备节点上了,在备节点用ip addr 查看
备节点显示,虚拟IP已经漂移过来啦~
再用虚拟IP访问,效果如下:
看见已经切换到106机器上提供服务啦,这样就实现高可用啦;
那主节点重新恢复,虚拟IP会不会恢复回来继续提供服务呢?
# 重启keepalived systemctl restart keepalived.service #ip addr 查看虚拟IP情况,恢复过来啦
继续用虚拟IP访问服务,又回到主服务啦,如果没有,那可能是浏览器缓存,因为这里用静态html演示,清掉缓存再访问。
对于上面的主备模式,只有主节点提供服务,如果主节点不发生故障,备节点服务器就有点资源浪费啦,这个时候多主多备不仅能合理利用资源,还得提供备用服务(根据实际需要配置),形成真正集群提供服务。
这里就演示一下双主双备的配置,思路就是在keepalived增加多个vrrp实例,105机器在vrrp实例VI_1中作为主节点,106机器作为备节点,在vrrp实例VI_2中,105机器作为备节点,106机器作为主节点,这样就形成了互为主备的模式,资源就能很好的利用啦;其他逻辑不变,只是分别在105、106机器上加上的keepalived.conf中加上VI_2实例即可,如下:
105机器上keepalived.conf内容如下:
global_defs { router_id 31 } #检测nginx服务是否在运行 vrrp_script chk_nginx { #使用脚本检测 script "/usr/local/src/chk_nginx.sh" #脚本执行间隔,每2s检测一次 interval 2 #脚本结果导致的优先级变更,检测失败(脚本返回非0)则优先级 -5 weight -5 #连续2次检测失败才确定是真失败 fall 2 #检测到1次成功就算成功 rise 1 } vrrp_instance VI_1 { state MASTER interface enp0s8 virtual_router_id 3 priority 200 advert_int 1 authentication { auth_type PASS auth_pass 123456 } track_script { chk_nginx } virtual_ipaddress { 192.168.30.108 } } vrrp_instance VI_2 { # VI_1是MASTER,这里就是备节点 state BACKUP interface enp0s8 # 修改路由编号 virtual_router_id 5 # 备节点优先级稍低 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 123456 } track_script { chk_nginx } virtual_ipaddress { # 虚拟IP 192.168.30.109 } }
106机器上keepalived.conf内容如下:
global_defs { router_id 32 } #检测nginx服务是否在运行 vrrp_script chk_nginx { #使用脚本检测 script "/usr/local/src/chk_nginx.sh" #脚本执行间隔,每2s检测一次 interval 2 #脚本结果导致的优先级变更,检测失败(脚本返回非0)则优先级 -5 weight -5 #连续2次检测失败才确定是真失败 fall 2 #检测到1次成功就算成功 rise 1 } vrrp_instance VI_1 { state BACKUP interface enp0s8 virtual_router_id 3 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 123456 } track_script { chk_nginx } virtual_ipaddress { 192.168.30.108 } } vrrp_instance VI_2 { # 这里是主节点 state MASTER interface enp0s8 # 这里和105机器上的VI_2中id一致 virtual_router_id 5 priority 200 advert_int 1 authentication { auth_type PASS auth_pass 123456 } track_script { chk_nginx } virtual_ipaddress { # 虚拟IP 192.168.30.109 } }
分别重启两台机器上的keepalived,执行命令如下:
然后分别访问虚拟ip 192.168.30.108 和192.168.30.109,都能提供对应的服务啦,这里不截图了。
开发和生产环境比较常用的功能大概就这么多,后续如果用得多的功能会及时和小伙伴分享哦。
这次主要遇见一些问题,小伙伴可以作为参考,汇总如下:
VMware虚拟机网络问题,主机ping不通虚拟机、虚拟机ping不通主机、上不了外网
这个问题折腾了两个晚上,原因是之前的网络配置有一些问题,然后重新装了虚拟机,但是用单网卡的方式依然没有同时解决上面的问题,最后使用两个网卡的方式解决了; 一个网卡使用动态分配,另外一个使用静态IP,信息如下:
keepalived启动不起来
使用yum直接安装的方式,可能会遇到启动不起来的情况,排查了服务里面配置路径,目录都对,依赖包也装了还不行;最后使用源码方式安装没问题。
keepalived的虚拟ip主机ping不通
这也是个棘手的问题,虚拟ip能在主、备机器之间正常漂移,就是主机ping不同虚拟IP,当前解决的措施主要步骤,如下:
首先注释掉keepalived.conf 中vrrp_strict ,然后重启keepalived;
如果还不行,就排查防火墙;
再不行,就清arp缓存