Требования к серверу
Минимальная серверная конфигурация
| Компонент | Требование |
|---|---|
| PHP | 8.2+ с необходимыми расширениями |
| Веб-сервер | Nginx (рекомендуется) или Apache |
| База данных | MySQL 8.0+, PostgreSQL 13+, SQLite 3.35+ |
| Composer | 2.x |
| Node.js | 18+ (для сборки assets) |
| Права на запись | storage/, bootstrap/cache/ |
Необходимые PHP-расширения
# Required PHP extensions for production
php -m | grep -E "(bcmath|ctype|curl|dom|fileinfo|json|mbstring|openssl|pcre|pdo|tokenizer|xml)"
# Additional recommended extensions
# - Redis (phpredis) — for cache/sessions/queues
# - Imagick or GD — for image processing
# - Zip — for file compression
# - Intl — for internationalization
# - OPcache — for performance (critical!)
Конфигурация веб-сервера
Nginx (рекомендуемый)
server {
listen 80;
listen [::]:80;
server_name example.com;
root /var/www/my-app/public;
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.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_hide_header X-Powered-By;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
Для экзамена: Ключевая директива Nginx --
try_files $uri $uri/ /index.php?$query_string;. Она обеспечивает паттерн front controller: все запросы, которые не соответствуют реальным файлам, перенаправляются наindex.php.
Apache (.htaccess)
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
RewriteEngine On
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect Trailing Slashes If Not A Folder
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
# Send Requests To Front Controller
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
Оптимизация для продакшена
Команда php artisan optimize
# Laravel 11: single optimization command
php artisan optimize
# This command runs:
# 1. config:cache — Cache configuration
# 2. route:cache — Cache routes
# 3. view:cache — Compile and cache views
# 4. event:cache — Cache event-listener mappings
# Clear all caches
php artisan optimize:clear
# This command runs:
# 1. config:clear
# 2. route:clear
# 3. view:clear
# 4. event:clear
# 5. cache:clear
Кэширование конфигурации
# Cache all config files into a single file
php artisan config:cache
# Benefits:
# - Single file load instead of ~15 separate config files
# - No .env file parsing on each request
# - ~50% faster configuration loading
# IMPORTANT: After config:cache, env() returns null
# outside of config/ files
# Clear config cache
php artisan config:clear
Кэширование маршрутов
# Cache all routes into a single file
php artisan route:cache
# Benefits:
# - Routes loaded from a single cached file
# - Significant performance improvement for large apps
# LIMITATION: Route caching does NOT work with Closure routes!
# Only controller-based routes can be cached
# Clear route cache
php artisan route:clear
<?php
declare(strict_types=1);
// WRONG — Closure routes CANNOT be cached
Route::get('/dashboard', function () {
return view('dashboard');
});
// CORRECT — Controller routes CAN be cached
Route::get('/dashboard', [DashboardController::class, 'index']);
// CORRECT — Invokable controller
Route::get('/dashboard', DashboardController::class);
Ловушка экзамена: Команда
php artisan route:cacheНЕ работает с маршрутами-замыканиями (Closure). Если в файлах маршрутов есть хотя бы одно замыкание, команда выбросит ошибку. Для кэширования все маршруты должны ссылаться на методы контроллеров.
Кэширование представлений
# Pre-compile all Blade views
php artisan view:cache
# Benefits:
# - All Blade templates compiled ahead of time
# - No compilation overhead on first request
# - Faster time-to-first-byte (TTFB)
# Clear compiled views
php artisan view:clear
Кэширование событий
# Cache the event-listener mapping
php artisan event:cache
# Benefits:
# - Event discovery results cached
# - No directory scanning on each request
# Clear event cache
php artisan event:clear
Оптимизация Composer
# CRITICAL for production
# Generate optimized autoloader
composer install --optimize-autoloader --no-dev
# Flags explained:
# --optimize-autoloader (-o): Generate classmap for PSR-4 autoloading
# → Converts PSR-4/PSR-0 rules to classmap for faster lookups
# --no-dev: Skip dev dependencies (phpunit, faker, etc.)
# → Reduces vendor/ size significantly
# For maximum performance:
composer dump-autoload --optimize --classmap-authoritative
# --classmap-authoritative: Only look for classes in classmap
# → Even faster but classes not in classmap won't be found
# → Use only if all classes are known at build time
Для Senior: На продакшене ВСЕГДА используйте
--optimize-autoloader --no-dev. Флаг--classmap-authoritativeещё быстрее, но несовместим с пакетами, которые генерируют классы в рантайме (например, некоторые ORM прокси-объекты).
OPcache -- критически важно
; php.ini — OPcache settings for production
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0 ; CRITICAL: disable in production
opcache.save_comments=1 ; Required for annotations/attributes
opcache.enable_file_override=1
; JIT (PHP 8.4+)
opcache.jit=1255
opcache.jit_buffer_size=128M
<?php
declare(strict_types=1);
// OPcache preloading (PHP 8.0+)
// config/opcache.php or preload.php
// In php.ini:
// opcache.preload=/var/www/my-app/preload.php
// opcache.preload_user=www-data
// preload.php
require __DIR__ . '/vendor/autoload.php';
// Preload frequently used classes
// Laravel provides a built-in preload script in some configs
// This loads framework classes into OPcache at startup
Важно:
opcache.validate_timestamps=0означает, что PHP не будет проверять изменения файлов. После деплоя нужно перезагрузить PHP-FPM (systemctl reload php8.4-fpm) или вызватьopcache_reset().
Процесс деплоя
Типичный сценарий деплоя
#!/bin/bash
# deploy.sh — Standard Laravel deployment script
set -e
APP_DIR="/var/www/my-app"
echo "Starting deployment..."
# 1. Pull latest code
cd $APP_DIR
git pull origin main
# 2. Install PHP dependencies (production)
composer install --no-dev --optimize-autoloader --no-interaction
# 3. Install and build frontend assets
npm ci --production
npm run build
# 4. Run database migrations
php artisan migrate --force
# 5. Clear and rebuild caches
php artisan optimize:clear
php artisan optimize
# 6. Restart queue workers (if using)
php artisan queue:restart
# 7. Restart PHP-FPM to clear OPcache
sudo systemctl reload php8.4-fpm
echo "Deployment complete!"
Zero-downtime деплой
#!/bin/bash
# Zero-downtime deployment with symlinks
RELEASE_DIR="/var/www/releases/$(date +%Y%m%d%H%M%S)"
SHARED_DIR="/var/www/shared"
CURRENT_LINK="/var/www/current"
# 1. Create new release directory
mkdir -p $RELEASE_DIR
git clone --depth 1 --branch main [email protected]:user/repo.git $RELEASE_DIR
# 2. Link shared resources
ln -sf $SHARED_DIR/.env $RELEASE_DIR/.env
ln -sf $SHARED_DIR/storage $RELEASE_DIR/storage
# 3. Install dependencies
cd $RELEASE_DIR
composer install --no-dev --optimize-autoloader --no-interaction
npm ci && npm run build
# 4. Run migrations
php artisan migrate --force
# 5. Cache everything
php artisan optimize
# 6. Swap symlink (atomic operation)
ln -sfn $RELEASE_DIR $CURRENT_LINK
# 7. Restart workers and PHP-FPM
php artisan queue:restart
sudo systemctl reload php8.4-fpm
# 8. Clean up old releases (keep last 5)
cd /var/www/releases
ls -t | tail -n +6 | xargs rm -rf
Для Senior: Zero-downtime деплой с симлинками -- это стандартная практика для продакшен-серверов. Операция
ln -sfnатомарна на уровне файловой системы, что обеспечивает мгновенное переключение без простоя. Инструменты вроде Deployer, Envoyer и Capistrano автоматизируют этот процесс.
Laravel Forge
<?php
declare(strict_types=1);
// Laravel Forge — server management platform
// https://forge.laravel.com
// Key features:
// - Automated server provisioning (DigitalOcean, AWS, Linode, etc.)
// - Nginx configuration
// - SSL certificates (Let's Encrypt)
// - PHP version management
// - Database management
// - Queue worker management (Supervisor)
// - Scheduled tasks (cron)
// - Zero-downtime deployments
// - Server monitoring
// Forge deploy script (configured in web UI):
// cd /home/forge/example.com
// git pull origin $FORGE_SITE_BRANCH
// $FORGE_COMPOSER install --no-dev --no-interaction --prefer-dist --optimize-autoloader
// npm ci && npm run build
// $FORGE_PHP artisan migrate --force
// $FORGE_PHP artisan optimize
// $FORGE_PHP artisan queue:restart
Laravel Vapor
<?php
declare(strict_types=1);
// Laravel Vapor — serverless deployment on AWS Lambda
// https://vapor.laravel.com
// Key features:
// - Serverless (no server management)
// - Auto-scaling (handles traffic spikes automatically)
// - AWS Lambda for compute
// - AWS RDS for databases
// - AWS S3 for file storage
// - AWS SQS for queues
// - AWS CloudFront for CDN
// - Environment management
// vapor.yml — deployment configuration
// id: 12345
// name: my-app
// environments:
// production:
// memory: 1024
// cli-memory: 512
// runtime: php-8.4
// build:
// - 'composer install --no-dev'
// - 'npm ci && npm run build'
// deploy:
// - 'php artisan migrate --force'
// - 'php artisan optimize'
// staging:
// memory: 512
// runtime: php-8.4
// build:
// - 'composer install'
// - 'npm ci && npm run build'
Переменные окружения для продакшена
# Production .env — critical settings
APP_ENV=production
APP_DEBUG=false # NEVER true in production!
APP_URL=https://example.com
# Logging — stack with daily rotation
LOG_CHANNEL=stack
LOG_LEVEL=warning # Don't log debug/info in production
# Cache — use Redis for performance
CACHE_STORE=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis
# Database
DB_CONNECTION=pgsql
DB_HOST=db-server.example.com
DB_PORT=5432
DB_DATABASE=myapp_production
DB_USERNAME=myapp
DB_PASSWORD=secure_password_here
# Redis
REDIS_HOST=redis-server.example.com
REDIS_PASSWORD=redis_password_here
# Mail — production mail service
MAIL_MAILER=ses # Amazon SES, Postmark, etc.
Критически важно:
APP_DEBUG=falseна продакшене. ЕслиAPP_DEBUG=true, пользователи увидят стектрейсы с путями к файлам, переменными окружения и данными подключения к БД. Это серьёзная уязвимость безопасности.
Очереди на продакшене
Supervisor для queue workers
; /etc/supervisor/conf.d/laravel-worker.conf
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/my-app/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stopastype=KILL
user=www-data
numprocs=4
redirect_stderr=true
stdout_logfile=/var/www/my-app/storage/logs/worker.log
stopwaitsecs=3600
# Start Supervisor
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start "laravel-worker:*"
# After deployment, restart queue workers
php artisan queue:restart
# This signals workers to finish current job and restart
# Workers will pick up new code after restart
Планировщик задач (Cron)
# Add to crontab (crontab -e)
* * * * * cd /var/www/my-app && php artisan schedule:run >> /dev/null 2>&1
<?php
declare(strict_types=1);
// routes/console.php (Laravel 11)
use Illuminate\Support\Facades\Schedule;
// Schedule tasks
Schedule::command('telescope:prune --hours=48')->daily();
Schedule::command('queue:prune-failed --hours=72')->daily();
Schedule::command('backup:run')->dailyAt('02:00');
Schedule::command('sitemap:generate')->weekly();
// With output logging
Schedule::command('reports:generate')
->dailyAt('06:00')
->appendOutputTo(storage_path('logs/reports.log'))
->emailOutputOnFailure('[email protected]');
Проверка здоровья (Health Check)
<?php
declare(strict_types=1);
// Laravel 11 includes a built-in health check endpoint
// Configured in bootstrap/app.php:
// ->withRouting(health: '/up')
// GET /up returns 200 if application is running
// Returns 500 if application fails to boot
// Custom health check
use Illuminate\Support\Facades\Route;
Route::get('/health', function () {
// Check database
try {
\DB::connection()->getPdo();
} catch (\Exception $e) {
return response()->json(['status' => 'error', 'db' => false], 503);
}
// Check Redis
try {
\Illuminate\Support\Facades\Redis::ping();
} catch (\Exception $e) {
return response()->json(['status' => 'error', 'redis' => false], 503);
}
// Check storage
$storageWritable = is_writable(storage_path());
return response()->json([
'status' => 'ok',
'db' => true,
'redis' => true,
'storage' => $storageWritable,
'version' => app()->version(),
]);
});
Чеклист деплоя
<?php
declare(strict_types=1);
// Production deployment checklist:
//
// PRE-DEPLOY:
// [ ] APP_DEBUG=false
// [ ] APP_ENV=production
// [ ] Error pages configured (403, 404, 500, 503)
// [ ] HTTPS enforced (TrustProxies middleware, APP_URL with https)
// [ ] Database backups configured
// [ ] Log rotation configured
//
// DEPLOY:
// [ ] composer install --no-dev --optimize-autoloader
// [ ] npm ci && npm run build
// [ ] php artisan migrate --force
// [ ] php artisan optimize (config:cache, route:cache, view:cache, event:cache)
// [ ] php artisan storage:link
// [ ] php artisan queue:restart
// [ ] Restart PHP-FPM (reload OPcache)
//
// POST-DEPLOY:
// [ ] Health check endpoint responds 200
// [ ] Monitor error logs
// [ ] Monitor queue workers
// [ ] Check scheduled tasks are running
//
// SECURITY:
// [ ] .env not accessible via web
// [ ] Document root points to public/
// [ ] Directory listing disabled
// [ ] Sensitive headers hidden (X-Powered-By)
// [ ] CORS configured properly
// [ ] Rate limiting active
// [ ] CSP headers set