WEB服务-Nginx之7-反向代理

Posted 原因与结果

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WEB服务-Nginx之7-反向代理相关的知识,希望对你有一定的参考价值。

WEB服务-nginx之7-反向代理

Nginx代理基本概述

什么是代理?

代理一词往往并不陌生, 该服务我们常常用到如:代理理财、代理租房、代理收货等等。

img


没有代理:

客户端直接请求服务端,服务端直接响应客户端。

img


有代理:

在实际互联网请求时,客户端因为种种原因,往往无法直接向服务端发起请求,需要使用代理服务帮助客户端请求服务端。

img

Nginx代理常见模式

按应用场景划分:代理分为正向代理、反向代理


正向代理

用于内部上网中,客户端<-->代理-->服务端

img


反向代理

用于公司集群架构中,客户端-->代理<-->服务端

img


正向代理与反向代理的区别

  1. 形式上服务的”对象”不一样

  2. 正向代理代理的对象是客户端,为客户端服务

  3. 反向代理代理的对象是服务端,为服务端服务

Nginx代理支持协议

img


Nginx反向代理使用协议

img


模块总结

反向代理模式 Nginx模块
http、websocket、https ngx_http_proxy_module
fastcgi ngx_http_fastcgi_module
uwsgi ngx_http_uwsgi_module
grpc ngx_http_v2_module

Nginx反向代理配置

ngx_http_proxy_module模块允许将请求传递到另一台服务器。


配置代理服务器的协议和地址以及位置映射到的URI

Syntax:     proxy_pass URL;
Default:    —
Context:    location, if in location, limit_except

URL可以是:

http://localhost:80/uri
http://10.0.0.7:80/uri
http://unix:/tmp/backend.socket:/uri

URL最后不以/结尾,直接访问目的主机location块的uri下的文件,功能类似 root,常用

URL最后以/结尾,直接访问此uri下的文件,功能类似 alias,不常用

注意:proxy_pass后面路径不带uri时,会将location块的uri传递(附加)给后端主机


配置代理服务器响应的“Location”和“Refresh”头部字段文本

Syntax:     proxy_redirect default;
            proxy_redirect off;
            proxy_redirect redirect replacement;
Default:    proxy_redirect default;
Context:    http, server, location

示例:

假设代理服务器返回了头部字段“ Location: http://localhost:8000/two/some/uri/

proxy_redirect http://localhost:8000/two/ http://frontend/one/;

将头部字段字符串重写为“ Location: http://frontend/one/some/uri/”。


添加或修改代理发往后端的请求头部信息

Syntax:     proxy_set_header field value;
Default:    proxy_set_header Host $proxy_host;
            proxy_set_header Connection close;
Context:    http, server, location

常用请求头:

proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

$proxy_add_x_forwarded_forngx_http_proxy_module模块提供的嵌入式变量,表示“X-Forwarded-For”客户机请求头字段,并附加$remote_addr变量,用逗号分隔,格式如下:X-Forwarded-For: client1, proxy1, proxy2。如果客户端请求标头中不存在“ X-Forwarded-For”字段,则该$proxy_add_x_forwarded_for变量等于$remote_addr变量。


配置代理服务器与后端的TCP连接、响应、返回等超时时间

# nginx代理与后端服务器连接超时时间(代理连接超时),这个时间不能超过75秒。
Syntax:  proxy_connect_timeout time;
Default: proxy_connect_timeout 60s;
Context: http, server, location
 
# nginx代理从后端读取数据的超时时间
Syntax:  proxy_read_timeout time;
Default: proxy_read_timeout 60s;
Context: http, server, location
 
# nginx代理向后端写数据的超时时间
Syntax:  proxy_send_timeout time;
Default: proxy_send_timeout 60s;
Context: http, server, location

配置代理服务器缓冲

Syntax:  proxy_buffering on | off;
Default: proxy_buffering on;
Context: http, server, location

proxy_buffering启用或禁用代理服务器响应的缓冲。

启用缓冲后,nginx会尽快从代理服务器收到响应,并将其保存到proxy_buffer_sizeproxy_buffers指令设置的缓冲区中 。如果整个响应都无法容纳到内存中,则可以将一部分响应保存到磁盘上的临时文件中。写入临时文件由 proxy_max_temp_file_sizeproxy_temp_file_write_size指令控制。

禁用缓冲后,响应一收到就立即传递给客户端。nginx不会尝试从代理服务器读取整个响应。nginx一次可以从服务器接收的最大数据大小由proxy_buffer_size指令设置。

