Linux学习108 nginx实现模块化应用实战
一、相应模块
1、ngx_http_ssl_module模块
a、ssl on | off
Enables the HTTPS protocol for the given virtual server
b、ssl_certificate file
当前虚拟主机上与其证书匹配的私钥文件
c、ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2];
支持ssl协议版本,默认为后三个
d、ssl_session_cache off | none | [builtln[:size]] [shared:name:size];
builtin[size]:使用OpenSSL内建的缓存,此缓存为每worker进程私有
[shared:name:size]:在各worker之间使用一个共享的缓存
e、ssl_session_timeout time
客户端一侧的连接可以复用ssl session cache中缓存的ssl参数的有效时长。
f、配置示例
(1)、我们在192.168.10.13上配置一个https的虚拟主机。我们把192.168.10.14节点作为CA服务器。
(2)、我们先在192.168.10.14上创建一个CA
1)、首先我们创建私钥
[root@node2 ~]# (umask 077;openssl genrsa -out /etc/pki/CA/private/cakey.pem 2048) Generating RSA private key, 2048 bit long modulus ............................................................+++ .....................................+++ e is 65537 (0x10001) [root@node2 ~]# ll /etc/pki/CA/private/cakey.pem -rw------- 1 root root 1675 Jun 17 20:09 /etc/pki/CA/private/cakey.pem
2)、然后我们创建一个自签证书
[root@node2 ~]# openssl req -new -x509 -key /etc/pki/CA/private/cakey.pem -out /etc/pki/CA/private/cacert.pem -days 365 You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [XX]:CN State or Province Name (full name) []:Chengdu Locality Name (eg, city) [Default City]:Chengdu Organization Name (eg, company) [Default Company Ltd]:wohaoshuai Organizational Unit Name (eg, section) []:devops Common Name (eg, your name or your server's hostname) []:cahost.wohaoshuai.com Email Address []:
3)、创建相应的文件和路径
[root@node2 ~]# echo 01 > /etc/pki/CA/serial
(3)、我们在192.168.10.13上创建相应的私钥和证书申请文件
1)、创建存放路径
[root@www /]# mkdir -p /etc/nginx/ssl [root@www /]# cd /etc/nginx/ssl
2)、创建nginx的私钥
[root@www ssl]# (umask 077; openssl genrsa -out /etc/nginx/ssl/nginx.key 2048) Generating RSA private key, 2048 bit long modulus ..........................+++ ...+++ e is 65537 (0x10001)
3)、创建证书签署请求
[root@www ssl]# openssl req -new -key /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.csr -days 365 You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [XX]:CN State or Province Name (full name) []:Chengdu Locality Name (eg, city) [Default City]:Chengdu Organization Name (eg, company) [Default Company Ltd]:wohaoshuai Organizational Unit Name (eg, section) []:devops Common Name (eg, your name or your server's hostname) []:www.wohaoshuai1.com Email Address []:1209989516@qq.com Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []:
4)、然后将这个证书签署请求从192.168.10.13复制到192.168.10.14进行签署
[root@www ssl]# scp /etc/nginx/ssl/nginx.csr root@192.168.10.14:/tmp/ root@192.168.10.14's password: nginx.csr
然后在192.168.10.14进行签署
[root@node2 CA]# openssl ca -in /tmp/nginx.csr -out /etc/pki/CA/certs/nginx.crt -days 365 Using configuration from /etc/pki/tls/openssl.cnf Check that the request matches the signature Signature ok Certificate Details: Serial Number: 1 (0x1) Validity Not Before: Jun 18 01:58:12 2020 GMT Not After : Jun 18 01:58:12 2021 GMT Subject: countryName = CN stateOrProvinceName = Chengdu organizationName = wohaoshuai organizationalUnitName = devops commonName = www.wohaoshuai1.com emailAddress = 1209989516@qq.com X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: B1:1A:16:00:86:31:44:A5:C6:EA:E1:2C:CC:4F:49:EA:EE:0D:41:7C X509v3 Authority Key Identifier: keyid:CF:B4:6A:51:6B:CE:9E:E8:25:6B:91:65:09:CC:4B:AE:53:66:85:28 Certificate is to be certified until Jun 18 01:58:12 2021 GMT (365 days) Sign the certificate? [y/n]:y 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated
然后将签署的证书复制到192.168.10.13上
5)、然后我们在192.168.10.13主机上就可以看到相应的证书了
[root@www nginx]# ll /etc/nginx/ssl/ 总用量 16 -rw-r--r-- 1 root root 4603 6月 18 10:00 nginx.crt -rw-r--r-- 1 root root 1070 6月 18 09:56 nginx.csr -rw------- 1 root root 1675 6月 18 09:55 nginx.key
(4)、然后我们在192.168.10.13上开始做证书配置
[root@www /]# cat /etc/nginx/conf.d/vhost1_ssl.conf server { listen 443 ssl; server_name www.wohaoshuai1.com; root /data/nginx/vhost1; access_log /var/log/nginx/vhost1_ssl_access.log main; #这个main是主配置文件/etc/nginx/nginx.conf中定义的main类日志格式 #ssl on; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; ssl_protocols sslv3 tlsv1 tlsv1.1 tlsv1.2; ssl_session_cache shared:SSL:10m; location / { #root /data/nginx/vhost2; allow all; } location ~* ^/(admin|login) { auth_basic "admin area or login url"; auth_basic_user_file /etc/nginx/.ngxpasswd; access_log /var/log/nginx/vhost1_admin_access.log main; } location ~*\.(jpg|png)$ { deny 192.168.10.14; allow all; } location ^~ /images/ { alias /data/pictures/; } error_page 404 =200 /notfound.html; location = /notfound.html { root /data/nginx/error_pages; } location /ngxstatus { #最好把auth_basic也写上,因为不能随意让其他人访问 stub_status; access_log off; } } [root@www /]# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful [root@www /]# nginx -s reload
[root@www /]# netstat -anpt|grep 443 tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 2924/nginx: master
(5)、然后我们在浏览器中导入192.168.10.14的自签证书就可以正常进行https访问了。
2、ngx_http_rewrite_module模块
a、The ngx_http_rewrite_module module is used to change request URI using PCRE regular expressions,return redirects,and conditionally select configurations
b、bbs.wohaoshuai.com/ --> www.wohaoshuai.com/bbs/,http://www.wohaoshuai.com/ --> https://www.wohaoshuai.com/ :重写的意思是,可以看到我们用户去访问bbs.wohaoshuai.com下面的/的时候我们要将其路径转换为www.wohaoshuai.com/bbs/这个路径
http://www.wohaoshuai.com/login.php:username=tom --> http://www.wohaoshuai.com/tom/
所以这个请求就变成这样:我们客户端发请求请求的URL是www.wohaoshuai.com/bbs,我们主机在自己内部读取配置文件时发现这个URL其实已经本地不存在了改成别的了,于是返回一个信息给客户端告诉你新位置在响应报文中使用location这个响应报文守护,指定新位置为http://bbs.wohaoshuai.com/,于是你的客户端浏览器会再一次自动的去找bbs.wohaoshuai.com这个域名,这个域名可能是另外一台服务器,那么bbs.wohaoshuai.com这台服务器就返回结果给我们的主机。
还有一种情形,假如我们网站做的全栈https,比如你访问www.wohaoshuai.com就是明文的,现在假如我们不期望是明文的要怎么办呢?这时候我们就可以重定向,即将www.wohaoshuai.com的访问重定向到https://www.wohaoshuai.com上
假如现在我们有http://www.wohaoshuai.com/media/audio/.wmv这个站点文件,这是一个音频文件,这个文件压缩以后失真比较大,我们后来对各种音频文件重新提供了mp3格式的,但是很多人通常还是习惯访问这种格式要怎么办呢?而且我们把路径也改了,改成了http://www.wohaoshuai.com/media/mp3/a.mp3了,于是再有人访问我们原链接时我们就将其重写为http://www.wohaoshuai.com/media/mp3/a.mp3。
c、将用户请求的URL基于regex所描述的模式进行检查,而后完成替换
d、rewrite regex replacement [flag]
(1)、将用户请求的URL基于regex所描述的模式进行检查,匹配到时将其替换为replacement指定的新的URL;
(2)、注意:如果在同一级配置块中存在多个rewrite规则,那么会自上而下逐个检查,被某条件规则替换完成后,会重新一轮的替换检查,因此,隐含有循环机制;[flag]所表示的标志位用于控制此循环机制
(3)、如果replacement是以http://或https://开头,则替换结果会直接以重向返回给客户端
301:永久重定向
e、[flag]:
(1)、last:重写完成后停止对当前URL在当前location中后续的其它重写操作,而后对新的URL启动新一轮重写检查,提前重启新一轮循环。即在一个配置段中你很有可能有多条rewrite规则,比如某个location其内部的rewrite规则有三条,他是怎么去实现这些规则检查的呢?其实他的工作逻辑是这样的,即用户请求这个url时他只要匹配到这个URL他才会到里面的rewrite上来,第一个rewrite检查完以后就重写完成了,完成后意味着已经是一个新URL了,新的URL还能匹配这个location么?是不一定的,因此一旦规则重写完以后他会拿着新的URL去重新检查整个配置文件的,或者你可以理解为他会再去检查整个配置文件中location的规则。直到循环到再也匹配不到谁了于是这个location就处理完往后走了。我们发现我们的循环有点像continue,即一旦被某个规则匹配了那就提前结束本轮循环而进入下一轮,而下一轮如果被某个rewrite匹配了就又提前结束本轮循环再到下一轮。我们的默认的行为就是这样的。因此我们每一个循环后面我们可以写一个last标志,他的意思是如果本次匹配到了就将重写后的URL拿过来再重新循环进行匹配检查。但是我们这种行为有可能导致死循环,因为有可能存在说第一条改回去被第二条匹配,第二条改回去又被第一条匹配。
(2)、break,那么我们如果明知道第一条改写完后第二条能匹配,第二条改写完后第一条能匹配,现在我们期望的是由第一条改完以后第二条就不要检查了,或者由第二条改完以后第一条就不要再检查了,我们就可以使用break,即跳出循环。
图中表示如果第一个rewrite检查匹配了就直接跳到后面的配置中去了,就不需要再循环检查了。
(3)、redirect,表示重定向。即使用302的重定向响应码来响应,即告诉客户端这是重定向的。我们一般默认的响应码都是200,即浏览器自己就给你重定向新位置去了。如果我们改成了redirect,那么他会告诉客户端新的位置在哪儿,然后客户端就自己请求新位置。即使用redirect就是客户端你自己动,不使用redirect的话就是服务器主动。
(4)、permanent,表示永久重定向,即客户端请求的时候重定向响应码为301,但是访问到的资源的响应码为200。此配置也是需要浏览器重新发请求的。
f、return
return code [text];
return code URL;
return URL;
Stops processing and returns the specified code to a client
g、rewrite_log on | off
是否开启重写日志
h、if (condition){...}
(1)、引入一个新的配置上下文,条件满足时,执行配置块中的配置命令;server,location
(2)、condition:
1)、比较操作符:
==
!=
~:模式匹配,区分字符大小写
~*:模式匹配,不区分字符大小写
!~:模式不匹配,区分字符大小写
!~*:模式不匹配,不区分字符大小写
2)、文件即目录存在性判断:
-e,!-e
-f,!-f
-d,!-d
-x,!-x
i、set $variable value
用户自定义变量;
g、示例
(1)示例1:假如此前我们访问我们服务器上的图片都是png格式的,后来我们提供了jpg格式的,即只要访问png格式的我们统统给你重写成jpg结尾的。
: 1)、在配置文件中进行配置
server { listen 80; server_name www.wohaoshuai1.com; root /data/nginx/vhost1; access_log /var/log/nginx/vhost1_access.log main; #这个main是主配置文件/etc/nginx/nginx.conf中定义的main类日志格式 rewrite /(.*)\.png$ /$1.jpg; location / { #root /data/nginx/vhost2; allow all; } location ~* ^/(admin|login) { auth_basic "admin area or login url"; auth_basic_user_file /etc/nginx/.ngxpasswd; access_log /var/log/nginx/vhost1_admin_access.log main; } location ~*\.(jpg|png)$ { deny 192.168.10.14; allow all; } location ^~ /images/ { alias /data/pictures/; } error_page 404 =200 /notfound.html; location = /notfound.html { root /data/nginx/error_pages; } location /ngxstatus { #最好把auth_basic也写上,因为不能随意让其他人访问 stub_status; access_log off; } }
配置文件中的/(.*)\.png$ /$1.jpg 的意思是/下匹配任意多个内容然后以.png结尾的文件都重写成/下任意内容.jpg,其中的这个$1是引用的前面的这个(.*)。后面重写的/$1.jpg这一项是不支持正则表达式的,因此我们的点号不用添加转义。
2)、我们查看我们相应目录中的图片
[root@www images]# ll /data/pictures/ 总用量 960 drwxr-xr-x 2 root root 25 6月 18 13:23 images -rw-r--r-- 1 root root 980265 6月 18 13:25 morning.jpg
3)、然后我们访问http://www.wohaoshuai1.com/images/morning.png,可以看到我们服务器上并没有morning.png这个图片,但是我们可以访问到morning.jpg,这是因为我们对访问的url进行了重写。
(2)、示例2:用户无论请求任何内容,都统统改写为https://www.wohaoshuai1.com/加相应的路径内容
1)、配置文件配置
[root@www images]# cat /etc/nginx/conf.d/vhost1.conf server { listen 80; server_name www.wohaoshuai1.com; root /data/nginx/vhost1; access_log /var/log/nginx/vhost1_access.log main; #这个main是主配置文件/etc/nginx/nginx.conf中定义的main类日志格式 #rewrite /(.*)\.png$ /$1.jpg; rewrite /(.*)$ https://www.wohaoshuai1.com/$1; location / { #root /data/nginx/vhost2; allow all; } location ~* ^/(admin|login) { auth_basic "admin area or login url"; auth_basic_user_file /etc/nginx/.ngxpasswd; access_log /var/log/nginx/vhost1_admin_access.log main; } location ~*\.(jpg|png)$ { deny 192.168.10.14; allow all; } location ^~ /images/ { alias /data/pictures/; } error_page 404 =200 /notfound.html; location = /notfound.html { root /data/nginx/error_pages; } location /ngxstatus { #最好把auth_basic也写上,因为不能随意让其他人访问 stub_status; access_log off; } } [root@www images]# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful [root@www images]# nginx -s reload
2)、然后我们访问http://www.wohaoshuai1.com/的时候就发现会被重定向到https://www.wohaoshuai1.com/。
(3)、示例3
1)、如果我们上面的两个rewrite都写上,那么两个规则都会生效的,比如我们请求http://www.wohaoshuai1.com/images/morning.png他就会将我们的连接重写为http://www.wohaoshuai1.com/images/morning.jpg,然后他又会将我们的http://www.wohaoshuai1.com/images/morning.jpg链接重写为https://www.wohaoshuai1.com/images/morning.jpg。我们在示例1中请求的内容在浏览器中看到的是http://www.wohaoshuai1.com/images/morning.png,而此时我们在浏览器中看到的就是https://www.wohaoshuai1.com/images/morning.jpg了。因此两个规则都生效的。即我们的规则是会自上而下依次检查匹配的。那么这儿检查是怎么实现的呢?为什么检查完第一个还要检查第二个呢?我能不能改成别的呢?并且万一我们写了两条规则造成死循环,第一条匹配完就匹配第二条第二条匹配完后又匹配第一条。
(4)、rewrite flag配置
[root@www images]# cat /etc/nginx/conf.d/vhost1.conf server { listen 80; server_name www.wohaoshuai1.com; root /data/nginx/vhost1; access_log /var/log/nginx/vhost1_access.log main; #这个main是主配置文件/etc/nginx/nginx.conf中定义的main类日志格式 #rewrite /(.*)\.png$ /$1.jpg; rewrite /(.*)$ https://www.wohaoshuai1.com/$1 break; location / { #root /data/nginx/vhost2; allow all; } location ~* ^/(admin|login) { auth_basic "admin area or login url"; auth_basic_user_file /etc/nginx/.ngxpasswd; access_log /var/log/nginx/vhost1_admin_access.log main; } location ~*\.(jpg|png)$ { deny 192.168.10.14; allow all; } location ^~ /images/ { alias /data/pictures/; } error_page 404 =200 /notfound.html; location = /notfound.html { root /data/nginx/error_pages; } location /ngxstatus { #最好把auth_basic也写上,因为不能随意让其他人访问 stub_status; access_log off; } }
3、ngx_http_referer_module模块
a、The ngx_http_referer_module module is used to block access to a site for requests with invalid values in the "Referer" header field。即我们的网站允许谁来引用
b、valid_referers none | blocked | server_names | string ...; #即合法引用,即我们网站的图片只允许我们自己的站点来引用,别的网站引用我都可以拒绝你。我们这儿是定义谁是合法的,不符合我们定义的都是非法的
(1)、定义referer首部的合法可用值
none:请求报文首部没有referer首部。即request报文中没有referer引用标签的话就合法,即可以引用我们的资源。我们如果一开始直接输入我们的连接的话就没有引用,即request中没有referer字段,如果我们是从某个链接跳转过去的那么就有referer字段了,我们也就没法引用了。
blocked:请求报文的referer首部没有值。即我们request中有referer字段但是没有值,他没有值的话就无法判定他来自于哪儿,有可能这个值被他的代理服务器给删掉了,所以就只能委屈的放行让其访问了。
server_names:参数,其可以有值作为主机名或主机名模式
regular expression:被指定的正则表达式模式匹配到的字符串;要使用~打头,例如~.*\.wohaoshuai\.com;
c、配置示例:
valid_referers none block server_names *.wohaoshuai.com *.wohaooshuai.com wohaoshuai.* wohaooshuai.* ~\.wohaoshuai\.;
if($invalid_referer){
return 403;
}
上面的意思是我们网站允许哪些站点引用,如果不是被允许的就返回403,即非法引用就返回403;
我们还可以将其return到某个链接上去,比如
if($invalid_referer){
return http://www,wohaoshuai.com/invalid.jpg;
}