第 18 章 部署 + 性能 + 安全(教程收官)
本章定位:把
playground/这种"开发环境跑得欢"的项目变成生产可用所需的全部知识。不是单点教程——本章覆盖部署 / 配置 / 性能 / 安全 / 监控 / dev 包清理6 个维度。
教程整体收官:本章末尾给出 18 章成稿后的"教程整体回顾"+ 致谢。
0. 序章:从开发到生产的 6 道关
"我的项目能跑了" ≠ "我的项目能上线"
考虑你刚做完前 17 章的 playground/ 项目:
✓ 63 个 Pest 测试 passed
✓ 浏览器访问 / /posts /admin 都看得到东西
✓ 队列、API、后台都跑通→ 但这离生产还有 6 道关:
开发环境
│
▼
[1] 部署 ─────► 选 Forge / Vapor / Cloud / 自建?
│
▼
[2] 配置 ─────► 14 项检查(APP_DEBUG / 缓存 / HTTPS / 时区...)
│
▼
[3] 性能 ─────► OPcache / config:cache / Octane / Eager load
│
▼
[4] 安全 ─────► CSRF / SQL注入 / Rate Limit / 密钥管理
│
▼
[5] 监控 ─────► Horizon / Telescope / Sentry / Logs
│
▼
[6] dev 包清理 ─► Boost / Pail / Sail 不应该上生产
│
▼
生产环境(真实用户访问)→ **每一道关都是"开发环境 OK 但生产会爆"**的潜在踩坑点。
这一章解决什么
| 问题 | 答案在第几节 |
|---|---|
| 我应该选哪个部署平台? | §1 |
| 上线前必检的配置项有哪些? | §2 ⭐ |
| 怎么让 Laravel 跑得快? | §3-§4 |
| 怎么防住常见安全攻击? | §5 |
| 出了 bug 怎么追? | §6 |
| Boost 是 dev 包,怎么处理? | §7 |
| 一步步部署 playground 到生产 | §8 |
→ 本章读完,你的 playground 可以真的开放给真实用户用。
1. 部署方案选型(4 个候选)
4 个候选
| # | 方案 | 类型 | 推荐度 | 月成本起点 |
|---|---|---|---|---|
| 1 | Laravel Forge | 托管 | ⭐⭐⭐⭐⭐ | $12(Forge 订阅)+ $5(VPS) |
| 2 | Laravel Vapor | Serverless(AWS Lambda) | ⭐⭐⭐⭐ | $39 起 + AWS 用量 |
| 3 | Laravel Cloud | 全托管(2025 推出) | ⭐⭐⭐⭐ | $0 试用 + 按量 |
| 4 | 自建 VPS(手撸) | 完全自管 | ⭐⭐ | $5(如腾讯云轻量) |
1. Laravel Forge(最常见选择)
一句话:Forge 是"在你的 VPS 上自动配置 Nginx + PHP + MySQL + Redis 的服务"。
它做什么:
- 你买一台 VPS(DigitalOcean / Linode / Hetzner / 腾讯云 / 阿里云都行)
- Forge 远程登录帮你装 Nginx / PHP 8.2 / MySQL / Redis / Supervisor / Certbot
- 你点击 "Deploy" 它自动
git pull + composer install + migrate + queue restart
适合:
- 单 VPS / 小团队 / SaaS 早期
- 想要"全托管 + 灵活定制"
- 不想自己学 Nginx / PHP-FPM 调优
踩坑:
- 国外 VPS(DigitalOcean 等)国内访问慢——用 CloudFlare 或选香港/新加坡机房
- Forge 不替你选 PHP 版本——确保点 Server → "PHP" 装 8.2/8.3
- 队列要在 Forge 的 Daemon 配置里开,不要在 ssh 里 nohup——重启会丢
2. Laravel Vapor(Serverless)
一句话:把 Laravel 部署到 AWS Lambda + RDS + S3。
它做什么:
- 把你的应用打包成 Lambda 函数
- HTTP 请求、队列 Worker、定时任务都在 Lambda 上跑
- 自动伸缩,按请求计费
适合:
- 流量波动大(白天高峰、夜里低谷)
- 不想运维服务器
- 团队熟悉 AWS 生态
踩坑:
- 冷启动——第一次请求可能 2-3 秒(用 Lambda Provisioned Concurrency 解决,但贵)
- 文件存储必须用 S3(Lambda 文件系统是临时的)
- SQLite 不能用,必须用 RDS / DynamoDB
- 国内用户不要选 Vapor——AWS 中国区不支持 Vapor,要用海外 region 网络损耗大
3. Laravel Cloud(2025 推出,全托管)
一句话:Vercel for Laravel ——
vercel deploy那种体验,但是给 Laravel 的。
它做什么:
- 你 push 代码,它自动部署
- 自动配 PostgreSQL / Redis / S3-like storage
- 自动 HTTPS / CDN / 队列 / 定时任务
适合:
- 不想运维任何东西
- 单仓 + 简单架构
- 早期项目快速上线
踩坑:
- 2025 年还在快速迭代——某些复杂场景可能不支持
- 数据库锁定 PostgreSQL(如果你执着 MySQL,选 Forge)
4. 自建 VPS(手撸 Nginx + PHP-FPM)
一句话:最便宜、最灵活、最累。
适合:
- 国内服务器(Forge 不太完美支持国内 VPS)
- 想完全控制
- 团队有 DevOps 能力
最小命令清单(参考):
# 1. 装环境
sudo apt install nginx php8.2-fpm php8.2-cli php8.2-mysql php8.2-redis \
php8.2-mbstring php8.2-xml php8.2-curl php8.2-zip \
mysql-server redis-server supervisor certbot
# 2. 配置 Nginx(参考 Laravel 官方文档)
sudo nano /etc/nginx/sites-available/playground
# 3. HTTPS(Certbot 一键)
sudo certbot --nginx -d your-domain.com
# 4. 部署
git clone ... && cd ... && composer install --no-dev --optimize-autoloader
cp .env.example .env && php artisan key:generate && php artisan migrate --force
# 5. 队列 Worker(用 Supervisor 守护)
sudo nano /etc/supervisor/conf.d/laravel-queue.conf
sudo supervisorctl reread && sudo supervisorctl update踩坑:
- Nginx 配置写错 → 502
- PHP-FPM 不重启 → 代码不生效
- Worker 没用 Supervisor → 服务器重启后队列死
- 忘配 HTTPS → 浏览器不让用 service worker / cookie secure
选型决策树
┌─────────────────────────────────────┐
│ 你团队会运维吗? │
└────────┬────────────────────┬───────┘
│ 会 │ 不会
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ 流量波动大吗? │ │ 用 Laravel Cloud │
└────┬─────────┬───┘ │ (2025 起) │
│ │ └──────────────────┘
│ 是 │ 否
▼ ▼
┌──────┐ ┌──────────┐
│Vapor │ │ Forge ⭐ │
└──────┘ └──────────┘
│
▼
┌──────────────┐
│ 国内服务器? │
└──┬───────┬───┘
│ 是 │ 否
▼ ▼
┌──────┐ ┌──────────┐
│自建 │ │Forge + 国 │
│ VPS │ │外 VPS │
└──────┘ └──────────┘→ 本教程的推荐:新项目用 Forge(学习曲线低 + 灵活),国内项目自建 VPS(合规 + 速度)。
2. 生产环境配置 14 项检查清单 ⭐
这一节是整章最值的一节——14 项检查,每项都是"开发期 OK 上线会爆"的真实风险。 部署前逐项过一遍,能避免 80% 的生产事故。
检查清单
| # | 项 | 开发期 | 生产期 | 命令 / 方法 |
|---|---|---|---|---|
| 1 | APP_ENV | local | production | .env 改 + 不进 git |
| 2 | APP_DEBUG | true | false | 否则错误页泄露代码 |
| 3 | APP_KEY | dev key | 生成新的 | php artisan key:generate |
| 4 | APP_URL | http://127.0.0.1:8000 | https://yourdomain.com | 影响邮件链接、绝对 URL |
| 5 | APP_TIMEZONE | UTC 或本地 | 明确设置 | Asia/Shanghai 或 UTC(推荐 UTC) |
| 6 | LOG_LEVEL | debug | error 或 warning | 否则日志爆炸 |
| 7 | LOG_CHANNEL | stack | daily + cron 删旧 | 防磁盘爆 |
| 8 | DB_CONNECTION | sqlite | mysql / pgsql | SQLite 生产并发会锁(见 15 章) |
| 9 | QUEUE_CONNECTION | sync 或 database | redis | 性能 + 失败重试 |
| 10 | CACHE_STORE | database 或 file | redis | 性能 |
| 11 | SESSION_DRIVER | database | redis | 同上 |
| 12 | MAIL_MAILER | log | 真实 SMTP / Resend / SES | 否则邮件不发 |
| 13 | BROADCAST_CONNECTION(如用) | null | pusher / reverb | 用 WebSocket 时 |
| 14 | SANCTUM_STATEFUL_DOMAINS(如 SPA) | localhost | 生产域名 | API 跨域时 |
部署前一键检查脚本
把下面这段保存为 bin/preflight-check.sh:
#!/bin/bash
set -e
echo "=== Laravel Preflight Check ==="
php artisan tinker --execute="
echo 'APP_ENV: ' . config('app.env') . PHP_EOL;
echo 'APP_DEBUG: ' . (config('app.debug') ? 'TRUE ⚠️' : 'false ✓') . PHP_EOL;
echo 'APP_URL: ' . config('app.url') . PHP_EOL;
echo 'DB_CONNECTION: ' . config('database.default') . PHP_EOL;
echo 'QUEUE: ' . config('queue.default') . PHP_EOL;
echo 'CACHE: ' . config('cache.default') . PHP_EOL;
echo 'SESSION: ' . config('session.driver') . PHP_EOL;
echo 'MAIL: ' . config('mail.default') . PHP_EOL;
echo 'LOG: ' . config('logging.default') . '/' . config('logging.channels.single.level', 'n/a') . PHP_EOL;
"
echo ""
echo "Migrations status:"
php artisan migrate:status | tail -10→ 部署时跑一次,眼睛过一遍,红色 ⚠️ 项必修。
5 个最容易踩的"配置坑"
坑 1:APP_DEBUG=true 上了生产 ❌
后果:访问任何报错页面,Laravel 完整堆栈跟踪会显示给攻击者——含数据库密码、API key、文件路径。 修复:APP_DEBUG=false,错误用 Sentry 等工具收集。
坑 2:APP_KEY 没改 ❌
后果:所有加密的数据(cookie、session、Crypt::encrypt)用的是默认 dev key——任何人都能解密。 修复:上线前 php artisan key:generate,然后 --force 写到 .env。
坑 3:SQLite 上了生产 ❌
后果:用户多了立刻撞 database is locked(参考第 15 章 §8 我们已经经历过)。 修复:MySQL 8.0 / PostgreSQL 16+。
坑 4:QUEUE_CONNECTION=sync 上了生产 ❌
后果:用户提交表单转圈圈到天荒地老(同步发邮件等)。 修复:QUEUE_CONNECTION=redis + 跑 worker 进程(见 §6)。
坑 5:LOG_LEVEL=debug 上了生产 ❌
后果:每次请求写 100KB 日志——1 周磁盘爆。 修复:LOG_LEVEL=error + LOG_CHANNEL=daily + 配 cron 自动删 30 天前的日志。
部署后的 4 个性能缓存命令
php artisan config:cache # 缓存配置(启动快)
php artisan route:cache # 缓存路由(启动快)
php artisan view:cache # 编译所有 Blade
php artisan event:cache # 缓存 event 监听或一键:
php artisan optimize # 等同上面 4 条⚠️ config:cache 后:所有 .env 修改不再生效——必须 optimize:clear 才能重新读 .env。
→ 生产部署流程的标准模式:
# Forge 自动跑的"deploy 钩子"通常是:
git pull origin main
composer install --no-dev --optimize-autoloader
php artisan migrate --force
php artisan optimize
php artisan queue:restart3. 性能优化的 4 个层级
Laravel 性能优化按"投入产出比"分 4 层。先解决底层,再向上。
4 层架构
┌──────────────────────────────────────────┐
│ 4. 进程层(Octane / FrankenPHP) │ ⚡⚡⚡⚡ 最快但最复杂
│ → 5x 性能(不重新 boot 框架) │
├──────────────────────────────────────────┤
│ 3. 框架层(cache / session / queue) │ ⚡⚡⚡
│ → 用 Redis 替换 file/database │
├──────────────────────────────────────────┤
│ 2. 应用层(Eager Load / 索引 / OPcache) │ ⚡⚡
│ → 防 N+1 + 慢 SQL + PHP 编译缓存 │
├──────────────────────────────────────────┤
│ 1. 配置层(config:cache / route:cache) │ ⚡
│ → 启动 boot 时间从 100ms 降到 10ms │
└──────────────────────────────────────────┘第 1 层:配置缓存(5 分钟搞定)
php artisan optimize收益:每个请求的"框架 boot 时间"从 ~100ms 降到 ~10ms。
→ 部署 hook 必跑。
第 2 层:应用层
2.1 防 N+1(最高优先级)
// 开发期开启检测
Model::preventLazyLoading(! $this->app->isProduction());→ 任何 lazy load 直接抛异常,强制你 eager load。
// ❌
Post::all()->each(fn ($p) => $p->author->name); // N+1
// ✓
Post::with('author')->get();→ 实证:第 13 章 §7——AI 在 Boost 加持下主动加 with('author')。
2.2 数据库索引
5 个最值得加的索引:
// 外键(Laravel 自动加)
$table->foreignId('user_id')->constrained();
// 经常搜索的字段
$table->string('slug')->unique(); // unique 索引
$table->index('published_at'); // 普通索引
// 复合索引(按业务查询模式)
$table->index(['user_id', 'created_at']); // 用户+时间排序
// 部分索引(PostgreSQL)
// 类似 "未删除的活跃用户" 之类2.3 OPcache(PHP 字节码缓存)
php.ini 配置:
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0 ; 生产环境关,重启 PHP-FPM 才更新代码→ Laravel 同样的代码有了 OPcache 比没有快 2-3 倍。
⚠️ opcache.validate_timestamps=0 后,部署完必须 sudo systemctl reload php8.2-fpm 让 OPcache 重读代码。
第 3 层:框架层
3.1 Redis 替换 file/database
CACHE_STORE=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis→ 同样的工作量,Redis 比 file 快 10-100 倍。
Redis 内存预算:
| 应用规模 | 推荐 Redis 内存 |
|---|---|
| 小 SaaS(< 1万 DAU) | 256 MB |
| 中等(1-10万 DAU) | 1-4 GB |
| 大(10万+ DAU) | 8 GB+ |
3.2 Cache 业务数据
// ❌ 每次请求都查 DB
$config = AppConfig::first();
// ✓ 缓存 1 小时
$config = Cache::remember('app:config', 3600, fn () => AppConfig::first());
// ✓ 永久缓存 + 显式失效
$config = Cache::rememberForever('app:config', fn () => AppConfig::first());
// 配置改的时候 Cache::forget('app:config')3.3 Tag 化失效(Redis 才支持)
Cache::tags(['posts', 'user:'.$userId])->put('user-posts', $posts, 3600);
// 用户改了任何一篇文章
Cache::tags(['user:'.$userId])->flush();第 4 层:进程层(Octane)
详见下一节 §4。
性能优化的"黄金顺序"
1. 先做 §2.1 防 N+1(成本最低,收益最大)
2. 再做 §1 config:cache(5 分钟一次性)
3. 再做 §2.2 索引(按慢 SQL 来)
4. 再做 §3.1 Redis(中规模时切)
5. 最后才考虑 §4 Octane(已经优化到瓶颈再上)→ 不要倒着做——很多人一上来就装 Octane,发现 N+1 还在,提速没感觉。
4. Octane 实战(Swoole / FrankenPHP)
Octane 是什么
一句话:让 Laravel 应用 boot 一次后常驻内存——后续请求不重新 boot 框架。
对比:
| 模式 | 每个请求的 boot 时间 | 性能 |
|---|---|---|
| 传统 PHP-FPM | ~50-100ms boot | 1x |
| Octane + Swoole | ~0ms boot(已驻留) | 5-10x |
| Octane + FrankenPHP | ~0ms boot | 5-10x |
→ Octane 的本质是把 Laravel 应用变成长进程 server,类似 Node.js 那种模式。
选哪个 driver?
| Driver | 特点 | 推荐场景 |
|---|---|---|
| Swoole | 老牌,稳定,C 扩展 | 国内 SaaS(PECL 安装方便) |
| RoadRunner | Go 写的,单二进制 | DevOps 倾向 |
| FrankenPHP | 2024 新秀,Caddy 生态 | 现代项目(推荐) |
→ 本节用 FrankenPHP 演示(最新最简单)。
装 FrankenPHP(5 分钟)
# 1. 装 Octane + FrankenPHP
composer require laravel/octane --dev
php artisan octane:install --server=frankenphp
# 2. 启动(开发期)
php artisan octane:start --server=frankenphp --port=8000
# 3. 启动(生产,含监听)
php artisan octane:start --server=frankenphp \
--host=0.0.0.0 \
--port=8000 \
--workers=4 \
--max-requests=500Octane 的 4 个"陷阱"
陷阱 1:单例污染 ⚠️
传统 PHP:每个请求一个全新进程,单例对象互不干扰。 Octane:进程常驻,单例可能跨请求共享。
// ❌ 危险
class StatsService {
public array $cache = [];
public function record($event) {
$this->cache[] = $event; // 跨请求累积,最终 OOM
}
}
// ✓ 安全
public function record($event) {
Cache::increment("stats:$event"); // 用外部 store
}陷阱 2:Container 对象在请求间没自动重置
修复:在 config/octane.php 配置 flush 列表,每个请求开始前重置某些单例:
'flush' => [
\App\Services\StatsService::class,
],陷阱 3:内存泄漏
症状:跑几小时后 worker 内存涨到几 GB。 修复:--max-requests=500——每个 worker 处理 500 个请求自动重启。
陷阱 4:调试更难
dd() 输出会进入 worker 日志,不是直接给浏览器——用 Telescope / Log::debug 替代。
Octane 的 ROI
| 维度 | 数字 |
|---|---|
| 性能提升 | 5-10x(针对 Laravel 应用层瓶颈) |
| 配置成本 | 1-2 小时(学习单例陷阱) |
| 持续维护 | 需要监控内存(不像 FPM 那样省心) |
推荐时机:
- ✓ 你的应用 P99 响应时间 > 500ms 且已经做完 §3 所有优化
- ❌ 应用还有 N+1 / 慢 SQL —— 先解决底层
- ❌ 团队没人懂"长进程 PHP" —— 先培训
→ 大多数 SaaS 项目在没装 Octane 也能轻松扛 1万 DAU。不必神话 Octane。
5. 安全加固 10 大项
这一节列出 Laravel 项目最容易被攻击的 10 个面 + 对应防护。
1. CSRF(Laravel 默认开,别关)
// resources/views/layouts/app.blade.php
<meta name="csrf-token" content="{{ csrf_token() }}">
<form method="POST">
@csrf <!-- 必须 -->
...
</form>→ POST/PUT/DELETE 不带 CSRF token → 419 Page Expired。
⚠️ API 路由不需要 CSRF(用 token 认证)——但 web 路由必须有。
2. SQL 注入(Eloquent / Query Builder 默认安全)
// ✓ 安全(参数化)
User::where('email', $email)->first();
DB::table('users')->where('email', $email)->first();
// ❌ 危险(直接拼 SQL)
DB::select("SELECT * FROM users WHERE email = '$email'");
// ⚠️ 需小心(whereRaw)
User::whereRaw("email = '$email'"); // ❌
User::whereRaw('email = ?', [$email]); // ✓ 参数化→ 80% 的 SQL 注入来自 whereRaw / DB::statement 拼字符串。
3. XSS(Blade {{ }} 默认 HTML 转义)
{{ $user_input }} <!-- ✓ 自动转义 -->
{!! $user_input !!} <!-- ❌ 危险(除非你 100% 确定来源) -->→ 需要输出 HTML(如富文本)时用 Str::sanitizeHtml($content)(需装 mews/purifier 或类似包)。
4. Mass Assignment(Eloquent $fillable 必写)
class User extends Model {
protected $fillable = ['name', 'email']; // ⭐ 显式白名单
// 不在 fillable 里的字段(如 is_admin)无法批量赋值
}
// 攻击场景
User::create($request->all()); // 安全 — is_admin 不在 fillable,攻击者传 is_admin=1 无效→ 永远不要写 protected $guarded = [](关闭保护)—— 这是 mass assignment 漏洞最大来源。
5. Rate Limiting(防暴力破解 + 防爬虫)
// routes/api.php
Route::middleware('throttle:60,1')->group(function () {
// 每分钟 60 次
});
// 登录路由(防暴力)
Route::post('/login', ...)->middleware('throttle:5,1'); // 5 次/分钟自定义 Limiter(更细粒度):
// app/Providers/AppServiceProvider.php boot()
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(60)
->by($request->user()?->id ?: $request->ip())
->response(fn () => response()->json(['message' => 'Too many requests'], 429));
});6. HTTPS(强制 + HSTS)
// app/Providers/AppServiceProvider.php boot()
if ($this->app->isProduction()) {
URL::forceScheme('https');
}# Nginx
server {
listen 443 ssl http2;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# ...
}→ Forge / Cloud / Vapor 自动配 HSTS。自建要手加。
7. Session / Cookie 安全
SESSION_SECURE_COOKIE=true # 仅 HTTPS 才发送 cookie
SESSION_HTTP_ONLY=true # JS 不能读 cookie(防 XSS 偷 session)
SESSION_SAME_SITE=lax # 防 CSRF(Laravel 默认 lax)8. Sanctum / 密码安全
// 密码必须 hashed(cast 自动)
protected function casts(): array {
return ['password' => 'hashed']; // ⭐ Laravel 11+ 自动 bcrypt
}
// Token 撤销
$user->currentAccessToken()->delete(); // ⭐ 仅当前设备
$user->tokens()->delete(); // 全部撤销(账号被盗时)9. 密钥管理(不要进 git)
.env ❌ 必须 .gitignore
.env.example ✓ 进 git(无敏感值,写"DB_PASSWORD=")
config/services.php ⚠️ 用 env() 读密钥,不要硬编码→ 生产环境的 .env 由部署平台(Forge / Vapor / Cloud)管理,不放 git 里。
10. 生产 PHP 配置
php.ini 生产配置:
expose_php = Off # 不在 HTTP 头泄露 PHP 版本
display_errors = Off # 不在响应里显示错误
log_errors = On # 错误写日志
allow_url_fopen = Off # 防 SSRF
allow_url_include = Off # 防 RFI
disable_functions = exec,passthru,shell_exec,system # 限制危险函数安全自检清单
| # | 检查项 | 命令 / 方法 |
|---|---|---|
| 1 | APP_DEBUG=false | 看 .env |
| 2 | APP_KEY 已重新生成 | 看 .env(不是 dev key) |
| 3 | 数据库密码足够强 | 至少 16 字符 |
| 4 | HTTPS 强制 + HSTS | 浏览器看 https + curl -I yourdomain.com 看 HSTS 头 |
| 5 | Rate Limit 已配 | php artisan route:list --middleware=throttle |
| 6 | .env 没进 git | git ls-files 不应有 .env |
| 7 | 所有 Eloquent 模型有 $fillable | grep class.*extends Model 后看 |
| 8 | 所有 Form Request 有 authorize() | 不要 return true 当万能开关 |
| 9 | OpCache 启用 + 验证关闭 | php -i | grep opcache |
| 10 | 错误日志监控(Sentry 等) | 见 §6 |
6. 监控、日志、错误追踪
监控的 4 个层次
┌──────────────────────────────────────────────┐
│ 4. 业务监控(DAU、注册、订单) │
│ 工具:自建 Dashboard / Grafana │
├──────────────────────────────────────────────┤
│ 3. 错误追踪(异常、堆栈、用户上下文) │
│ 工具:Sentry / Bugsnag │
├──────────────────────────────────────────────┤
│ 2. 应用监控(响应时间、慢查询、队列健康) │
│ 工具:Telescope(dev)/ Horizon(队列)/ │
│ New Relic / Datadog(APM) │
├──────────────────────────────────────────────┤
│ 1. 基础设施(CPU、内存、磁盘、连接数) │
│ 工具:Forge / Cloud 自带 / Prometheus │
└──────────────────────────────────────────────┘4 个必装工具
1. Sentry(错误追踪)
composer require sentry/sentry-laravel
php artisan sentry:publish --dsn=https://xxx@sentry.io/xxx→ 任何 PHP 异常 / Job 失败 / 5xx 都自动上报 Sentry,含完整堆栈 + 用户 ID + 请求 URL。
对比 ThinkPHP:你大概率用 try/catch + Log::error 自己拼——Sentry 是这种活的工业化解决方案。
2. Horizon(队列监控)
仅当 QUEUE_CONNECTION=redis 才有效:
composer require laravel/horizon
php artisan horizon:install
php artisan horizon # 替代 queue:work→ 浏览器访问 /horizon:
- 实时看队列任务速率
- 看失败 job 详情 + retry
- 看每个 queue 的延迟
- 看每个 worker 的内存
→ 实证:15 章 §11——推荐生产用 Horizon 替代手工跑 queue:work。
3. Telescope(开发期 + staging 调试器)
composer require laravel/telescope --dev
php artisan telescope:install
php artisan migrate→ 浏览器访问 /telescope 看到:
- 所有 HTTP 请求 + payload + 响应时间
- 所有 SQL 查询 + bindings + 执行时间
- 所有 Job dispatch / 处理 / 失败
- 所有缓存读写
- 所有 mail 发送
⚠️ 生产环境慎装——Telescope 会记录大量数据,可能写满磁盘 + 性能拖慢。 正确做法:装在 staging 环境,生产只装 Horizon。
4. Pail(实时日志流)
composer require laravel/pail --dev
php artisan pail→ 实时彩色显示 storage/logs/laravel.log——比 tail -f 友好。
⚠️ 也是 dev 包——生产用 LogStash / Datadog Logs / Loki 等流式日志收集。
日志最佳实践
1. 配 daily 通道 + 自动清理
LOG_CHANNEL=daily
LOG_DAILY_DAYS=30 # 保留 30 天→ Laravel 12 默认每天一个文件 storage/logs/laravel-2026-05-08.log。
2. 结构化日志(JSON)
// 在 Job / Controller 里
logger()->info('Order placed', [
'order_id' => $order->id,
'user_id' => auth()->id(),
'total' => $order->total,
]);→ JSON 格式更适合 LogStash / Datadog 解析。
3. 别把敏感信息写日志
// ❌ 危险
logger()->info('User login', ['email' => $user->email, 'password' => $password]);
// ✓ 安全
logger()->info('User login', ['user_id' => $user->id]);→ 实证:15 章 §3 Job 失败时用 failed() 钩子写日志,只写 post_id 和 error message,不写敏感字段。
监控告警
最简单的告警系统:
// 在 bootstrap/app.php
->withExceptions(function (Exceptions $exceptions) {
$exceptions->report(function (\Throwable $e) {
// Sentry 自动接管,但你也可以加自定义
if ($e instanceof CriticalException) {
// 比如发 Slack 通知运维
}
});
})→ 实战推荐:Sentry + Slack 集成——重大异常自动 ping 运维群。
7. 部署前 dev 包移除清单(含 Boost 处理)
为什么 dev 包不能上生产
| 包 | 风险 |
|---|---|
laravel/boost | MCP server 暴露 + 内部 API(攻击面) |
laravel/telescope | 记录所有请求详情(隐私 + 磁盘) |
laravel/pail | 调试用,无生产价值 |
laravel/sail | Docker 开发环境,无生产价值 |
pestphp/pest | 测试框架 |
nunomaduro/collision | 美化 CLI 输出 |
barryvdh/laravel-debugbar | 在 HTML 里显示 SQL/timing(严重隐私漏洞) |
自动移除(Composer 标准做法)
部署命令里加 --no-dev:
composer install --no-dev --optimize-autoloader→ Composer 会完全跳过 require-dev 里的所有包——不下载、不 autoload。
Boost 是 dev 包,自动跳过 ✓
打开 playground 的 composer.json:
"require-dev": {
"fakerphp/faker": "^1.23",
"laravel/boost": "^2.4", ← 在这里 ⭐
"laravel/pail": "^1.2.2",
"laravel/pint": "^1.24",
"laravel/sail": "^1.41",
"mockery/mockery": "^1.6",
"nunomaduro/collision": "^8.6",
"pestphp/pest": "^3.8",
"pestphp/pest-plugin-laravel": "^3.2",
"phpunit/phpunit": "^11.5.50"
}→ 部署时 composer install --no-dev 这些包全部自动跳过——你什么都不用做。
上生产前的"清单确认"
| # | 项 | 验证方法 |
|---|---|---|
| 1 | Boost / Telescope / Pail 在 require-dev(不在 require) | 看 composer.json |
| 2 | 部署脚本用 --no-dev | 看 deployment.yml / Forge "Deploy Script" |
| 3 | php artisan list 不应该看到 boost:* 命令 | ssh 到生产跑命令 |
| 4 | 浏览器访问 /telescope 应该 404 | 验证 |
| 5 | 浏览器访问 /horizon 应该有保护(auth) | 验证 |
Horizon 的特殊保护
Horizon 是生产级工具(不是 dev 包),但它的 /horizon 路由默认所有人可访问——必须加保护:
// app/Providers/HorizonServiceProvider.php
protected function gate(): void
{
Gate::define('viewHorizon', function ($user) {
return $user?->is_admin === true; // ⭐ 复用 16 章 is_admin
});
}→ 实证:16 章 §3 加的 is_admin 字段,在这里继续复用。
Boost 在生产的"残留"
理论上 --no-dev 完全移除——但有 1 个文件可能残留:
.ai/guidelines/ ← 这些 markdown 文件进了 git
.ai/skills/ ← 同上→ 这些文件进入生产 server。它们:
- ❌ 不影响功能(只是给 AI 看的 markdown)
- ✓ 占空间极小(几 KB)
- ✓ 不构成安全风险
→ 你可以保留(无害)或通过 .gitignore 排除(不进 git)。本教程推荐保留——团队成员 clone 仓库时直接拿到代码风格规范。
.cursor/mcp.json 千万不要进 git
.cursor/mcp.json ← 含本地绝对路径,每个开发者不同→ 必须 .gitignore。 → 实证:03 章 §5。
8. 真实部署演练:把 playground 部署到 Forge
这一节是走完一整套部署流程的"实战预演"——我们用 Forge + DigitalOcean 演示。 实测时间:约 30-60 分钟(含申请 VPS / 域名 DNS 传播)。
前置准备(约 20 分钟)
| # | 准备项 | 时间 |
|---|---|---|
| 1 | 注册 Laravel Forge($12/月) | 5 分钟 |
| 2 | 注册 DigitalOcean 等 VPS 商家($5/月起) | 5 分钟 |
| 3 | 准备域名(DNS 解析能改) | 5 分钟 |
| 4 | playground/ 推到 GitHub(含 .env.example) | 5 分钟 |
部署流程(10 步)
1. 在 Forge 创建 Server
Forge → "Create Server" → 选 DigitalOcean → 选 region(新加坡 / 香港给国内用户) → 选 PHP 8.2 → 创建。
⏱ 约 5-10 分钟,Forge 自动装 Nginx + PHP + MySQL + Redis + Supervisor。
2. 在 Forge 创建 Site
Forge → 你的 server → "New Site" → 填域名 playground.yourdomain.com → "App / Web Directory: /public"。
3. 关联 GitHub 仓库
Site → "App" → "Repository" → 输 your-username/playground → 选 main 分支 → "Install Repository"。
Forge 会自动 clone + 跑首次 composer install。
4. 配置 .env
Site → "Environment" → 编辑:
APP_NAME=Playground
APP_ENV=production ← ⭐
APP_KEY= ← 等下生成
APP_DEBUG=false ← ⭐
APP_URL=https://playground.yourdomain.com
LOG_CHANNEL=daily
LOG_LEVEL=warning
DB_CONNECTION=mysql ← ⭐ 不再用 SQLite
DB_HOST=127.0.0.1
DB_DATABASE=playground
DB_USERNAME=forge
DB_PASSWORD=... ← 在 Forge "Database" 页生成
CACHE_STORE=redis ← ⭐
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis ← ⭐
MAIL_MAILER=smtp ← ⭐ 真实邮件服务
MAIL_HOST=smtp.resend.com
MAIL_PORT=465
MAIL_USERNAME=resend
MAIL_PASSWORD=re_xxx
MAIL_FROM_ADDRESS=hello@yourdomain.com
MAIL_FROM_NAME="Playground"
SANCTUM_STATEFUL_DOMAINS=playground.yourdomain.com→ 保存。
5. 改 Deployment Script
Site → "App" → "Deployment" → 改成:
cd /home/forge/playground.yourdomain.com
git pull origin $FORGE_SITE_BRANCH
$FORGE_COMPOSER install --no-dev --no-interaction --prefer-dist --optimize-autoloader
if [ -f artisan ]; then
$FORGE_PHP artisan migrate --force
$FORGE_PHP artisan optimize:clear
$FORGE_PHP artisan optimize
$FORGE_PHP artisan queue:restart
fi注意 4 个改动 vs Forge 默认脚本:
--no-dev⭐(不装 Boost / Telescope)--optimize-autoloader⭐(更快)optimize:clear后再optimize⭐(重新缓存)queue:restart⭐(让 worker 用新代码)
6. 生成 APP_KEY
ssh 到 server(Forge "SSH" 标签):
cd ~/playground.yourdomain.com
php artisan key:generate --force→ Forge 自动同步到 Site 的 .env。
7. 跑首次部署
Site → "App" → "Deploy Now"。
→ 会跑你刚才写的 deployment script。约 30 秒。
8. 配 HTTPS
Site → "SSL" → "LetsEncrypt" → 输域名 → "Obtain Certificate"。
⏱ 约 30 秒。
9. 配 Queue Worker(不要忘!)
Site → "Queue" → "Create Queue Worker":
| 字段 | 值 |
|---|---|
| Connection | redis |
| Queue | default |
| Sleep | 3 |
| Tries | 3 |
| Processes | 2 |
| Timeout | 90 |
→ Forge 会用 Supervisor 守护这个 worker。
10. 配定时任务(schedule)
Server → "Scheduler" → "New Scheduled Job":
php /home/forge/playground.yourdomain.com/artisan schedule:run→ 每分钟跑一次,触发你 app/Console/Kernel.php 里的 schedule() 内容。
部署后验证清单
| # | 检查 | 方法 |
|---|---|---|
| 1 | 网站能访问 | 浏览器 https://playground.yourdomain.com |
| 2 | HTTPS 强制 | curl -I http://playground.yourdomain.com 应该 301 → https |
| 3 | /api/posts 返回 JSON | curl https://playground.yourdomain.com/api/posts |
| 4 | /admin/login 能看到登录页 | 浏览器访问 |
| 5 | 创建文章触发邮件 Job | 看 Resend 后台是否收到 |
| 6 | /horizon 有保护 | 未登录访问应该 403 |
| 7 | Sentry 收到 1 条测试错误 | Sentry dashboard |
实测耗时表
| 阶段 | 耗时 |
|---|---|
| 注册 Forge / VPS / 域名 | 20 分钟 |
| Forge 装环境 | 10 分钟 |
| 配置 + 部署 | 15 分钟 |
| HTTPS + Worker + 监控 | 10 分钟 |
| 验证 + 调试 | 10 分钟 |
| 合计 | 约 65 分钟 |
→ 一杯咖啡的时间,把 playground 推到生产。
如果用自建 VPS(无 Forge)
参考:Laravel 官方部署文档 + 上面 Forge 流程手工跑一遍。 约 2-4 小时(含 Nginx / Supervisor / Certbot 学习)。
9. ThinkPHP vs Laravel 部署对照
部署流程对照
| 维度 | ThinkPHP 6 | Laravel 12 |
|---|---|---|
| 部署平台 | 通常宝塔面板 / 自建 LNMP | Forge / Vapor / Cloud / 自建 |
| 部署脚本 | rsync + 手工 cp | git pull + composer install --no-dev |
| 配置缓存 | 没有等价 | php artisan optimize |
| 队列守护 | 自己写脚本 + nohup | Supervisor + queue:restart |
| HTTPS | 手工配 Nginx + Certbot | Forge 一键 / Cloud 自动 |
| 监控 | 自己装 Zabbix | Sentry + Horizon + Laravel Cloud Dashboard |
| 错误追踪 | Log::error + 自己看 | Sentry 自动收集 |
| 性能优化 | OPcache | OPcache + config:cache + Octane |
配置管理对照
| ThinkPHP | Laravel |
|---|---|
config/database.php 直接写值 | config/database.php 读 env('DB_HOST') |
多环境:自己写 dev/prod/test 目录 | 多环境:.env 切换 |
调试开关:APP_DEBUG = true 在配置里 | .env 里 APP_DEBUG=true/false |
性能优化对照
| ThinkPHP | Laravel |
|---|---|
| OPcache | 一致 |
没有 config:cache | php artisan config:cache 必跑 |
没有 route:cache | php artisan route:cache |
| 没有 Octane | Octane(5x 性能) |
| 自己写缓存 | Cache::remember() + 自动 tag |
安全对照
| ThinkPHP | Laravel |
|---|---|
| CSRF:手动加 token | 自动(@csrf Blade) |
SQL 注入:自己写 quote() | Eloquent / Query Builder 自动参数化 |
| Mass assignment:默认不防 | 默认 $fillable 必填 |
| Rate Limit:自己写 | throttle:60,1 中间件 |
| Sanctum / API Token | 第三方包 / 自写 vs 内置 |
一句话总结部署对照
ThinkPHP 部署:你拼装一套——脚本 / 配置 / 监控 / 安全自己写。
Laravel 部署:约定 + 工业化平台(Forge/Vapor/Cloud)+ Sentry/Horizon = 一杯咖啡上线。
ThinkPHP 老手转 Laravel 部署的 3 个心理障碍
障碍 1:"Forge $12/月,自建免费"
回应:算上你自己的运维时间(每月 $1000+ 的工时),Forge 是几乎白送。
障碍 2:"我的项目在国内,Forge 不好用"
回应:用 Forge 接腾讯云/阿里云的 VPS(Custom server provider)即可。或者自建。
障碍 3:"Octane / Redis / Sentry 一堆要装,太麻烦"
回应:先按 §3 性能优化的"黄金顺序"——先做 N+1 / config cache / Redis(30 分钟)。Octane / Sentry 等到流量上来再装。不是一次全做。
10. 教程整体收官:18 章回顾 + "30 个最值得记住的事"
这是这本教程的最后一节。读完这节,你就完整看完了 18 章。
18 章全部成稿 ⭐⭐⭐
第一阶段·认知篇
第二阶段·环境篇
- ✓ 第 3 章 环境安装
- ✓ 第 4 章 安装 Boost
- ✓ 第 5 章 配置 AI 编辑器
- 集合在 03-环境搭建实测
第三阶段·基础篇
- ✓ 第 6-11 章 路由 / Eloquent / Migration / Controller / Blade / Auth
- 集合在 06-11-章节速查
第四阶段·实战篇
- ✓ 第 12 章 Boost 工具大全
- ✓ 第 13 章 博客实战
- ✓ 第 14 章 API 化实战
- ✓ 第 15 章 队列实战
- ✓ 第 16 章 Filament 后台
第五阶段·进阶篇
- ✓ 第 17 章 Prompt 工程反例集
- ✓ 第 18 章 部署 + 生产实践(本篇)
特别篇
- ✓ 00 教程导读(全书入口)
- ✓ Laravel_Boost_教程大纲
→ 完整 18 章 + 11 篇笔记 + 1 个跑通的 playground 项目 = 这本教程的全部产出。
"30 个最值得记住的事"回顾
详见 00 教程导读 §四。
把 30 条压缩成 5 行:
1. Laravel 12 = casts() 方法 + HasMiddleware 接口 + Foundation\Queue\Queueable
2. Eloquent = 关系命名 + scope + with() 防 N+1 + getRouteKeyName
3. Form Request + Policy + ?User 类型签名 = 跨端权限复用(web/API/Filament)
4. Job + Mail + Markdown 邮件 + Queue::fake() = 异步通信 + 测试
5. Boost = AI 在 Laravel 项目里有"老手意识"这本教程的"元"价值
不是"教 Laravel"——是教**"AI + Laravel + Boost 协作的标准工作流"**。
3 个层次的元价值:
层次 1:可复制的"实战 + 笔记"流程
每一章都是 7 个 Sprint:
- 装包 / 配置
- 核心实现
- 集成 / 业务关联
- 验证
- 测试
- 处理失败 / 边界
- 写成笔记
→ 这套流程可以复制到任何 Laravel 项目的任何模块。
层次 2:可复制的"踩坑 + 修复"流程
12 个真实踩坑都遵循同一套调试 SOP:
- 看现象(FAIL / 报错 / 不工作)
- 看 log(
storage/logs/laravel.log+failed_jobs) - 看工具(Boost 的
database-query/read-log-entries) - 分析根因(版本?锁?路径?)
- 选解决方案(A/B/C 各有取舍)
- 验证修复(测试通过)
- 写到笔记里防退化
→ 这套 SOP 是生产环境调试的标准流程。
层次 3:可复制的"prompt 工程"
17 章 §8 给的 6 个模板覆盖:
- 新增资源型功能
- 修改现有功能
- debug
- 性能优化
- UI 美化
- API 化
→ 这 6 个模板是ThinkPHP 老手 → 高效 AI 协作者的桥梁。
数字总结
教程产出:
├── 11 篇 Markdown 文档
├── 约 13000 行内容(~32 万字)
├── playground/ 实战项目
│ ├── Laravel 12.58 + Sanctum 4.3.2 + Filament 5.6.2
│ ├── 5 件套(博客 + 认证 + 队列 + API + 后台)
│ ├── 63 个 Pest 测试 in 2.79s
│ └── 15 个数据表
├── 9 个 Boost 工具实测覆盖
├── 12 个真实踩坑诊断
├── 6 个 prompt 模板
├── 30 个必背知识点
└── 18 章主线 + 1 篇导读 + 1 篇大纲
总耗时:
├── 实战部分:约 8-10 小时(4 章 × 2 小时)
├── 写作部分:约 6-8 小时
└── 合计:约 15 小时(一个周末)给读完整本教程的你
如果你读到这里,且 playground 在你机器上跑得起来:
你已经掌握了 2026 年 Laravel + AI 协作的完整技术栈。
下一步:把它用到你工作项目里——按 00 教程导读 §三 路径 E 的"一周计划"。
如果你读完但还没动手:
现在就
composer create-project laravel/laravel my-app开个新项目,从 03 章环境搭建 开始走一遍。不动手永远不会真懂。
致谢
- Laravel 团队 —— 12 年来引领 PHP 框架现代化方向
- Filament 团队 —— v5 的 schema 体系真的优雅
- Pest 团队 —— 让 PHP 测试体验追上 Vitest
- Cursor 团队 —— MCP + 编辑器集成让 AI 协作真的能跑
- Anthropic(Claude 团队) —— 提出 MCP 协议让 AI 工具生态可能
- ThinkPHP 社区 —— 中国 PHP 圈的入门启蒙
- 被各种坑过的所有同行 —— 我们的痛是一致的
给读者最后一句话
一本教程读完了,故事才刚开始。
把这套工作流用到自己的项目里,把踩坑写进自己的笔记里,把更多 ThinkPHP 同行带到 Laravel + Boost 的世界里。
这才是这本教程真正的延续。
第 18 章 完。18 章 / 11 篇笔记 / 13000 行 / 63 测试 / 1 个 playground 项目—— 全教程到此完结。
收获满满,祝你 Laravel + Boost 之旅顺利。🚀