nginx反向代理-后端服务器组设置

时间:2024-03-11 19:27:48

nginx服务器的反向代理时其最常用的重要功能之一,在实际工作中应用广泛,涉及的配置指令也比较多。下面会尽量详细地介绍对应的指令,及其使用状态。

反向代理一般是互联网需要向内网拉取资源,比如访问一个web网站时,互联网应用通过一个代理服务器到后面真实的web服务器拉取应用所需的数据。

nginx服务器反向代理用到的指令如果没有特别的说明,原则上可以出现在nginx配置文件的http块,server块和location块中,但是同正向代理一样,一般是搭建在nginx服务器中单独配置一个server块用来设置代理服务。这些指令主要由ngx_http_proxy_module模块进行解析和处理。该模块是nginx服务器的标准http模块。

nginx服务器支持设置一组服务器作为后端服务器,因此在说明nginx反向代理指令之前,首先说明nginx的后端服务器组的配置。

后端服务器组的指令,是由nginx标准模块ngx_http_upstream_module进行解析和处理的。

后端服务器组的指令

1.upstream指令,该指令是设置后端服务器组的主要指令,其他指令都在该指令中进行配置。语法结构为

upstream  name {
      ......              #后端服务器设置

}

#其中name是后端服务器的组名。花括号中列出了后端服务器组中包含的服务器。

默认情况下,某个服务器组接收到请求后,按照轮叫调度策略顺序选择组内的服务器处理请求。如果一个服务器在处理请求过程中出现错误,则请求会被顺序交给组内的下一个服务器处理,一直到返回正常响应。但是如果所有组内的服务器出错,则返回最后一个服务器的处理结果。还可以在根据每个服务器的处理能力不同,给各个服务器配置不同的权重。权重的配置包含在server指令中。

2:server指令

该指令用于设置组内的服务器,语法结构为

server  address  [parameters];

#address: 服务器的地址,可以是包含端口号的ip地址,域名或者以“unix:”为前缀的用于进程间通信的套接字

#parameters: 为当前服务器的更多属性,如下。
  • weight=number, 为组内的服务器设置权重,权重高的被优先用于请求处理。默认服务器权重为1.
  • max_fails=number, 设置请求失败次数。在一定时间范围内,当对组内某台服务器请求失败的次数超过该变量设置的值时,认为该服务器无效。默认是1,

若设置为0则不用上面的办法检查服务器是否有效、

  • fial_timeout=time;有两个作用,一个是 设置 max_fails指令中“一定时间范围”的时长,二是在检查服务器是否有效时,如果一台服务器被认为是无效的,

   该变量设置的时间为认为服务器无效持续的时间。在这个时间内不再检查该服务器的状态,并一直认为它是无效的。默认是10s。

  • backup: 将组内服务器标记为备用服务器,只有当正常的服务器处于无效(down)状态或者繁忙(busy)状态时,该服务器才被用来处理客户请求。
  • down:将某台服务器标记为永久无效状态。

3: ip_hash指令,该指令用于实现会话保持功能,将某个客户端的多次请求定向到组内同一台服务器上,保证客户端与服务器之间建立稳定的会话。只有当该服务器无效处于down状态时,客户端请求才会被下一个服务器接收和处理。

ip_hash;
ip_hash技术在一些情况下非常有用,能够避免我们关心的服务组内各个服务器之间会话共享的问题。但是ip_hash技术在应用过程中是有限制的。
首先,ip_hash指令不能与server指令中的weight变量一起使用。其次,由于ip_hash技术主要根据客户端的ip地址分配服务器,因此整个系统中,nginx服务器应该是处于最
前端的服务器,这样才能获取到客户端的ip地址,同时还要注意客户端的ip地址必须是C类地址。
upstream  backend
{
      ip_hash;
      server  www.test1.com;
      server  www.test2.com;       
}

如上一个实例,在添加ip_hash指令后,使用同一台服务器发送请求,将会看到一只是test1在响应;如果注释掉ip_hash,将会看到的是轮询响应请求。

