从零到一:Nginx反向代理Spring Boot+Vue全栈项目部署实战

部署全栈项目到云服务器时,Nginx配置往往是让开发者最头疼的环节。我曾见过不少团队在开发阶段一切顺利,却在部署时因为Nginx配置不当导致前端白屏、API调用失败甚至安全漏洞。本文将手把手带你拆解Nginx配置的每个关键环节,提供可直接复用的配置模板,并解释背后的原理,让你彻底掌握这"最后一公里"。

1. 环境准备与基础概念

在开始配置之前,我们需要明确几个核心概念。反向代理是Nginx在此场景中的核心角色——它接收客户端请求,根据规则转发到后端服务,再将响应返回给客户端。这种架构带来的好处包括:

  • 隐藏真实服务端口,提升安全性
  • 负载均衡能力(虽然本文不涉及)
  • 静态资源高效服务
  • 统一入口便于管理

对于典型的Spring Boot+Vue项目,部署架构通常如下:

客户端 → Nginx(80/443)
       ├── 静态资源(Vue打包产物)
       └── 反向代理 → Spring Boot(如8080端口)

在开始前,请确保已完成以下准备:

  • 云服务器已开通80端口(HTTP)和/或443端口(HTTPS)
  • Vue项目已通过npm run build生成dist目录
  • Spring Boot打包为可执行jar并测试能独立运行
  • 服务器已安装Nginx(可通过nginx -v验证)

提示:建议使用全新的Nginx配置,而不是直接修改默认配置。可以新建/etc/nginx/conf.d/your_project.conf文件来管理你的配置。

2. Nginx核心配置详解

让我们从一个最小化但完整的配置开始,逐步添加关键功能。以下是基础骨架:

# /etc/nginx/conf.d/your_project.conf
server {
    listen 80;
    server_name your_domain_or_ip;
    
    # 前端静态资源配置
    location / {
        root /path/to/your/dist;
        index index.html;
        try_files $uri $uri/ /index.html;
    }
    
    # 后端API代理
    location /api/ {
        proxy_pass http://localhost:8080/;
    }
}

2.1 静态资源服务配置

Vue项目打包后是纯静态资源,Nginx需要正确配置才能服务这些文件。关键参数解析:

参数作用典型值
root静态资源根目录/usr/share/nginx/html/dist
index默认访问文件index.html
try_files路由回退策略$uri $uri/ /index.html

特别注意try_files $uri $uri/ /index.html是支持Vue Router history模式的关键配置。它让Nginx在找不到对应文件时返回index.html,由前端路由处理。

2.2 反向代理配置

Spring Boot应用的代理配置更为复杂,需要处理各种HTTP头和信息转发。以下是增强版的API代理配置:

location /api/ {
    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;
    
    # 超时设置
    proxy_connect_timeout 60s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;
    
    # WebSocket支持
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

关键头信息说明:

  • X-Forwarded-For:保留原始客户端IP
  • X-Forwarded-Proto:让后端知道原始请求是HTTP还是HTTPS
  • Upgrade头:支持WebSocket的必要配置

3. 高级配置与优化

3.1 性能调优参数

在高并发场景下,这些参数可以显著提升性能:

# 在http块中添加
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;

# 开启gzip压缩
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 1k;
gzip_comp_level 2;

3.2 安全加固配置

安全是部署时最容易被忽视的环节。以下配置可以显著提升安全性:

# 隐藏Nginx版本信息
server_tokens off;

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

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

# 内容安全策略(根据实际调整)
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' cdn.example.com;";

# 禁用不安全的HTTP方法
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
    return 405;
}

3.3 多环境配置管理

实际开发中,我们通常需要区分开发、测试和生产环境。可以通过include方式实现:

