Nginx 教程

纯干货教学,从零开始学习 Nginx

Nginx 反向代理

掌握 Nginx 作为反向代理服务器的配置和最佳实践

什么是反向代理?

反向代理是一种服务器架构模式,其中代理服务器位于客户端和后端服务器之间,代表客户端向后端服务器发送请求,并将后端服务器的响应返回给客户端。

反向代理的工作原理

  1. 客户端向反向代理服务器发送请求
  2. 反向代理服务器接收请求
  3. 反向代理服务器根据配置将请求转发到后端服务器
  4. 后端服务器处理请求并返回响应
  5. 反向代理服务器接收后端服务器的响应
  6. 反向代理服务器将响应返回给客户端

反向代理的优势

  • 负载均衡:将请求分发到多个后端服务器,提高系统可用性和性能
  • 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:基本反向代理配置

  1. 启动一个后端服务(如 Node.js 或 Python 服务器),监听在 3000 端口
  2. 配置 Nginx 作为反向代理,将请求转发到后端服务
  3. 测试反向代理是否生效(访问 Nginx 服务器,应该看到后端服务的响应)
  4. 检查后端服务的日志,确认收到的请求头是否包含 X-Real-IP 等信息

练习 2:基于路径的反向代理

  1. 启动两个后端服务,分别监听在 3000 端口(API 服务)和 8080 端口(前端服务)
  2. 配置 Nginx,将 /api 路径的请求转发到 3000 端口,将其他路径的请求转发到 8080 端口
  3. 测试不同路径的请求是否正确转发到对应的后端服务

练习 3:WebSocket 反向代理

  1. 启动一个支持 WebSocket 的后端服务,监听在 8080 端口
  2. 配置 Nginx 作为 WebSocket 反向代理
  3. 使用 WebSocket 客户端(如浏览器的开发者工具或专门的 WebSocket 测试工具)连接到 Nginx 服务器
  4. 测试 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;
        }
    }
}