Nginx 反向代理:从原理到生产实践 —— 以 What-to-eat-today 项目为例

Nginx反向代理DevOpsDocker架构设计

Nginx 反向代理:从原理到生产实践 —— 以 What-to-eat-today 项目为例

深入理解 Nginx 反向代理的核心原理、配置技巧与生产最佳实践,结合 Datawhale all-in-rag 实战项目进行工程化应用分析。

目录


一、为什么需要学习 Nginx 反向代理?

核心原因

原因说明生产影响
前后端分离架构的必然要求前端 SPA + 后端 API 需要统一入口不配置反向代理就会存在 CORS 跨域问题
微服务网关的基石多个微服务通过 Nginx 路由分发单点入口才能做统一的鉴权、限流、日志
SSL/TLS 统一终结证书只需配置在 Nginx 一层后端服务无需处理 HTTPS,降低复杂度
静态资源高性能托管Nginx 处理静态文件比 Python/Java 快 10x+直接提升首屏加载性能

直观理解

反向代理就是”前台接待员”:访客(客户端)不需要知道公司内部谁在做什么(后端服务),只需对接待员说出需求,接待员在内部找到对应的人并转达结果。

相比之下,正向代理(VPN)是”你替我去拿”——你告诉代理服务器你要访问某个网站,代理帮你去取回来。


📘 背景 反向代理不只是"转发请求"那么简单。它统一承担了 SSL 终结、静态资源托管、负载均衡、请求限流、访问日志等职责。这意味着后端服务可以专注于业务逻辑,不需要处理 HTTPS 证书、CORS 头、静态文件等基础设施问题。

二、反向代理核心原理

2.1 架构模型对比

模式示意图特点
直连模式客户端 → 后端服务暴露后端端口、CORS 问题、无法统一鉴权
反向代理模式客户端 → Nginx(:80) → 后端服务(:3000/:8000)隐藏后端、统一入口、可扩展

2.2 Nginx 反向代理的工作流程

客户端请求 example.com/api/users


    DNS 解析 → 指向 Nginx 服务器 IP(:80)


    Nginx 接收请求,解析 Host 头部

        ├── location /api/    → proxy_pass http://backend:8000
        ├── location /        → proxy_pass http://frontend:3000


    后端服务处理请求 → 返回响应 → Nginx 转发回客户端

关键配置指令拆解:

server {
    listen 80;                          # 监听 80 端口(HTTP)
    server_name example.com;            # 匹配的域名

    location /api/ {
        proxy_pass http://backend:8000; # 转发到后端 API
        proxy_set_header Host $host;    # 传递原始 Host
        proxy_set_header X-Real-IP $remote_addr;  # 传递客户端真实 IP
    }

    location / {
        proxy_pass http://frontend:3000; # 转发到前端 SPA
    }
}

2.3 为什么 Nginx 速度这么快?

特性说明优势
事件驱动架构非阻塞 I/O,单进程处理万级并发对比 Apache 的进程/线程模型,内存占用低 10x
零拷贝静态文件直接从内核缓存发送到网卡CPU 几乎不参与大文件传输
异步非阻塞一个 worker 进程可同时处理数千连接无需为每个连接创建线程

💡 技巧 理解 Nginx 的事件驱动模型有助于排查性能问题。一个常见的误区是盲目增加 worker_processes —— 事实上 worker 数量通常设为 CPU 核心数即可,关键是调整 worker_connections 和开启 epoll(Linux)或 kqueue(macOS)事件驱动。

三、实战项目配置:What-to-eat-today

3.1 项目架构

What-to-eat-today
├── frontend/          # React 前端
│   ├── src/
│   └── Dockerfile
├── backend/           # FastAPI 后端
│   ├── app/
│   └── Dockerfile
├── nginx/             # Nginx 配置
│   └── nginx.conf
└── docker-compose.yml # 编排文件

3.2 Nginx 配置

# nginx/nginx.conf
events {
    worker_connections 1024;
}

http {
    upstream backend {
        server backend:8000;
    }

    upstream frontend {
        server frontend:3000;
    }

    server {
        listen 80;
        server_name localhost;

        # 前端静态资源
        location / {
            proxy_pass http://frontend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }

        # 后端 API
        location /api/ {
            proxy_pass http://backend;
            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 支持
        location /ws/ {
            proxy_pass http://backend;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    }
}

3.3 Docker Compose 编排

# docker-compose.yml
version: '3.8'

services:
  frontend:
    build: ./frontend
    ports:
      - "3000:3000"

  backend:
    build: ./backend
    ports:
      - "8000:8000"

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - frontend
      - backend

四、生产最佳实践

4.1 SSL/TLS 配置

server {
    listen 443 ssl;
    server_name your-domain.com;

    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;

    # SSL 优化
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # HSTS
    add_header Strict-Transport-Security "max-age=63072000" always;
}

# HTTP 重定向到 HTTPS
server {
    listen 80;
    server_name your-domain.com;
    return 301 https://$server_name$request_uri;
}

4.2 性能优化

http {
    # 开启 Gzip 压缩
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

    # 静态资源缓存
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # 连接优化
    keepalive_timeout 65;
    keepalive_requests 100;
}

⚠️ 注意 生产环境中安全配置不可省略。版本号隐藏(server_tokens off)防止攻击者探测 Nginx 版本漏洞;X-Frame-OptionsX-Content-Type-Options 防止点击劫持和 MIME 嗅探攻击。这些配置仅需几行,却能在安全扫描中避免大量高风险告警。

4.3 安全配置

http {
    # 隐藏版本号
    server_tokens off;

    # 防止点击劫持
    add_header X-Frame-Options "SAMEORIGIN" always;

    # 防止 MIME 类型嗅探
    add_header X-Content-Type-Options "nosniff" always;

    # XSS 防护
    add_header X-XSS-Protection "1; mode=block" always;

    # 限制请求大小
    client_max_body_size 10M;
}

结语

Nginx 反向代理是每个开发者都应该掌握的技能。它是前后端分离架构的必备技能,也是微服务网关的基石。基本配置很简单,10 行配置就能解决 CORS 问题。建议读者在实践中多尝试不同的配置,找到最适合自己项目的方案。

关键要点:每个开发者都应该掌握 Nginx 反向代理。基本配置很简单,10 行配置就能解决 CORS 问题。