nginx反向代理

一、概念理解


正向代理

在说啥啥反向代理之前,先说下什么是代理或者正向代理

正向代理也就是代理,他的工作原理就像一个跳板,简单的说,我访问不了google.com,但是我能访问一个代理服务器A,A能访问google.com,于是我先连上代理服务器A,告诉他我需要google.com的内容,A就去取回来,然后返回给我。从网站的角度,只在代理服务器来取内容的时候有一次记录,有时候并不知道是用户的请求,也隐藏了用户的资料,这取决于代理告不告诉网站。

结论就是,正向代理是一个位于客户端原始服务器(origin server)之间的服务器。为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。

目前代理软件很多,浏览器上的代理就更多了。翻墙一般就是使用代理服务器的。

反向代理

ok,说完正向代理,再来说啥是反向代理

举个例子,比如我想访问 http://www.test.com/readme,但www.test.com上并不存在readme页面,于是他是偷偷从另外一台服务器上取回来,然后作为自己的内容返回用户,但用户并不知情。这里所提到的 www.test.com 这个域名对应的服务器就设置了反向代理功能

结论就是,反向代理正好相反,对于客户端而言它就像是原始服务器,并且客户端不需要进行任何特别的设置。客户端向反向代理的命名空间(name-space)中的内容发送普通请求,接着反向代理将判断向何处(原始服务器)转交请求,并将获得的内容返回给客户端,就像这些内容原本就是它自己的一样。而正向代理用户是知道内容来自哪个网站的。

嗯。正向代理和反向代理就基本清楚了,那我们就来用nginx来配置一个反向代理。

nginx 使用反向代理,主要是使用location模块下的proxy_pass选项

二、环境


client:192.168.17.122         proxy:192.168.119.130       real-server1:192.168.119.133     real-server2: 192.168.17.120

准备工作:代理服务器都能正常提供web服务。

        proxy安装nginx,real-server安装nginx或apache。笔者三台机器都是安装nginx

real-server1配置文件:

[root@localhost]# egrep -v "^$|#" /usr/local/nginx/conf/nginx.conf
user  www;
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        location / {
            root   /mywww;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}
RS1: nginx.conf

real-server1目录结构:

[root@localhost]# tree /mywww/
/mywww/
├── hehe
│   └── index.html
├── hello
│   └── index.html
└── index.html

2 directories, 3 files

RS2配置与RS1类似,两台机器安装nginx后配置文件几乎没改,因为测试越简单越易于理解

三、proxy配置


