Nginx 的 proxy 配置

lance 2020-04-17 AM 265℃ 0条

正向代理与反向代理

正向代理

09456-g5culhu90b9.png
70441-g0yumi7rjlm.png

反向代理

61946-x2z4hn1ssgk.png
65296-5j9g8bf86dd.png


Nginx 的正向代理

Nginx 正向代理配置

Nginx 正向代理使用场景并不多见。
需求场景 1:
如果在机房中,只有一台机器可以联网,其他机器只有内网,内网的机器想用使用 yum 安装软件包,在能联网的机器上配置一个正向代理即可。

Nginx 正向代理配置文件

server {
    listen 80 default_server;
    resolver 119.29.29.29;
    location / {
        proxy_pass http://$host$request_uri;
    }
}

Nginx 正向代理配置执行说明

  • resolver
语法:resolver address;

address 为 DNS 服务器的地址,国内通用的 DNS 119.29.29.29 为 dnspod 公司提供。 国际通用 DNS 8.8.8.8 或者 8.8.4.4 为 google 提供。
其他可以参考 http://dns.lisect.com/

示例:resolver 119.29.29.29;
  • default_server
之所以要设置为默认虚拟主机,是因为这样就不用设置 server_name 了,任何域名解析过来都可以正常访问。
  • proxy_pass
该指令用来设置要代理的目标 url,正向代理服务器设置就保持该固定值即可。关于该指令的详细解释在反向代理配置中。

Nginx 的反向代理

Nginx 反向代理配置

Nginx 反向代理在生产环境中使用很多的。

场景 1:
域名没有备案,可以把域名解析到香港一台云主机上,在香港云主机做个代理,而网站数据是在大陆的服务器上。

