部署
把 Laravel 应用部署到生产环境时,有几件事做好了能让应用跑得更稳、更快。这篇带你过一遍关键的部署要点。
服务器要求
Laravel 框架对系统有一定要求。你的 Web 服务器至少要满足以下 PHP 版本和扩展:
- PHP >= 8.3
- Ctype PHP 扩展
- cURL PHP 扩展
- DOM PHP 扩展
- Fileinfo PHP 扩展
- Filter PHP 扩展
- Hash PHP 扩展
- Mbstring PHP 扩展
- OpenSSL PHP 扩展
- PCRE PHP 扩展
- PDO PHP 扩展
- Session PHP 扩展
- Tokenizer PHP 扩展
- XML PHP 扩展
服务器配置
Nginx
如果你把应用部署在 Nginx 上,下面这份配置可以当起点,大概率需要根据你自己的服务器情况调整。想要省心的话,可以考虑用全托管的 Laravel 平台,比如 Laravel Cloud。
注意,像下面配置那样,Web 服务器必须把所有请求都指向应用的 public/index.php 文件。千万别把 index.php 挪到项目根目录——如果从项目根目录对外提供服务,大量敏感配置文件就会暴露到公网:
# ==========================================
# 1. 基础监听和域名
# ==========================================
# 同时监听 IPv4 和 IPv6 的 80 端口
server {
listen 80;
listen [::]:80;
# 换成你自己的域名
server_name yeetu.com;
# ==========================================
# 2. 站点根目录 —— 关键!必须指向 public/
# ==========================================
# public/ 是 Laravel 应用的"前门",只有这里的文件该被外部访问。
# 指向项目根目录会把 .env、composer.json 等敏感文件暴露出去
root /srv/yeetu.com/public;
# ==========================================
# 3. 安全响应头
# ==========================================
# 防止页面被别的站点用 <iframe> 嵌入(防点击劫持)
add_header X-Frame-Options "SAMEORIGIN";
# 禁止浏览器瞎猜 MIME 类型(防 MIME 嗅探攻击)。
# 作用:强制浏览器只认服务器发的 Content-Type,不自作主张"嗅探"文件内容来猜类型。
# 不然攻击者可能把恶意脚本伪装成图片上传,浏览器一嗅探就当脚本执行了
add_header X-Content-Type-Options "nosniff";
# ==========================================
# 4. 默认首页和字符集
# ==========================================
# 访问目录时优先找 index.php
index index.php;
# 统一用 UTF-8,中文不乱码
charset utf-8;
# ==========================================
# 5. 主路由:所有请求先找文件,找不到就给 index.php
# ==========================================
# try_files 逻辑:
# 1) $uri —— 尝试直接访问文件(如 /css/app.css)
# 2) $uri/ —— 尝试目录索引
# 3) /index.php —— 都不存在就交给 Laravel 控制器处理
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# ==========================================
# 6. 静态资源 —— 关掉访问日志,减少磁盘 I/O
# ==========================================
# favicon 和 robots.txt 每个页面都会请求,没必要记日志
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
# ==========================================
# 7. 404 统一交给 Laravel
# ==========================================
error_page 404 /index.php;
# ==========================================
# 8. PHP 处理 —— 通过 FastCGI 转发给 PHP-FPM
# ==========================================
# 匹配 /index.php 及 /index.php/xxx 这种路径
location ~ ^/index\.php(/|$) {
# PHP-FPM 的 socket 地址(版本号换成你装的 PHP 版本)
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
# 告诉 PHP-FPM 要执行哪个文件
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
# 引入 Nginx 默认的 FastCGI 参数(如 QUERY_STRING、REQUEST_METHOD 等)
include fastcgi_params;
# 隐藏响应头里"X-Powered-By: PHP",不暴露技术栈
fastcgi_hide_header X-Powered-By;
}
# ==========================================
# 9. 禁止访问隐藏文件(.env、.git 等)
# ==========================================
# 拒绝所有以 . 开头的文件/目录请求……
# 但放行 /.well-known/(Let's Encrypt 等 ACME 验证需要这个目录)
location ~ /\.(?!well-known).* {
deny all;
}
}
FrankenPHP
也可以用 FrankenPHP 来跑 Laravel 应用。FrankenPHP 是一个用 Go 写的现代 PHP 应用服务器。用 FrankenPHP 跑 Laravel 很简单,一条命令就行:
frankenphp php-server -r public/
如果想用 FrankenPHP 更高级的功能——比如 Laravel Octane 集成、HTTP/3、现代压缩、把 Laravel 应用打包成独立二进制文件——看 FrankenPHP 的 Laravel 文档。
目录权限
Laravel 需要对 bootstrap/cache 和 storage 目录有写入权限,所以确保 Web 服务器进程的用户能写这两个目录。
优化
部署到生产环境时,配置、事件、路由、视图等文件都应该缓存起来。Laravel 提供了一个 optimize Artisan 命令,一次性缓存所有这些文件。通常把它放在部署流程里执行:
php artisan optimize
optimize:clear 命令可以清除 optimize 生成的所有缓存文件,以及默认缓存驱动里的所有 key:
php artisan optimize:clear
下面分别介绍 optimize 命令背后各项具体的优化命令。
缓存配置
部署到生产环境时,记得在部署流程中跑 config:cache 命令:
php artisan config:cache
这条命令会把所有 Laravel 配置文件合并到一个缓存文件里,框架加载配置时就不用频繁读文件系统了,大幅减少磁盘 I/O。
注意
如果在部署流程中跑了 config:cache,注意 env() 函数只能用在配置文件里。配置一旦缓存,.env 文件就不会再被加载,所有在配置文件之外对 env() 的调用都会返回 null。
缓存事件
部署时应该把应用自动发现的事件到监听器的映射缓存起来。在部署流程中跑 event:cache 命令就行:
php artisan event:cache
缓存路由
如果你的应用路由很多,记得在部署流程中跑 route:cache 命令:
php artisan route:cache
这条命令把所有路由注册压缩成缓存文件里的一个方法调用。路由上百条时,注册性能提升很明显。
缓存视图
部署到生产环境时,记得在部署流程中跑 view:cache 命令:
php artisan view:cache
这条命令预编译所有 Blade 视图,不再按需编译,每次返回视图的请求都能快一点。
重启服务
信息
部署到 Laravel Cloud 时不需要手动跑 reload 命令,Cloud 会自动优雅重启所有服务。
部署新版本后,所有长驻进程——比如队列 worker、Laravel Reverb、Laravel Octane——都需要重启,让它们用上新代码。Laravel 提供了 reload Artisan 命令来终止这些服务:
php artisan reload
如果你没用 Laravel Cloud,需要手动配一个进程监控器,让它能感知可重启的进程退出并自动拉起。
调试模式
config/app.php 里的 debug 选项决定了出错时向用户显示多少信息。默认情况下,这个选项会跟 .env 里的 APP_DEBUG 环境变量走。
注意
生产环境中,这个值永远应该是 false。如果生产环境 APP_DEBUG 设成 true,敏感配置值可能暴露给普通用户。
健康检查路由
Laravel 内置了健康检查路由,用来监控应用状态。在生产环境中,可以把这个路由接入 uptime 监控、负载均衡器或 Kubernetes 这类编排系统。
默认情况下,健康检查路由在 /up,应用正常启动(无异常)返回 200,否则返回 500。你可以在 bootstrap/app 文件里自定义这个路由的 URI:
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up', // [tl! remove]
health: '/status', // [tl! add]
)
当有 HTTP 请求打到这个路由时,Laravel 还会派发 Illuminate\Foundation\Events\DiagnosingHealth 事件,让你在事件监听器里做额外的健康检查——比如检查数据库连接、缓存状态。发现问题直接抛异常就行。
在宝塔面板上 部署
安装完宝塔面板后,有以下默认几个路径
/www/wwwroot这里是放代码的地方/www/backup备份的地方/www/server安装软件的地方,比如安装的PHP、nignx、NodeJs、 pgsql等
部署前都需要将代码先放到服务器上
- 通常代码都是通过
git拉取到服务上的,先将SSH公钥放到你git的服务器上,然后通过下面的命令拉取:
cd /www/wwwroot # 进入项目的文件夹
sudo -u www git clone git@xxxx.git # 使用www的账户拉取,因为nignx使用www账户运行的,这样避免权限问题
- 有mysql或pgsql数据库的,提前先建好数据库
纯 Laravel 项目部署
代码拉取到服务器后:
cd /www/wwwroot/laravel-project
cp .env.example .env # 并修改.env中对应的key的value
composer install
php artisan migrate # 有数据迁移的,先迁移
php artisan storage:link # 如果有本地的资源文件
php artisan optimize # 缓存配置文件、事件、路由、视图
然后进入宝塔面板,在网站 -> PHP项目下 点击添加站点:

