PHP与Vue前后端分离项目的生产环境部署实战指南(Nginx + Docker + CI/CD)
目录导读
- 为什么需要关注PHP+Vue的部署架构?
- 部署前的核心认知:动态接口与静态资源的边界
- 经典Nginx反向代理(同域名部署)
- Docker容器化独立部署(高可用)
- 环境变量与API地址的动态切换(前端构建的坑)
- 常见故障排查(404、跨域、Session失效)
- 高频问答(FAQ)与面试知识点
为什么需要关注PHP+Vue的部署架构?

很多开发者本地开发时使用php artisan serve或npm run dev,一路顺畅,但一到线上服务器就崩溃,核心原因在于:PHP(Laravel/ThinkPHP等)是服务端渲染动态脚本,而Vue是客户端静态资源,它们本质上是两套运行机制,部署时必须明确分离:
- PHP代码运行在
php-fpm进程中,处理/api路由、数据库交互。 - Vue构建后生成纯静态的
index.html、JS、CSS,需要Web服务器(Nginx/Apache)直接读取。
若不做特殊处理,用户访问域名根路径时,Nginx会优先去找index.html,然后Vue路由跳转/user/1时,Nginx又去请求PHP找不到对应文件,直接404,这就是部署混乱的根源。
部署前的核心认知:动态接口与静态资源的边界
在写任何配置前,先在Vue项目里确定所有请求PHP的URL前缀,通常为/api。axios.get('/api/user/info'),部署时唯一的目标就是:Nginx将所有/api开头的请求转发给PHP-FPM,其余所有请求返回Vue的index.html。
方案一:经典Nginx反向代理(同域名部署)
这是中小项目最推荐的方案,不涉及跨域,且配置简单,假设你的域名是https://example.com,服务器目录结构如下:
/var/www/project/
├── backend/ # PHP代码(Laravel)
└── frontend/ # Vue打包产物
├── index.html
└── static/
Nginx核心配置(/etc/nginx/sites-available/project.conf):
server {
listen 80;
server_name example.com;
# 1. Vue静态资源根目录
root /var/www/project/frontend;
index index.html;
# 2. 关键:处理Vue History模式路由(避免404)
location / {
try_files $uri $uri/ /index.html;
}
# 3. 动态API转发给PHP-FPM(Laravel)
location /api {
alias /var/www/project/backend/public;
try_files $uri @backend;
# 或者更标准的方式:
# rewrite ^/api/(.*)$ /$1 break;
# 然后转发到fastcgi
}
location @backend {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/project/backend/public/index.php;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
# 4. 禁止访问隐藏文件
location ~ /\.ht { deny all; }
}
部署步骤:
- 前端执行
npm run build,将dist拷贝到frontend/。 - 后端执行
composer install --no-dev,确保.env配置了APP_URL=https://example.com。 - 重启Nginx和PHP-FPM。
重点陷阱: Laravel的public/目录下必须有.htaccess(Apache)或依赖Nginx的try_files逻辑,若使用alias方式,务必注意SCRIPT_FILENAME的路径计算。
方案二:Docker容器化独立部署(高可用)
对于微服务架构或需要水平扩展的场景,建议将PHP和Nginx(Vue静态文件)拆成两个容器,通过Docker Compose编排。
docker-compose.yml核心服务示例:
version: '3.8'
services:
backend:
image: php:8.2-fpm
volumes:
- ./backend:/var/www/html
environment:
- DB_HOST=mysql
networks:
- app-network
frontend:
image: nginx:alpine
volumes:
- ./frontend/dist:/usr/share/nginx/html:ro
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
ports:
- "8080:80"
depends_on:
- backend
networks:
- app-network
nginx.conf(容器内)关键配置:
location /api {
proxy_pass http://backend:9000; # 关键:通过容器名访问PHP-FPM
# 注意:不需要fastcgi_pass,这里是用HTTP代理到PHP的内置服务器
# 实际需要将PHP-FPM监听TCP端口(需在PHP容器内改配置)
}
location / {
try_files $uri $uri/ /index.html;
}
注意: 要让PHP-FPM支持TCP访问,需修改php-fpm.d/www.conf:listen = 9000,并注释掉listen = /var/run/php/php-fpm.sock。
优势: 前端服务可挂CDN,后端服务可独立扩容,但需自行处理跨域(如Access-Control-Allow-Origin)。
环境变量与API地址的动态切换(前端构建的坑)
很多前端团队会把API地址写死在axios里,导致每次换环境都要重新构建,解决思路有两种:
- 构建时注入: 在
package.json中设置环境变量VUE_APP_API_BASE,打包时通过--mode staging切换。 - 运行时动态读取: 在Vue的
public/目录下放置一个config.js,里面定义window.API_BASE = 'https://api.example.com',然后在index.html中引入,这样运维只需修改config.js即可,无需重新构建。
常见故障排查
- 刷新页面404: 确保Nginx配置了
try_files $uri $uri/ /index.html;。 - API请求401/Session失效: PHP的
SESSION_DOMAIN必须设置为顶级域名,且Vue请求需携带withCredentials: true。 - 跨域(CORS): 若前后端分离部署不同域名,在Laravel中配置
cors.php,允许allowed_origins为前端域名。
高频问答(FAQ)
Q1:一定要用Nginx吗?Apache可以吗?
A:可以,Apache使用mod_rewrite实现相同效果:RewriteRule ^(.*)$ /index.php [QSA,L]处理Vue路由,ProxyPass /api转发给PHP,但Nginx静态文件性能高出30%以上。
Q2:前端用Hash路由(带)是不是就不用配try_files了?
A:对,Hash路由不向后端发请求,但不利于SEO且URL不美观,强烈建议使用History路由并正确配置服务器。
Q3:如何让Vue的构建产物自动部署到服务器?
A:推荐使用GitHub Actions或GitLab CI,在代码推送时,触发npm run build,然后通过rsync同步到服务器frontend/目录,并执行nginx -s reload。
Q4:PHP端需要开启OPcache吗?
A:需要,生产环境执行php artisan optimize,并在php.ini中开启opcache.enable=1,可提升30%-50%的API响应速度。
部署的本质是理清“谁处理静态文件,谁处理动态请求”,Nginx作为门卫,负责分流;PHP-FPM干活;Vue静态文件则像“一张刻好的光盘”,只需被正确读取,掌握上述方法,无论项目大小,你都能游刃有余地应对线上发布,最后建议:在服务器上先用curl -I https://example.com/user测试路由,再用curl https://example.com/api/health测试接口,两步验证部署是否成功。