# 设置nginx代理保存用户头信息的缓冲区大小
Syntax:  proxy_buffer_size size;
Default: proxy_buffer_size 4k|8k;
Context: http, server, location
 
# 设置nginx代理单个连接缓冲区的number和size。
Syntax:  proxy_buffers number size;
Default: proxy_buffers 8 4k|8k;
Context: http, server, location

# 设置nginx代理缓冲区的总size。
Syntax:  proxy_busy_buffers_size size;
Default: proxy_busy_buffers_size 8k | 16k;
Context: http, server, location

配置代理服务器缓存

Syntax: 	proxy_cache_valid [code ...] time;
Default:	—
Context:	http, server, location

设置不同响应码的内容的缓存时间。例如

proxy_cache_valid 200 302 10m;
proxy_cache_valid 404      1m;

为代码200和302的响应设置10分钟的缓存,为代码404的响应设置1分钟的缓存。

  1. 不指定响应码,默认仅缓存200、301和302响应。

  2. 指定any缓存任何响应。

  3. 直接在响应头中设置,优先级比使用proxy_cache_valid设置的高。

    • “ X-Accel-Expires”标头字段设置响应的缓存时间(以秒为单位)。零值禁用缓存响应。如果该值以@前缀开头,则它设置自Epoch以来的绝对时间(以秒为单位),直到该时间为止,响应都可以被缓存。
    • 如果标题不包括“ X-Accel-Expires”字段,则可以在标题字段“ Expires”或“ Cache-Control”中设置缓存参数。
    • 如果标头包含“ Set-Cookie”字段,则不会缓存此类响应。
    • 如果标头包含带有特殊值“ *” 的“ Vary”字段,则不会缓存此类响应(1.7.7)。如果标头包含带有另一个值的“ Vary”字段,则将考虑相应的请求标头字段(1.7.7)来缓存此类响应。
    • 可以用proxy_ignore_headers指令禁用如上响应头设置。

Syntax: 	proxy_cache_key string;
Default:	proxy_cache_key $scheme$proxy_host$request_uri;
Context:	http, server, location

proxy_cache_key定义用于缓存的密钥,用于“键”,例如

proxy_cache_key "$host$request_uri $cookie_user";

默认情况下,指令的值接近字符串

proxy_cache_key $scheme$proxy_host$uri$is_args$args;

Syntax: 	proxy_cache zone | off;
Default:	proxy_cache off;
Context:	http, server, location

proxy_cache定义用于缓存的共享内存区域。同一区域可以在多个地方使用。参数值可以包含变量。off禁用从之前配置级别继承的缓存。


Syntax:  proxy_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [min_free=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];
Default: -
Context: http

proxy_cache_path设置缓存的路径和其他参数。缓存数据存储在文件中,会自动创建。

高速缓存文件名是proxy_cache_key的MD5校验值。

levels参数定义高速缓存的目录层次结构级别:从1到3,每个级别接受值1或2。例如,1:2:2可以生成24x28x2^8=1048576个目录

keys_zone=name:size指定内存中缓存的大小,用于存放所有活动密钥key和有关数据metadata(如:使用次数)/http/caches/,1 MB可以存储大约4000个密钥。

inactive参数指定的时间内未访问的缓存数据,直接删除。默认10分钟。

max_sizemin_free参数设置缓存文件占用的最大和最小可用磁盘空间,当超出大小或没有足够的可用空间时,它将删除最近最少使用的数据。

例如,配置

proxy_cache_path /data/nginx/cache levels=1:2:2 keys_zone=one:10m inactive=120s max_size=1g;

生成缓存文件名:

/data/nginx/cache/c/29/b7f54b2df7773722d382f4809d65029c

首先将缓存的响应写入临时文件,然后重命名该文件。可以将临时文件和缓存放在不同的文件系统上,但这会导致文件复制了两份。建议将高速缓存和临时文件存放目录放在同一文件系统上。

临时文件的目录是use_temp_path参数设置的。默认为on,使用proxy_temp_path指令设置的目录。设为off,则临时文件将直接放置在缓存目录中。


Syntax: 	proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | http_429 | off ...;
Default:	proxy_cache_use_stale off;
Context:	http, server, location

proxy_cache_use_stale指定被代理的后端服务器出现哪种情况,可直接使用过期的缓存响应客户端。与proxy_next_upstream指令的参数匹配 。

error如果无法选择代理服务器来处理请求,响应旧缓存。

