Nginx反向代理详解(附带完整配置实例)
Igor Vladimirovich Sysoev 在刚开始设计 Nginx 时,对它的定位是轻量级、高性能的 Web 服务和反向代理服务,本节我们学习反向代理。
在没有代理的情况下,客户端和服务端之间的通信如下图所示:

图 1 客户端和服务端正常通信过程
代理是什么?其实很好理解,房屋中介就是我们生活中最常见的代理。房屋中介通过在房源和租客之间建立联系,帮助租客找到合适的房子,如下图所示:

图 2 常见的代理——房屋中介
Nginx 代理的作用就是代替客户端或服务端处理请求,如下图所示:

图 3 Nginx代理
若按照企业应用场景来划分,Nginx 代理还可以分为正向代理和反向代理。
由下图可见,在整个企业内部的服务架构中,Nginx 反向代理服务器将代替服务端接收客户端的请求,当反向代理服务器接收到客户端的请求后,会将请求转发给服务端,服务端将请求处理完毕之后会将结果再转交给反向代理服务器,这时反向代理服务器就会把响应的数据发送给客户端。

图 4 Nginx反向代理
反向代理的主要作用就是接收客户端发送过来的请求并转发给服务端,获得服务端响应数据后返回给客户端。从用户的角度看,公司的核心服务器仿佛就是反向代理服务器,但事实上它只是一个中转站而已。
现在很多大型的网站都在使用反向代理技术,主要归因于它具备 3 个优点:
搭建 Nginx 反向代理服务器的过程非常简单,不需要新增额外的模块,Nginx 默认自带 proxy_pass 指令,只需要修改配置文件就可以实现反向代理。
如果请求不是发往 http 类型的被代理服务器,还可以选择以下几种模块:
反向代理是在 Nginx 配置文件中的 location 配置项中配置的,下面演示一种最简单的:
在 Nginx 配置文件中配置反向代理时,除了指定被代理服务器的地址,还会有几个附加的配置项,这些配置项会起到辅助和微调的作用:
除了这几项之外,还有一个常用的模块 proxy_set_header,此模块的主要作用就是允许重新定义或者添加发往后端服务器的请求头信息。
例如,在 location 配置项中添加以上辅助配置:
除此之外,在 Nginx 配置文件中,还有一块被注释的区域是用来反向代理 PHP 服务的。
Nginx 在配置 Fastcgi 解析 PHP 时会调用 fastcgi_params 配置文件来传递一些变量,默认的一些变量对应关系如下。

图 5 Nginx反向代理案例的架构
在后端服务器上搭建一个简单的网站,通过 Nginx 反向代理这台后端服务器,Nginx 反向代理服务器中只搭建了 Nginx 服务并配置了反向代理,本身并不存放网站相关的任何资源。最后的结果是用户访问代理服务器,得到的却是后端服务器上的网站。
1) 在后端服务器上搭建一个简单的网站——虚拟机二(192.168.1.130)。建议用 DNF 部署 Nginx 服务,在 Nginx 服务上放一个网站,最后验证 Nignx 服务能否正常启动,如下图所示。安装 Nginx 服务的过程在上文已经演示过了,这里就不再赘述。

图 6 验证Nignx服务能否正常启动
2) 在虚拟机一(192.168.1.128)中部署 Nginx 服务并配置反向代理。
3) 用机器本身充当用户,直接访问 Nginx 反向代理服务器,如下图所示。因为原则上我们并不知道后端服务器的存在。

图 7 访问Nginx反向代理服务器
4) 再到虚拟机二(192.168.1.130),也就是后端服务器上查看Nginx访问日志,容易发现,虚拟机一(192.168.1.128),也就是反向代理服务器来访问过。
5) 大家有没有发现,日志中记录的是 Nginx 反向代理服务器的 IP 地址,而不是客户端的 IP 地址,那如何让后端服务器直接记录客户端的 IP 地址呢?这就需要用到上文介绍的几个辅助配置项。
6) 再用机器本身假装用户访问 Nginx 反向代理服务器,这时看后端服务器上的 Nginx 访问日志,日志中记录了客户端的真实 IP 地址。
在没有代理的情况下,客户端和服务端之间的通信如下图所示:

图 1 客户端和服务端正常通信过程
代理是什么?其实很好理解,房屋中介就是我们生活中最常见的代理。房屋中介通过在房源和租客之间建立联系,帮助租客找到合适的房子,如下图所示:

图 2 常见的代理——房屋中介
Nginx 代理的作用就是代替客户端或服务端处理请求,如下图所示:

图 3 Nginx代理
若按照企业应用场景来划分,Nginx 代理还可以分为正向代理和反向代理。
由下图可见,在整个企业内部的服务架构中,Nginx 反向代理服务器将代替服务端接收客户端的请求,当反向代理服务器接收到客户端的请求后,会将请求转发给服务端,服务端将请求处理完毕之后会将结果再转交给反向代理服务器,这时反向代理服务器就会把响应的数据发送给客户端。

