正向代理、反向代理是运维工作中非常容易混淆的概念,也是 Nginx 核心能力之一。Nginx 依托不同模块,既可以实现简单的 HTTP 转发、动静分离,也能实现后端集群负载均衡、缓存加速,是企业 Web 架构里非常常用的接入层组件。
正向代理 vs 反向代理
- 正向代理 :代理代表客户端去访问服务端。客户端需要手动配置代理地址,服务器感知到的访问来源是代理服务器,不知道真实客户端。典型场景:翻墙代理。
- 反向代理 :代理代表后端服务器集群接收客户端请求。客户端不需要做任何配置,只访问反向代理地址,感知不到后端真实服务器,由代理把请求转发给后端节点。典型场景:网站入口、负载均衡。
Nginx 除了本身作为高性能 Web 服务,还可以把自身无法处理的请求,按照协议转发给其他服务,依靠下面几个核心模块实现:
ngx_http_proxy_module:HTTP 协议反向代理,最常用ngx_http_upstream_module:定义后端服务器组,给 proxy_pass、fastcgi_pass 等引用,实现负载均衡ngx_stream_proxy_module:TCP 四层代理,做端口转发ngx_http_fastcgi_module:FastCGI 协议代理,转发 PHP 请求ngx_http_uwsgi_module:uWSGI 协议代理,转发 Python Web 项目请求
同构代理:直接使用 HTTP/TCP 协议转发,后端本身就是 Web 服务,不需要额外协议解析,如静态页面、接口服务。 异构代理:请求需要后端程序解析处理,不能直接返回文件,例如 PHP、Python 动态程序。
1.1 HTTP 反向代理
官方文档:https://nginx.org/en/docs/http/ngx_http_proxy_module.html
1.1.1 反向代理常用配置参数
| 参数 | 说明 |
|---|---|
proxy_pass |
核心指令,指定转发目标,可以是 IP: 端口、域名,或者 upstream 后端组 |
proxy_hide_header field |
隐藏后端返回给客户端的响应头 |
proxy_pass_header field |
透传后端默认不对外发送的响应头 |
proxy_set_header |
修改 / 新增请求头,常用X-Forwarded-For传递客户端真实 IP |
proxy_connect_timeout |
Nginx 和后端建立连接超时,默认 60s |
proxy_read_timeout |
连接成功后,读取后端响应超时,默认 60s |
proxy_send_timeout |
向后端发送请求数据的超时,默认 60s |
proxy_http_version |
设置代理使用的 HTTP 版本,默认 1.0 |
proxy_ignore_client_abort |
客户端断开连接时,Nginx 是否继续等待后端返回,off 则直接终止,记录 499 |
1. proxy_pass 基础示例
环境准备:
-
RS3:
172.25.254.11 -
RS4:
172.25.254.12RS3
[root@RS3 ~]# echo 172.25.254.11-RS3 > /var/www/html/index.html
RS4
[root@RS4 ~]# echo 172.25.254.12-RS4 > /var/www/html/index.html
[root@RS4 ~]# mkdir /var/www/html/web
[root@RS4 ~]# echo 172.25.254.12-RS4-web > /var/www/html/web/index.htmlNginx主机测试连通性
[root@Nginx ~]# curl 172.25.254.11
172.25.254.11-RS3
[root@Nginx ~]# curl 172.25.254.12
172.25.254.12-RS4
Nginx 配置 /usr/local/nginx/conf/conf.d/vhost.conf
server {
listen 80;
server_name www.doubledragon.org;
root /webdata/nginx/doubledragon.org;
location / {
proxy_pass http://172.25.254.11:80;
}
location /web {
proxy_pass http://172.25.254.12:80;
}
}
重载配置:
[root@Nginx ~]# nginx -s reload
访问测试:
[root@Nginx ~]# curl www.doubledragon.org
172.25.254.11-RS3
[root@Nginx ~]# curl www.doubledragon.org/web/
172.25.254.12-RS4-web
2. proxy_hide_header 隐藏响应头示例
不加配置前,curl -v 可以看到后端返回的ETag头信息:
< ETag: "16-64de788fdf02b"
修改配置,隐藏 ETag:
location /web {
proxy_pass http://172.25.254.12:80;
proxy_hide_header ETag;
}
再次curl -v访问,ETag 头部不再返回给客户端,常用于安全脱敏。
3. proxy_pass_header 透传响应头示例
默认 Nginx 不会透传后端Server头部,我们使用proxy_pass_header开启透传:
location / {
proxy_pass http://172.25.254.11:80;
proxy_pass_header server;
}
访问后可以看到后端真实 Server 版本:
< Server: Apache/2.4.57 (Red Hat Enterprise Linux)
4. proxy_set_header 传递真实客户端 IP
后端服务器默认拿到的源 IP 是 Nginx 代理 IP,需要设置X-Forwarded-For传递真实客户端 IP。
修改 RS3 的 httpd 日志格式,增加 X-Forwarded-For 字段:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{X-Forwarded-For}i\"" combined
重启 httpd。
Nginx 配置:
location / {
proxy_pass http://172.25.254.11:80;
proxy_pass_header server;
proxy_set_header X-Forwarded-For $remote_addr;
}
访问后查看 RS3 日志,即可拿到客户端真实 IP。
1.1.2 实战案例:反向代理动静分离
动静分离是生产常用架构:静态资源(html、图片、js、css)交给静态服务器;PHP 动态请求转发给后端 PHP 服务。
环境准备:RS3 安装 httpd+php
[root@RS3 ~]# dnf install php -y
[root@RS3 ~]# systemctl restart httpd
[root@RS3 ~]# vim /var/www/html/index.php
php 页面内容:
<?php
echo "<h2>172.25.254.11</h2>";
phpinfo();
?>
Nginx 配置:
server {
listen 80;
server_name www.doubledragon.org;
root /webdata/nginx/doubledragon.org;
location / {
proxy_pass http://172.25.254.12:80;
}
location ~* \.(php|js)$ {
proxy_pass http://172.25.254.11:80;
}
}
重载 Nginx,浏览器访问www.doubledragon.org/index.php测试。
1.1.3 反向代理缓存 proxy_cache
代理缓存可以把后端返回的内容缓存到 Nginx 本地,后续相同请求直接由 Nginx 返回,大幅降低后端压力、提升响应速度,默认关闭。
核心缓存参数
proxy_cache_path:http 块中定义缓存存储路径、目录层级、内存 key 空间、过期、磁盘上限proxy_cache:location 中启用缓存,引用上面定义的 zoneproxy_cache_key:缓存的主键,默认$scheme$proxy_host$request_uriproxy_cache_valid:针对不同状态码设置缓存时长proxy_cache_use_stale:后端异常时,允许返回过期缓存兜底proxy_cache_methods:指定哪些 HTTP 方法可以缓存,GET、HEAD 默认缓存
proxy_cache_path示例:
proxy_cache_path /usr/local/nginx/proxy_cache
levels=1:2:2
keys_zone=proxycache:20m
inactive=120s
max_size=1g;
levels=1:2:2:三级目录结构,分散缓存文件,避免单目录文件过多keys_zone=proxycache:20m:内存存放缓存 key 和元数据inactive=120s:120s 没有访问则缓存失效清理max_size=1g:缓存磁盘最大容量
1. 无缓存压测
使用 ab 压测动态 PHP 页面,动态页面每次都请求后端 PHP,并发高时大量失败:
ab -n 10000 -c 50 www.doubledragon.org/index.php
压测结果:大量 Failed requests,QPS 低,等待耗时高。
2. 开启缓存加速
-
主配置 nginx.conf 的 http 段添加 proxy_cache_path
-
vhost.conf 在 php 的 location 启用缓存
location ~* .(php|js) { proxy_pass http://172.25.254.11:80; proxy_cache proxycache; proxy_cache_key request_uri;
proxy_cache_valid 200 302 301 10m;
proxy_cache_valid any 1m;
}
重启 Nginx,再次压测。
3. 验证缓存效果
开启缓存后,同样压测参数:请求全部成功,QPS 大幅上涨,响应时间显著降低。 查看缓存目录:
tree /usr/local/nginx/proxy_cache
可以看到 Nginx 自动生成缓存目录与缓存实体文件。
1.2 HTTP 反向代理负载均衡(upstream)
上面的 proxy_pass 只能转发到单台后端;ngx_http_upstream_module可以定义后端服务器组,实现多节点负载均衡、故障摘除、备份节点、多种调度算法。 官方文档:https://nginx.org/en/docs/http/ngx_http_upstream_module.html
1.2.1 upstream 参数说明
upstream backend {
server backend1.example.com weight=5;
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server backup1.example.com backup;
}
server 后面支持的参数:
weight:权重,默认 1,权重越高分配请求越多max_conns:当前节点最大并发连接,0 代表无限制max_fails:连续失败多少次,标记节点不可用,默认 1fail_timeout:节点标记失败后,多久之后重新探测,默认 10sbackup:备份节点,全部主节点故障才启用down:标记永久下线,平滑维护ip_hash:源 IP 哈希,会话保持,同一个客户端 IP 固定访问一台后端least_conn:最少连接算法,优先分给当前连接数少的节点hash $key consistent:一致性哈希,适合缓存集群
1.2.2 负载均衡完整示例
编辑负载均衡配置文件 loadbalance.conf
upstream webserver {
server 172.25.254.11:80 weight=1 fail_timeout=15s max_fails=3;
server 172.25.254.12:80 weight=1 fail_timeout=15s max_fails=3;
server 172.25.254.10:8888 backup;
}
server {
listen 80;
server_name www.doubledragon.org;
location ~ / {
proxy_pass http://webserver;
}
}
重启 Nginx 测试:
curl www.doubledragon.org
轮流返回 RS3、RS4 内容,实现轮询负载均衡;RS3、RS4 全部宕机后,自动切换到 backup 备份节点。
1.2.3 基于 Cookie 的会话绑定
ip_hash是基于源 IP 做会话保持,当大量用户出口 NAT 时会有问题;基于 Cookie 里的 sessionid 做 hash,是更精准的会话绑定方案:
upstream webserver {
hash $cookie_sessionid consistent;
server 172.25.254.11:80;
server 172.25.254.12:80;
}
用户 Cookie 里 sessionid 不变,则始终调度到同一台后端,适合需要会话保持的业务。