Laravel 13 部署与运维指南

部署是将应用程序推向生产环境的关键步骤。本文将介绍 Laravel 13 的部署和运维最佳实践。

服务器要求

基本要求

  • PHP >= 8.2
  • Composer
  • Nginx / Apache
  • MySQL / PostgreSQL
  • Redis(可选)

PHP 扩展

1
2
3
4
5
6
7
8
9
10
11
12
- BCMath
- Ctype
- cURL
- DOM
- Fileinfo
- JSON
- Mbstring
- OpenSSL
- PCRE
- PDO
- Tokenizer
- XML

环境配置

.env 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
APP_NAME=Laravel
APP_ENV=production
APP_KEY=base64:...
APP_DEBUG=false
APP_URL=https://example.com

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

CACHE_DRIVER=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

Web 服务器配置

Nginx 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
server {
listen 80;
listen [::]:80;
server_name example.com;
return 301 https://$server_name$request_uri;
}

server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
root /var/www/example.com/public;

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";

index index.php;

charset utf-8;

location / {
try_files $uri $uri/ /index.php?$query_string;
}

location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }

error_page 404 /index.php;

location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}

location ~ /\.(?!well-known).* {
deny all;
}
}

部署流程

手动部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1. 拉取代码
git pull origin main

# 2. 安装依赖
composer install --no-dev --optimize-autoloader

# 3. 缓存配置
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache

# 4. 运行迁移
php artisan migrate --force

# 5. 重启队列工作进程
php artisan queue:restart

# 6. 清除缓存
php artisan cache:clear

部署脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/bin/bash

set -e

echo "Deploying application..."

# 进入项目目录
cd /var/www/example.com

# 维护模式
php artisan down

# 拉取最新代码
git pull origin main

# 安装依赖
composer install --no-interaction --prefer-dist --no-dev --optimize-autoloader

# 运行迁移
php artisan migrate --force

# 缓存配置
php artisan config:cache
php artisan route:cache
php artisan view:cache

# 重启服务
php artisan queue:restart
sudo systemctl restart php8.3-fpm

# 退出维护模式
php artisan up

echo "Deployment complete!"

CI/CD 配置

GitHub Actions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
name: Deploy

on:
push:
branches: [main]

jobs:
deploy:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring, xml, mysql

- name: Install Dependencies
run: composer install --no-dev --optimize-autoloader

- name: Run Tests
run: php artisan test

- name: Deploy to Server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_KEY }}
script: |
cd /var/www/example.com
./deploy.sh

进程管理

Supervisor 配置

1
2
3
4
5
6
7
8
9
10
11
12
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/example.com/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www-data
numprocs=8
redirect_stderr=true
stdout_logfile=/var/www/example.com/storage/logs/worker.log
stopwaitsecs=3600

Supervisor 命令

1
2
3
4
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl restart laravel-worker:*
sudo supervisorctl status

监控

健康检查

1
2
3
4
5
6
7
8
Route::get('/health', function () {
return response()->json([
'status' => 'ok',
'timestamp' => now()->toIso8601String(),
'database' => DB::connection()->getPdo() ? 'connected' : 'disconnected',
'cache' => Cache::get('health-check') ? 'connected' : 'disconnected',
]);
});

日志监控

1
2
3
4
5
6
7
8
9
10
11
12
13
// config/logging.php
'channels' => [
'production' => [
'driver' => 'stack',
'channels' => ['daily', 'slack'],
],

'slack' => [
'driver' => 'slack',
'url' => env('LOG_SLACK_WEBHOOK_URL'),
'level' => 'error',
],
],

性能优化

OPcache 配置

1
2
3
4
5
6
7
8
; php.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.save_comments=1

数据库优化

1
2
3
4
5
-- 添加索引
CREATE INDEX idx_users_email ON users(email);

-- 优化查询
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';

备份策略

数据库备份

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash

DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/var/backups/mysql"
DB_NAME="laravel"

mkdir -p $BACKUP_DIR

mysqldump -u root -p$DB_PASSWORD $DB_NAME | gzip > $BACKUP_DIR/$DB_NAME_$DATE.sql.gz

# 保留最近 7 天的备份
find $BACKUP_DIR -type f -name "*.sql.gz" -mtime +7 -delete

文件备份

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash

DATE=$(date +%Y%m%d)
BACKUP_DIR="/var/backups/files"
SOURCE_DIR="/var/www/example.com/storage"

mkdir -p $BACKUP_DIR

tar -czf $BACKUP_DIR/storage_$DATE.tar.gz $SOURCE_DIR

find $BACKUP_DIR -type f -name "*.tar.gz" -mtime +30 -delete

安全加固

文件权限

1
2
3
4
5
6
7
8
9
10
11
12
# 设置所有者
chown -R www-data:www-data /var/www/example.com

# 设置目录权限
find /var/www/example.com -type d -exec chmod 755 {} \;

# 设置文件权限
find /var/www/example.com -type f -exec chmod 644 {} \;

# 设置存储目录权限
chmod -R 775 /var/www/example.com/storage
chmod -R 775 /var/www/example.com/bootstrap/cache

安全头

1
2
3
4
5
6
7
8
9
10
11
12
13
// app/Http/Middleware/SecurityHeaders.php
public function handle($request, Closure $next)
{
$response = $next($request);

$response->headers->set('X-Content-Type-Options', 'nosniff');
$response->headers->set('X-Frame-Options', 'DENY');
$response->headers->set('X-XSS-Protection', '1; mode=block');
$response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');
$response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');

return $response;
}

故障排查

常见问题

1
2
3
4
5
6
7
8
9
10
11
# 查看日志
tail -f storage/logs/laravel.log

# 检查队列状态
php artisan queue:work --once

# 清除所有缓存
php artisan optimize:clear

# 检查配置
php artisan config:show

性能分析

1
2
3
4
# 安装 Laravel Telescope
composer require laravel/telescope --dev
php artisan telescope:install
php artisan migrate

最佳实践

1. 使用环境变量

1
2
3
4
5
// 好的做法
$value = config('app.name');

// 不好的做法
$value = 'My App';

2. 启用缓存

1
2
3
php artisan config:cache
php artisan route:cache
php artisan view:cache

3. 使用队列

1
2
3
4
5
// 好的做法
ProcessPodcast::dispatch($podcast);

// 不好的做法
$podcast->process();

4. 监控日志

1
tail -f storage/logs/laravel.log | grep ERROR

总结

Laravel 13 的部署和运维涉及多个方面,包括服务器配置、部署流程、进程管理、监控和安全加固。通过合理使用 CI/CD、Supervisor、日志监控和备份策略,可以构建出稳定、安全、高性能的生产环境。记住关闭调试模式、启用配置缓存、使用队列处理耗时任务,并定期备份数据。良好的部署和运维实践是应用程序稳定运行的基础。