图 4 Nginx反向代理
反向代理的主要作用就是接收客户端发送过来的请求并转发给服务端,获得服务端响应数据后返回给客户端。从用户的角度看,公司的核心服务器仿佛就是反向代理服务器,但事实上它只是一个中转站而已。
现在很多大型的网站都在使用反向代理技术,主要归因于它具备 3 个优点:
- 隐藏公司核心服务器(服务端)的网络位置,保护服务端免受黑客攻击;
- 配合location配置项,减缓服务端处理数据的压力;
- 实现负载均衡,将客户端的请求分配给多台服务器处理。
搭建 Nginx 反向代理服务器的过程非常简单,不需要新增额外的模块,Nginx 默认自带 proxy_pass 指令,只需要修改配置文件就可以实现反向代理。
如果请求不是发往 http 类型的被代理服务器,还可以选择以下几种模块:
- fastcgi_pass:传递请求给 FastCGI 接口类型的服务器,常用于代理 PHP 服务的请求;
- uwsgi_pass:传递请求给 uwsgi 接口类型的服务器;
- scgi_pass:传递请求给 SCGI 接口类型的服务器;
- memcached_pass:传递请求给 memcached 服务器。
反向代理是在 Nginx 配置文件中的 location 配置项中配置的,下面演示一种最简单的:
location / { proxy_pass https://c.biancheng.net }在 location 配置项中使用 proxy_pass 关键字来指定被代理服务器的地址,proxy_pass 关键字后面的被代理服务器(后端服务器)的地址可以用域名、域名+端口、IP、IP+端口这几种方式表示。
在 Nginx 配置文件中配置反向代理时,除了指定被代理服务器的地址,还会有几个附加的配置项,这些配置项会起到辅助和微调的作用:
proxy_connect_timeout 60 s;
Nginx 代理连接后端服务的超时时间(代理连接超时),默认时间是 60 s。proxy_read_timeout 60 s;
Nginx 代理等待后端服务器处理请求的时间,默认时间是 60 s。proxy_send_timeout 60 s;
后端服务器响应数据回传给 Nginx 代理时的超时时间,规定在 60 s 之内后端服务器必须传完所有的响应数据,时间可以自定义。除了这几项之外,还有一个常用的模块 proxy_set_header,此模块的主要作用就是允许重新定义或者添加发往后端服务器的请求头信息。
proxy_set_header Host$proxy_host;
默认值。proxy_set_header X-Real-IP$remote_addr;
将 $remote_addr 的值放到变量 X-Real-IP 中,$remote_addr 的值是客户端的 IP 地址。经过反向代理后,由于在客户端和后端服务器之间增加了中间层(反向代理),后端服务器无法直接获得客户端的 IP 地址,只能通过 $remote_addr 变量获得反向代理服务器的IP地址,通过这个赋值操作就能让后端服务器获得客户端的 IP 地址。proxy_set_header X-Forwarded-For$proxy_add_x_forwarded_for;
一种让后端服务器直接获得客户端 IP 地址的方法。例如,在 location 配置项中添加以上辅助配置:
location / { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_connect_timeout 60s; proxy_read_timeout 60s; proxy_send_timeout 60s; proxy_pass https://c.biancheng.net }
除此之外,在 Nginx 配置文件中,还有一块被注释的区域是用来反向代理 PHP 服务的。
#location ~ \.php$ { -->所有关于 PHP 的请求符合这个 location 配置项中的匹配规则 # root html; -->网站根目录的位置 # fastcgi_pass 127.0.0.1:9000; -->fastcgi_pass 表示反向代理的是 FastCGI 接口类型的请求,也就是 PHP 服务器的地址 -->因为要把 PHP 的请求发送到 PHP 服务器上,让 PHP 服务来处理 -->Nginx 本身是处理不了 PHP 这种动态请求的,PHP 服务将请求处理完后会把结果返回给 Nginx # fastcgi_index index.php; -->默认打开的 PHP 页面,也就是输入网址后默认看到的页面 # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; -->设置 fastcgi 请求中的参数 # include fastcgi_params; -->附加配置 #}
Nginx 在配置 Fastcgi 解析 PHP 时会调用 fastcgi_params 配置文件来传递一些变量,默认的一些变量对应关系如下。
# 参数设定 #传递为 PHP 变量名 #Nginx 自有变量,可自定义 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;#脚本文件请求的路径 fastcgi_param QUERY_STRING $query_string; #请求的参数,如?app=123 fastcgi_param REQUEST_METHOD $request_method; #请求的动作(GET, POST) fastcgi_param CONTENT_TYPE $content_type; #请求头中的 Content-Type 字段 fastcgi_param CONTENT_LENGTH $content_length; #请求头中的 Content-length 字段 fastcgi_param SCRIPT_NAME $fastcgi_script_name; #脚本名称 fastcgi_param REQUEST_URI $request_uri; #请求的地址不带参数 fastcgi_param DOCUMENT_URI $document_uri; #与$uri 相同 fastcgi_param DOCUMENT_ROOT $document_root; #网站的根目录。在 server 配置中 root 指令指定的值 fastcgi_param SERVER_PROTOCOL $server_protocol; #请求使用的协议,通常是 HTTP/1.0 或 HTTP/1.1。 fastcgi_param GATEWAY_INTERFACE CGI/1.1; #cgi 版本 fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; #Nginx 版本号,可修改、隐藏 fastcgi_param REMOTE_ADDR $remote_addr; #客户端 IP 地址 fastcgi_param REMOTE_PORT $remote_port; #客户端端口 fastcgi_param SERVER_ADDR $server_addr; #服务器 IP 地址 fastcgi_param SERVER_PORT $server_port; #服务器端口 fastcgi_param SERVER_NAME $server_name; #服务器名,域名在 server 配置中指定 server_name #fastcgi_param PATH_INFO $path_info; #可自定义变量 # PHP only, required if PHP was built with --enable-force-cgi-redirect #fastcgi_param REDIRECT_STATUS 200;
案例演示
演示简单的 Nginx 反向代理,案例架构如下图所示:
图 5 Nginx反向代理案例的架构
在后端服务器上搭建一个简单的网站,通过 Nginx 反向代理这台后端服务器,Nginx 反向代理服务器中只搭建了 Nginx 服务并配置了反向代理,本身并不存放网站相关的任何资源。最后的结果是用户访问代理服务器,得到的却是后端服务器上的网站。
1) 在后端服务器上搭建一个简单的网站——虚拟机二(192.168.1.130)。建议用 DNF 部署 Nginx 服务,在 Nginx 服务上放一个网站,最后验证 Nignx 服务能否正常启动,如下图所示。安装 Nginx 服务的过程在上文已经演示过了,这里就不再赘述。
-----省略部分内容----- [root@bogon html]# cd /usr/share/nginx/html [root@bogon html]# pwd /usr/share/nginx/html [root@bogon html]# vim index.html #将原先的 Nginx 欢迎界面改成自己的网站页面 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>这是一个非常简单的网站!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>这是一个非常简单的网站!</h1> <p><em>简单到让人惊叹不已!</em></p> </body> </html> [root@bogon html]# systemctl start nginx #启动 Nginx 服务 [root@localhost html]# systemctl stop firewalld #别忘了关掉防火墙

图 6 验证Nignx服务能否正常启动
2) 在虚拟机一(192.168.1.128)中部署 Nginx 服务并配置反向代理。
-----省略编译安装 Nginx 服务步骤----- [root@linux nginx]# vim conf/nginx.conf worker_processes 1; user nginx; pid logs/nginx.pid; 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 / { #反向代理,将用户请求反向代理到后端服务器 proxy_pass http://192.168.1.130; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } } [root@linux nginx]# ./sbin/nginx -c conf/nginx.conf #启动 Nginx 服务
3) 用机器本身充当用户,直接访问 Nginx 反向代理服务器,如下图所示。因为原则上我们并不知道后端服务器的存在。