示例 1:
server 
{
    listen 80;
    server_name a.com;

    location /
    {
        proxy_pass http://123.23.13.11/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

配置说明

  • proxy_pass

在正向代理中,已经使用过该指令。
格式很简单: proxy_pass URL;
其中 URL 包含:传输协议(http://, https://等)、主机名(域名或者 IP:PORT)、uri。

示例如下:
proxy_pass http://www.a.com/;
proxy_pass http://192.168.200.101:8080/uri;
proxy_pass unix:/tmp/www.sock;

对于 proxy_pass 的配置有几种情况需要注意。
示例 2:
location /a/
{
    proxy_pass http://192.168.1.10;
    ...
}

示例 3:
location /a/
{
    proxy_pass http://192.168.1.10/;
    ...
}

示例 4:
location /a/
{
    proxy_pass http://192.168.1.10/linux/;
    ...
}

示例 5:
location /a/
{
    proxy_pass http://192.168.1.10/linux;
    ...
}

假设 server_name 为 www.a.com
当请求 http://www.a.com/a/a.html 的时候,以上示例 2-5 分别访问的结果是

示例2:http://192.168.1.10/a/a.html

示例3:http://192.168.1.10/a.html

示例4:http://192.168.1.10/linux/a.html

示例5:http://192.168.1.10/linuxa.html
  • proxy_set_header
proxy_set_header 用来设定被代理服务器接收到的 header 信息。

语法:proxy_set_header field value;
field 为要更改的项目,也可以理解为变量的名字,比如 host
value 为变量的值

如果不设置 proxy_set_header,则默认 host 的值为 proxy_pass 后面跟的那个域名或者 IP(一般写 IP),
比如示例 4,请求到后端的服务器上时,完整请求 uri 为:http://192.168.1.10/linux/a.html

如果设置 proxy_set_header,如 proxy_set_header host $host;
比如示例 4,请求到后端的服务器完整 uri 为:http://www.a.com/linux/a.html

proxy_set_header X-Real-IP $remote_addr; 和 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
用来设置被代理端接收到的远程客户端 IP,如果不设置,则 header 信息中并不会透传远程真实客户端的 IP 地址。
可以用如下示例来测试:

示例 6(被代理端)
server{
    listen 8080;
    server_name www.a.com;
    root /tmp/123.com_8080;
    index index.html;
    location /linux/ {
    echo "$host";
        echo $remote_addr;
        echo $proxy_add_x_forwarded_for;
    }
}

示例 7(代理服务器上)
server {
    listen 80;
    server_name www.a.com;

    location /a/
    {
    proxy_pass http://192.168.1.10:8080/linux/;
    proxy_set_header host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
  • proxy_redirect
该指令用来修改被代理服务器返回的响应头中的 Location 头域和 refresh 头域。
语法结构为:
proxy_redirect redirect replacement;
proxy_redirect default;
proxy_redirect off;

示例 8:
server {
    listen 80;
    server_name www.a.com;
    index  index.html;

    location /
    {
    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;
    }
}

当请求的链接为 http://www.a.com/a
结果会返回 301,定向到了 http://www.a.com:8080/a/

注意:返回 301 有几个先决条件
1. location 后面必须是 /; 
2. proxy_pass 后面的 URL 不能加 uri,只能是 IP 或者 IP:port 结尾,并不能以 / 结尾;
3. 访问的 uri 必须是一个真实存在的目录,如,这里的 a 必须是存在的
4. 访问的时候,不能以 / 结尾,只能是 www.a.com/a

虽然,这 4 个条件挺苛刻,但确实会遇到类似的请求。解决方法是,加一行 proxy_redirect http://$host:8080/ /;

示例 9:
server {
    listen 80;
    server_name www.a.com;
    index  index.html;

    location /
    {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header host $host;
        proxy_redirect http://$host:8080/ /;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Nginx 反向代理中的 proxy_buffering 和 proxy_cache

  • 两个都是 nginx 代理中内存设置相关的参数。

proxy_buffering 设置

proxy_buffering 主要是实现被代理服务器的数据和客户端的请求异步。
为了方便理解,我们定义三个角色,A 为客户端,B 为代理服务器,C 为被代理服务器。

当 proxy_buffering 开启,A 发起请求到 B,B 再到 C,C 反馈的数据先到 B 的 buffer 上,
然后 B 会根据 proxy_busy_buffer_size 来决定什么时候开始把数据传输给 A。在此过程中,如果所有的 buffer 被写满,
数据将会写入到 temp_file 中。

相反,如果 proxy_buffering 关闭,C 反馈的数据实时地通过 B 传输给 A。

以下配置,都是针对每一个 http 请求的。

1. proxy_buffering on;
该参数设置是否开启 proxy 的 buffer 功能,参数的值为 on 或者 off。
如果这个设置为 off,那么 proxy_buffers 和 proxy_busy_buffers_size 这两个指令将会失效。 
但是无论 proxy_buffering 是否开启,proxy_buffer_size 都是生效的

2. proxy_buffer_size 4k;
该参数用来设置一个特殊的 buffer 大小的。
从被代理服务器(C)上获取到的第一部分响应数据内容到代理服务器(B)上,通常是 header,就存到了这个 buffer 中。 
如果该参数设置太小,会出现 502 错误码,这是因为这部分 buffer 不够存储 header 信息。建议设置为 4k。

3. proxy_buffers 8 4k;
这个参数设置存储被代理服务器上的数据所占用的 buffer 的个数和每个 buffer 的大小。
所有 buffer 的大小为这两个数字的乘积。

4. proxy_busy_buffer_size 16k;
在所有的 buffer 里,我们需要规定一部分 buffer 把自己存的数据传给 A,这部分 buffer 就叫做 busy_buffer。
proxy_busy_buffer_size 参数用来设置处于 busy 状态的 buffer 有多大。

对于 B 上 buffer 里的数据何时传输给 A,我个人的理解是这样的:
1)如果完整数据大小小于 busy_buffer 大小,当数据传输完成后,马上传给 A;
2)如果完整数据大小不少于 busy_buffer 大小,则装满 busy_buffer 后,马上传给 A;

5. proxy_temp_path
语法:proxy_temp_path  path [level1 level2 level3]
定义 proxy 的临时文件存在目录以及目录的层级。

例:proxy_temp_path /usr/local/nginx/proxy_temp 1 2;
其中 /usr/local/nginx/proxy_temp 为临时文件所在目录,1 表示层级 1 的目录名为一个 数字(0-9),2 表示层级 2 目录名为 2 个 数字(00-99)

6. proxy_max_temp_file_size
设置临时文件的总大小,例如  proxy_max_temp_file_size 100M;

7. proxy_temp_file_wirte_size
设置同时写入临时文件的数据量的总大小。通常设置为 8k 或者 16k。

proxy_buffer 示例

server
{
    listen 80;
    server_name www.a.com;
    proxy_buffering on;
    proxy_buffer_size 4k;
    proxy_buffers 2 4k;
    proxy_busy_buffers_size 4k;
    proxy_temp_path /tmp/nginx_proxy_tmp 1 2;
    proxy_max_temp_file_size 20M;
    proxy_temp_file_write_size 8k;

    location /
    {
    proxy_pass http://192.168.10.110: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;
    }
}

proxy_cache 设置

proxy_cache 将从 C 上获取到的数据根据预设规则存放到 B 上(内存+磁盘)留着备用,
A 请求 B 时,B 会把缓存的这些数据直接给 A,而不需要再去向 C 去获取。

proxy_cache 相关功能生效的前提是,需要设置 proxy_buffering on;

proxy_cache 主要参数

1. proxy_cache
语法:proxy_cache zone|off
默认为 off,即关闭 proxy_cache 功能,zone 为用于存放缓存的内存区域名称。
例:proxy_cache my_zone;
从 nginx 0.7.66 版本开始,proxy_cache 机制开启后会检测被代理端的 HTTP 响应头中的 "Cache-Control"、"Expire" 头域。
如,Cache-Control为no-cache 时,是不会缓存数据的。

2. proxy_cache_bypass 
语法:proxy_cache_bypass string;
该参数设定,什么情况下的请求不读取 cache 而是直接从后端的服务器上获取资源。
这里的 string 通常为 nginx 的一些变量。
例:proxy_cahce_bypass $cookie_nocache $arg_nocache$arg_comment;
意思是,如果 $cookie_nocache $arg_nocache$arg_comment 这些变量的值只要任何一个不为 0 或者不为空时,
则响应数据不从 cache 中获取,而是直接从后端的服务器上获取。

3. proxy_no_cache
语法:proxy_no_cache string;
该参数和proxy_cache_bypass类似,用来设定什么情况下不缓存。
例:proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
表示,如果 $cookie_nocache $arg_nocache $arg_comment 的值只要有一项不为 0 或者不为空时,不缓存数据。

4. proxy_cache_key
语法:proxy_cache_key string;
定义cache key,如:proxy_cache_key $scheme$proxy_host$uri$is_args$args; (该值为默认值,一般不用设置)

5. proxy_cache_path
语法:proxy_cache_path path [levels=levels] keys_zone=name:size  [inactive=time] [max_size=size] 
path 设置缓存数据存放的路径;
levels 设置目录层级,如 levels=1:2,表示有两级子目录,第一个目录名取 md5 值的倒数第一个值,第二个目录名取 md5 值的第 2 和 3 个值。如下图:

63387-5r0jod2m5b8.png

keys_zone 设置内存 zone 的名字和大小,如 keys_zone=my_zone:10m

inactive 设置缓存多长时间就失效,当硬盘上的缓存数据在该时间段内没有被访问过,就会失效了,该数据就会被删除,默认为 10s。

max_size 设置硬盘中最多可以缓存多少数据,当到达该数值时,nginx 会删除最少访问的数据。

例:proxy_cache_path /data/nginx_cache/ levels=1:2 keys_zone=my_zone:10m inactive=300s max_size=5g

proxy_cache 示例

http 
{
    ...;

    proxy_cache_path /data/nginx_cache/ levels=1:2 keys_zone=my_zone:10m inactive=300s max_size=5g;

    ...;

    server
    {
        listen 80;
        server_name www.a.com;
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 2 4k;
        proxy_busy_buffers_size 4k;
        proxy_temp_path /tmp/nginx_proxy_tmp 1 2;
        proxy_max_temp_file_size 20M;
        proxy_temp_file_write_size 8k;

    location /
    {
        proxy_cache my_zone;
        proxy_pass http://192.168.10.110: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;
    }
    }
}

说明:核心配置为 proxy_cache_path 那一行。

Nginx 的负载均衡

  • Nginx 通过 upstream 和 proxy_pass 实现了负载均衡。本质上也是 Nginx 的反向代理功能,只不过后端的 server 为多个。

案例一(简单的轮询)

upstream www {
    server 172.37.150.109:80;
    server 172.37.150.101:80;
    server 172.37.150.110:80;
}

server {
    listen 80;
    server_name www.a.com;
    location / {
        proxy_pass http://www/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

说明:当被代理的机器有多台时,需要使用 upstream 来定义一个服务器组,
其中 www 名字可以自定义,在后面的 proxy_pass 那里引用。
这样 nginx 会将请求均衡地轮询发送给 www 组内的三台服务器。

案例二(带权重轮询 + ip_hash 算法)

upstream www {
    server 172.37.150.109:80 weight=50;
    server 172.37.150.101:80 weight=100;
    server 172.37.150.110:80 weight=50;
    ip_hash;
}

server {
    listen 80;
    server_name www.a.com;
    location / {
        proxy_pass http://www/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

说明:可以给 www 组内的三台机器配置权重,权重越高,则分配到的请求越多。
ip_hash 为 nginx 负载均衡算法,原理很简单,它根据请求所属的客户端 IP 计算得到一个数值,然后把请求发往该数值对应的后端。
所以同一个客户端的请求,都会发往同一台后端,除非该后端不可用了。ip_hash 能够达到保持会话的效果。

案例三(upstream 其他配置)

upstream www {
    server 172.37.150.109:80 weight=50 max_fails=3 fail_timeout=30s;
    server 172.37.150.101:80 weight=100;
    server 172.37.150.110:80 down;
    server 172.37.150.110:80 backup;
}

server
{
    listen 80;
    server_name www.a.com;
    location / {
        proxy_next_upstream off;
        proxy_pass http://www/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

说明:
down,表示当前的 server 不参与负载均衡;
backup 为预留的机器,当其他的 server(非 backup)出现故障或者忙的时候,才会请求 backup 机器;
max_fails,允许请求失败的次数,默认为 1。当失败次数达到该值,就认为该机器 down 掉了。 失败的指标是由 proxy_next_upstream 模块定义,其中 404 状态码不认为是失败。
fail_timeount,定义失败的超时时间,也就是说在该时间段内达到 max_fails,才算真正的失败。默认是 10 秒。
proxy_next_upstream,通过后端服务器返回的响应状态码,表示服务器死活,可以灵活控制后端机器是否加入分发列表。
语法: proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 |http_404 | off ...; 
默认值: proxy_next_upstream error timeout

error:和后端服务器建立连接时,或者向后端服务器发送请求时,或者从后端服务器接收响应头时,出现错误
timeout:和后端服务器建立连接时,或者向后端服务器发送请求时,或者从后端服务器接收响应头时,出现超时
invalid_header:后端服务器返回空响应或者非法响应头
http_500:后端服务器返回的响应状态码为 500
http_502:后端服务器返回的响应状态码为 502
http_503:后端服务器返回的响应状态码为 503
http_504:后端服务器返回的响应状态码为 504
http_404:后端服务器返回的响应状态码为 404
off:停止将请求发送给下一台后端服务器

案例四(根据不同的 uri)

upstream aa.com {         
    server 192.168.0.121;
    server 192.168.0.122;  
}

upstream bb.com {  
    server 192.168.0.123;
    server 192.168.0.124;
}

server {
    listen 80;
    server_name www.a.com;
    location ~ aa.php
    {
        proxy_pass http://aa.com/;
        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 ~ bb.php
    {
        proxy_pass http://bb.com/;
        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 /
    {
        proxy_pass http://bb.com/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

说明:请求 aa.php 的,会到 aa.com 组,请求 bb.php 的会到 bb.com,其他请求全部到 bb.com。

案例五(根据不同的目录)

upstream aaa.com
{
    server 192.168.111.6;
}

upstream bbb.com
{
    server 192.168.111.20;
}

server {
    listen 80;
    server_name www.a.com;
    location /aaa/
    {
        proxy_pass http://aaa.com/aaa/;
        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 /bbb/
    {
        proxy_pass http://bbb.com/bbb/;
        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 /
    {
        proxy_pass http://bbb.com/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

标签: linux, nginx, proxy

非特殊说明,本博所有文章均为博主原创。

觉得文章不错,打赏一点吧,1分也是爱😀

WeChat Pay

微信打赏

Alipay

支付宝打赏

评论啦~