updating如果在更新缓存时,响应旧缓存。这样可以在更新缓存的数据时最大程度地减少对代理服务器的访问次数。

响应标头中指定超时秒数,超时使用旧缓存响应。比使用proxy_cache_use_stale的优先级低。

  • “ Cache-Control”标头字段的“ stale-while-revalidate ”扩展当前正在更新,则允许使用过期的缓存响应。
  • “ Cache-Control”标头字段的“ stale-if-error ”扩展允许在出现错误的情况下使用过期的缓存响应。

使用proxy_cache_lock在更新缓存时最大程度地减少对代理服务器的访问次数。


Syntax: 	proxy_cache_methods GET | HEAD | POST ...;
Default:	proxy_cache_methods GET HEAD;
Context:	http, server, location

proxy_cache_methods指定对哪些客户端请求方法对应的响应进行缓存,GET和HEAD方法总是被缓存。


创建配置文件:

[root@lb01 ~]# cat > /etc/nginx/conf.d/proxy_node.conf <<EOF
proxy_cache_path /var/cache/nginx/proxy_cache  levels=1:2:2 keys_zone=proxycache:20m inactive=120s max_size=1g;
server {
    listen 80;
    server_name node.oldboy.com;

    proxy_cache proxycache;
    proxy_cache_key \\$request_uri; 
    proxy_cache_valid 200 302 301 1h;
    proxy_cache_valid any 1m;

    location / {
        proxy_pass http://10.0.0.7:80;
        include proxy_params;
    }
}
EOF

创建缓存目录,重载

[root@lb01 ~]# mkdir /var/cache/nginx
[root@lb01 ~]# systemctl reload nginx

访问页面,记录缓存,查看缓存目录文件结构

[root@lb01 ~]# curl node.oldboy.com
Web01...
[root@lb01 ~]# tree /var/cache/nginx
/var/cache/nginx
└── proxy_cache
     └── 9
         └── 7d
             └── cc
                 └── 6666cd76f96956469e7be39d750cc7d9

允许或禁止代理返回客户端的头部信息

Syntax: 	proxy_hide_header field;
Default:	—
Context:	http, server, location

proxy_hide_header禁止指定头部字段从代理服务器传递到客户端。

Syntax: 	proxy_pass_header field;
Default:	—
Context:	http, server, location

proxy_pass_header允许指定头部字段从代理服务器传递到客户端。

注意:nginx默认不会将代理服务器的响应中的头部字段“ Date”,“ Server”,“ X-Pad”和“ X-Accel -...”传递给客户端。

示例:

proxy_hide_header Etag;
proxy_pass_header X-Pad;
  1. 创建配置文件:
[root@lb01 ~]# cat > /etc/nginx/conf.d/proxy_node.conf <<EOF
server {
    listen 80;
    server_name node.oldboy.com;

    location / {
        proxy_pass http://10.0.0.7:80;
        include proxy_params;
    }
}
EOF
  1. 重载查看头部文件:
[root@lb01 ~]# systemctl reload nginx
[root@lb01 ~]# curl -I node.oldboy.com
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Mon, 21 Sep 2020 12:47:54 GMT
Content-Type: text/html
Content-Length: 9
Connection: keep-alive
Last-Modified: Fri, 18 Sep 2020 09:13:15 GMT
ETag: "5f647a2b-9"
Accept-Ranges: bytes
  1. 修改配置文件:
[root@lb01 ~]# cat > /etc/nginx/conf.d/proxy_node.conf <<EOF
server {
    listen 80;
    server_name node.oldboy.com;

    proxy_hide_header ETag;
    proxy_hide_header Date;
    proxy_pass_header Date;

    location / {
        proxy_pass http://10.0.0.7:80;
        include proxy_params;
    }
}
EOF
  1. 重载查看头部文件:
[root@lb01 ~]# systemctl reload nginx
[root@lb01 ~]# curl -I node.oldboy.com
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Mon, 21 Sep 2020 12:49:30 GMT
Content-Type: text/html
Content-Length: 9
Connection: keep-alive
Last-Modified: Fri, 18 Sep 2020 09:13:15 GMT
Accept-Ranges: bytes

添加或修改代理返回客户端的头部或尾部信息

ngx_http_headers_module允许将“ Expires”和“ Cache-Control”头字段以及任意字段添加到响应头中。


Syntax: 	add_header name value [always];
Default:	-
Context:	http, server, location, if in location

如果响应代码等于200、201,204、206、301、302、303、304、307或308,则将指定的字段添加到代理服务器返回客户端的响应报文的头部。参数值可以包含变量。always表示无论响应代码如何,都添加字段。