[root@zabbix ~]# egrep -v "^$|^#" /usr/local/nginx/conf/nginx.conf
user  deamon;
worker_processes  8; 
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx/nginx.pid;
events {
    use epoll;  #使用epoll高效模式,适用于Linux,Unix使用kqueue
    worker_connections  100000; 
}
worker_rlimit_nofile 100000; #打开的文件句柄数量最高为10万
http {
    include       mime.types;
    default_type  application/octet-stream;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile        on;
    #tcp_nopush     on;
    #keepalive_timeout  0;
    keepalive_timeout  65;
    ...
    ...
    ...
    server {
        listen       80 ; #监听端口号
        server_name  localhost;
        root         /www/;
        location / {
            index index.php index.html index.htm;
            if (!-e $request_filename) {
                return 444;
            }
        }
        location ~ .php$ {
            root           /www;
            fastcgi_pass   unix:/tmp/php-cgi.sock;
            fastcgi_index  index.php;
            fastcgi_cache_valid 200 60m;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }
########################################################################### location /zabbix{ proxy_pass http://192.168.17.120; } location /haha { proxy_pass http://192.168.119.133/hello; } location /hehe { proxy_pass http://192.168.119.133:80; }
#
###########################################################################
#指定对网页图片格式进行缓存max表示10年,也可以是30d(天) location ~ .(swf|js|css|xml|gif|jpg|jpeg|png|bmp)$ { error_log off; access_log off; #expires 30d; expires max; } } }
[root@zabbix ~]# egrep -v "^$|^#" /usr/local/nginx/conf/nginx.conf
user  deamon;
worker_processes  8;  #指定了要开启的进程数,每进程占用10M~12M的内存,建议和CPU的核心数量一样多的进程就行了。
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx/nginx.pid;
events {
    use epoll;  #使用epoll高效模式,适用于Linux,Unix使用kqueue
    worker_connections  100000; #定义Ningx没个进程最大的连接数。默认为1024,受到文件句柄的约束。
}
worker_rlimit_nofile 100000; #打开的文件句柄数量最高为10万
http {
    include       mime.types;
    default_type  application/octet-stream;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile        on;
    #tcp_nopush     on;
    #keepalive_timeout  0;
    keepalive_timeout  65;
    server_names_hash_bucket_size 128;
    client_header_buffer_size 32k; #客户端请求头部的缓冲区大小,一般一个请求头的大小不会超过1k
    large_client_header_buffers 4 32k; #客户请求头缓冲大小 nginx默认会用client_header_buffer_size这个buffer来读取header值
    client_max_body_size 8m; #设定通过nginx上传文件的大小
    gzip              on; #该指令用于开启或关闭gzip模块(on/off)
    gzip_min_length   1k; #设置允许压缩的页面最小字节数,页面字节数从header头得content-length中进行获取
    gzip_buffers      4 16k; #设置系统获取几个单位的缓存用于存储gzip的压缩结果数据流
    gzip_http_version 1.0; #识别http的协议版本
    gzip_comp_level   2;   #gzip压缩比,1压缩比最小处理速度最快
        #匹配mime类型进行压缩,无论是否指定,”text/html”类型总是会被压缩的
    gzip_types        text/plain application/x-javascript text/css application/xml text/javascript;
    gzip_vary         on; #和http头有关系,加个vary头,给代理服务器用的
    charset      utf-8;  #字符集为utf-8
    access_log   off;    # 日常日志关闭
    log_not_found off;   # 日常日志关闭
    fastcgi_connect_timeout 300; #指定连接到后端FastCGI的超时时间。
    fastcgi_send_timeout 300; #向FastCGI传送请求的超时时间,这个值是指已经完成两次握手后向FastCGI传送请求的超时时间。
    fastcgi_read_timeout 300; #接收FastCGI应答的超时时间,这个值是指已经完成两次握手后接收FastCGI应答的超时时间。
    fastcgi_buffer_size 254k; #指定读取FastCGI应答第一部分需要用多大的缓冲区
    fastcgi_buffers 16 256k; #指定本地需要用多少和多大的缓冲区来缓冲FastCGI的应答。
    fastcgi_busy_buffers_size 512k; #这个指令我也不知道是做什么用,只知道默认值是fastcgi_buffers的两倍。
    fastcgi_temp_file_write_size 512k; #在写入fastcgi_temp_path时将用多大的数据块,默认值是fastcgi_buffers的两倍。
    server {
        listen       80 ; #监听端口号
                #域名为
        server_name  localhost;
        # 指定网站的目录
                root         /www/;
                # localtion模块指定网站首页名称
        location / {
            index index.php index.html index.htm;
            if (!-e $request_filename) {
                return 444;
            }
        }
        location ~ .php$ {
            root           /www;
            #fastcgi_cache MYAPP;
            #fastcgi_cache_valid 200 60m;
            fastcgi_pass   unix:/tmp/php-cgi.sock;
            fastcgi_index  index.php;
            fastcgi_cache_valid 200 60m;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }
        location /zabbix{
        proxy_pass http://192.168.17.120;
}
    location /haha {
        proxy_pass http://192.168.119.133/hello;
}
    location /hehe {
        proxy_pass http://192.168.119.133:80;
}
                #指定对网页图片格式进行缓存max表示10年,也可以是30d(天)
        location ~ .(swf|js|css|xml|gif|jpg|jpeg|png|bmp)$ {
            error_log    off;
            access_log   off;
                        #expires      30d;
            expires      max;
        }
}
完整proxy nginx.conf

由于之前在proxy上放了zabbix服务,所以配置文件稍微复杂一点,但不用管这些,只需要关注#####框住部分配置

实际上proxy机器上并没有zabbix目录,也没有hehe、haha目录

这一配置实现的结果就是client访问proxy的zabbix目录时,proxy会从192.168.17.120的web根目录下的zabbix目录获取数据(index.html),再返回给client,这中间发生的一切对client完全透明,client一直认为数据是从proxy获取。、

client访问proxy的haha目录时,proxy会从192.168.119.133的web根目录的hello目录下获取数据(index.html),为什么不是web根目录下的haha目录?只能意会不能言传,比较比较应该能得出结果

client访问proxy的hehe目录时,proxy会从192.168.119.133的web根目录下的hehe目录下获取数据(index.html)

四、访问结果


#####################################################################

利用tcpdump查看RS1(192.168.119.133)的真实客户端,RS1运行tcpdump后用client浏览器访问proxy的haha目录

tcpdump抓取数据包结果:
[root@localhost mywww]# tcpdump -i eth0 dst host 192.168.119.133 and dst port 80 -n
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
14:47:42.156816 IP 192.168.119.130.54144 > 192.168.119.133.http: Flags [S], seq 1736642454, win 14600, options [mss 1460,sackOK,TS val 2464156420 ecr 0,nop,wscale 6], length 0
14:47:42.157102 IP 192.168.119.130.54144 > 192.168.119.133.http: Flags [.], ack 1302104194, win 229, options [nop,nop,TS val 2464156420 ecr 2378460417], length 0
14:47:42.157119 IP 192.168.119.130.54144 > 192.168.119.133.http: Flags [P.], seq 0:491, ack 1, win 229, options [nop,nop,TS val 2464156420 ecr 2378460417], length 491
14:47:42.157539 IP 192.168.119.130.54144 > 192.168.119.133.http: Flags [.], ack 174, win 245, options [nop,nop,TS val 2464156421 ecr 2378460418], length 0
14:47:42.158316 IP 192.168.119.130.54144 > 192.168.119.133.http: Flags [F.], seq 491, ack 175, win 245, options [nop,nop,TS val 2464156421 ecr 2378460418], length 0

由此可见是proxy在访问RS1

RS1数据是直接返回给client还是proxy呢?

[root@localhost mywww]# tcpdump -i eth0 src host 192.168.119.133 and dst host 192.168.119.130 -n
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
14:55:28.542770 IP 192.168.119.133.http > 192.168.119.130.55754: Flags [S.], seq 198025648, ack 2710538549, win 14480, options [mss 1460,sackOK,TS val 2378926803 ecr 2464622812,nop,wscale 6], length 0
14:55:28.542949 IP 192.168.119.133.http > 192.168.119.130.55754: Flags [.], ack 492, win 243, options [nop,nop,TS val 2378926803 ecr 2464622812], length 0
14:55:28.543039 IP 192.168.119.133.http > 192.168.119.130.55754: Flags [P.], seq 1:174, ack 492, win 243, options [nop,nop,TS val 2378926803 ecr 2464622812], length 173
14:55:28.543068 IP 192.168.119.133.http > 192.168.119.130.55754: Flags [F.], seq 174, ack 492, win 243, options [nop,nop,TS val 2378926803 ecr 2464622812], length 0
14:55:28.543167 IP 192.168.119.133.http > 192.168.119.130.55754: Flags [.], ack 493, win 243, options [nop,nop,TS val 2378926803 ecr 2464622812], length 0

数据也是直接返回给proxy的

 #####################################################################################

  怎么降低代理服务器的负载?

方法倒是有:nginx proxy只负责分发客户端请求,响应由后端服务器直接返回给客户端,但这种方法不符合通信过程,因为数据包包头的目的地址和源地址不会改变,假设客户端IP为a,代理服务器IP为b,后端服务器IP为c,那么分发请求时源地址为b,目的地址为c,当后端服务器返回时将c作为源地址,b作为目的地址,这样就不能实现后端服务器直接返回数据给客户端。

   怎么解决该问题?
把客户端信息,如IP也传给后端服务器即可,这需要nginx支持realip,所以编译时需要加上:--with-http_realip_module

  

原文地址:https://www.cnblogs.com/xiami-xm/p/7459033.html