Skip to content

Nginx 反向代理

一、Nginx 的三大职责

  1. 静态资源托管:前端构建产物的 Web 服务器。
  2. 反向代理/api 请求转发给后端,隐藏内部端口。
  3. HTTPS + 反向代理 + 负载均衡:生产入口的标准组件。
用户 → 80/443(Nginx)
         ├── /          → 前端静态文件(Vue/React 页面)
         ├── /assets/*  → 前端静态资源
         └── /api/*     → 后端 http://127.0.0.1:8080

二、前端容器内的 nginx.conf

前端 Dockerfile 里已经 COPY 了一个 nginx 配置,实现 SPA 路由和 /api 转发:

nginx
# web-vue/nginx.conf
server {
    listen 80;
    server_name localhost;

    root /usr/share/nginx/html;
    index index.html;

    # 静态资源缓存
    location /assets/ {
        expires 7d;
        add_header Cache-Control "public";
    }

    # SPA 路由:前端路由刷新不 404
    location / {
        try_files $uri $uri/ /index.html;
    }

    # API 反向代理到后端
    location /api/ {
        proxy_pass http://server: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;
    }
}

SPA 路由为什么必须 try_files

Vue/React 是单页应用,路由在前端。用户刷新 https://mall.com/order/list 时,Nginx 找不到 /order/list 这个文件,必须回退到 index.html 让前端路由接管。漏了这一行,刷新页面就 404。

三、生产服务器上的 Nginx(宿主机)

上线时更常见的做法:前端构建产物直接放服务器,由宿主机 Nginx 托管 + 反向代理到容器内的后端:

nginx
# /etc/nginx/conf.d/mall.conf
server {
    listen 80;
    server_name mall.example.com;

    # 前端静态文件
    root /var/www/mall-web;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }

    location /api/ {
        proxy_pass http://127.0.0.1:8080;   # 后端容器映射到 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;
    }
}
bash
sudo nginx -t                  # 检查配置语法
sudo systemctl reload nginx    # 平滑重载,不中断服务

四、HTTPS:Let's Encrypt 免费证书

bash
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d mall.example.com

Certbot 会自动:

  1. 申请证书
  2. 改写 Nginx 配置加 listen 443 ssl
  3. 配置 HTTP → HTTPS 跳转
  4. 设置定时自动续期(证书 90 天有效期)

生成后的配置(certbot 自动生成,了解即可):

nginx
server {
    listen 443 ssl http2;
    server_name mall.example.com;

    ssl_certificate     /etc/letsencrypt/live/mall.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mall.example.com/privkey.pem;

    # 其余同 http 配置...
}

server {  # HTTP 自动跳 HTTPS
    listen 80;
    server_name mall.example.com;
    return 301 https://$host$request_uri;
}

五、验证 HTTPS

bash
curl -I https://mall.example.com        # 看 200 和证书
curl -I http://mall.example.com         # 301 跳转

浏览器访问确认地址栏出现小锁。

混合内容问题

页面已 HTTPS,但里面请求 http://api 会被浏览器拦截。生产环境前端构建时 VITE_API_BASE 要用 https:// 前缀,保证全站 HTTPS

六、本章验收

  • [ ] 前端刷新 /order/list 不 404(SPA 路由正确)
  • [ ] https://域名/api/product/list 能返回数据
  • [ ] HTTP 访问自动跳转 HTTPS
  • [ ] 浏览器地址栏有小锁,无混合内容警告

基于 MIT 协议发布,可自由学习与修改