4.keepalive指令,该指令用于控制网络连接保持功能。通过该指令,能够保证nginx服务器工作进程为服务器组打开一部分网络连接,并且将数量控制在一定范围内。类似于进程池。

keepalive  connections;

#connections为nginx1服务器每一个工作进程运行服务器组保持的空闲网络连接数的上限值。如果超过该值,工作进程将采用最近最少使用策略关闭网络连接、

5:least_conn指令,该指令用于配置nginx服务器使用负载均衡的策略。该指令在功能上实现了最少连接负载均衡算法,在选择组内的服务器时,考虑个服务器权重的同时,每次选择的都是当前连接最少的那台服务器,如果这样的服务器有多台,则选用加权轮叫原则选择权重最大的服务器。

least_conn;

反向代理指令

nginx的反向代理指令有很多,这里我们会详细的介绍的!

1.proxy_pass指令,该指令用来设置被代理服务器的地址,可以是主机名称,IP地址加端口号的形式。

proxy_padd  URL;

#其中,URL为要设置的被代理服务器的地址,包含传输协议,主机名称或IP地址加端口号,uri等,传输协议通常是http或者https。也可以是unix开头的套接字路径。

若是被代理的是一组服务器,则需要使用upstream指令配置后端服务器组!

通过简单的实例说明proxy_pass的用法!

#第一种仅代理一个服务器
        location / {

            proxy_pass http://10.0.102.214:8080;
        }
