1 反向代理相关概念
什么是反向代理?
根据上图我们看出,反向代理服务器是位于client与真实server之间的一台代理服务,对于用户而言,proxy server就是真实的server服务器,用户获取的是proxy server的ip,而不是后端server的服务器ip。
过程:
例如:www.test.com就是上图的架构,我要访问www.test.com/test.html
1. client发起请求访问www.test.com/test.html,通过解析得到proxy server的ip,向proxy server发起http请求
2.proxy server收到client请求(假设proxy server没有缓存你的数据),发现本地没有缓存test.html,向后端server发起请求转发
3.后端server收到请求并且响应请求,将数据返回给proxy server
4.proxy server(假设做了缓存配置)返回响应给client,并且自己缓存一份。
注:在整个过程中,proxy server自己不生产数据,只缓存数据和转发请求,所以可以支持很高的并发,因为处理请求是消耗系统性能的,专业的事,给专业服务器去做即可。但是proxy server一定得有公网ip,支持http及https,后端server建议不要给公网ip,降低风险,就算有攻击也是代理在扛着。并且proxy server 及后端server 可以是一台,也可以是多台,主要看需求了。
2 实现反向代理功能需要的模块(是基于Nginx的反向代理)
有2个模块:ngx_stream_proxy_module 及 ngx_http_proxy_module 都是Nginx内置模块,不需要额外进行编译,下面介绍下一些需要用到的功能,详细的功能请参考官网(简单介绍一下)。
ngx_stream_proxy_module 用于定义可由proxy_pass、fastcgi_pass、uwsgi_pass、scgi_pass和memcached_pass指令引用部署服务器群,一般在负载均衡方面用的多。下面功能的话主要强调在代理这一方面,一般应用于server段:
官方链接:http://nginx.org/en/docs/stream/ngx_stream_proxy_module.html
例如:
server { listen 127.0.0.1:12345; proxy_pass 127.0.0.1:8080; }
ngx_http_proxy_module 也是提供代理功能的,提供允许将请求传递到另外一台服务,也就是请求转发。一般做代理是基本应用于此模块。一般应用于location段。
官方链接:http://nginx.org/en/docs/http/ngx_http_proxy_module.html
示例:
location / { proxy_pass http://localhost:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }
3 配置反向代理
当前架构:1台client 1台proxy server 1台后端server 注:默认是安装好了Nginx,申请了证书,关闭防火墙及关闭selinux。
3.1 配置后端主机(默认是已经安装好了Nginx服务的)
日志格式(查看下文日志的时候请参考我的日志格式,不然会看出问题的):
log_format jflog '$remote_addr | $remote_user | $time_local | $request | $status | '
'$bytes_sent | $body_bytes_sent | $host | $http_referer | $http_user_agent | '
'$upstream_addr | $scheme | $http_x_forwarded_for | $request_time | $upstream_response_time';
注:配置后端server,使你的后端服务器支持http及https
3.11 配置10.28.88.188 nginx 虚拟主机
#配置后端虚拟机主机
$ vim /usr/local/nginx/conf/vhost/test.conf
server {
listen 80;
listen 443 ssl; #你的域名得有https证书才能开启443端口,没有的话则不配置https
server_name www.test.com; #域名(选择你有证书的域名)
root /data/www/; #然后其他配置就是常规的https配置
index index.html index.php;
ssl_certificate /usr/local/nginx/conf/cert/www.test.com.crt;
ssl_certificate_key /usr/local/nginx/conf/cert/www.test.com.key;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
access_log /data/logs/www/test_ssl.log jflog;
}
#重新加载nginx
$ /usr/local/nginx/sbin/nginx -t
$ /usr/local/nginx/sbin/nginx -s reload
3.12 在 10.28.88.188 创建测试文件并测试
#编辑hosts,让当前主机可以识别你刚才配置的内容
$ vim /etc/hosts
127.0.0.1 www.test.com
#创建测试文件并且授权
$ vim /data/www/test.html
test
$ chown www.www /data/www/ -R
#测试
$ curl www.test.com/test.html
test
$ curl https://www.test.com/test.html
test
注:测试没有问题,那么当前后端既支持http也支持https.
3.2 配置proxy server,使其支持HTTP及HTTPS转发
3.21 在10.28.88.199配置代理文件
#创建proxy.conf文件(把代理相关选项,参数都放到这里面,好方面其他文件调用)
$ vim /usr/local/nginx/conf/proxy.conf
proxy_connect_timeout 300s;
proxy_send_timeout 900;
proxy_read_timeout 900;
proxy_buffer_size 32k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_redirect off;
proxy_hide_header Vary;
proxy_set_header Accept-Encoding '';
proxy_set_header Host $host;
proxy_set_header Referer $http_referer;
proxy_set_header Cookie $http_cookie;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_next_upstream http_500 http_502 http_503 http_504 error timeout invalid_header;
#proxy_next_upstream http_502 http_503 http_504 error timeout invalid_header;
proxy_intercept_errors on;
proxy_redirect default;
#proxy_hide_header "Cache-Control";
#proxy_hide_header "Set-Cookie";
#proxy_hide_header "Pragma";
#proxy_hide_header "X-Powered-By";
3.22 在10.28.88.199配置代理转发
#配置代理转发
$ vim /usr/local/nginx/conf/vhost/test.conf
upstream test.com {
#如果有多个后端则在这里定义多个server,可以通过权重,ip哈希等算法实现负载均衡。
server 10.28.88.106;
}
server {
listen 80;
listen 443;
server_name www.test.com;
include proxy.conf;
ssl_certificate /usr/local/nginx/conf/cert/www.test.com.crt;
ssl_certificate_key /usr/local/nginx/conf/cert/www.test.com.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
#这里就是实现代理的关键部分
location / {
inlcude proxy.conf; #如果你不想传太多的header信息,可在这通过set自定义header信息
proxy_pass http://test.com;
}
access_log /data/logs/www/test.ssl.log jflog;
}
#重新加载nginx
$ /usr/local/nginx/sbin/nginx -t
$ /usr/local/nginx/sbin/nginx -s reload
3.23 在10.28.88.199 进行测试
#绑host
$ vim /etc/hosts
127.0.0.1 www.test.com
#测试
$ ip a | grep inet | grep -v inet6 | grep -w enp0s3 | awk '{print $2}'
10.28.88.199/24
$ curl www.test.com/test.html
test
$ curl https://www.test.com/test.html
test
#查看日志
##在proxy server查看
$ ip a | grep inet | grep -v inet6 | grep -w enp0s3 | awk '{print $2}'
10.28.88.199/24
$ tail -2 /data/logs/www/test.com.ssl.log
127.0.0.1 | - | 10/Dec/2019:03:05:57 -0500 | GET /test.html HTTP/1.1 | 200 | 232 | 5 | www.test.com | - | curl/7.29.0 | 10.28.88.106:443 | http | - | 0.014 | 0.014
127.0.0.1 | - | 10/Dec/2019:03:06:11 -0500 | GET /test.html HTTP/1.1 | 200 | 232 | 5 | www.test.com | - | curl/7.29.0 | 10.28.88.106:443 | https | - | 0.003 | 0.004
注:此时,当前代理作为client总共发起2次请求,一次是http,一次是https,通过日志发现是通过10.28.88.106:443端口转发给后端server,完全符合我们的proxy_pass设置
##在后端server查看
$ ip a | grep inet | grep -v inet6 | grep -w enp0s3 | awk '{print $2}'
10.28.88.106/21
$ tail -2 /data/logs/www/test.com.ssl.log
10.28.88.199 | - | 10/Dec/2019:03:06:13 -0500 | GET /test.html HTTP/1.0 | 200 | 227 | 5 | www.test.com | - | curl/7.29.0 | - | https | 127.0.0.1 | 0.000 | -
10.28.88.199 | - | 10/Dec/2019:03:10:03 -0500 | GET /test.html HTTP/1.0 | 200 | 227 | 5 | www.test.com | - | curl/7.29.0 | - | https | 127.0.0.1 | 0.000 | -
注:当前机器为后端server,通过日志显示是由proxy server通过https协议发起了2次请求,并且返回响应
总结:当你proxy server设置proxy_pass指定以啥协议转发请求时,无论你请求的内容是https还是http,都会以固定的方式转发。
3.3 client 操作
#本机mac作为纯粹的client,只要做一个操作即可测试,那就绑定hosts
#绑hosts
ytsdeMacBook-Air:~$vim /etc/hosts
10.28.88.199 www.test.com
#测试
ytsdeMacBook-Air:~$curl www.test.com/test.html
test
ytsdeMacBook-Air:~$curl https://www.test.com/test.html
test
#查看日志:
#proxy server
$ tail -2 /data/logs/www/test.com.ssl.log
10.28.89.104 | - | 10/Dec/2019:03:30:52 -0500 | GET /test.html HTTP/1.1 | 200 | 232 | 5 | www.test.com | - | curl/7.54.0 | 10.28.88.106:443 | http | - | 0.006 | 0.007
10.28.89.104 | - | 10/Dec/2019:03:30:58 -0500 | GET /test.html HTTP/1.1 | 200 | 232 | 5 | www.test.com | - | curl/7.54.0 | 10.28.88.106:443 | https | - | 0.003 | 0.003
注:客户ip 为10.28.89.104 是我mac的ip,后端服务器地址为10.28.88.106 也没有任何问题
远程客户ip是由$remote_addr获取
后端服务器地址是由$upstream_addr获取
#后端server
$ tail -2 /data/logs/www/test.com.ssl.log
10.28.88.199 | - | 10/Dec/2019:03:30:53 -0500 | GET /test.html HTTP/1.0 | 200 | 227 | 5 | www.test.com | - | curl/7.54.0 | - | https | 10.28.89.104 | 0.000 | -
10.28.88.199 | - | 10/Dec/2019:03:31:00 -0500 | GET /test.html HTTP/1.0 | 200 | 227 | 5 | www.test.com | - | curl/7.54.0 | - | https | 10.28.89.104 | 0.000 | -
注:客户ip 为10.28.88.199, 获取客户端真实ip 10.28.89.104 是我的mac ip 没有任何问题
客户ip是由$remote_addr获取
客户真实ip是由$http_x_forwarded_for获取
总结:根据客户端测试的结果完全符合我们的预期,至于ip获取不同,请看我的日志格式
4.相关配置文件及参数介绍
4.1 日志格式
日志格式请参考我的另一章节专门关于日志的介绍:https://blog.csdn.net/yts1115084429/article/details/102327761
4.2 proxy.conf
$ vim /usr/local/nginx/conf/proxy.conf
#设置proxy server与后端的连接超时时间
proxy_connect_timeout 300s; #设置跟后端连接的超时时间
proxy_send_timeout 900; #设置跟后端进行请求传输的超时时间,仅用于2次连续写操作
proxy_read_timeout 900 #设置跟后端进行响应读取的超时时间,仅用于2次连续读操作
#设置缓冲功能
proxy_buffer_size 32k; #设置单个缓冲区大小
proxy_buffers 4 32k; #最多用几个缓冲区快及缓冲区来处理单一请求
proxy_busy_buffers_size 64k; #设置最大单个缓冲区大下 (用于请求繁忙时)
proxy_buffering on
#设置代理缓存功能(源配置文件没有的,可以加可以不加)
proxy_cache cache-v; #定义名字缓存系统
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=one:10m;
proxy_cache_valid 200 304 10m; #将http code为200,304缓存10天
proxy_cache_key $uri; #指定缓存唯一key,缓存通过此keyJinxhash存取
#proxy_set_header 主要用于设置proxy server要传递的header信息
proxy_set_header Accept-Encoding ' '; #字段值为 ' ' 代表此header信息将不会被proxy server传递出去
proxy_set_header Host $host; #
proxy_set_header Referer $http_referer;
proxy_set_header Cookie $http_cookie;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#其它设置
proxy_redirect off; #主要用于内容替换,类似于rewrite
proxy_hide_header Vary; #隐藏vary头部信息
proxy_next_upstream http_500 http_502 http_503 http_504 error timeout invalid_header; #当出现这些错误时,会将请求自动发给下一个服务器,可以提升容错率。
proxy_intercept_errors on; ; #获得后端服务器响应后,可以根据响应状态码的值进行拦截错误处理,与error_page 指令相互结合。用在访问上游服务器出现错误的情况下。
4.3 proxy server的test.conf
$ vim /usr/local/nginx/conf/vhost/test.conf server { listen 80; listen 443; server_name www.test.com; #这个文件就是单独写的存放代理参数的文件,你可以放在server,也可以放在location中 include proxy.conf; #这样写的话,你的文件得放在conf目录下 #ssl证书配置 ssl_certificate /usr/local/nginx/conf/cert/www.test.com.crt; ssl_certificate_key /usr/local/nginx/conf/cert/www.test.com.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"; #代理转发 location / { proxy_pass https://10.28.88.106; } #日志,建议加上,方便查看 access_log /data/logs/www/test.ssl.log jflog; }
注:上面proxy server虚拟机主机的配置是不是跟后端server的test.conf配置文件很像,但是还是有点区别滴。
证书:证书看起来不是一模一样么,的确是一模一样,但是与后端的证书的没有任何关系,你可以把它看成一个单独的证书配置,当前ssl配置只对当前虚拟主机负责,相当于重新配置了一个https。
当用户发起https请求,是请求到proxy server,不是请求到后端,如果你的proxy server不支持https,则无法响应用户https请求,对于后端而言,你的proxy server就是client,只需要响应proxy server的请求即可。
根据上诉所说,后端配不配制https都无所谓了,大致意思是这样的,但是在生产环境,能配置https就配置https,从安全系数方面来说,对信息进行加密,提升安全等级,万一哪天你的内网被入侵了,最关键是不需要加成本,何乐而不为了。
location模块:在后端server的location是具体定义某个处理请求功能,然而这里的location就只提供请求转发的功能。
proxy.conf在后端是不需要添加的,但是这里必须添加,因为那些参数只对当前代理生效。
proxy_pass,提供转发功能,支持http及https,proxy server获取的数据都是通过此模块提供的,获取原始数据。
有proxy server,返回给用户数据的协议类型是取决于proxy server支持协议类型而不是后端server支持类型,反向代理支持https,那么就可以响应client https请求。
简单流程:client请求数据—>proxy server返回用户响应<—后端 server提供数据。
至于后端server的配置就不讲述了,配置过Nginx的基本都看的明白
如果想对反代了解更深入,那就得去看各个指令的具体用法及适用场景,也比较复杂,大家可以找博文或者去官网进行查看。