# 主配置文件
server {
    listen 80;
    server_name your_domain;
    
    include /etc/nginx/conf.d/your_project/*.conf;
}

# 然后按环境创建不同文件
# /etc/nginx/conf.d/your_project/frontend.conf
# /etc/nginx/conf.d/your_project/backend.conf
# /etc/nginx/conf.d/your_project/prod.conf

4. 常见问题排查指南

即使按照最佳实践配置,部署过程中仍可能遇到各种问题。以下是几个常见问题的排查方法:

4.1 前端路由刷新404

症状:直接访问路由正常,但刷新页面返回404。 原因:Vue Router的history模式需要特殊配置。 解决方案

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

4.2 跨域问题

症状:前端报跨域错误,即使后端已配置CORS。 原因:代理配置不当导致头信息丢失。 解决方案

location /api/ {
    proxy_pass http://localhost:8080/;
    # 添加以下头信息
    add_header 'Access-Control-Allow-Origin' '$http_origin' always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
    add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type' always;
    
    # 处理OPTIONS预检请求
    if ($request_method = 'OPTIONS') {
        return 204;
    }
}

4.3 静态资源缓存策略

症状:前端更新后用户仍看到旧版本。 解决方案:为静态资源添加版本哈希并配置长期缓存:

location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
    expires 1y;
    add_header Cache-Control "public, no-transform";
    access_log off;
}

5. HTTPS配置与最佳实践

现代Web应用必须使用HTTPS。以下是Let's Encrypt免费证书的配置示例:

server {
    listen 443 ssl http2;
    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_prefer_server_ciphers on;
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256...';
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_stapling on;
    ssl_stapling_verify on;
    
    # 其他配置与HTTP版本相同
    ...
}

# HTTP强制跳转HTTPS
server {
    listen 80;
    server_name your_domain.com;
    return 301 https://$host$request_uri;
}

6. 完整配置模板

以下是经过生产验证的完整配置模板,可根据实际需求调整:

# 全局配置
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';
    
    access_log /var/log/nginx/access.log main;
    
    sendfile on;
    tcp_nopush on;
    keepalive_timeout 65;
    
    # 包含各站点配置
    include /etc/nginx/conf.d/*.conf;
}

# 站点配置示例 (/etc/nginx/conf.d/your_project.conf)
server {
    listen 80;
    server_name your_domain.com;
    
    # 重定向到HTTPS
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name your_domain.com;
    
    # SSL配置
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256...';
    
    # 静态资源
    location / {
        root /var/www/your_project/dist;
        index index.html;
        try_files $uri $uri/ /index.html;
        
        # 长期缓存静态资源
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
    }
    
    # API代理
    location /api/ {
        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;
        
        # 超时设置
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
    
    # 健康检查端点
    location /health {
        access_log off;
        return 200 "OK";
    }
    
    # 禁止访问隐藏文件
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }
}

7. 部署流程与验证

最后,让我们总结下完整的部署流程:

  1. 准备阶段

    • 打包Vue项目:npm run build
    • 打包Spring Boot项目:mvn clean package
    • 上传dist目录和jar包到服务器
  2. Nginx配置

    • 安装Nginx(如未安装)
    • 创建配置文件/etc/nginx/conf.d/your_project.conf
    • 根据模板调整配置
    • 测试配置:nginx -t
    • 重载配置:nginx -s reload
  3. 启动后端服务

    nohup java -jar your_application.jar --server.port=8080 > app.log 2>&1 &
    
  4. 验证步骤

    • 访问域名,确认前端加载正常
    • 测试API调用是否成功
    • 检查浏览器开发者工具中的网络请求
    • 查看Nginx和后端日志排查问题
  5. 监控与维护

    • 设置日志轮转
    • 配置进程监控(如systemd或supervisor)
    • 定期更新SSL证书

在实际项目中,我发现最容易出错的环节是路径配置和权限设置。特别是在使用非root用户运行Nginx时,经常因为权限问题导致静态资源无法访问。建议部署后立即检查Nginx错误日志:tail -f /var/log/nginx/error.log

更多推荐