创建完后,点击设置 -> 网站目录, 将运行目录指向到 /public

在伪静态中,添加下面的配置
location / {
try_files $uri $uri/ /index.php?$query_string;
}

这样纯 laravel 站的部署就完成了。
Laravel + vue + Nuxt 开发的项目部署
前后端分离的项目部署
如果项目是前后端分离的,接口是用Laravel开发的, 后台的前端 admin 使用vite+vue 开发的, 前台的前端fronted 是用nuxt 开发的,要使用同一个域名,比如:
https://d.yeetu.com这里访问nuxt开发的fronted的前端项目https://d.yeetu.com/api这里访问Laravel开发的后端接口https://d.yeetu.com/admin这里访问vue开发的后端前台项目
先把代码拉到服务器,接口按上面的跑完命令,前端项目都打包好,打包后项目的结构如下:
server # 接口
-- public
admin # 后台
-- dist
fronted # 前台
-- .output
---- server
------ index.mjs
在宝塔面板上,网站 -> php项目 -> 添加站点

创建完后,网站目录和伪静态都不需要填写,我们都用不到 直接打开配置文件,按下面的改写:
server
{
...
# Laravel API:/api/* 交给 php-fpm(不变)
location ^~ /api/ {
root /www/wwwroot/yeetu/server/public; # 这里改成你laravel项目的public地址
try_files $uri $uri/ @laravel;
}
location @laravel {
root /www/wwwroot/yeetu/server/public; # 这里也改成laravel项目的public地址
fastcgi_pass unix:/tmp/php-cgi-85.sock; # 这里是你运行的php版本
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
}
# Laravel 公开磁盘(不变)
location ^~ /storage/ {
alias /www/wwwroot/yeetu/server/storage/app/public/; # 这里改成larvel资源文件的路径
}
# admin 后台(Vite + Vue 静态 SPA)
location /admin/ {
alias /www/wwwroot/yeetu/admin/dist/;
try_files $uri $uri/ /admin/index.html;
index index.html;
# 静态资源长缓存(带 hash 的文件名,放心缓存)
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
alias /www/wwwroot/yeetu/yeetu-dedoc/admin/dist/;
expires 1y;
add_header Cache-Control "public, immutable";
}
}
# 这里是 fronted 的,全部反代到 Nuxt Node 进程(SSR)
location / {
proxy_pass http://127.0.0.1:3000;
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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
...
}
接着在宝塔面板上点击Node项目,然后选择 pm2项目

这里的环境变量如下:
NITRO_PORT=3000 # 端口号,要对应之前nignx的配置
NITRO_HOST=127.0.0.1 # 只监听本机回环地址,要和之前的nginx那边对应
NUXT_PUBLIC_API_BASE=/api # 前端代码里发 API 请求的根地址。NUXT_PUBLIC_ 前缀表示这个变量会打包进客户端代码,浏览器能直接读到
NUXT_PUBLIC_SITE_URL=https://d.yeetu.com # 站点完整 URL,Nuxt 生成 SEO 标签(canonical、og:url 等)时用
好了, 这样就配置完成了。