图 7 访问Nginx反向代理服务器
4) 再到虚拟机二(192.168.1.130),也就是后端服务器上查看Nginx访问日志,容易发现,虚拟机一(192.168.1.128),也就是反向代理服务器来访问过。
[root@linux html]# cat /var/log/nginx/access.log 192.168.1.1 - - [18/Dec/2021:23:06:30 +0800] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36" "-" 192.168.1.128 - - [18/Dec/2021:23:19:16 +0800] "GET / HTTP/1.0" 200 353 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36" "-" 192.168.1.128 - - [18/Dec/2021:23:19:16 +0800] "GET /favicon.ico HTTP/1.0" 404 555 "http://192.168.1.128/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36" "-" 192.168.1.128 - - [18/Dec/2021:23:19:18 +0800] "GET / HTTP/1.0" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36" "-"
5) 大家有没有发现,日志中记录的是 Nginx 反向代理服务器的 IP 地址,而不是客户端的 IP 地址,那如何让后端服务器直接记录客户端的 IP 地址呢?这就需要用到上文介绍的几个辅助配置项。
[root@linux nginx]# vim conf/nginx.conf ----省略部分内容---- location / { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_connect_timeout 60s; proxy_read_timeout 60s; proxy_send_timeout 60s; proxy_pass http://192.168.1.130; } ----省略部分内容---- [root@linux nginx]# ./sbin/nginx -s reload #重新加载 Nginx 配置
6) 再用机器本身假装用户访问 Nginx 反向代理服务器,这时看后端服务器上的 Nginx 访问日志,日志中记录了客户端的真实 IP 地址。
[root@linux html]# cat /var/log/nginx/access.log -----省略部分内容----- 192.168.1.128 - - [18/Dec/2021:23:32:17 +0800] "GET / HTTP/1.0" 304 0 "-" "Mozilla/5.ike Gecko) Chrome/96.0.4664.110 Safari/537.36" "192.168.1.1" 192.168.1.128 - - [18/Dec/2021:23:32:19 +0800] "GET / HTTP/1.0" 304 0 "-" "Mozilla/5.ike Gecko) Chrome/96.0.4664.110 Safari/537.36" "192.168.1.1"在真实的企业运维架构环境中,后端服务器只会允许代理服务器访问,用户是无法直接访问后端服务器的。