Syntax: 	add_trailer name value [always];
Default:	—
Context:	http, server, location, if in location

如果响应代码等于200、201、206、301、302、303、307或308,则将指定的字段添加到代理服务器返回客户端的响应报文的末尾。参数值可以包含变量。always表示无论响应代码如何,都添加字段。

示例:

add_header X-Via $server_addr;
add_header X-Cache $upstream_cache_status;
add_header X-Accel $server_name;
  1. 创建配置文件:
[root@lb01 ~]# cat > /etc/nginx/conf.d/proxy_node.conf <<EOF
proxy_cache_path /var/cache/nginx/proxy_cache  levels=1:2:2 keys_zone=proxycache:20m inactive=120s max_size=1g;
server {
    listen 80;
    server_name node.oldboy.com;

    proxy_cache proxycache;
    proxy_cache_key \\$request_uri; 
    proxy_cache_valid 200 302 301 1h;
    proxy_cache_valid any 1m;

    add_header X-Cache \\$upstream_cache_status;

    location / {
        proxy_pass http://10.0.0.7:80;
        include proxy_params;
    }
}
EOF
  1. 重载查看头部文件:

    X-Cache缓存命中效果,第一次访问时,没有缓存,不会命中:第二次访问时,此时已经有缓存,会命中

[root@lb01 ~]# systemctl reload nginx
[root@lb01 ~]# curl -I node.oldboy.com
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Mon, 21 Sep 2020 13:13:27 GMT
Content-Type: text/html
Content-Length: 9
Connection: keep-alive
Last-Modified: Fri, 18 Sep 2020 09:13:15 GMT
ETag: "5f647a2b-9"
X-Cache: MISS
Accept-Ranges: bytes
[root@lb01 ~]# curl -I node.oldboy.com
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Mon, 21 Sep 2020 13:13:29 GMT
Content-Type: text/html
Content-Length: 9
Connection: keep-alive
Last-Modified: Fri, 18 Sep 2020 09:13:15 GMT
ETag: "5f647a2b-9"
X-Cache: HIT
Accept-Ranges: bytes

其他配置

Syntax:	proxy_http_version 1.0 | 1.1;
Default:	
proxy_http_version 1.0;
Context:	http, server, location

设置用于代理的HTTP协议版本。默认1.0版。建议将1.1版与keepalive连接和NTLM身份验证配合使用。


Syntax: 	proxy_connect_timeout time;
Default:	proxy_connect_timeout 60s;
Context:	http, server, location

设置与后端服务器建立连接的超时时长,如超时会出现502错误,一般不建议超出75s。

注意:proxy_timeout转发超时时间是ngx_stream_proxy_module模块提供的


Syntax: 	proxy_send_timeout time;
Default:	proxy_send_timeout 60;
Context:	http, server, location

对后端服务器send,将请求发送给后端服务器的超时时长。超时仅在两个连续的写操作之间设置,而不用于整个请求的传输。超时连接将关闭。


Syntax: 	proxy_read_timeout time;
Default:	proxy_read_timeout 60;
Context:	http, server, location

从后端服务器read,等待后端服务器发送响应报文的超时时长。超时仅在两次连续的读取操作之间设置,而不用于传输整个响应。超时连接将关闭。


Syntax: 	proxy_ignore_client_abort on | off;
Default:	proxy_ignore_client_abort off;
Context:	http, server, location

确定当客户端在不等待响应的情况下中断请求关闭连接时,是否应关闭nginx服务器中断其对后端服务器的请求。

设为on,则nginx会忽略客户端中断,并一直等着代理服务执行返回;

设为off,则客户端中断后,nginx也会中断其对后端服务器的请求,并立即记录499日志。


Syntax: 	proxy_headers_hash_bucket_size size;
Default:	proxy_headers_hash_bucket_size 64;
Context:	http, server, location

设置proxy_hide_header和proxy_set_header需要使用的hash表(nginx用来保存HTTP报文头的hash表)的储存桶的大小


Syntax: 	proxy_headers_hash_max_size size;
Default:	proxy_headers_hash_max_size 512;
Context:	http, server, location

设置proxy_hide_header和proxy_set_header需要使用的hash表(nginx用来保存HTTP报文头的hash表)的最大大小

注意:在开始和每次重新配置期间,nginx都会选择哈希表的最小可能大小,以使存储具有相同哈希值的键的存储桶大小不会超过哈希存储桶大小。表的大小以存储桶表示。再继续进行调整,直到表大小超过哈希最大大小参数为止。因此,如果需要增加,请首先调整最大大小。


