把Vue项目从本地跑到线上看起来就三步打包、传文件、配一个Web服务器。但很多前端同学在第三步栽跟头——项目传到服务器上双击index.html能打开一刷新就404或者接口全部飘红控制台一片报错。这些问题十有八九出在Nginx反向代理配置上。Nginx反向代理部署前端Vue项目核心就两件事第一把打包出来的静态文件用正确的路径交给浏览器第二把前端发出的 /api 请求转给后端服务解决跨域、隐藏服务地址同时让前后端保持同源。这篇文章会从“为什么需要反向代理”讲到“配置文件的每一行怎么理解”再到“完整部署的每一步命令”和“上线后常见问题的排查套路”。不管你是第一次部署个人项目的前端新人还是在公司环境里上线业务系统的工程师这套经验都能直接用。1. 为什么前端部署绕不开Nginx反向代理1.1 打包后的Vue项目离“能上线”还差一步运行npm run build之后你会得到一个 dist 目录里面通常有一个 index.html加一个 assets 目录js、css、图片都放在里面文件名一般带 hash。Vue 是单页应用整个应用只有一个真实的 HTML 文件后续路由跳转全靠 JS 在浏览器里渲染。也就是说浏览器要访问你的项目服务器必须能提供 index.html以及它引用的那批资源文件。问题在于这个 index.html 里引用的路径是绝对路径还是相对路径直接决定线上能不能打开。用默认配置构建时它通常是/assets/index-xxxx.js这种根路径引法。浏览器访问 example.com 时会去 example.com/assets/index-xxxx.js 下载 JS。如果服务器上没把静态文件放在对应目录或者 Nginx 的 root 配置不对资源直接404页面就白屏。所以部署的第一件事就是搞清楚Web服务器是怎么把一个 URL 映射到磁盘上某个文件的。Nginx 做这件事极其擅长它就像一个高速公路收费站每条 URL 都能被精准导向正确的文件或后端服务。1.2 反向代理解决的不只是跨域开发环境里Vue 项目跑在 vite 或 webpack-dev-server 上它内部已经帮你处理好了静态服务和开发代理。接口请求比如/api/user/list在vue.config.js里配了 proxy 之后dev server 会把它转发到后端的http://localhost:9090。浏览器端看到的始终是http://localhost:5173/api/user/list这种同源请求压根没有跨域的概念。但一到生产环境静态文件不会自己跑。很多人把 dist 目录上传后直接扔给 Nginx发现接口请求全挂了因为浏览器请求http://your-server/api/user/listNginx 如果真的去磁盘上找api/user/list当然找不到。这时候就需要反向代理把/api/这个路径转发给后端服务后端处理完再把响应通过 Nginx 返回给浏览器。浏览器全程不知道后端的真实地址请求和响应都经过 Nginx 中转同源问题自然消失。反向代理的价值还不止于此。它能把后端服务的真实端口、IP、内网结构全部藏在幕后外部只能看到一个入口。遇到多台后端实例时还能做简单的负载均衡。对前端来说最直观的收获是不用再在前端代码里写死跨域地址所有请求统一走同源相对路径部署时只需要改 Nginx 配置代码一行都不用动。1.3 横向对比Nginx、Apache、Caddy、Node可能有人会问用 Node 自己写个静态服务器不行吗用 Apache 不行吗都可以但实际选型时各有取舍。我整理过一份简单对比放这里给大家参考方案静态文件性能反向代理配置内存占用生态与文档适合场景Nginx高灵活功能全低极其丰富绝大多数生产环境Apache中可用但配置偏重中高丰富老牌Linux环境Caddy中高配置极简自动HTTPS低增长中个人项目、快速上线Node自写中需要自己实现视实现而定一般极简内部工具Nginx 胜在均衡静态文件性能好反向代理功能成熟配置语法虽然不算友好但资料实在太多了。面试里也经常问 Nginx 相关的问题比如反向代理原理、location 匹配顺序、跨域解决方案这些都是前端进阶绕不开的知识点。所以不管从项目上线还是职业发展角度Nginx 都值得花时间搞明白。2. 理解这几组Nginx概念配置不再靠猜2.1 配置文件是分层的动手前先看清层次Nginx 装好之后主配置文件一般在/etc/nginx/nginx.conf里面通过 include 引入了一堆子配置。Ubuntu 系的通常还有/etc/nginx/sites-available和/etc/nginx/sites-enabled一个放可用配置一个放启用配置实际生效的是 enabled 里的软链接。CentOS 系更习惯直接用/etc/nginx/conf.d/下的 .conf 文件。Nginx 配置是分层的从外到内大致是main 层、events 层、http 块、server 块、location 块。main 层管 worker 进程数量、日志级别这些全局设置http 块是所有虚拟主机的公共区域gzip、超时时间、日志格式经常写在这里server 块就是一个虚拟主机负责监听某个端口或域名location 块则是在一个 server 里按 URL 路径细分处理逻辑。前端新人最容易搞混的是 server 和 location 的关系。我打一个比方server 是一栋楼的门牌号location 是大楼里各楼层的分诊台。请求到达 80 端口时Nginx 先根据 server_name 和端口决定进哪栋楼然后根据 URL 前缀决定去哪个分诊台处理。理解这个层级后面配置看到一堆花括号就不会晕了。2.2 location匹配优先级才是请求分流的根本部署 Vue 项目时90% 的场景只需要两个 location一个托管前端页面一个代理后端接口。但很多人一上来就写一堆 location结果某个请求走进了错误的 location出现各种匪夷所思的 404。Nginx location 匹配优先级从高到低是这样的精确匹配^~前缀匹配命中后不再检查正则~或~*正则匹配区分大小写与不区分/普通前缀匹配举个例子如果同时存在location ^~ /assets/和location ~ \.js$请求/assets/app.js会按^~规则走不再管后面的正则。反过来如果只有location ~ \.js$和location /那/assets/app.js就会走进正则块。实际部署中如果手误把location /assets/写成了location ~ /assets/那么所有以 /assets/ 开头的请求都会优先匹配到正则块。如果那个块没有配置正确的 root静态资源就全挂了页面看起来就是“样式丢失、布局错乱”。这类问题排查起来很费劲因为 Nginx 的报错可能很隐晦但只要掌握优先级规则一眼就能看出问题所在。2.3 proxy_pass的斜杠之争剥前缀与不剥前缀这是反向代理配置里最经典的坑没有之一。看两段配置location /api/ { proxy_pass http://127.0.0.1:8080; }请求/api/user/list到后端时后端收到的是/api/user/list。location /api/ { proxy_pass http://127.0.0.1:8080/; }请求/api/user/list到后端时后端收到的是/user/list。区别就在proxy_pass末尾这个斜杠。Nginx 的规则是如果 proxy_pass 后面带了 URI也就是有/或者完整路径那么 location 匹配到的前缀会被替换成这个 URI如果不带 URI原路径原封不动转发。这个坑决定了后端接口的匹配方式。后端如果所有接口已经挂在/api下那 proxy_pass 末尾不能加斜杠如果后端接口本身没有/api前缀就必须加斜杠把前缀剥掉。配错的结果通常就是接口404或者后端收到一堆奇怪的路径。我每次写配置都会专门确认一遍后端网关的路径规则宁可多花一分钟也不想上线后抓耳挠腮。2.4 try_files是history路由刷新404的唯一解药Vue Router 默认用 history 模式地址栏里是 example.com/user/123 这样的真实路径。但这个路径在服务器磁盘上根本不存在因为 SPA 只有一个 index.html。如果 Nginx 只配置了 root 和 index没有额外处理浏览器刷新/user/123时 Nginx 去磁盘找这个文件找不到直接返回404。try_files 就是为这个场景设计的location / { root /var/www/my-vue; index index.html; try_files $uri $uri/ /index.html; }这行的意思是请求进来后先按 URL 找文件$uri找不到就找目录$uri/还是找不到就统一返回 /index.html。浏览器拿到 index.html 之后Vue Router 读取当前URL匹配到 user 详情路由页面正常渲染。这就是 “history 模式刷新404” 的标准解药。如果你用的是 hash 模式URL 带#跳转时不会真的请求服务器路径可以不配 try_files。但实际部署我还是建议统一配上因为 history 模式更干净也更符合多数项目的路由规划。3. 手把手完成Vue项目部署全流程3.1 打包前最后确认的三个关键参数很多人打包失败不是命令不对而是构建前的配置没弄对。我总结成三个必须确认的点第一路由模式。开发完成后确认项目用的是 history 还是 hash。history 模式需要 Nginx 配 try_files这个前面已经讲过千万别漏。第二publicPath 或 base。Vue CLI 项目叫 publicPathVite 项目叫 base。部署在域名根路径时保持/即可部署在子路径比如 https://example.com/tools/ 就要设置成/tools/。这个配置决定 index.html 里脚本和样式资源的前缀配错的结果就是页面白屏或者布局异常。第三生产环境接口地址。在.env.production里如果后端接口统一走/api前缀那么前端代码里的请求地址就应该写成相对路径/api/xxx而不是写死某个 IP。这样打包产物里就不会有任何跨域地址上线后只需要让 Nginx 把/api转发到后端即可。一旦前端代码写死了跨域地址Nginx 反代也帮不上忙只能重新打包。3.2 构建产物检查先自检再上线执行npm run build之后进入 dist 目录打开 index.html重点看script标签的 src 路径。根路径部署预期是/assets/index-xxxx.js。子路径部署预期是/tools/assets/index-xxxx.js。如果发现路径不对回去改 publicPath 或 base重新构建。这一步省掉的话等上了服务器再发现资源404来回传文件特别浪费时间。另外一个容易忽略的细节dist 目录里不要有多余的 map 文件。生产环境构建默认不生成 sourcemap如果某些旧项目配置过productionSourceMap: true记得关掉。sourcemap 在线上的作用很小反而会暴露源码还增加部署体积。3.3 上传与安装Nginx的实操命令上传 dist 内容到服务器我推荐用 rsync。命令大概是rsync -avz --delete dist/ rootyour-server:/var/www/my-vue/注意dist/后面有斜杠表示把 dist 目录里的内容同步到目标目录而不是把 dist 目录本身打包放进去。--delete会删除目标目录里多余的旧文件做全量发布时很有用能避免旧文件残留引发路径混淆。Ubuntu 系统安装 Nginx 很简单sudo apt update sudo apt install nginx -y sudo systemctl enable --now nginxCentOS 系的话是sudo yum install nginx安装后配置文件路径和默认站点目录略有不同。Ubuntu 的默认站点根目录是/var/www/htmlNginx 默认配置会在/etc/nginx/sites-available/default里定义。实际部署时我更建议新建一个独立的配置文件不要直接改默认配置这样项目隔离清晰出问题也容易回滚。3.4 可直接抄作业的Nginx完整配置下面这份配置是我平时项目上线用的模板支持静态文件托管和 API 反向代理注释也写在里面了server { listen 80; server_name example.com; root /var/www/my-vue; index index.html; # 前端路由兜底解决 history 模式刷新 404 location / { try_files $uri $uri/ /index.html; } # 后端接口反向代理 location /api/ { proxy_pass http://127.0.0.1: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 30s; proxy_read_timeout 60s; } # 静态资源缓存带 hash 的文件可以放心缓存 location /assets/ { expires 7d; add_header Cache-Control public, no-transform; } }逐段说明一下root /var/www/my-vue;指向打包产物所在目录可以按自己的路径改。location /里的try_files解决刷新404必须配。location /api/的proxy_pass我用了尾部斜杠是因为后端接口没有/api前缀。如果你的后端接口本身就带/api请把末尾斜杠去掉否则路径会被剥掉后端反而匹配不上。proxy_set_header这几行让后端能拿到真实客户端 IP、协议和 Host。如果不配后端看到的所有请求都来自 127.0.0.1日志和风控都会受影响。超时时间根据业务调整。如果是文件上传接口proxy_read_timeout要适当加大。配置写好后依次执行nginx -t nginx -s reloadnginx -t是测试语法报错的话会提示具体行号。改完配置先测试再 reload这个习惯能规避掉 90% 的在线事故。3.5 部署完成后的验证步骤配置生效后不要急着关终端验证一遍再走。首先访问http://你的域名/页面正常打开Network 面板里没有红色请求。然后随便刷新一个前端路由地址比如/user/123页面仍然正常没有404。接着看接口请求比如/api/user/list返回200数据正常。如果是登录功能再测一次登录确认 Cookie 能正常写入和携带。如果这几步都通过部署基本没问题。剩下就是观察日志确认没有持续报错再离开服务器。4. 上线后的坑位地图与日常维护4.1 高频故障速查表这是我平时帮同事排查问题用的速查表遇到类似现象可以直接对照现象大概率原因排查手段处理方式首页打开后刷新404history模式缺少try_filescurl -I http://ip/user/xxx 返回404location / 加 try_files页面打开接口404proxy_pass路径没剥掉或剥多了看后端日志或直接curl /api/xxx调整proxy_pass末尾斜杠白屏且Network资源404publicPath/base和部署路径不匹配看index.html里script src路径修改publicPath后重新打包提示跨域前端代码写死了跨域地址看浏览器请求URL改为同源相对路径走Nginx代理上传文件报413client_max_body_size太小看error.log里有413加大client_max_body_size后端看到所有请求IP都是127.0.0.1缺少X-Forwarded-For配置后端打印remoteAddr确认补proxy_set_header配置配置改完没生效没reload或语法错误nginx -t 后 nginx -s reload修正语法后reload4.2 排查三板斧curl、日志、nginx -t遇到线上问题别慌按顺序来。第一板斧是 curl。页面打不开先curl -I http://127.0.0.1看服务是否活着接口报错先curl http://127.0.0.1/api/user/list看返回内容。curl 能直接还原请求行为比浏览器缓存里的结果可靠得多。第二板斧是看日志。Nginx 的访问日志和错误日志在/var/log/nginx/下常见的是 access.log 和 error.log。用tail -f /var/log/nginx/error.log持续观察任何配置或路径问题都会在这里留下线索。比如 404 会显示文件路径502 会显示上游连接失败这些信息对定位问题至关重要。第三板斧是nginx -t。改完配置第一时间执行语法错误会直接告诉你。很多人图省事改完直接 reload结果带着错误配置上线整个站点直接不可用。这个习惯必须养好。另外补充一个点Nginx 在 HTTP 层转发时客户端的 TCP 五元组信息不会原样透传给后端后端看到的源 IP 默认是 Nginx 所在机器的内网 IP。如果需要真实客户端 IP必须依赖X-Forwarded-For、X-Real-IP这些头部这也是速查表里那一条配置存在的意义。4.3 一台服务器部署多个Vue项目的两种姿势实际工作里一台服务器上挂好几个前端项目是很常见的事。有两种主流方案。第一种不同端口。每个项目一个 server 块listen 不同的端口server { listen 8081; root /var/www/app1; location / { try_files $uri $uri/ /index.html; } } server { listen 8082; root /var/www/app2; location / { try_files $uri $uri/ /index.html; } }这种方式配置简单项目隔离干净但每个项目都要占一个端口访问时要带上端口号。第二种同端口不同子路径。所有项目共用一个 80 端口然后用 location 区分。这种方式部署时Vue 打包的 publicPath 必须和子路径一致比如项目A打包时设置publicPath/app1/项目B设置publicPath/app2/。Nginx 配置有点像这样location /app1/ { alias /var/www/app1/; index index.html; try_files $uri $uri/ /app1/index.html; } location /app2/ { alias /var/www/app2/; index index.html; try_files $uri $uri/ /app2/index.html; }这里必须注意 root 和 alias 的区别。root 会把 location 后面的路径拼在 root 后面alias 则直接用 alias 指定的路径替换掉 location 匹配的部分。子路径部署最怕 alias 写错目录对不上就全是404。我自己的经验是子路径部署尽量用 alias路径映射关系一眼就能看清。4.4 顺手就做的性能与安全小优化部署上线不等于结束以下几个配置我一般会顺手加上。开启 gzip 压缩减少传输体积对前端项目收益明显gzip on; gzip_types text/css application/javascript application/json image/svgxml; gzip_min_length 1k; gzip_vary on;静态资源缓存。打包后的文件通常带 hash内容一变文件名就变非常适合强缓存。上面模板里location /assets/的expires 7d就是这个思路。需要注意index.html 本身不能做强缓存否则发新版后用户加载的还是旧 HTML。加client_max_body_size 20m;放在 http 或 server 层避免上传功能出现 413。默认值只有 1m做文件上传的项目不加大必踩坑。加server_tokens off;隐藏 Nginx 版本号减少被扫描的风险。这算是最基础的安全加固了。还有个冷门但实用的经验如果项目里有 m3u8 这类视频流播放需求Nginx 默认 MIME type 可能不认这些格式浏览器会拒绝播放。需要在 location 里加上对应的 types比如application/vnd.apple.mpegurl m3u8; video/mp2t ts;。这类问题平时不好遇到但真遇到时排查方向就对了。我个人把部署经验总结为一句话配置 Nginx 不是背指令而是搞清楚一个 URL 请求进来Nginx 怎么一步步找到文件和转发请求。把 location 优先级、try_files 兜底、proxy_pass 的路径替换这三件事理解透Vue 项目部署里 80% 的问题都能解决剩下 20% 大多能在 error.log 里找到答案。最后再分享一个小习惯每次改完配置文件一定要先nginx -t再nginx -s reload别嫌麻烦。有一次我图快直接 reload结果配置里 root 目录写错整个站点直接 502那次教训到现在我都记着。部署这件事稳比快重要得多。