#第二种,代理一组服务器 upstream backend #需要注意的是upstream指令不能写在server块中 { server
10.0.102.214:8080; server 10.0.102.204:8080; } server { listen 80; server_name localhost; location / { proxy_pass http://backend; } }
##############################################
说明,之前有一种写法是把http协议写在upstream中,这样在proxy_pass中不用写http协议,但是我现在这样的写的话,检查的时候总是会报错!
    upstream backend
    {
        server  http://10.0.102.214:8080;
        server  http://10.0.102.204:8080;
    }

    server {
        listen       80;
        server_name  localhost;


        location / {

            proxy_pass backend;
        }
}

#这样配置的时候总是会报错,
[root@test1 conf]# nginx -t
nginx: [emerg] invalid host in upstream "http://10.0.102.214:8080" in /usr/local/nginx/conf/nginx.conf:37
nginx: configuration file /usr/local/nginx/conf/nginx.conf test failed

proxy_pass中url是否包含URI的处理方式:如果URL中包含了URI,nginx服务器会使用新的uri替代原来请求中的URI;如果URL中不包含URI,nginx服务器不会改变原地址请求的URI。

#URL中包含了URI的配置
location /first.html { root html; index index.html index.htm; proxy_pass http://10.0.102.214:8080/one.html; } ##看这个配置,URL中含有URI,那么nginx服务器会改变原来请求中的URI!
[root@test1 logs]# curl http://localhost/first.html #访问本机
111111111111111111
[root@test1 logs]# curl http://10.0.102.214:8080/one.html #后面代理服务器的one.html
111111111111111111
#上面两个可以看到,通过代理访问时,uri被nginx服务器改写了!

#URL不包含URI的配置
        location /first.html {
            root   html;
            index  index.html index.htm;
            proxy_pass http://10.0.102.214:8080;
        }

#可以看到如果URL中不含URI,则nginx服务器不会改写请求中的URI。
[root@test1 logs]# curl http://localhost/first.html
This is the first page!
[root@test1 logs]# curl http://10.0.102.214:8080/first.html
This is the first page

2.proxy_hide_header与proxy_pass_hide

默认情况下,nginx服务器在发送响应报文时候,报文头部不包含如“Date”,"Server","X-Accel"等来自被代理服务器的信息,但是也会发送一些与被代理服务器有关的信息。

proxy_hide_header  field;
#指令用于设置nginx服务器发送响应时,隐藏一些头部信息。
proxy_pass_header;
#该指令可以设置哪些头部信息被发送
上面的两个指令均可在http块,server块或者location块中进行配置

默认情况下,代理服务器不会发送后端服务器的server信息给客户端,这里我们设置代理服务器发送后端服务器的server信息给客户端!

#当前做代理服务器的nginx版本为
[root@test1 logs]# nginx -v
nginx version: nginx/1.10.2
[root@test1 logs]# 
#后端服务器的nginx版本为
[root@test3 html]# nginx -v
nginx version: nginx/1.0.15
[root@test3 html]# 

配置如下:

        proxy_pass_header server;             #设置要发送的信息
        location /first.html {
            root   html;
            index  index.html index.htm;
            proxy_pass http://10.0.102.214:8080;
        }

#访问对应的URL
[root@mgt01 ~]# curl http://10.0.102.179/first.html -I
HTTP/1.1 200 OK
Date: Sun, 16 Dec 2018 16:03:02 GMT
Content-Type: text/html
Content-Length: 24
Connection: keep-alive
Server: nginx/1.0.15 #可以看到发送的nginx服务器的版本为后端服务器的版本信息
Last-Modified: Sun, 16 Dec 2018 15:39:16 GMT
Accept-Ranges: bytes

#把配置文件中proxy_pass_header server; 注释掉,访问信息如下
[root@mgt01 ~]# curl http://10.0.102.179/first.html -I
HTTP/1.1 200 OK
Server: nginx/1.10.2 #这里的版本信息为代理服务器的版本信息
Date: Sun, 16 Dec 2018 16:07:41 GMT
Content-Type: text/html
Content-Length: 24
Connection: keep-alive
Last-Modified: Sun, 16 Dec 2018 15:39:16 GMT
Accept-Ranges: bytes

3.proxy_pass_request_body与proxy_pass_request_headers指令

这两个指令用于配置是否将客户端请求的请求体和请求头发送给后端服务器,语法结构如下:

proxy_pass_request_body   on | off;
proxy_pass_request_header   on | off;

#默认设置为开启。

4:proxy_set_header指令,该指令可以更改nginx服务器接收到客户端请求的请求头消息,然后将新的请求头发送给后端服务器。

proxy_set_header   field  value;

#field: 要更改的头域
#value: 更改的值,支持文本,变量或者变量的组合

默认情况下,nginx 重新定义代理请求HostConnection中的两个头字段,并删除了值为空字符串的头字段。其中请求头Host被设置为了变量$proxy_hostConnection被设定为close

proxy_set_header  Host  $http_host;             #将目前的host值填充为客户端请求的host
proxy_set_header  Host   $proxy_host;           #将当前location块的server_name填充到host头域。
proxy_set_header  Host  $host:$$proxy_port;     #将当前location块的server_name指令和listen指令值一起填充到host头域

5:proxy_set_body指令

该指令可以更改nginx服务器接收到客户端请求的请求体的信息,然后将新的请求体发送给后端服务器。

proxy_set_body value;

#value为更改的信息,支持使用文本,变量或者变量的组合。

6:proxy_bind指令。在配置了多个基于名称或者基于ip主机的情况下,如果我们希望代理连接由指定的主机处理,就可以使用该指令进行配置。

proxy_bind  address;

#address为指定主机的ip地址。

7:proxy_connect_timeout指令

该指令配置nginx服务器以后端服务器尝试建立连接的时间,

proxy_connect_timeout  time;

#time为设置的超时时间,默认是60s

8:proxy_read_timeout指令

该指令配置nginx服务器向后端被代理服务器发出read请求后,等待响应的超时时间。

proxy_read_timeout   time

#time为设置的超时时间,默认是60s

9:proxy_send_timeout指令

该指令配置nginx服务器向后端被代理服务器发出write请求后,等待响应的超时时间,

proxy_send_timeout  time;

#time为设置的超时时间,默认是60s

10:proxy_http_version指令

该指令用于配置nginx服务器提供代理服务的http版本,

proxy_http_version  1.0|1.1;

#默认是1.0版本。1.1版本支持upstream服务器组设置中的keepalive指令。

11.proxy_method指令

该指令用于设置nginx把请求发往后端服务器组时使用的请求方法,一般为POST或者GET。设置了该指令,客户端的请求方法将被忽略。

proxy_method  method;

#其中,method的值可以设置为POST或者GET,注意不加引号。

12:proxy_ignore_client_abort指令

该指令用于设置在客户端中断网络请求时,nginx服务器是否中断对后端服务器的请求。

proxy_ignore_client_abort  on|off;
#默认设置为off,当客户端中断网络请求时,nginx服务器中断对后端服务器的请求

13:proxy_ignore_headers指令

该指令用于设置一些http响应头域,nginx服务器接收到被代理服务器的响应数据后,不会处理被设置的头域。

proxy_ignore_headers  field....;
#field为要设置的http响应头,

14:proxy_redirect指令

该指令用于修改后端服务器返回的响应头中的location头域和refresh头域,与proxy_pass指令配合使用。比如,nginx服务器通过proxy_pass指令将客户端的请求地址重写为被代理服务器的地址,那么nginx服务器返回给客户端的响应头中“location”头域显示的地址就应该和客户端发起请求的地址相对应,而不是代理服务器直接返回的地址信息,否则就会出现问题。该指令解决了这个问题,可以把代理服务器返回的地址信息更改为需要的地址信息,语法结构如下!

1 proxy_redirect  redirect  replacement;
2 proxy_redirect default;
3 proxy_redireect off;           #表示当前作用于下所有的proxy_redirect指令配置全部设置为无效。
#redirect,匹配“Location”头域值的字符串,支持变量的使用和正则表达式
#replacement, 用于替换redirect变量内容的字符串,支持变量的引用。

 通过两个实例,来理解这个命令!【摘自nginx高性能web服务器详解】

第一个例子

假设被代理服务器返回的响应头中“location”头域为

Location:  http://localhost/proxy/some/uri

该指令设置为:

proxy_pass http://localhost/proxy/  http://x.x.x.x/fromtend/;

nginx服务器会将“Location”头域信息更改为:

Location:  http://x.x.x.x/fromtend/some/uri

这样客户端收到的响应信息头部中的“Location”头域已经被更改。注意还是为安全,把后端服务器的信息暴露出来是不安全的!

第二个例子

使用default,代理使用Location块的uri变量作为replacement,并使用proxy_pass变量为redirect。下面的两个配置结果是相等的。

#配置1
location  /server/
{
       proxy_pass  http://proxyserver/source/;
       proxy_redirect  default;   
}

#配置2
location  /server/
{
       proxy_pass  http://proxyserver/source/;
       proxy_redirect   http://proxyserver/source/  /server/;   
}

#配置1和配置2产生的结果是一样的

 

15:proxy_intercept_errors指令

该指令用于配置一个状态是开启还是关闭。在开启状态时,如果后端服务器返回的http状态码为400或者大于400,则nginx服务器使用自己定义的错误页(使用error_pages指令);如果关闭了该状态,nginx服务器直接将后端服务器返回的http状态返回给客户端。

proxy_intercept_errors  on | off;

16:proxy_headers_hash_max_size指令

该指令用于配置存放http报文头的哈希表的容量,语法结构为

proxy_headers_hash_max_size  size;

#size为http报头哈希表容量上限,默认为512个字符。

nginx服务器为了能够快速检索http报文头中的各项信息,比如服务器名称,MIME类型,请求头名称,使用哈希表存储这些信息。nginx服务器在申请存放http报文头空间时,通常以固定大小为单位申请,该大小由此指令设定。

在nginx配置中,不仅能够配置整个哈希表的上限,对于大部分内容,也可以配置其大小的上限。比如server_names_hash_max_size指令server_names_hash_bucket_size指令用来设置服务器名称的字符数长度。

17:proxy_headers_hash_bucket_szie指令

该指令用于设置nginx服务器申请存放http报文的哈希表容量的单位大小,具体使用见上一个命令。

proxy_headers_hash_bucket_szie  size;
#size为设置容量,默认为64个字符

18:proxy_next_upstream指令

在配置nginx服务器反向代理时,如果使用了upstream指令配置了一组服务器作为被代理服务器,服务器组中各个服务器的访问规则遵循upstream指令配置的轮询规则,同时也可以使用该指令配置在发生哪些异常情况下,将请求顺序交由下一个组内服务器处理。

proxy_next_upstream  status...;

status为设置的服务器返回的状态,可以是一个或者多个。状态取值如下:
  • error,在建立连接,向后端服务器发送请求,读取响应头时服务器发生连接错误。
  • timeout, 在建立连接,向后端服务器发送请求,读取响应头时服务器发生连接超时。
  • invalid_header, 后端服务器返回的响应头为空或者无效。
  • http_500|http_502|http_503|http_504|http_404,后端服务器返回500,502,503,504,404状态码。
  • off,无法将请求发送到后端服务器。

19:proxy_ssl_session_reuse指令

该指令用于配置是否使用基于ssl安全协议的会话连接被代理的服务器。

proxy_ssl_session_reuse  on|off;

默认设置为开启状态。

 我们通过实例来说明nginx反向代理的用法:

第一个实例,对所有的请求实现一般轮询的负载均衡

    upstream backend 
    {
        server  10.0.102.214:8080;
        server  10.0.102.204:8080;
    }

    server {
        listen       80;
        server_name  localhost;
        root   html;
        index  index.html index.htm;

        location / {
            proxy_pass_header server;
            proxy_pass http://backend;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

#默认情况下,后端服务器组中每台服务器的权重值为1,使用轮叫调度的策略。

第二个实例,对所有的请求实现加权轮叫调度

配置就是把上面后端服务器组中每台服务器后面加上权重即可!

    upstream backend 
    {
        server  10.0.102.214:8080 weight=1;
        server  10.0.102.204:8080 weight=2;
    }

    server {
        listen       80;
        server_name  localhost;
        root   html;
        index  index.html index.htm;

        location / {
            proxy_pass_header server;
            proxy_pass http://backend;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

#权重高的服务器优先处理请求和响应,所有的请求都会在backend服务器组中实现加权负载均衡。

第三个实例,对不同资源实现负载均衡,这里定义两组后端服务器组,对图片的访问和对文件的访问使用不同的服务器组,这样就可以对不同资源做负载均衡!

#定义两个服务器组,分别对文件和图片进行处理 
upstream file_backend #定义文件服务器组 { server
10.0.102.220; server 10.0.102.221; } upstream image_backend #定义图片服务器组 { server 10.0.102.214; server 10.0.102.204; } server { listen 80; server_name localhost; root html; index index.html index.htm; location /files/ { #针对文件访问,使用下面的服务器组 proxy_pass_header server; proxy_pass http://file_backend/files/; } location /images/ { #针对图片的访问使用下面的服务器组,, proxy_pass http://image_backend/images/; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }

第四种情况,针对不同的域名做负载均衡。

在配置文件中可以配置多个server块,每个块都是一个虚拟主机,每个块中根据server_name的不同,被转发到后端不同的服务器上。

    upstream bbs_backend 
    {
        server  10.0.102.214;
        server  10.0.102.204;
    }

    upstream home_backend
    {
        server 10.0.102.214;
        server 10.0.102.204;
    }

    server {                                          #根据不同的域名,访问到不同的服务器组
        listen       80;
        server_name  www.bbs.com;
        index  index.html index.htm;

        location   / {
            proxy_pass http://bbs_backend;
        }
  
    }

    server {
        listen       81;
        server_name  www.home.com;
        index  index.html index.htm;

        location   / {
            proxy_pass http://home_backend;
        }
    }