• 入门Nginx


    一、正向代理和反向代理

    正向代理举例:翻越万里长城去游览墙外的景色
    反向代理举例:负载均衡

    正向代理和反向代理涉及三个主体:

    • 请求方
    • 代理
    • 被请求方

    正向代理中,代理跟请求方是一家子,请求方说要啥,代理就给他啥。
    反向代理中,代理跟被请求方是一家子,代理统筹规划让哪一个被请求方来处理请求,对于请求方来说,代理就是处理请求的人。大多数情况下,反向代理和被请求方在同一个服务器上。Nginx就是最常用的反向代理服务器。

    这里也提一下:动态代理和静态代理
    正向代理和反向代理是代理服务器的两种类型
    动态代理和静态代理是Java中的设计模式:代理模式。
    Spring的两大核心:

    • IOC控制反转依赖注入
    • AOP面向切面编程

    面向切面编程中大量使用动态代理,在每一个方法调用前、调用后、抛异常时进行处理,跟装饰器模式很像。

    二、nginx配置体系

    nginx主要配置位于/etc/nginx目录下,nginx不仅仅可以用于负载均衡HTTP请求,也可以用于基于TCP的其它协议的负载均衡。/etc/nginx/nginx.conf是nginx的跟配置,一切配置都是这个配置的子孙。

    /etc/nginx/nginx.conf

    users www-data;定义当前用户
    worker_prosesses 4;定义worker数
    pid /run/nginx.pid;定义pid文件
    
    events{......}
    http{...
        http协议的相关配置
        include xxx路径下的conf.d/*.conf;  可以使用文件通配符来描述文件,但是一定是文件而非文件夹
    }
    mail{
        ....mail相关的一些配置
        server{
            listen localhost:xx;
            protocol pop3;
            proxy on;
        }
        server{
            listen localhost:xxxx;
            protocol imap;
            proxy on;
        }
    }
    

    可以发现,最外层是协议,协议内部有若干个server组成,每个server监听一个端口,根据路径可以转发到本地的其它端口进行处理。include是简单的复制粘贴。

    三、用Nginx反向代理Tomcat服务器和Gunicorn服务器

    需求说明:Tomcat和Gunicorn分别运行在8080端口和8000端口,现在要让它们共用80端口。
    当使用:localhost/tomcat/myapp时,相当于localhost:8080/myapp
    当使用:localhost/gunicorn/myapp时,相当于localhost:8000/myapp

    server {
    	listen	80;
    	server_name	www.haha.com;
    	access_log	/var/log/nginx/reverse.log;
    	location /tomcat {
    		proxy_pass	http://127.0.0.1:8080/;
    		proxy_set_header Host $host;  
            proxy_set_header X-Real-IP $remote_addr;  
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    	}
    	location /gunicorn {
    		proxy_pass	http://127.0.0.1:8000/;
    		proxy_set_header Host $host;  
            proxy_set_header X-Real-IP $remote_addr;  
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    	}
    }
    

    server_name描述了服务器地址部分,既可以是域名,也可以是IP地址。这一项不可省略。
    设置proxy_set_header部分是将请求者的真实信息告知后台服务器

    需要注意的是:

    • 配置nginx时,每一句后面都带有一个分号,不带分号会出错,这是conf文件的语法;
    • 配置proxy_pass时,只能精确到端口号,不能转发到再下一级,比如proxy_pass http://127.0.0.1:8000/myweb/ 这样是错误的;
    • 配置proxy_pass时,端口号后面必须加上反斜杠/,否则路径拼接时会因为少一个反斜杠而无法解析,导致404错误。

    四、了解负载均衡

    负载均衡必然要用到反向代理,让Nginx作为大管家凌驾于处理请求的服务器之上,Nginx可以动态决定让哪个服务器来处理请求。负载均衡问题源远流长:两台相同的处理机处理若干任务,怎么处理能够使得任务尽早完成?这是“双塔”问题;两台不同的处理机处理若干任务,不同处理机处理不同任务花费时间不同,怎样分配任务才能使得任务尽早完成?

    负载均衡的核心问题就是:建立用户请求和服务器之间的映射。有如下几种方式:

    • 轮询
      server=counter++%server_size
      用于后台服务器性能差不多的情况
    • 轮盘赌
      每个服务器有一个权重weight,表示选中这个服务器作为请求处理者的概率。
      用于后台服务器性能有差异的情况
    • IP-Hash
      建立用户IP地址和后台服务器之间的映射表。
      用于解决Session问题,避免了Session共享带来的IO压力。
    • URL-Hash
      建立用户请求URL和后台服务器之间的映射表。
      用于解决服务器缓存分布分散,让某个服务器专门负责某类请求,这样能够更专业地处理请求。
      这种方式其实就相当于新建了一个Web程序,这时Nginx的作用更像是正向代理而不是反向代理。
    • Fair:按照响应时间
      Nginx知道每个后端服务器处理请求的时间,谁处理时间短就让谁来处理请求。
      在轮盘赌方法中,需要明确知道各个后台服务器的性能好坏。使用Fair方法可以自动检测出后台服务器性能好坏,从而动态分配。

    轮盘赌的方式进行如下配置,首先定义一个upstream,它是多个server的集合。然后在location中就可以直接使用这个upstream。

    upstream your_host_or_ip {     
        server 127.0.0.3:8000 weight=5;     
        server 127.0.0.3:8001 weight=5;     
        server 192.168.0.1:8000;     
        server 192.168.0.1:8001;     
    }     
    
    server {     
        listen          80;     
        server_name     your_host_or_ip;     
        access_log      /var/log/nginx/my_access.log main;     
    
        location / {     
                proxy_pass      http://your_host_or_ip;     
        }     
    }     
    

    需要注意的是,一台服务器有两种访问方式:ip地址和域名方式。ip地址方式肯定只能有一种方式进行访问,因为ip地址是全网唯一的。而一台服务器可以绑定多个域名,这样就可以通过多个域名访问同一个服务器了。
    当配置了upstream之后,upstream的名称肯定跟服务器的名称(IP或者域名)相同,所以一个域名只能进行一个负载均衡,一个IP也只能进行一个负载均衡,而一台服务器可以进行多个负载均衡。

    五、地址匹配

    location配置:
    直接写一个字符串,常规字符串匹配
    ~ 表示执行一个正则匹配,区分大小写
    ~* 表示执行一个正则匹配,不区分大小写
    ^~ 表示普通字符匹配。使用前缀匹配。如果匹配成功,则不再匹配其他location。
    = 进行普通字符精确匹配。也就是完全匹配。

    location配置的优先级:
    在Nginx的location和配置中location的顺序没有太大关系。正location表达式的类型有关。相同类型的表达式,字符串长的会优先匹配。
    以下是按优先级排列说明:
    第一优先级:等号类型(=)的优先级最高。一旦匹配成功,则不再查找其他匹配项。
    第二优先级:^~类型表达式。一旦匹配成功,则不再查找其他匹配项。
    第三优先级:正则表达式类型(~ ~*)的优先级次之。如果有多个location的正则能匹配的话,则使用正则表达式最长的那个。
    第四优先级:常规字符串匹配类型。按前缀匹配。

    下面示例一下四种地址类型:

    location = / {
        # 仅仅匹配请求 /
        [ configuration A ]
    }
    location / {
        # 匹配所有以 / 开头的请求。但是如果有更长的同类型的表达式,则选择更长的表达式。如果有正则表达式可以匹配,则优先匹配正则表达式。
        [ configuration B ]
    }
    location /documents/ {
        # 匹配所有以 /documents/ 开头的请求。但是如果有更长的同类型的表达式,则选择更长的表达式。
        #如果有正则表达式可以匹配,则优先匹配正则表达式。
        [ configuration C ]
    }
    location ^~ /images/ {
        # 匹配所有以 /images/ 开头的表达式,如果匹配成功,则停止匹配查找。所以,即便有符合的正则表达式location,也
        # 不会被使用
        [ configuration D ]
    }
    location ~* .(gif|jpg|jpeg)$ {
        # 匹配所有以 gif jpg jpeg结尾的请求。但是 以 /images/开头的请求,将使用 Configuration D
        [ configuration E ]
    }
    

    请求匹配实例:

    / -> configuration A
    /index.html -> configuration B
    /documents/document.html -> configuration C
    /images/1.gif -> configuration D
    /documents/1.jpg -> configuration E
    

    应用举例:隐藏内在的地址

    server {
        # 用 xxoo_admin 来掩饰 admin
        location / {
            # 使用break拿一旦匹配成功则忽略后续location
            rewrite /xxoo_admin /admin break;
        }
    
        # 访问真实地址直接报没权限
        location /admin {
            return 403;
        }
    }
    

    六、重写

    Nginx的反向代理像一个URL函数,输入是一个URL,输出也是一个URL。运行过程可能是这样的:

    用户发起请求url0
    url1=f(url0)
    url2=f(url1)
    ...直到url不再被重写,被路由到合适的请求处理结点
    

    语法

    在配置文件的server块中写,如:

    server {
        rewrite 规则 定向路径 重写类型;
    }
    
    • 规则:可以是字符串或者正则来表示想匹配的目标url
    • 定向路径:表示匹配到规则后要定向的路径,如果规则里有正则,则可以使用$index来表示正则里的捕获分组
    • 重写类型:
    • last :浏览器地址栏URL地址不变,本条规则完成后,会对重写后的URL进行重新匹配。
    • break:浏览器地址栏URL地址不变。本条规则匹配完成后,终止匹配,不再匹配后面的规则,
    • redirect:返回302临时重定向,浏览器地址会显示跳转后的URL地址
    • permanent:返回301永久重定向,浏览器地址栏会显示跳转后的URL地址

    需要注意:

    • 重写表达式只对相对路径有效。如果想配对主机名,应该使用if语句。
    • rewrite只是会改写路径部分的东东,不会改动用户的输入参数,因此这里的if规则里面,你无需关心用户在浏览器里输入的参数,rewrite后会自动添加的

    下面举例说明4种重写类型

    server {
        # 访问 /last.html 的时候,页面内容重写到 /index.html 中
        rewrite /last.html /index.html last;
    
        # 访问 /break.html 的时候,页面内容重写到 /index.html 中,并停止后续的匹配
        rewrite /break.html /index.html break;
    
        # 访问 /redirect.html 的时候,页面直接302定向到 /index.html中
        rewrite /redirect.html /index.html redirect;
    
        # 访问 /permanent.html 的时候,页面直接301定向到 /index.html中
        rewrite /permanent.html /index.html permanent;
    
        # 把 /html/*.html => /post/*.html ,301定向
        rewrite ^/html/(.+?).html$ /post/$1.html permanent;
    
        # 把 /search/key => /search.html?keyword=key
        rewrite ^/search/([^/]+?)(/|$) /search.html?keyword=$1 permanent;
    }
    

    七、Nginx内置的全局变量

    在/etc/nginx/fastcgi.conf中可以看到全部定义。

    $args :这个变量等于请求行中的参数,同$query_string
    $content_length : 请求头中的Content-length字段。
    $content_type : 请求头中的Content-Type字段。
    $document_root : 当前请求在root指令中指定的值。
    $host : 请求主机头字段,否则为服务器名称。
    $http_user_agent : 客户端agent信息
    $http_cookie : 客户端cookie信息
    $limit_rate : 这个变量可以限制连接速率。
    $request_method : 客户端请求的动作,通常为GET或POST。
    $remote_addr : 客户端的IP地址。
    $remote_port : 客户端的端口。
    $remote_user : 已经经过Auth Basic Module验证的用户名。
    $request_filename : 当前请求的文件路径,由root或alias指令与URI请求生成。
    $scheme : HTTP方法(如http,https)。
    $server_protocol : 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。
    $server_addr : 服务器地址,在完成一次系统调用后可以确定这个值。
    $server_name : 服务器名称。
    $server_port : 请求到达服务器的端口号。
    $request_uri : 包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。
    $uri : 不带请求参数的当前URI,$uri不包含主机名,如”/foo/bar.html”。
    $document_uri : 与$uri相同。
    

    如:

    访问链接是:http://localhost:88/test1/test2/test.php
    网站路径是:/var/www/html

    $host:localhost
    $server_port:88
    $request_uri:http://localhost:88/test1/test2/test.php
    $document_uri:/test1/test2/test.php
    $document_root:/var/www/html
    $request_filename:/var/www/html/test1/test2/test.php
    

    八、使用if语句

    if (表达式) {
    }
    

    表达式的写法有很多:

    • 当表达式只是一个变量时,如果值为空或任何以0开头的字符串都会当做false
    • 直接比较变量和内容时,使用=或!=
    • 正则表达式匹配,`~*`不区分大小写的匹配,!区分大小写的不匹配

    表达式中可以使用shell常用运算符:

    • -f和!-f用来判断是否存在文件
    • -d和!-d用来判断是否存在目录
    • -e和!-e用来判断是否存在文件或目录
    • -x和!-x用来判断文件是否可执行

    下面看几个if语句的例子:
    例子一:简单的if语句

    # 如果文件不存在则返回400
    if (!-f $request_filename) {
        return 400;
    }
    
    # 如果host不是xuexb.com,则301到xuexb.com中
    if ( $host != 'xuexb.com' ){
        rewrite ^/(.*)$ https://xuexb.com/$1 permanent;
    }
    
    # 如果请求类型不是POST则返回405
    if ($request_method = POST) {
        return 405;
    }
    
    # 如果参数中有 a=1 则301到指定域名
    if ($args ~ a=1) {
        rewrite ^ http://example.com/ permanent;
    }
    

    例子二:在重写中使用if语句

    # 访问 /test.html 时
    location = /test.html {
        # 默认值为xiaowu
        set $name xiaowu;
    
        # 如果参数中有 name=xx 则使用该值
        if ($args ~* name=(w+?)(&|$)) {
            set $name $1;
        }
    
        # 301
        rewrite ^ /$name.html permanent;
    }
    

    举例说明运行结果:

    /test.html => /xiaowu.html
    /test.html?name=ok => /ok.html?name=ok
    

    九、常用命令

    service nginx configtest 用来检测配置是否正确
    service nginx reload 重新加载配置

    使用sudo service nginx命令可以查看可用参数.

    十、root和alias

    root

    location /request_path/image/ {
        root /local_path/image/;
    }
    

    这样配置的结果就是当客户端请求 /request_path/image/cat.png 的时候,
    Nginx把请求映射为/local_path/image/request_path/image/cat.png

    alias

    location /request_path/image/ {
        alias /local_path/image/;
    }
    

    这时候,当客户端请求 /request_path/image/cat.png 的时候,
    Nginx把请求映射为/local_path/image/cat.png

    下面举一个例子,当访问myip/poem/authorImage/libai.jpg的时候会自动去文件夹/home/USER_NAME/authorImage/下去寻找libai.jpg。

    location /poem/authorImage/ {
        alias /home/USER_NAME/authorImage/;
        autoindex on;
    }
    

    需要注意的是,必须保证authorImage这个文件夹权限足够,否则Nginx没有权力访问这个文件夹。最简单但是不够安全的方式就是把/etc/nginx.conf文件开头的user www-data改为user root,这样把管理员权限赋予Nginx,Nginx就能够访问任意文件了。这样做的缺点就是,一旦Nginx被攻破,整个系统的文件资源可能都会受到威胁。

    十一、例子集合

    1、访问http://IP:端口/myf_test/in_ftp/ftp/space_1/111.jpg

    实际访问/var/ftp/in_ftp/ftp/space_1/111.jpg

    location /myf_test/ {  
               root /;  
               rewrite ^/myf_test/(.*)$ /var/ftp/$1 break;  
            } 
    

    2、把www.ikscher.com/index.PHP?route=product/product&product_id=123 重定向到

    www.ikscher.com/product/product&product_id=123

    if ($request_uri ~* "(.*)index.php?route=(.*)"){  
        set $host_ $1;  
        set $last_ $2;  
        rewrite (.*)  $host_$last_? permanent; #这里的.*代表的是url的原先地址,即要转向的url地址。  
    }  
    

    注意:

    • 这段规则直接下到server里面,if后面必须有空格,否则报语法错误。
      正则表达式的 点和问号都需要斜杠转义。

    • nginx的问号处理,假如现在我要重定向到www.ikscher.com/?route=product/product&product_id=123,nginx在进行rewrite的正则表达式中只会将url中?前面的部分拿出来匹配,匹配完成后,?后面的内容将自动追加到url中(包含?),如果不让后面的内容追加上去,请在最后加上?即可。如果想要?后面的内容时请使用$query_string

    • 在这里提醒一点,调试的时候在rewrite的最后一个配置项中不要使用break last这些,使用redirect可以看到转换后的地址。综合以上几点,使用的配置项为

      rewrite (.)index.php(.) $1$query_string? permanent;

    3、多目录转成参数

    要求:abc.domian.com/sort/2 => abc.domian.com/index.PHP?act=sort&name=abc&id=2

    规则配置:

    if ($host ~* (.*).domain.com) { 
        set $sub_name $1;
        rewrite ^/sort/(d+)/?$ /index.php?act=sort&cid=$sub_name&id=$1 last; 
    } 
    

    4、目录对换

    要求:/123456/xxxx -> /xxxx?id=123456
    规则配置:rewrite ^/(d+)/(.+)/ /$2?id=$1 last;

    5、特殊浏览器特殊处理

    设定nginx在用户使用ie的使用重定向到/nginx-ie目录

    规则如下:

    if ($http_user_agent ~ MSIE) {
         rewrite ^(.*)$ /nginx-ie/$1 break; 
    } 
    

    6、请求目录自动加/

    目录自动加“/” ,这个功能一般浏览器自动完成

    if (-d $request_filename){ 
    	rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent; 
    } 
    

    7、禁止某些URL

    禁止多个目录 
    location ~ ^/(cron|templates)/ { 
        deny all; break; 
    } 
    禁止以/data开头的文件,可以禁止/data/下多级目录下.log.txt等请求
    location ~ ^/data { 
        deny all; 
    } 
    
    禁止单个文件 
    location ~ /data/sql/data.sql { 
        deny all; 
    } 
    

    8、让浏览器缓存静态数据,避免频繁请求静态数据

    给favicon.ico和robots.txt设置过期时间; 这里为favicon.ico为99天,robots.txt为7天并不记录404错误日志

    location ~(favicon.ico) { 
        log_not_found off; 
        expires 99d; 
        break; 
    } 
    location ~(robots.txt) { 
        log_not_found off; 
        expires 7d; 
        break; 
    } 
    

    设定某个文件的浏览器缓存过期时间;这里为600秒,并不记录访问日志

    location ^~ /html/scripts/loadhead_1.js { 
        access_log off; 
        expires 600; 
        break; 
    } 
    

    Nginx还可以自定义某一类型的文件的保质期时间,具体写法看下文的代码:

    location ~* .(js|css|jpg|jpeg|gif|png|swf)$ {
    	if (-f $request_filename) {
    	   expires    1h;
    	   break;
    	  }
    }
    //上段代码就将js|css|jpg|jpeg|gif|png|swf这类文件的保质期设置为一小时。
    

    9、防盗链的设置

    防盗链:如果你的网站是个下载网站,下载步骤应该是先经过你的主页找到下载地址,才能下载,为了防止某些网友直接访问下载地址完全不通过主页下载,我们就可以使用防盗链的方式,具体代码如下:

    location ~* .(gif|jpg|swf)$ {
      valid_referers none blocked start.igrow.cn sta.igrow.cn;
      if ($invalid_referer) {
      rewrite ^/ http://$host/logo.png;
      }
    }
    

    文件反盗链并设置过期时间

    --<盗链多次请求也会打开你的站点的图片啊,所以设置下缓存时间,不会每次盗链都请求并下载这张图片>
    location ~* ^.+.(jpg|jpeg|gif|png|swf|rar|zip|css|js)$ { 
    
        valid_referers none blocked *.jjonline.cn *.jjonline.com.cn *.lanwei.org *.jjonline.org localhost  42.121.107.189; 
        if ($invalid_referer) { 
            rewrite ^/ http://img.jjonline.cn/forbid.gif; 
            return 417; 
            break; 
        } 
        access_log off; 
        break; 
    } 
    

    说明:
    这里的return 417为自定义的http状态码,默认为403,方便通过nginx的log文件找出正确的盗链的请求地址
    rewrite ^/ http://img.jjonline.cn/forbid.gif;显示一张防盗链图片
    “access_log off;”不记录访问日志,减轻压力
    “expires 3d”所有文件3天的浏览器缓存

    10、只允许固定ip访问网站,并加上密码;这个对有权限认证的应用比较在行

    location  { 
        allow 22.27.164.25; #允许的ipd
        deny all; 
        auth_basic “KEY”; #认证的一些设置
        auth_basic_user_file htpasswd; 
    }
    

    11、文件和目录不存在的时重定向

    if (!-e $request_filename) { 
        #proxy_pass http://127.0.0.1; #这里是跳转到代理ip,这个代理ip上有一个监听的web服务器
        rewrite ^/ http://www.jjonline.cn/none.html;  #跳转到这个网页去
        #return 404; #直接返回404码,然后会寻找root指定的404.html文件
    } 
    

    12、域名跳转

    域名跳转

    server { 
        listen 80; 
        server_name jump.jjonline.cn ;#需要跳转的多级域名
        index index.html index.htm index.php; #入口索引文件的名字
        root /var/www/public_html/; #这个站点的根目录
        rewrite ^/ http://www.jjonline.cn/; 
        #rewrite到这个地址,功能表现:在浏览器上输入jump.jjonline.cn并回车,不会有任何提示直接变成www.jjonline.cn
        access_log off; 
    } 
    

    多域名转向

    server { 
        listen 80; 
        server_name www.jjonline.cn www.jjonline.org;
        index index.html index.htm index.php; 
        root /var/www/public_html/; 
        if ($host ~ “jjonline.org”) { 
            rewrite ^(.*) http://www.jjonline.cn$1 permanent; 
        } 
    }
    

    三级域名跳转

    if ($http_host ~* “^(.*).i.jjonline.cn$”) { 
        rewrite ^(.*) http://demo.jjonline.cn$1; 
        break; 
    } 
    

    13、域名镜像

    server { 
        listen 80; 
        server_name mirror.jjonline.cn; 
        index index.html index.htm index.php; 
        root /var/www/public_html; 
        rewrite ^/(.*) http://www.jjonline.cn/$1 last; 
        access_log off; 
    } 
    

    十二、Nginx的其他功能

    • 压缩
      使用gzip压缩的方式来传递HTML文件能够减少传输量。
    • 缓存
      对于常用的请求,可以设置缓存时间。

    最后、参考资料

    java静态代理和动态代理
    Nginx location在配置中的优先级
    nginx配置url重写
    nginx 重写 rewrite 基础及实例

  • 相关阅读:
    第二阶段每日总结01
    第十二周进度条
    构建之法阅读笔记05
    找水王01
    第十一周进度条
    第十周进度条
    构建之法阅读笔记04
    第九周进度条
    每日工作总结10
    每日工作总结09
  • 原文地址:https://www.cnblogs.com/weiyinfu/p/6857425.html
Copyright © 2020-2023  润新知