# Nginx代理

参考资料:

相关项目:

开源网关:

# 概念

代理服务器是客户端和服务器之间的一台中转服务器,代理分为正向代理(forward proxy)和反向代理(reverse proxy):

  • 正向代理:客户端向代理服务器发送一个请求并指定目标,然后代理服务器向目标服务器转交请求并将获得的内容返回给客户端。此时代理服务器代理了客户端,去和目标服务器交互。
  • 反向代理:代理服务器接收Internet上的连接请求,并将请求转发给内部网络上的服务器,将请求结果返回给Internet上的连接客户端。此时代理服务器代理了内网的服务器,去和来请求的客户端交互。

所以正向代理和反向代理主要看的是代理服务器代理了客户端(正向)还是服务器端(反向)。我们假设服务器端为房东,有房子资源,代理服务器为中介,寻找房子的租户为客户端。正向代理租户是去找中介,让中介对接房东帮自己找房子。反向代理为租户找到了房东的某个亲戚,这个亲戚和房东对接,并把结果告诉租户。

# 正向代理

下面说明了正向代理:

forwardproxy

在正向代理中:

  1. 客户端无法直接访问服务器,而代理服务器可以访问。
  2. 代理服务器会把客户端请求的缓存,其他客户端访问时直接反馈。
  3. 客户端需要浏览器设置代理服务器IP和端口。

它的作用是:

  1. 突破客户端的访问限制,通过代理服务器可突破自身IP访问限制,访问自身访问不到的资源。
  2. 提高访问速度,代理服务器会有缓存区,其他客户端请求时可直接返回。
  3. 隐藏客户端的真实IP。服务器并不知道客户端的真实IP。

# 反向代理

下面说明了反向代理:

reverseproxy

在反向代理中:

  1. 客户端访问服务器,认为反向代理就是正式服务器。实际上反向代理会与服务器通信,以把结果返回给客户端。
  2. 代理服务器会把客户端请求的缓存,其他客户端访问时直接反馈。
  3. 客户端不需要设置代理服务器IP和端口。

它的作用是:

  1. 负载均衡:根据所有真实服务器的负载情况,将客户端请求分发到不同的真实服务器上。
  2. 提高访问速度,有缓存,其他客户端访问时可直接返回。
  3. 隐藏服务器真实IP,提供安全保障,可以把反向代理看成是应用层的防火墙,防范恶意攻击(Dos/DDos),为后端服务器统一提供SSL加速,HTTP访问认证。

# 正向代理实操

参考资料:

nginx代理http都是没有问题,但是https会有问题。nginx有两种方式来处理。分别在L7和L4:

layer7

# L7Proxy

在应用层代理,Nginx需要第三方插件ngx_http_proxy_connect_module (opens new window)。除了这个貌似谷歌在用envoy (opens new window)

