Nginx 反向代理
Nginx 反向代理配置和使用详解
📋 目录
反向代理基础
什么是反向代理
正向代理(Forward Proxy):
客户端 → 代理服务器 → 互联网 → 目标服务器
(客户端知道目标服务器,目标服务器不知道真实客户端)
反向代理(Reverse Proxy):
客户端 → 反向代理 → 后端服务器
(客户端不知道后端服务器,后端服务器不知道真实客户端)
反向代理的作用:
- 隐藏后端服务器
- 负载均衡
- SSL/TLS 终端
- 缓存加速
- 安全防护
- 统一入口
Nginx 反向代理架构
客户端请求
↓
Nginx 反向代理
↓
后端服务器(Web 应用、API 服务等)
↓
响应返回 Nginx
↓
返回给客户端
基本配置
最简单的反向代理
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend_server:8080;
}
}带路径的反向代理
# 后端服务器: http://backend:8080/
# 方式 1: 不带 URI(保留原始路径)
location /api/ {
proxy_pass http://backend:8080; # 请求 /api/users → http://backend:8080/api/users
}
# 方式 2: 带 URI(替换路径)
location /api/ {
proxy_pass http://backend:8080/; # 请求 /api/users → http://backend:8080/users
}
# 方式 3: 自定义路径
location /old-api/ {
proxy_pass http://backend:8080/new-api/; # 请求 /old-api/users → http://backend:8080/new-api/users
}多后端代理
# 定义 upstream
upstream backend {
server app1.example.com:8080;
server app2.example.com:8080;
server app3.example.com:8080;
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://backend;
}
}请求头设置
基本请求头
server {
listen 80;
server_name example.com;
location / {
# 设置 Host 头(重要!)
proxy_set_header Host $host;
# 设置真实 IP
proxy_set_header X-Real-IP $remote_addr;
# 设置 X-Forwarded-For
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 设置协议
proxy_set_header X-Forwarded-Proto $scheme;
# 设置端口
proxy_set_header X-Forwarded-Port $server_port;
# 设置原始 Host
proxy_set_header X-Forwarded-Host $server_name;
# 传递后端
proxy_pass http://backend;
}
}完整请求头示例
location / {
# 基本信息
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Host $server_name;
# 附加信息
proxy_set_header X-Request-ID $request_id;
proxy_set_header X-Request-Start "t=${msec}";
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Original-Method $request_method;
# 客户端信息
proxy_set_header User-Agent $http_user_agent;
proxy_set_header Accept-Language $http_accept_language;
proxy_set_header Accept-Encoding $http_accept_encoding;
proxy_pass http://backend;
}条件设置请求头
location / {
# 仅对特定请求设置请求头
if ($request_method = POST) {
proxy_set_header X-Request-Type "form-submit";
}
if ($http_user_agent ~* "mobile") {
proxy_set_header X-Device-Type "mobile";
}
proxy_pass http://backend;
}
# 使用 map 更优雅的实现
map $http_user_agent $device_type {
default "desktop";
~*mobile|android|iphone|ipad "mobile";
~*tablet|ipad "tablet";
}
server {
location / {
proxy_set_header X-Device-Type $device_type;
proxy_pass http://backend;
}
}超时配置
连接超时
server {
listen 80;
server_name example.com;
location / {
# 连接超时(连接到后端)
proxy_connect_timeout 5s;
# 发送超时(发送请求到后端)
proxy_send_timeout 60s;
# 读取超时(等待后端响应)
proxy_read_timeout 60s;
proxy_pass http://backend;
}
}超时说明
| 指令 | 说明 | 推荐值 |
|---|---|---|
proxy_connect_timeout | 与后端建立连接的超时 | 3-5s(短) 10-30s(长) |
proxy_send_timeout | 发送请求到后端的超时 | 60s |
proxy_read_timeout | 等待后端响应的超时 | 60s(普通) 300s(长轮询) |
不同场景的超时配置
# 1. API 接口(短超时)
location /api/ {
proxy_connect_timeout 3s;
proxy_send_timeout 10s;
proxy_read_timeout 10s;
proxy_pass http://api_backend;
}
# 2. 文件上传(长超时)
location /upload/ {
proxy_connect_timeout 5s;
proxy_send_timeout 300s; # 上传可能需要很长时间
proxy_read_timeout 60s;
proxy_pass http://upload_backend;
}
# 3. 长轮询/Websocket(非常长)
location /ws/ {
proxy_connect_timeout 5s;
proxy_send_timeout 3600s; # 1 小时
proxy_read_timeout 3600s; # 1 小时
proxy_pass http://ws_backend;
}
# 4. 普通网页(中等超时)
location / {
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_pass http://web_backend;
}缓冲配置
请求缓冲
server {
location / {
# 是否缓冲客户端请求体
proxy_request_buffering on; # 默认 on
# 客户端请求体大小限制
client_max_body_size 10m;
# 请求体缓冲区大小
client_body_buffer_size 128k;
proxy_pass http://backend;
}
}响应缓冲
server {
location / {
# 是否缓冲后端响应
proxy_buffering on; # 默认 on
# 响应缓冲区数量和大小
proxy_buffers 8 4k; # 8 个 4k 缓冲区
# 响应头缓冲区大小
proxy_buffer_size 4k; # 默认大小
# 第一个响应包的超时
proxy_buffering on;
# 是否缓存到磁盘
proxy_max_temp_file_size 1024m; # 最大临时文件大小
proxy_temp_file_write_size 8k; # 每次写入大小
proxy_temp_path /var/tmp/nginx; # 临时文件路径
proxy_pass http://backend;
}
}缓冲配置说明
| 指令 | 说明 | 推荐值 |
|---|---|---|
proxy_buffering | 是否启用响应缓冲 | on(默认) |
proxy_buffers | 响应缓冲区数量和大小 | 8 4k 或 8 8k |
proxy_buffer_size | 响应头缓冲区大小 | 4k 或 8k |
proxy_busy_buffers_size | 忙缓冲区大小 | 8k 或 16k |
proxy_max_temp_file_size | 临时文件最大大小 | 1024m |
proxy_temp_file_write_size | 临时文件写入大小 | 8k |
不同场景的缓冲配置
# 1. 大文件下载(关闭缓冲)
location /download/ {
proxy_buffering off; # 关闭缓冲,直接转发
proxy_pass http://file_backend;
}
# 2. SSE (Server-Sent Events)
location /events/ {
proxy_buffering off; # 关闭缓冲,实时转发
proxy_cache off;
proxy_pass http://sse_backend;
}
# 3. 普通网页(开启缓冲)
location / {
proxy_buffering on; # 开启缓冲
proxy_buffers 16 4k;
proxy_buffer_size 8k;
proxy_pass http://web_backend;
}
# 4. API 接口(适度缓冲)
location /api/ {
proxy_buffering on;
proxy_buffers 4 4k;
proxy_buffer_size 4k;
proxy_pass http://api_backend;
}错误处理
错误页面配置
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
# 拦截后端错误
proxy_intercept_errors on;
# 自定义错误页面
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
# 错误页面位置
location = /50x.html {
root /usr/share/nginx/html;
}
location = /404.html {
root /usr/share/nginx/html;
}
}
}后端错误重试
server {
location / {
proxy_pass http://backend;
# 重试设置
proxy_next_upstream error timeout; # 在哪些情况下重试
proxy_next_upstream_tries 3; # 最大重试次数
proxy_next_upstream_timeout 10s; # 重试超时
# 或者显示错误页面
proxy_intercept_errors on;
error_page 502 503 504 /error.html;
}
}健康检查(需要 nginx-plus 或第三方模块)
upstream backend {
server backend1.example.com:8080 max_fails=3 fail_timeout=30s;
server backend2.example.com:8080 max_fails=3 fail_timeout=30s;
server backend3.example.com:8080 max_fails=3 fail_timeout=30s backup;
}
server {
location / {
proxy_pass http://backend;
# 健康检查参数
proxy_connect_timeout 3s;
proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
}
}负载均衡
基本负载均衡
upstream backend {
# 轮询(默认)
server backend1.example.com:8080;
server backend2.example.com:8080;
server backend3.example.com:8080;
}
server {
location / {
proxy_pass http://backend;
}
}加权轮询
upstream backend {
server backend1.example.com:8080 weight=3; # 3/6 的请求
server backend2.example.com:8080 weight=2; # 2/6 的请求
server backend3.example.com:8080 weight=1; # 1/6 的请求
}IP 哈希
upstream backend {
ip_hash; # 根据客户端 IP 哈希
server backend1.example.com:8080;
server backend2.example.com:8080;
server backend3.example.com:8080;
}最少连接
upstream backend {
least_conn; # 选择连接数最少的后端
server backend1.example.com:8080;
server backend2.example.com:8080;
server backend3.example.com:8080;
}后端参数配置
upstream backend {
server backend1.example.com:8080 max_fails=3 fail_timeout=30s weight=3;
server backend2.example.com:8080 max_fails=3 fail_timeout=30s weight=2;
server backend3.example.com:8080 max_fails=3 fail_timeout=30s backup; # 备用
keepalive 32; # 长连接数
keepalive_timeout 60s; # 长连接超时
keepalive_requests 100; # 长连接最大请求数
}
server {
location / {
proxy_pass http://backend;
proxy_http_version 1.1; # HTTP 1.1
proxy_set_header Connection "";
}
}WebSocket 代理
WebSocket 基础配置
server {
listen 80;
server_name ws.example.com;
location /ws/ {
proxy_pass http://ws_backend;
# WebSocket 支持
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 超时设置(WebSocket 需要长连接)
proxy_connect_timeout 7d;
proxy_send_timeout 7d;
proxy_read_timeout 7d;
# 关闭缓冲
proxy_buffering off;
}
}WebSocket 负载均衡
upstream ws_backend {
# IP 哈希(WebSocket 需要会话保持)
ip_hash;
server ws1.example.com:8080;
server ws2.example.com:8080;
}
server {
listen 80;
server_name ws.example.com;
location /ws/ {
proxy_pass http://ws_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# WebSocket 超时
proxy_connect_timeout 7d;
proxy_send_timeout 7d;
proxy_read_timeout 7d;
proxy_buffering off;
}
}🔧 高级技巧
动态后端选择
# 使用变量选择后端
upstream backend_a {
server backend-a.example.com:8080;
}
upstream backend_b {
server backend-b.example.com:8080;
}
server {
listen 80;
server_name example.com;
location / {
set $backend "backend_a";
if ($http_user_agent ~* "mobile") {
set $backend "backend_b";
}
proxy_pass http://$backend;
}
}
# 使用 map 更优雅的实现
map $http_user_agent $backend {
default "backend_a";
~*mobile "backend_b";
}
server {
location / {
proxy_pass http://$backend;
}
}基于 Cookie 的会话保持
upstream backend {
server backend1.example.com:8080;
server backend2.example.com:8080;
# 根据 Cookie 选择后端(需要第三方模块)
# hash $cookie_sessionid consistent;
}
server {
location / {
proxy_pass http://backend;
# 设置会话 Cookie
add_header Set-Cookie "backend=$upstream_addr; Path=/; HttpOnly";
}
}API 网关模式
# 多个后端服务
upstream user_service {
server user1.example.com:8080;
server user2.example.com:8080;
}
upstream order_service {
server order1.example.com:8080;
server order2.example.com:8080;
}
upstream product_service {
server product1.example.com:8080;
server product2.example.com:8080;
}
server {
listen 80;
server_name api.example.com;
# API 网关路由
location /api/users/ {
proxy_pass http://user_service;
proxy_set_header X-Service-Name "user-service";
}
location /api/orders/ {
proxy_pass http://order_service;
proxy_set_header X-Service-Name "order-service";
}
location /api/products/ {
proxy_pass http://product_service;
proxy_set_header X-Service-Name "product-service";
}
# 健康检查接口
location /health {
access_log off;
return 200 "OK\n";
add_header Content-Type text/plain;
}
}