Подготовка сервера:
Берем VPS с Ubuntu 24.04 (хостер любой, от Selectel до Timeweb), ставим nginx, php8.4-fpm с расширениями (mbstring, pdo_mysql, intl, redis), MySQL или PostgreSQL и Redis под кеш и очереди. Именно 8.4: active support у PHP 8.3 закончился в декабре 2025, а Laravel 12 с 8.4 работает штатно, ставить на свежий сервер ветку, которая доживает на security-фиксах, смысла нет. Критично одно: корень сайта в nginx должен смотреть строго в каталог public, а не в корень проекта. Иначе .env и весь код доступны по прямому URL.
Код: Выделить всё
server {
listen 80;
server_name app.example.ru;
root /var/www/app/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
}
location ~ /\.(?!well-known).* {
deny all;
}
}Код: Выделить всё
apt install certbot python3-certbot-nginx
certbot --nginx -d app.example.ruСтрока с $realpath_root вместо $document_root нужна при деплое через симлинки, без нее OPcache цепляется за старые пути. Раз уж зашла речь про OPcache: на проде стоит выставить opcache.validate_timestamps=0, тогда PHP перестает проверять файлы на изменения на каждый запрос, это заметный выигрыш. Цена: после каждого деплоя кеш надо сбрасывать самому, проще всего добавить systemctl reload php8.4-fpm в конец деплой-скрипта. Без такого сброса не включайте, иначе сервер продолжит исполнять старый код.
Шаги деплоя:
В .env на сервере выставляем APP_ENV=production и APP_DEBUG=false, генерируем APP_KEY один раз через php artisan key:generate и больше не трогаем (смена ключа сломает шифрованные данные и сессии). Сам деплой сводится к скрипту:
Код: Выделить всё
#!/usr/bin/env bash
set -e
cd /var/www/app
php artisan down
git pull origin main
composer install --no-dev --optimize-autoloader
npm ci && npm run build
php artisan migrate --force
php artisan storage:link
php artisan optimize
php artisan queue:restart
php artisan upФлаг --force у migrate тоже не для галочки. В production artisan как раз задает вопрос подтверждения перед миграцией, это защита от случайного запуска на боевой базе. В неинтерактивном скрипте отвечать на вопрос некому, и без флага миграция просто не выполнится. --force это подтверждение подавляет.
Команда optimize с Laravel 11 кеширует сразу конфиг, маршруты, события и шаблоны. После кеширования конфига функция env() работает только внутри файлов config/, в остальном коде она вернет null. Если у вас где-то env('SOMETHING') в контроллере, переносите значение в конфиг и читайте через config().
Последним шагом полезно дернуть health-check. С Laravel 11 маршрут /up регистрируется в bootstrap/app.php (параметр health у withRouting в свежем скелетоне включен по умолчанию) и отдает 200, если приложение поднялось. На него же удобно повесить внешний мониторинг или проверку балансировщика.
Очереди и планировщик:
queue:work должен жить под супервизором, иначе после первого падения воркера письма и джобы из главы 10 молча встанут. Планировщику хватает одной строки в cron.
Код: Выделить всё
; /etc/supervisor/conf.d/app-worker.conf
[program:app-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/app/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600
numprocs=2
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/www/app/storage/logs/worker.log
stopwaitsecs=3600
# crontab -e под тем же пользователем
* * * * * cd /var/www/app && php artisan schedule:run >> /dev/null 2>&1queue:restart в деплой-скрипте тоже не для красоты: воркер держит код в памяти, без рестарта он будет выполнять джобы старой версией приложения.
Весь этот блок (nginx, certbot, supervisor, cron) в 2026 необязательно собирать руками. Laravel Forge настраивает и обслуживает VPS у любого хостера кнопками, Envoyer поверх него дает zero-downtime деплой через симлинки, а Laravel Cloud (запустился в начале 2025) это полностью управляемая платформа от самой команды Laravel, где сервер вы не видите вообще. Для учебного и пет-проекта ручной VPS дешевле и полезнее для понимания, для коммерческой работы посчитайте стоимость своего времени.
Фронтенд: Vite, Livewire, Inertia:
Vite в Laravel отвечает за сборку ассетов. Локально npm run dev поднимает дев-сервер с горячей перезагрузкой, на проде npm run build собирает минифицированные файлы с хешами в именах и manifest.json. В шаблоне все подключается одной директивой:
Код: Выделить всё
<head>
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>Типичные грабли:
APP_DEBUG=true в проде, и страница ошибки показывает пользователям переменные окружения и куски кода. Забытый npm run build, и Vite кидает исключение про отсутствующий манифест. Права на запись: каталоги storage и bootstrap/cache должны принадлежать пользователю php-fpm, обычно www-data. Забытый storage:link, и загруженные файлы из главы 14 отдают 404. И если приложение живет за прокси или Cloudflare, настройте trustProxies в bootstrap/app.php, иначе Laravel будет генерировать http-ссылки вместо https.
Итог:
Деплой Laravel это не магия: правильный docroot, HTTPS через certbot, composer без dev-зависимостей, migrate --force, optimize, супервизор для очередей и cron для планировщика. На этом курс закончен. Дальше смотрите Laravel Octane для высоких нагрузок, Horizon для мониторинга очередей и Deployer для деплоя без даунтайма. База у вас уже есть.