反向代理配置

[root@lb01 ~]# cat > /etc/nginx/conf.d/proxy_web.conf <<EOF
server {
...
 
    location / {
        proxy_pass http://10.0.0.7:8080;
        include proxy_params;
    }
}
EOF

[root@lb01 ~]# vim /etc/nginx/proxy_params
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;

proxy_buffering on;
proxy_buffer_size 32k;
proxy_buffers 4 128k;

Nginx反向代理示例

img


环境准备

角色 外网IP(NAT) 内网IP(LAN) 主机名
Proxy eth0:10.0.0.5 eth1:172.16.1.5 lb01
web eth0:10.0.0.7 eth1:172.16.1.7 web01

web01配置:

[root@web01 ~]# cat > /etc/nginx/conf.d/www.conf <<EOF
server {
    listen 8080;
    server_name localhost;

    location / {
        root /code/proxy;
        index index.html;
    }
}
EOF
[root@web01 ~]# mkdir /code/proxy
[root@web01 ~]# echo "web01...." >/code/proxy/index.html
[root@web01 ~]# systemctl restart nginx

lb01配置:

[root@lb01 ~]# cat > /etc/nginx/conf.d/proxy_web.conf <<EOF
server {
    listen 80;
    server_name nginx.oldboy.com;
 
    location / {
        proxy_pass http://10.0.0.7:8080;
    }
}
EOF
[root@lb01 conf.d]# systemctl enable nginx
[root@lb01 conf.d]# systemctl start nginx

windows配置:

C:\\Windows\\System32\\drivers\\etc\\hosts文件中添加一行10.0.0.5 nginx.oldboy.com


抓包查看:

image-20200918161732069

image-20200918161846007

image-20200918161924671

image-20200918162009344

从图中可以看出,当我们仅用proxy_pass配置代理时,会有如下问题:

  1. 10.0.0.1请求10.0.0.5的时候用的是域名,协议是HTTP/1.1
    10.0.0.5请求10.0.0.7的时候用的是IP:port,协议是HTTP/1.0

  2. 10.0.0.7的nginx访问日志只显示代理服务器的地址

[root@web01 ~]# tail -1 /var/log/nginx/access.log
10.0.0.5 - - [18/Sep/2020:15:22:49 +0800] "GET / HTTP/1.0" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36" "-"

在生产环境中,我们必须要记录客户端的来源IP,如果所有的访问日志,全都来源于代理,那么我们根本不知道都有哪些地区的用户访问了我们什么页面。

proxy_set_header模块可以解决这些问题:


使用主机名

proxy_set_header Host $http_host;

使用HTTP/1.1协议

proxy_http_version 1.1;

记录客户端来源IP

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

lb01修改配置,重载nginx:

[root@lb01 ~]# vim /etc/nginx/conf.d/proxy_web.conf
server {
    listen 80;
    server_name nginx.oldboy.com;
 
    location / {
        proxy_pass http://10.0.0.7:8080;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
    }
}
[root@lb01 ~]# systemctl reload nginx

抓包查看:

image-20200918160703385


lb01配置代理web01的wordpress和wecenter

[root@lb01 ~]# cat > /etc/nginx/conf.d/proxy_web.conf <<EOF
server {
    listen 80;
    server_name blog.oldboy.com;
 
    location / {
        proxy_pass http://10.0.0.7:80;
        include proxy_params;
    }
}
server {
    listen 80;
    server_name zh.oldboy.com;
 
    location / {
        proxy_pass http://10.0.0.7:80;
        include proxy_params;
    }
}
EOF

[root@lb01 ~]# vim /etc/nginx/proxy_params
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;

proxy_buffering on;
proxy_buffer_size 32k;
proxy_buffers 4 128k;

windows修改hosts测试:

C:\\Windows\\System32\\drivers\\etc\\hosts文件中,

修改10.0.0.5 blog.oldboy.com zh.oldboy.com

网页测试成功!

以上是关于WEB服务-Nginx之7-反向代理的主要内容,如果未能解决你的问题,请参考以下文章

web服务之nginx反向代理功能

nginx反向代理

Nginx之反向代理

如何在 CentOS 7 用 cPanel 配置 Nginx 反向代理

如何在 CentOS 7 用 cPanel 配置 Nginx 反向代理

如何在 CentOS 7 用 cPanel 配置 Nginx 反向代理