共计 10486 个字符,预计需要花费 27 分钟才能阅读完成。
正向代理和反向代理的概念
代理服务(Proxy),通常也称为正向代理服务。
如果把局域网外 Internet 想象成一个巨大的资源库,那么资源就分布到了 Internet 的各个点上,局域网内的客户端要访问这个库里的资源就必须统一通过代理服务器才能对各个站点进行访问。
局域网内的机器借助代理服务访问局域网外的网站,这主要是为了增加局域网内部网络的安全性,使得网外的威胁因素不容易影响到网内,这里代理服务器起到了一部分防火墙的功能。同时,利用代理服务器也可以对局域网外的访问进行必要的监控和管理。正向代理服务器不支持外部对内部网络的访问请求。
与正向代理服务相反,如果局域网向 Internet 提供资源,让 Internet 上的其他用户可以访问局域网内的资源,也可以设置一个代理服务器,它提供的服务就叫做反向代理(Reverse Proxy)服务。可以看到,反向代理服务与代理服务在功能逻辑上刚好是相反的。
正向代理服务器与反向代理服务器的概念很简单,归纳起来就是,正向代理服务器用来让局域网客户机接入外网以访问外网资源,反向代理服务器用来让外网的客户端接入局域网中的站点以访问站点中的资源。理解这两个概念的关键是要明白我们当前的角色和目的是什么,在正向代理服务器中,我们的角色是客户端,目的是要访问外网的资源;在反向代理服务器中,我们的角色是站点,目的是把站点的资源发布出去让其他客户端能够访问。
知道了这两个概念,就可以学习如何让 Nginx 服务器来提供代理和反向代理服务器了。
Nginx 的正向代理服务
Nginx 服务器正向代理服务的配置的 3 个指令
在实际应用中,使用 Nginx 服务器代理服务功能的情况相对少一些,Nginx 代理服务本向也相对简单,涉及的主要指令不多。这些指令原则上可以出现在 Nginx 配置文件的 http 块、server 块或者 location 块中,但一般是在搭建的 Nginx 服务器中单独配置一个 server 块用来设置代理服务。
1.resolver 指令
该指令用于指定 DNS 服务器的 IP 地址。DNS 服务器的主要工作是进行域名的解析,将域名映射为对应的 IP 地址。该指令的语法结构为:
resolver address ... [valid=
time
];
address,DNS 服务器的 IP 地址。如果不指定商品号,默认使用 53 端口。
time,设置数据包在网络中的有效时间。出现该指令的主要原因是,在访问站点时,有很多情况使得数据包在一定时间内不能被传递到目的地,但是又不能让该数据包无期限地存在,于是就需要设定一段时间,当数据包在这段时间内没有到达目的地,就会被丢弃,然后发送都会接收到一个消息,并决定是否要重发数据包。
使用该指令的一个例子如下:
resolver 127.0.0.1 [::1}:5353 valid=30s
在实际应用中,一般不需要设置这么复杂,只要将 DNS 服务器的 IP 地址设置给该指令即可。
从 Nginx1.1.7 版本开始,该指令支持设置多个 IP 地址,从 Nginx1.3.1 开发版本和 Nginx1.2.2 稳定版本开始,该指令支持设置 IPV6 地址。
2.resolver_timeount 指令
resolver_timeount
time
;
该指令用于设置 DNS 服务器域名解析超时时间,语法结果为:
3.proxy_pass 指令
该指令用于设置代理服务器的协议和地址,它不仅仅用于 Nginx 服务器的代理服务器,更主要的是应用于反向代理服务,我们马上就会谈及。该指令的语法结构为:
proxy_pass URL;
其中,URL 即为设置的代理服务器协议和地址。
在代理服务配置中,该指令的设置相对固定,因此在这里就不介绍其他细节了,具体内容在学习 Nginx 服务器的反向代理服务时再重点阐述。在代理服务配置中,该指令配置为:
proxy_pass http:
//
$http_host$request_uri;
其中,代理服务器协议设置为 HTTP,$http_host 和 $request_uri 两个变量是 Nginx 配置支持的用于自动获取主机和 URI 的变量。配置代理服务时,一般不要改变该指令的配置。
正向代理服务使用示例
..
server
{
resolver 8.8.8.8;
listen 82;
location /
{
proxy_pass http:
//
$http_host$request_uri;
}
}
实现的片段很简单,设置 DNS 服务器地址为 8.8.8.8,使用默认的 53 号端口作为 DNS 服务器的服务端口,代理服务的监听端口设置为 82 端口,Nginx 服务器接收到的所有请求都由第 5 行的 location 块进行过滤处理。
Nginx 服务器代理服务使用的场合不多,从上一节的配置指令来看,功能也相对简单。在使用过程中,有一些需要注意的事项在这里说明一下。
首先,我们在上面提到过,设置 Nginx 服务器的代理服务器,一般是配置到一个 server 块中,注意,在该 server 块中,不要出现 server_name 指令,即不要设置虚拟主机的名称或 IP。而 resolver 指令是必需的,如果没有该指令,Nginx 服务器无法处理接收到的域名。
其次,Nginx 服务器的代理服务器不支持正向代理 HTTPS 站点。
Nginx 的反向代理服务
Nginx 服务器的反向代理服务是其最常用的重要功能之一,在实际工作中应用广泛,涉及的配置指令也比较多,各类指令完成的功能也不尽相同。下面按照功能分类向大家介绍配置该服务需要掌握的指令。由反向代理服务又可以衍生出多种与此相关的 Nginx 服务器的重要功能,随后将逐步梳理这些功能,并提供配置实例供大家参考。
Nginx 服务器提供的反向代理服务也是比较高效的。它能够同时接收的客户端连接由 worker_processes 指令和 worker_connections 指令决定,计算方法为:worker_processes * worker_connections / 4.
配置 Nginx 服务器反向代理用到的指令如果没有特别说明,原则上可以出现在 Nginx 配置文件的 http 块、server 块或者 location 块中,但同正向代理服务的设置一样,一般是在搭建的 Nginx 服务器中单独配置一个 server 块来设置反射代理服务。这些指令主要由 ngx_http_proxy_module 模块进行解析和处理。该模块是 Nginx 服务器的标准 HTTP 模块。
反向代理的基本设置的 27 个指令
学习 Nginx 服务器的反向代理 服务,要涉及与后端代理服务器相关的配置,是客户端提供正常 Web 服务的基础,大家应该熟练掌握,尤其是 proxy_pass 指令,在实际应用过程中需要注意一些配置细节,需要小心使用。
1.proxy_pass 指令
该指令用来设置被代理服务器的地址,可以是主机名称、IP 地址加端口号等形式。其语法结构为:
proxy_pass URL;
其中,URL 为要设置的被代理服务器的地址,包含传输协议、主机名称或 IP 地址加商品号、URI 等要素。传输协议通常是“http”或者“https”。指令同时还接受以“unix”开始的 UNIX-domain 套接字路径。例如:
proxy_pass http:
//www
.myweb.name
/uri
;
proxy_pass http:
//localhost/uri
;
proxy_pass http:
//unix
:
/tmp/backend
.socket:
/uri/
;
如果被代理服务器是一组服务器的话,可以使用 upstream 指令配置后端服务器组。例如:
# 多个服务器
...
upstream proxy_svrs
# 配置后端服务器
{
server http:
//192
.168.1.1:8001
/uri/
;
server http:
//192
.168.1.2:8001
/uri/
;
server http:
//192
.168.1.3:8001
/uri/
;
}
server
{
...
listen 80;
server_name www.myweb.name;
location /
{
proxy_pass proxy_svrs;
# 使用服务器组名称
}
}
这里首先需要提醒大家 proxy_pass 指令在使用服务器组名称时应该注意一个细节。在上例中,在组内的各个服务器中都指明了传输协议“http://”,而在 proxy_pass 指令中就不需要指明了。如果 现在将 upstream 指令的配置改为:
# 不指明 http
...
upstream proxy_svrs
# 配置后端服务器
{
server 192.168.1.1:8001
/uri/
;
server 192.168.1.2:8001
/uri/
;
server 192.168.1.3:8001
/uri/
;
}
我们就需要在 proxy_pass 指令中指明传输协议“http://”;
proxy_pass http:
//proxy_svrs
;
在使用该指令的过程中还需要注意,URL 中是否包含有 URI,Nginx 服务器的处理方式是不同的。如果 URL 中不包含 URI,Nginx 服务器不会改变原地址的 URI;但是如果包含了 URI,Nginx 服务器将会使用新的 URI 替代原来的 URI。我们举例来说明。
请看下面的 Nginx 配置片段:
..
server
{
...
server_name www.myweb.name;
resolver 8.8.8.8;
listen 82;
location
/server/
{
...
proxy_pass http:
//192
.168.1.1;
}
}
如果客户端使用“http://www.myweb.name/server”发起请求,该请求被配置中显示的 location 块进行处理,由于 proxy_pass 指令变量不含有 URI,所以转向的地址为“http:///192.168.1.1/server”;我们再来看下面的 Nginx 片段:
..
server
{
...
server_name www.myweb.name;
resolver 8.8.8.8;
listen 82;
location
/server/
{
...
proxy_pass http:
//192
.168.1.1
/loc
;
}
}
在该配置实例中,proxy_pass 指令的 URI 包含了 URI“/loc”;如果客户端仍然使用“http://www.myweb.name/server”发起请求,Nginx 服务器将会把地址转向“http://192.168.1.1/loc/”;
通过上面的实例,我们可以总结 出,在使用 proxy_pass 指令时,如果不想改变原地址中的 URI,就不要在 URL 变量中配置 URI。
明白了上面这两个例子的用法,我们来解释大家经常讨论的一个问题,就是 proxy_pass 指令的 URL 变量末尾是否加斜杠“/”的问题。
请看这两个配置示例:
# 配置 1 proxy_pass http://192.168.1.1;
# 配置 2 proxy_pass http://192.168.1.1/;
配置 1 和配置 2 的区别在于,配置 2 中的 proxy_pass 指令的 URL 变量末尾添加了斜杠“/”,这意味着配置 2 中的 proxy_pass 指令的 URL 变量包含了 URI“/”,而配置 1 中的 proxy_pass 指令的 URL 变量不包含 URI。理解了这一点,我们就可以解释下面的实例和现象了。大家注意各例子之间的对比。
实例 1:
..
server
{
...
listen 80;
server_name www.myweb.name;
# 注意 location 的 uri 变量
location /
{
...
# 配置 1 proxy_pass http://192.168.1.1;
# 配置 2 proxy_pass http://192.168.1.1/;
}
}
在该配置中,location 块使用“/”作为 uri 变量的值来匹配不包含 URI 的请求 URL。由于请求 URL 中不包含 URL,因此配置 1 和配置 2 的效果是一样的。比如客户端的请求 URL 为“http://www.myweb.name/index.htm”,其将会被实例 1 中的 location 块匹配成功并进行处理。不管使用配置 1 不是配置 2,转向的 URL 都为:“http://192.168.1.1/index.htm”。
实例 2:
..
server
{
...
listen 80;
server_name www.myweb.name;
# 注意 location 的 uri 变量
location
/server/
{
...
# 配置 1 proxy_pass http://192.168.1.1;
# 配置 2 proxy_pass http://192.168.1.1/;
}
}
在该配置中,location 块使用“/server/”作为 uri 变量的值来匹配包含的 URI“/server/”的请求 URL。这时,使用配置 1 和配置 2 的转向结果就不相同了。使用配置 1 和配置 2 的转向效果就不相同了。使用配置 1 时候,proxy_pass 指令中的 URL 变量不包含 URI,Nginx 服务器将不改变原地址的 URI,使用配置 2 的时候,proxy_pass 指令中的 URL 变量包含 URI“/”,Nginx 服务器会将原地址的 URI 替换为 ”/”。
比如客户端的请求 URI 为“http://www.myweb.name/server/index.htm”将会被实例 2 的 location 块匹配成功并进行处理。使用配置 1 的时候,转向的 URL 为“http://192.168.1.1/server/index.htm”,原地址的 URI“、server/”示被改变;使用配置 2 时,转向的 URL 为“http://192.168.1.1/index.htm”, 可以看到原地址的 URI“/server/”被替换为“/”。
大家在应用过程中,一定要注意到该指令在配置上的细节问题,分清楚 URL 和 URI 的区别与联系,并能够正确使用它们配置出符合需求的 Nginx 服务器。
2.proxy_hide_header 指令
该指令用于设置 Nginx 服务器在发送 HTTP 响应时,隐藏一些头域信息。其语法结构为:
proxy_hide_header field;
其中,field 为需要隐藏的头域。该指令可以在 http 块、server 块或者 location 块中进行配置。
3.proxy_pass_header 指令
默认情况下,Nginx 服务器在发送响应报文时,报文头中不包含“Date”、“Server”、“X-Accel”等来自被代理服务器的头域信息。该指令可以设置这些头域信息以被发送,其语法结构为:
proxy_pass_header field;
4.proxy_pass_request_body 指令
该指令用于配置是否将客户端请求的请求体发送给代理服务器,其语法结构为:
proxy_pass_request_body on | off;
默认开启(on),开头可以在 http 块、server 块或者 location 块中进行配置。
5.proxy_pass_request_headers 指令
该指令用于配置是否将客户端请求的请求头发送给代理服务器,其语法结构为:
proxy_pass_request_headers on | off;
默认开启(on),开头可以在 http 块、server 块或者 location 块中进行配置。
6.proxy_set_header 指令
该指令可以理发 Nginx 服务器接收到的客户端请求的请求头信息,然后将新的请求头发送给被代理的服务器,其语法结构为:
proxy_set_header field value;
field,要更新的信息所在的区域;value,更改的值,支持使用文本、变量或者变量的组合。
默认情况下,该指令的设置为:
proxy_set_header Host $proxy_host;
proxy_set_header Connection close;
请看一些设置实例:
proxy_set_header Host $http_host;
# 将目前 Host 头域的值填充成客户端的地址
proxy_set_header Host $$host;
# 将当前 location 块的 server_name 指令填充到 Host 头域
proxy_set_header Host $$host:$proxy_port;
#listener 指令值一起填充到 Host 头域.
7.proxy_set_body 指令
指该指令可以更改 Nginx 服务器接收到的客户端请求的请求信息,然后将新的请求体发送给被代理的服务器。其语法结构为:
proxy_set_body_value;
其中,value 为更改的信息,支持使用文本、变量或者变量的组合。
8.proxy_bind 指令
官方文档中对该指令的解释是,强制将与代理主机的连接绑定到指定的 IP 地址。通俗来讲就是,在配置多个基于名称或者基于 IP 地址。通俗来讲就是,在配置了多个基于名称或者基于 IP 主机的情况下,如果我们希望代理连接由指定的主机处理,就可以使用该指令进行配置,其语法结构为:
proxy_bind adress;
其中,adress 为指定主机的 IP 地址。
9.proxy_connect_timeout 指令
该指令配置 Nginx 服务器与后端被代理服务器尝试建立连接的超时时间,其语法结构为:
proxy_connect_timeout
time
;
其中,time 为设置的超时时间,默认 60s。
10.proxy_read_timeout 指令
该指令配置 Nginx 服务器向后端被代理服务器(组)发出的 read 请求后,等待响应的超时时间,其语法结构为:
proxy_read_timeout
time
;
其中,time 为设置的超时时间,默认 60s。
11.proxy_send_timeout 指令
该指令配置 Nginx 服务器向后端被代理服务器(组)发出的 write 请求后,等待响应的超时时间,其语法结构为:
proxy_write_timeount
time
其中,time 为设置的超时时间,默认 60s。
12.proxy_http_version 指令
该指令设置用于 Nginx 服务器提供代理服务的 HTTP 协议版本,其语法结构为:
proxy_http_version 1.0 | 1.1;
默认版本为 1.0 版本,1.1 版本支持 upstream 服务器组设置的 keepalive 指令。
13.proxy_method 指令
该指令用于设置 Nginx 服务器请求被代理服务器时使用的请求方法,一般为 POST 或者 GET。设置了该指令,客户端的请求方法将被忽略。其语法结构为:
proxy_method method;
其中,method 的值可以设置为 POST 或者 GET,注意不加引号。
14.proxy_ignore_client_abort 指令
该指令用过设置在客户端中断网络请求时,Nginx 服务器是否中断对被代理服务器的请求,其语法结构为:
proxy_ignore_client_abort on | off
默认设置为 off,当客户端中断网络请求时,Nginx 服务器中断对被代理服务器的请求。
15.proxy_ignore_header 指令
该指令用于设置一些 HTTP 响应头的头域,Nginx 服务器接收到被代理服务器的响应数据后,不会处理被设置的头域。其语法结构为:
proxy_ignore_header field ...;
其中,field 为要设置的 HTTP 响应头的头域,例如“X-Accel-Redirect”、“X-Accel-Expires”、“Cache-Control”、“Expires”或“Set-Cookie”等。
16.proxy_redirect 指令
该指令用于修改被代理服务器返回的响应头中的 Location 头域和“Refresh”头域,与 proxy_pass 指令配合使用。比如,Nginx 服务器通过 proxy_pass 指令将客户端的请求地址重写为被代理服务器的地址,那么 Nginx 服务器返回客户端的响应头中“Location”头域显示的地址就应该和客户端发起请求的地址相对应,而不是代理服务器直接返回的地址信息,否则就会出问题。该指令解决了这个问题,可以把代理服务器返回的地址信息更改为需要的地址信息。其语法结构为:
proxy_redirect redirect replacement
proxy_redirect default;
proxy_redirect off;
redirect,匹配“Location”头域值的字符串,支持变量的使用和正则表达式。
replacement,用于替换 redirect 变量内容的字符串,支持变量的使用。
该指令的用法我们通过几个配置实例来解释。
对于第 1 个结构,假设被代理服务器返回的响应头中的“Location”头域为:
Location: http:
//localhost
:8081
/proxy/some/uri
该指令设置为:
proxy_redirect http:
//localhost
:8081
/proxy/
http:
//myweb/fronted/
;
Nginx 服务器会将“Location”头域信息更改为:
Location:http:
//myweb/frontend//some/uri
;
这样,客户端收到的响应信息头部中的“Location”头域就被更改了。
结构 2 使用 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/
;
}
使用结构 3 可以将当前作用域下所有的 proxy_redirect 指令全部设置为无效。
17.proxy_intercept_errors 指令
该指令用于配置一个状态是否开启还是关闭。在开启状态时,如果被代理的服务器返回的 HTTP 状态码为 400 或者大于 400,则 Nginx 服务器使用自己定义的错误页(使用 error_page 指令);如果是关闭状态,Nginx 服务器直接将被代理服务器返回的 HTTP 状态返回给客户端。其请求结构为
proxy_intercept_errors on | off
18.proxy_headers_hash_max_size 指令
该指令用于配置 HTTP 报文头哈希表的容量,其语法结构为:
proxy_headers_hash_max_size size;
其中,size 为 HTTP 报文头哈希表的容量上限,默认为 512 个字符,即:
proxy_headers_hash_max_size 512;
Nginx 服务器为了能够快速检索 HTTP 报文头中的各项信息,比如服务器名称、MIME 类型、请求头名等,使用哈希表存储这些信息。Nginx 服务器在申请存放 HTTP 报文头的空间时,通常以固定大小为单位申请,该大小由 proxy_headers_hash_bucket_size 指令配置。
在 Nignx 配置中,不仅能够配置整个哈希表的大小上限,对大部分内容项,也可以配置其大小上限,比如 server_names_hash_max_size 指令和 server_names_hash_bucket_size 指令用来设置服务器名称的字符数长度。
19.proxy_headers_hash_bucket_size 指令
该指令用于设置 Nginx 服务器申请存放 HTTP 报文头的哈希表容量的单位大小。该指令的具体作用在上面 proxy_headers_bucket_size 指令的使用中已经说明。其语法结构为:
proxy_headers_hash_bucket_size size;
20.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,无法将请求发送给被代理的服务器。
注意
与被代理的服务器进行数据传输的过程中发送错误的请求,不包含在该指令支持的状态之内。
21.proxy_ssl_session_reuse 指令
该指令用于配置是否使用基于 SSL 安全协议的会话连接(“https://”)被代理的服务器,其语法结构为:
proxy_ssl_session_reuse on | off
: