零、文章目录
Nginx08-反向代理
1、概述
-
关于正向代理和反向代理,我们在前面已经介绍过了,简而言之就是正向代理代理的对象是客户端,反向代理代理的是服务端,这是两者之间最大的区别。
-
Nginx即可以实现正向代理,也可以实现反向代理。
2、正向代理
(1)需求
- 客户端服务器192.168.119.1使用服务器192.168.119.162做正向代理访问服务器192.168.119.161
(2)服务器设置
- 192.168.119.161:被访问服务器nginx设置如下
http {
log_format main 'client send request=>clientIp=$remote_addr serverIp=$host';
server{
listen 80;
server_name localhost;
access_log logs/access.log main;
location / {
root html;
index index.html index.htm;
}
}
}
- 192.168.119.162:作为正向代理服务器nginx配置如下
server {
listen 82;
resolver 8.8.8.8; # 设置 DNS 的 IP,用来解析 proxy_pass 中的域名
location / {
proxy_pass http://$host$request_uri; # proxy_pass 实现正向代理
}
}
(3)客户端设置
- 192.168.119.1:在客户端配置代理服务器,控制面板->Internet选项->连接->局域网设置->勾选为LAN使用代理服务器(这些设置不用于拨号或VPN连接)
(4)客户端访问
- 192.168.119.1:客户端访问代理服务器192.168.119.162,代理服务器会实现代理访问最终服务器192.168.119.161打印出日志如下
client send request=>clientIp=192.168.119.162 serverIp=192.168.119.161
3、反向代理
(1)概述
-
Nginx 反向代理模块的指令是由
ngx_http_proxy_module
模块进行解析,该模块在安装 Nginx 的时候已经自动加载到 Nginx 中了,接下来我们把反向代理中的常用指令如下:-
proxy_pass:配置代理的服务器地址
-
proxy_set_header:转发给被代理服务器时,设置一些请求头信息
-
proxy_redirect:防止客户端可以看到被代理服务器的地址
-
-
这里只介绍三个指令,关于反向代理的指令非常多,想要了解更多,请前往 Nginx 反向代理文档
(2)proxy_pass
- 该指令用来设置被代理服务器地址,可以是主机名称、IP 地址加端口号形式,没有默认值。
- URL:为要设置的被代理服务器地址,包含传输协议(
http
,https://
)、主机名称或IP地址加端口号、URI等要素。
- URL:为要设置的被代理服务器地址,包含传输协议(
语法 | proxy_pass URL; |
---|---|
默认值 | — |
位置 | location |
- 在服务器192.168.119.161配置nginx
http {
# ......
server {
listen 8080;
server_name localhost;
location / {
proxy_pass http://192.168.119.162;
}
}
# ......
}
- 客户端请求192.168.119.161的时候他会转发到192.168.119.162,服务器192.168.119.161就是代理服务器。
- 问题:在编写 proxy_pass 的时候,后面的值要不要加 /?
server {
listen 80;
server_name localhost;
location / {
# 下面两个地址加不加斜杠,效果都一样,因为 location 后的 / 会添加在代理地址后面
proxy_pass http://192.168.119.161;
proxy_pass http://192.168.119.161/;
}
}
server{
listen 80;
server_name localhost;
location /server {
# 下面两个地址必须加斜杠,因为 location 后的 /server 会添加在代理地址后面,第一个将没有 / 结尾
#proxy_pass http://192.168.119.161;
proxy_pass http://192.168.119.161/;
}
}
# 上面的 location:当客户端访问 http://localhost/server/index.html
# 第一个 proxy_pass 就变成了 http://localhost/server/index.html
# 第二个 proxy_pass 就变成了 http://localhost/index.html 效果就不一样了。
(3)proxy_set_header
- 该指令可以更改 Nginx 服务器接收到的客户端请求的请求头信息,然后将新的请求头发送给代理的服务器。默认值是发送代理服务器的地址和 close。
语法 | proxy_set_header field value; |
---|---|
默认值 | proxy_set_header Host $proxy_host; proxy_set_header Connection close; |
位置 | http、server、location |
- 访问过程:客户端访问代理服务器192.168.119.161,代理服务器对header进行处理转发给被代理服务器192.168.119.162
- 代理服务器192.168.119.161的nginx配置如下
server {
listen 8080;
server_name localhost;
location /server { # 访问 /server 触发代理
proxy_pass http://192.168.119.162:8080/; # 配置被代理服务器的地址
proxy_set_header username TOM; # 发送 key 为 username,value 为 TOM 的请求头给服务器 B
}
}
- 被代理服务器192.168.119.162的nginx配置如下
server {
listen 8080;
server_name localhost;
default_type text/plain;
return 200 $http_username; # 获取代理服务器发送过来的 http 请求头的 username 值
}
- 客户端访问代理服务器,代理服务器在头信息加上了TOM,到服务器再返回给客户端。
(4)proxy_redirect
- 该指令是用来重置头信息中的"Location"和"Refresh"的值。防止客户端可以看到被代理服务器的地址。
- proxy_redirect redirect replacement:redirect(目标,被替换的地址)replacement(替换的地址)
- proxy_redirect default:将location块的uri变量作为replacement,将proxy_pass变量作为redirect进行替换
- proxy_redirect off:关闭proxy_redirect的功能
语法 | proxy_redirect redirect replacement; proxy_redirect default; proxy_redirect off; |
---|---|
默认值 | proxy_redirect default; |
位置 | http、server、location |
-
为什么要用该指令?
- 客户端通过 代理服务器A 找 服务器B 不存在的资源,B 不想返回报错页面,于是重定向到自己的欢迎页面地址并返回给 A,A 收到了页面和地址直接返回给客户端,浏览器返回的是服务器B的地址,这是重定向造成的。
- 但是作为代理服务器A是用来封装隐藏服务器B的,不应该暴露服务器B 的地址,此时用到
proxy_redirect
指令,代理服务器A重置服务器 B 返回过来的『 Location 』和『 Refresh 』值,将两个值改为代理服务器 A 的某个地址,因为改为了代理服务器 A 的某个地址,所以代理服务器 A 根据这个地址又去获取理服务器 B 的欢迎页面地址,返回给客户端。
-
代理服务器A 192.168.119.161的nginx配置如下
server {
listen 8081;
server_name localhost;
location / {
proxy_pass http://192.168.119.162:8081/; # 1.转发给服务器 B
proxy_redirect http://192.168.119.162 http://192.168.119.161; # 3.修改服务器 B 的地址为代理服务器A地址
}
}
# 该 server 去请求服务器 B 的欢迎页面
server {
listen 80;
server_name 192.168.119.161;
location / {
proxy_pass http://192.168.119.162; # 4.重新发送请求给服务器 B获取欢迎页面
}
}
- 被代理服务器B 192.168.119.162的nginx配置如下
server {
listen 8081;
server_name localhost;
if (!-f $request_filename){
return 302 http://192.168.119.162;# 2.如果请求的资源不存在,则重定向到服务器 B 欢迎页
}
}
(5)实战
- 需求如下:服务器内容不一致
- 代理服务器192.168.119.161的nginx配置如下
# 代理服务器
server {
listen 8082;
server_name localhost;
location /server1 {
proxy_pass http://192.168.119.162:9001/; # 代理 server1
}
location /server2 {
proxy_pass http://192.168.119.162:9002/; # 代理 server2
}
location /server3 {
proxy_pass http://192.168.119.162:9003/; # 代理 server3
}
}
- 服务器配置:我们这里用端口号来区分,正常会使用不同IP不同服务器,如下nginx配置文件正常是三个
# 服务器
# server1
server {
listen 9001;
server_name localhost;
default_type text/html;
return 200 '<h1>192.168.119.162:9001</h1>'
}
# server2
server {
listen 9002;
server_name localhost;
default_type text/html;
return 200 '<h1>192.168.119.162:9002</h1>'
}
# server3
server {
listen 9003;
server_name localhost;
default_type text/html;
return 200 '<h1>192.168.119.162:9003</h1>'
}
- 访问验证
- 客户端访问:http://192.168.119.161:8082/server1 最终返回:192.168.119.162:9001
- 客户端访问:http://192.168.119.161:8082/server2 最终返回:192.168.119.162:9002
- 客户端访问:http://192.168.119.161:8082/server3 最终返回:192.168.119.162:9003
4、反向代理安全控制
- 问题:Nginx 反向代理是如何来提升 Web 服务器的安全呢?
- 答案
- 安全隔离
- 使用SSL对流量进行加密
(1)安全隔离是什么
- 通过代理分开了客户端到应用程序服务器端的连接,实现了安全措施。在反向代理之前设置防火墙,仅留一个入口供代理服务器访问。
(2)使用SSL对流量进行加密
-
相关SSL知识请参考http详解安全章节
-
SSL对流量进行加密:将我们常用的http请求转变成https请求,那么这两个之间的区别简单的来说就是https是身披SSL外壳的http。
-
HTTPS:是一种通过计算机网络进行安全通信的传输协议。它经由HTTP进行通信,利用SSL/TLS建立全通信,加密数据包,确保数据的安全性。
- SSL(Secure Sockets Layer)安全套接层
- TLS(Transport Layer Security)传输层安全
- TLS和SSL在传输层和应用层对网络连接进行加密
- http协议是明文传输数据,存在安全问题,而https是加密传输,相当于http+ssl,并且可以防止流量劫持。
-
Nginx使用SSL:需要添加一个模块
--with-http_ssl_module
,而该模块在编译的过程中又需要OpenSSL的支持,这个我们之前已经准备好了。
(3)Nginx添加SSL支持
- 查看 configure arguments 的配置信息,拷贝出来
[root@localhost sbin]# nginx -V
nginx version: nginx/1.26.2
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
configure arguments: --prefix=/usr/local/nginx
- 将原有
/usr/local/nginx/sbin/nginx
进行备份
cd /usr/local/nginx/sbin
mv nginx nginx.backup
- 进入 Nginx 的安装目录,执行 make clean 清空之前编译的内容
cd /opt/nginx/core/nginx-1.26.2
make clean
- 使用 configure 来配置参数,添加
ngx_http_ssl_module
模块,记得加上第(2)步拷贝的配置信息
./configure --with-http_ssl_module --prefix=/usr/local/nginx # 记得添加 configure arguments 后的数据
- 通过 make 模板进行编译
make
- 将 objs 下面的 nginx 可执行文件移动到
/usr/local/nginx/sbin
下
mv /opt/nginx/core/nginx-1.26.2/objs/nginx /usr/local/nginx/sbin
- 在源码目录(安装包目录)下执行
make upgrade
进行升级,这个可以实现不停机添加新模块的功能
cd /opt/nginx/core/nginx-1.26.2
make upgrade
(4)Nginx中SSL相关指令
-
该模块的指令都是通过
ngx_http_ssl_module
模块来解析的,我们上一步已经添加了。 -
这里只介绍常用的几个指令,了解更多指令请前往 ngx_http_ssl_module 模块文档 。
-
**ssl:**用来在指定的服务器开启 HTTPS,默认关闭。可以使用 listen 443 ssl,这种方式更通用些。
语法 | ssl on | off; |
---|---|
默认值 | ssl off; |
位置 | http、server |
server{
listen 443 ssl;
}
# ssl 默认监听的是 443 端口,所以和 ssl on 效果一致,因为能突出 sll 的监听端口,所以建议使用它。
- ssl_certificate: 指令是为当前这个虚拟主机指定一个带有 PEM 格式证书的证书。
语法 | ssl_certificate file; |
---|---|
默认值 | — |
位置 | http、server |
- **ssl_certificate_key:**该指令用来指定PEM secret key文件的路径。
语法 | ssl_ceritificate_key file; |
---|---|
默认值 | — |
位置 | http、server |
- **ssl_session_cache:**该指令用来配置用于SSL会话的缓存。
- off:禁用会话缓存,客户端不得重复使用会话。
- none:禁止使用会话缓存,客户端可以重复使用,但是并没有在缓存中存储会话参数。
- builtin:内置OpenSSL缓存,仅在一个工作进程中使用。
- shared:所有工作进程之间共享缓存,缓存的相关信息用name和size来指定。同 name 的缓存可用于多个虚拟服务器,name 是允许缓存的数据名,size 是允许缓存的数据大小,以字节为单位。
语法 | ssl_sesion_cache off|none|[builtin[:size]] [shared:name:size] |
---|---|
默认值 | ssl_session_cache none; |
位置 | http、server |
ssl_session_cache builtin:1000 shared:SSL:10m;
# 10m 的 m 是兆。
- **ssl_session_timeout:**开启SSL会话功能后,设置客户端能够反复使用储存在缓存中的会话参数时间。
语法 | ssl_session_timeout time; |
---|---|
默认值 | ssl_session_timeout 5m; |
位置 | http、server |
- **ssl_ciphers:**指出允许的密码,密码指定为OpenSSL支持的格式。
- 可以直接在 Linux 系统上使用
openssl ciphers
查看 OpenSSl 支持的格式。
- 可以直接在 Linux 系统上使用
语法 | ssl_ciphers ciphers; |
---|---|
默认值 | ssl_ciphers HIGH:!aNULL:!MD5; |
位置 | http、server |
- **ssl_prefer_server_ciphers:**该指令指定是否服务器密码优先客户端密码,默认关闭,建议开启。
语法 | ssl_perfer_server_ciphers on|off; |
---|---|
默认值 | ssl_perfer_server_ciphers off; |
位置 | http、server |
(5)SSL证书生成方式1-使用阿里云购买
- 登录阿里云,搜索SSL
- 进入SSL控制台,点击购买证书
- 选择免费证书购买
- 进入证书控制台,对购买的证书进行申请,申请证书需要购买域名进行证书的绑定,否则证书无法使用。
- 证书会变成待验证状态,然后变成待审批,审批完成就是已签发状态,就能下载证书了。
- 下载下来的证书就是一个压缩包,里面是两个文件,一个是key,一个是pem
(6)SSL证书生成方式2-使用openssl生成证书
- 先要确认当前系统是否有安装openssl
openssl version
- 生成证书
# 创建 /root/cerr 目录并进入
mkdir /root/cert
cd /root/cert
# 指定加密算法和加密方式,生成 server.key
openssl genrsa -des3 -out server.key 1024
# 根据你注册的 server.key 密码,生成 server.csr 文件,生成后它会让你注册你的基本信息,因为是个人的,所以信息随便填写
openssl req -new -key server.key -out server.csr
# 备份 server.key
cp server.key server.key.org
# 重新生成 server.key 文件,并输入刚才注册的密码
openssl rsa -in server.key.org -out server.key
# 生成 server.crt 文件
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
- 查看生成的证书
[root@localhost cert]# ll
总用量 16
-rw-r--r-- 1 root root 887 10月 5 17:11 server.crt
-rw-r--r-- 1 root root 725 10月 5 17:10 server.csr
-rw-r--r-- 1 root root 887 10月 5 17:11 server.key
-rw-r--r-- 1 root root 963 10月 5 17:11 server.key.org
(7)SSL配置案例
- 在nginx配置文件中添加https的配置
server {
listen 80;
# ......
}
server {
listen 443 ssl; # 开启 SSL 功能
server_name localhost; # 如果是购买的域名,这里加上该域名
ssl_certificate /root/cert/server.cert; # 生成的 cert 或者 pem 证书路径,根据需求修改
ssl_certificate_key /root/cert/server.key; # 生成的 key 证书路径,根据需求修改
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5; # 表示使用的加密套件的类型
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; # 表示使用的TLS协议的类型
ssl_prefer_server_ciphers on;
location / {
root html;
index index.html index.htm;
}
}
- 我们希望在直接访问域名的时候,自动加上前缀https而不是http,需要配置rewrite实现,在http的server进行如下配置
server {
listen 443 ssl;
server_name www.baidu.com; # 如果是 www.baidu.com 发送请求
location / {
# ......
rewrite ^(.*)$ https://www.baidu.com$1; # 则改为 https 方式
# ......
}
# ......
}
5、反向代理系统调优
(1)概述
-
反向代理优化有两种方式
- Buffer翻译过来是"缓冲"。
- Cache翻译过来是"缓存"。
-
缓存过程:客户端通过代理服务器向被代理服务器获取数据后,代理服务器在获取的数据存储在缓存「瓶子」里,客户端再次获取相同资源时,直接从缓存「瓶子」里获取数据,不需要向被代理服务器获取数据,减轻压力。
- 缓存和缓冲的异同
- 相同点:
- 两种方式都是用来提供IO吞吐效率,都是用来提升Nginx代理的性能。
- 不同点:
- 缓冲主要用来解决不同设备之间数据传递速度不一致导致的性能低的问题,缓冲中的数据一旦此次操作完成后,就可以删除
- 缓存主要是备份,将被代理服务器的数据缓存一份到代理服务器,这样的话,客户端再次获取相同数据的时候,就只需要从代理服务器上获取,效率较高,缓存中的数据可以重复使用,只有满足特定条件才会删除
- 相同点:
(2)Proxy Buffer 相关指令
- **proxy_buffering:**该指令用来开启或者关闭代理服务器的缓冲区。
语法 | proxy_buffering on|off; |
---|---|
默认值 | proxy_buffering on; |
位置 | http、server、location |
- **proxy_buffers:**该指令用来指定单个连接从代理服务器读取响应的缓存区的个数和大小。
- number:缓冲区的个数
- size:每个缓冲区的大小,缓冲区的总大小就是number*size
语法 | proxy_buffers number size; |
---|---|
默认值 | proxy_buffers 8 4k | 8K;(与系统平台有关) |
位置 | http、server、location |
- **proxy_buffer_size:**该指令用来设置从被代理服务器获取的第一部分响应数据的大小。保持与proxy_buffers中的size一致即可,当然也可以更小。
语法 | proxy_buffer_size size; |
---|---|
默认值 | proxy_buffer_size 4k | 8k;(与系统平台有关) |
位置 | http、server、location |
- **proxy_busy_buffers_size:**该指令用来限制同时处于BUSY状态的缓冲总大小。
语法 | proxy_busy_buffers_size size; |
---|---|
默认值 | proxy_busy_buffers_size 8k|16K; |
位置 | http、server、location |
- **proxy_temp_path:**当缓冲区存满后,仍未被Nginx服务器完全接受,响应数据就会被临时存放在磁盘文件上,该指令设置文件路径。注意 path 最多设置三层。
语法 | proxy_temp_path path; |
---|---|
默认值 | proxy_temp_path proxy_temp; |
位置 | http、server、location |
- **proxy_temp_file_write_size:**该指令用来设置磁盘上缓冲文件的大小。
语法 | proxy_temp_file_write_size size; |
---|---|
默认值 | proxy_temp_file_write_size 8K|16K; |
位置 | http、server、location |
(3)优化配置参考模板
proxy_buffering on;
proxy_buffers 4 64k;
proxy_buffer_size 64k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;