server {
     listen                         3128;

     # dns resolver used by forward proxying
     resolver                       8.8.8.8;

     # forward proxy for CONNECT request
     proxy_connect;
     proxy_connect_allow            443 563;
     proxy_connect_connect_timeout  10s;
     proxy_connect_read_timeout     10s;
     proxy_connect_send_timeout     10s;

     # forward proxy for non-CONNECT request
     location / {
         proxy_pass http://$host;
         proxy_set_header Host $host;
     }
 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

测试代理:

curl https://github.com/ -v -x 127.0.0.1:3128
1

# L4Proxy

在TCP/IP层,从1.11.5开始,nginx支持ngx_stream_ssl_preread_module。编译的时候加-with-stream, --with-stream_ssl_preread_module和--with-stream_ssl_module。

stream {
    resolver 114.114.114.114;
    server {
        listen 443;
        ssl_preread on;
        proxy_connect_timeout 5s;
        proxy_pass $ssl_preread_server_name:$server_port;
    }
}
1
2
3
4
5
6
7
8
9

测试代理的时候注意它跟L7不一样,在L4的代理,nginx只是把包传给上层,并不使用HTTP CONNECT来建立隧道,因此L4适合透明代理模式,比如目标域名直接通过域名解析到代理服务器,需要直接添加到host文件。

112.112.332.122 www.baidu.com
# 在linux下面改了/etc/hosts记得需要重启网络来让其立即起作用
apt-get install network-manager
/etc/init.d/network-manager restart
1
2
3
4

# 反向代理实操

反向代理看到一个比较好的项目,有时间研究下:nginx proxy manager (opens new window)

# 实例

# node代理

参考资料:

正常它是一个普通应用,但是可能会涉及到websocket:

upstream backend {
    server node:5000;
}

server {
    location /sockjs-node/ {
            proxy_pass http://backend;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
            proxy_read_timeout 300s;
            proxy_set_header Host $host;         
            proxy_set_header X-Real-IP $remote_addr;                  
            proxy_redirect off;
            
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

如果是socket.io的话:

upstream websocket {
    server localhost:3000;
}

server {
    listen       80;
    server_name  localhost;

    access_log  /var/log/nginx/websocket.access.log  main;

    location /socket.io/ {
        proxy_pass http://websocket;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    location /socket.io/socket.io.js {
        proxy_pass http://websocket;
    }

    location /sample.html {
        root   /usr/share/nginx/html/;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

这里面涉及的变量:

  • proxy_set_header:允许重新定义或者添加发往后端服务器的请求头。
    • Host:把原http请求的Header中的Host字段放到转发的请求里,如果没有这个,转发的请求里没有Host字段,被代理的后端服务器不能得知前端用户访问的真正的域名。
      • $http_host:代理服务器请求的host,即后端服务器/源站的IP,后端服务器有可能还是代理服务器。该变量里已经包含了端口。
      • $host:不会包含端口。
        • $proxy_port:被代理的服务器真正的端口。代理服务器请求的后端服务器的端口。
        • $server_port:反向代理的nginx监听的端口。
    • X-Real-IP:通过它获取客户端的真实IP,如果设置了$remote_addr这个值,后端服务器就能获取到客户端的真实IP。$http_x_real_ip中获取的是上一层节点的ip,只有一层代理的情况下是用户的ip。
      • $remote_addr:前一节点的IP,并不一定是用户的真实IP。
      • $proxy_add_x_forwarded_for:包含客户端请求头中的 X-Forwarded-For 与 $remote_addr 两部分,他们之间用逗号分开,这样能获取所有的代理ip和客户端ip。
    • X-Forwarded-For:是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段。如果设置了该字段,每次经过proxy转发都会有记录,格式就是 client1,proxy1,proxy2,以逗号隔开各个地址,由于它是非rfc标准,所以默认是没有的,需要强制添加。
    • X-Forwarded-Port:给出客户端连接到代理上的端口。
    • X-Forwarded-Host:给出客户端发送到代理的Host标头的内容。
  • proxy_redirect:是否将被代理服务器的响应头中的location字段进行修改后返回给客户端。
    • proxy_redirect http://localhost:8000/two/ /; 将服务器的location替换成这个来达到隐藏的目的。

# yum代理

参考资料:

有很多时候我们的服务器是不能上网的,而局域网是有一台能上网,这个时候我们需要给yum设置代理让它能通过这台电脑上网。

给能上网的电脑设置nginx代理:

server {
    listen  8080;
    location /centos/ {
        proxy_pass http://mirrors.aliyun.com/centos/;
    }

    location /epel/ {
        proxy_pass http://mirrors.aliyun.com/epel/;
    }
}
1
2
3
4
5
6
7
8
9
10

在不能上网的电脑中的/etc/yum.conf中设置:

proxy=http://目标ip:端口
1

# docker代理

参考资料:

如果是docker的话,可以设置

server {
    listen  8080;

    location / {
        auth_basic off;
        proxy_pass https://5yzx6sxk.mirror.aliyuncs.com;
        proxy_redirect default;
    }

}
1
2
3
4
5
6
7
8
9
10

给docker中/etc/docker/daemon.json设置

{
  "registry-mirrors": ["http://ip:8080"]
}
1
2
3

# 代理

总结下各种应用的代理方式

# Windows

# 设置代理:
set http_proxy=http://IP:端口号
set https_proxy=http://IP:端口号
# 取消代理:
set http_proxy=
set https_proxy=
# 如果要设置密码:
set http_proxy_user=
set http_proxy_pass=
1
2
3
4
5
6
7
8
9

上面是在命令行上临时设置,如果需要永久设置,需要在环境变量中来设置上面的变量。

我的电脑 -> 属性 -> 高级系统设置 -> 高级 -> 环境变量

# Linux

设置代理:

# 在/etc/profile中设置:
export http_proxy=http://proxy.com:8080/
export https_proxy=http://proxy.com:8080/
# 更新环境文件
source /etc/profile
1
2
3
4
5

# Git设置

# 设置代理
git config --global http.proxy http://127.0.0.1:11000
git config --global https.proxy http://127.0.0.1:11000
# 取消代理
git config --global --unset http.proxy
1
2
3
4
5

# yum设置代理

# 在/etc/yum.conf中设置:
proxy=http://proxy.com:8080/
proxy_username=代理服务器用户名
proxy_password=代理服务器密码
# 更新环境文件
source /etc/yum.conf
1
2
3
4
5
6

# wget设置

# 在/etc/wgetrc中设置
http_proxy=http://proxy.com:8080/
https_proxy=http://proxy.com:8080/
# 更新文件
source /etc/wgetrc
1
2
3
4
5