zoukankan      html  css  js  c++  java
  • 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;

            }

  • 相关阅读:
    [Python] socket实现TFTP上传和下载
    [Python] socket发送UDP广播实现聊天室功能
    [C#] 建立UDP连接、发送广播
    [Python] Scrapy爬虫框架入门
    [Python] 常见的排序与搜索算法
    [Python] 数据结构--实现顺序表、链表、栈和队列
    [Python] Django框架入门5——静态文件、中间件、上传图片和分页
    [Python] Django框架入门4——深入模板
    [Python] Django框架入门3——深入视图
    [Python] Django框架入门2——深入模型
  • 原文地址:https://www.cnblogs.com/Presley-lpc/p/13154568.html
Copyright © 2011-2022 走看看