Nginx 反向代理
掌握 Nginx 作为反向代理服务器的配置和最佳实践
什么是反向代理?
反向代理是一种服务器架构模式,其中代理服务器位于客户端和后端服务器之间,代表客户端向后端服务器发送请求,并将后端服务器的响应返回给客户端。
反向代理的工作原理
- 客户端向反向代理服务器发送请求
- 反向代理服务器接收请求
- 反向代理服务器根据配置将请求转发到后端服务器
- 后端服务器处理请求并返回响应
- 反向代理服务器接收后端服务器的响应
- 反向代理服务器将响应返回给客户端
反向代理的优势
- 负载均衡:将请求分发到多个后端服务器,提高系统可用性和性能
- SSL 终止:在代理服务器上处理 SSL/TLS 加密和解密,减轻后端服务器负担
- 缓存:缓存静态内容和动态响应,减少后端服务器负载
- 安全防护:作为应用程序的前沿,提供额外的安全层
- URL 重写和路由:根据 URL 路径将请求路由到不同的后端服务
- 统一入口:为多个后端服务提供单一访问点
Nginx 反向代理基础配置
基本反向代理配置
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://localhost:3000;
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_pass - 指定后端服务器的地址,可以是 IP 地址、域名或 Unix 套接字
- proxy_set_header - 设置传递给后端服务器的请求头
- Host - 保持原始请求的主机名
- X-Real-IP - 传递客户端的真实 IP 地址
- X-Forwarded-For - 传递客户端 IP 地址链
- X-Forwarded-Proto - 传递原始请求的协议(http 或 https)
代理参数配置
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://localhost:3000;
# 基本代理头
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_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 60;
# 缓冲区设置
proxy_buffers 16 16k;
proxy_buffer_size 32k;
proxy_busy_buffers_size 64k;
# 代理重定向
proxy_redirect off;
}
}
高级反向代理配置
基于路径的反向代理
根据 URL 路径将请求转发到不同的后端服务:
server {
listen 80;
server_name example.com;
# 转发 API 请求到后端 API 服务
location /api {
proxy_pass http://localhost:3000;
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;
}
# 转发前端请求到前端服务
location / {
proxy_pass http://localhost:8080;
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;
}
}
基于主机名的反向代理
根据主机名将请求转发到不同的后端服务:
# API 服务
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://localhost:3000;
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;
}
}
# 前端服务
server {
listen 80;
server_name www.example.com;
location / {
proxy_pass http://localhost:8080;
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;
}
}
反向代理与静态文件服务结合
server {
listen 80;
server_name example.com;
root /var/www/html;
# 静态文件服务
location ~* \.(jpg|jpeg|png|gif|css|js|ico)$ {
expires 30d;
add_header Cache-Control "public, max-age=2592000";
}
# 动态内容反向代理
location / {
try_files $uri $uri/ @proxy;
}
# 反向代理
location @proxy {
proxy_pass http://localhost:3000;
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;
}
}
WebSocket 反向代理
Nginx 可以作为 WebSocket 连接的反向代理,支持实时通信应用:
server {
listen 80;
server_name example.com;
location /ws {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
# WebSocket 连接超时设置
proxy_read_timeout 86400;
}
}
配置说明
- proxy_http_version 1.1 - WebSocket 需要 HTTP/1.1 协议
- proxy_set_header Upgrade $http_upgrade - 传递 Upgrade 头
- proxy_set_header Connection "upgrade" - 传递 Connection 头,设置为 upgrade
- proxy_read_timeout - 设置较长的超时时间,确保 WebSocket 连接不会被过早关闭
反向代理缓存
配置 Nginx 反向代理缓存,提高响应速度和减轻后端服务器负担:
http {
# 配置代理缓存
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=proxy_cache:10m max_size=10g inactive=60m use_temp_path=off;
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://localhost:3000;
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_cache proxy_cache;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_key "$scheme$request_method$host$request_uri";
add_header X-Cache-Status $upstream_cache_status;
}
}
}
缓存清除配置
http {
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=proxy_cache:10m max_size=10g inactive=60m use_temp_path=off;
server {
listen 80;
server_name example.com;
# 缓存清除端点
location ~ /purge(/.*) {
allow 127.0.0.1;
deny all;
proxy_cache_purge proxy_cache "$scheme$request_method$host$1";
}
location / {
proxy_pass http://localhost:3000;
# 其他代理配置...
proxy_cache proxy_cache;
# 其他缓存配置...
}
}
}
反向代理与 SSL 终止
Nginx 可以作为 SSL 终止点,在代理服务器上处理 SSL/TLS 加密和解密:
server {
listen 443 ssl http2;
server_name example.com;
# SSL 配置
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
location / {
proxy_pass http://localhost:3000;
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 https;
}
}
# HTTP 重定向到 HTTPS
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
配置说明
- ssl_certificate - SSL 证书文件路径
- ssl_certificate_key - SSL 私钥文件路径
- ssl_protocols - 启用的 SSL/TLS 协议版本
- ssl_ciphers - 启用的密码套件
- X-Forwarded-Proto https - 告诉后端服务器原始请求使用的是 HTTPS 协议
实践练习
练习 1:基本反向代理配置
- 启动一个后端服务(如 Node.js 或 Python 服务器),监听在 3000 端口
- 配置 Nginx 作为反向代理,将请求转发到后端服务
- 测试反向代理是否生效(访问 Nginx 服务器,应该看到后端服务的响应)
- 检查后端服务的日志,确认收到的请求头是否包含 X-Real-IP 等信息
练习 2:基于路径的反向代理
- 启动两个后端服务,分别监听在 3000 端口(API 服务)和 8080 端口(前端服务)
- 配置 Nginx,将 /api 路径的请求转发到 3000 端口,将其他路径的请求转发到 8080 端口
- 测试不同路径的请求是否正确转发到对应的后端服务
练习 3:WebSocket 反向代理
- 启动一个支持 WebSocket 的后端服务,监听在 8080 端口
- 配置 Nginx 作为 WebSocket 反向代理
- 使用 WebSocket 客户端(如浏览器的开发者工具或专门的 WebSocket 测试工具)连接到 Nginx 服务器
- 测试 WebSocket 连接是否正常建立和通信
常见问题解答
Q: 反向代理与正向代理的区别是什么?
A: 正向代理是代表客户端向互联网发送请求,而反向代理是代表后端服务器接收客户端请求。正向代理隐藏客户端信息,反向代理隐藏后端服务器信息。
Q: 如何解决反向代理中的 CORS 问题?
A: 可以在 Nginx 中添加 CORS 头:
location /api {
proxy_pass http://localhost:3000;
# 添加 CORS 头
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
# 处理 OPTIONS 请求
if ($request_method = 'OPTIONS') {
return 204;
}
}
Q: 如何配置反向代理以支持长连接?
A: 需要在 Nginx 配置中设置适当的超时时间和保持连接相关的指令:
location / {
proxy_pass http://localhost:3000;
# 保持连接
proxy_http_version 1.1;
proxy_set_header Connection "keep-alive";
# 设置超时时间
proxy_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 60;
}
Q: 如何在反向代理中处理大文件上传?
A: 需要调整客户端请求体大小限制和相关超时设置:
http {
# 允许上传大文件
client_max_body_size 100m;
server {
listen 80;
server_name example.com;
location /upload {
proxy_pass http://localhost:3000;
# 调整超时设置
proxy_connect_timeout 120;
proxy_send_timeout 120;
proxy_read_timeout 120;
}
}
}