Деплой Laravel: Envoyer, Deployer или свой bash-скрипт
Три подхода к выкатке Laravel-приложения без даунтайма: платный Envoyer, PHP-инструмент Deployer и самописный скрипт. Что каждый выигрывает, чем платит и когда какой брать.

Задача звучит просто: залить новую версию Laravel-приложения на боевой сервер так, чтобы пользователи не увидели ни 502, ни белый экран во время composer install. Наивный вариант — git pull прямо в рабочей директории — ломается ровно в момент, когда composer уже удалил старые классы, а новые ещё не докачал: часть запросов попадает в полуразобранное приложение и падает. Ниже — три способа сделать выкатку атомарной, с разной ценой по деньгам, контролю и сложности.
Что вообще должен уметь деплой Laravel
Проблема git pull не только в гонке во время установки зависимостей. Laravel кеширует конфиг, маршруты и события; при переезде на новый код старый кеш указывает на несуществующие классы. Плюс миграции БД, symlink на хранилище, перезапуск очередей и FPM. Минимальный корректный сценарий выглядит так:
- Собрать новую версию в отдельной директории (release), не трогая работающую.
- Установить зависимости:
composer install --no-dev --optimize-autoloader. - Прогреть кеши:
php artisan config:cache,route:cache,event:cache,view:cache. - Прогнать миграции:
php artisan migrate --force. - Переключить symlink
currentна новый release — это и есть атомарный момент выкатки. - Перезапустить php-fpm и очереди:
php artisan queue:restart.
Ключевая идея всех трёх инструментов — atomic deploy: несколько нумерованных релиз-папок и символическая ссылка current, которую в конце переключают одной операцией. Пользователь в момент между старой и новой версией видит либо полностью старое приложение, либо полностью новое, но не мешанину.
Даунтайм при деплое — это почти всегда не отсутствие инструмента, а composer install, запущенный поверх живого кода. Разнесите сборку и переключение — и проблема исчезает без единого платного сервиса.
Envoyer: SaaS от команды Laravel
Envoyer — платный сервис от Laravel (та же команда, что делает Forge). Он делает zero-downtime deploy из коробки: держит папки releases/, переключает symlink, умеет деплоить сразу на несколько серверов, показывает историю релизов и откатывает одной кнопкой. Настройка — через веб-интерфейс: подключаете репозиторий, сервер по SSH, задаёте список команд деплоя (deployment hooks) и линкуемые файлы вроде .env.
Сильная сторона — heartbeats и health checks: сервис пингует ваши cron-задачи и после выкатки дёргает URL, чтобы убедиться, что приложение отвечает. Если проверка провалилась, релиз не активируется. Это то, что в своём скрипте писать долго и муторно.
Цена вопроса — подписка и зависимость от внешнего сервиса. Актуальную стоимость тарифов сверяйте на сайте Envoyer, она менялась. Если у вас один-два проекта и вы не хотите держать инфраструктуру деплоя в голове — это самый быстрый путь к результату.
Deployer: PHP-инструмент, живёт в репозитории
Deployer — консольный инструмент на PHP. Устанавливается как dev-зависимость через Composer, конфигурация деплоя лежит в файле рядом с кодом и версионируется в Git. Есть готовый рецепт под Laravel, который уже знает про artisan migrate, кеши и структуру релизов.
Установка (проверяйте актуальную версию на deployer.org, ниже — для Deployer 7.x):
composer require deployer/deployer --dev
vendor/bin/dep init
Минимальный deploy.php с рецептом Laravel выглядит так:
<?php
namespace Deployer;
require 'recipe/laravel.php';
// Репозиторий и путь на сервере
set('repository', 'git@github.com:acme/shop.git');
set('keep_releases', 5); // сколько старых релизов хранить
// Файлы, общие между релизами (не перезаписываются)
add('shared_files', ['.env']);
add('shared_dirs', ['storage']);
add('writable_dirs', ['storage', 'bootstrap/cache']);
// Боевой хост
host('shop.example.com')
->set('remote_user', 'deploy')
->set('deploy_path', '/var/www/shop');
// После деплоя перезапускаем очереди
after('deploy:symlink', 'artisan:queue:restart');
after('deploy:failed', 'deploy:unlock');
Запуск: vendor/bin/dep deploy production. Deployer сам создаст структуру releases/, shared/, current, склонирует нужный коммит, поставит зависимости и переключит symlink. Откат — vendor/bin/dep rollback.
Задачи вроде перезапуска FPM пишутся явно. Проверьте имя artisan-задачи для перезапуска очередей и точный набор шагов рецепта в документации вашей версии Deployer — состав рецепта laravel.php между мажорными версиями менялся.
Свой bash-скрипт: полный контроль, полная ответственность
Если инфраструктура нестандартная — деплой инициирует CI, окружение экзотическое, а платить за SaaS не хочется — атомарную выкатку несложно собрать руками. Идея та же: собрать в новой папке, переключить symlink. Схематичный скрипт (запускается на сервере, например из GitHub Actions по SSH):
#!/usr/bin/env bash
set -euo pipefail
APP_DIR=/var/www/shop
RELEASES=$APP_DIR/releases
SHARED=$APP_DIR/shared
TS=$(date +%Y%m%d%H%M%S)
RELEASE=$RELEASES/$TS
# 1. Забираем код в новую release-папку
git clone --depth 1 git@github.com:acme/shop.git "$RELEASE"
cd "$RELEASE"
# 2. Линкуем общие файлы и каталоги
ln -s "$SHARED/.env" "$RELEASE/.env"
rm -rf "$RELEASE/storage"
ln -s "$SHARED/storage" "$RELEASE/storage"
# 3. Зависимости и кеши
composer install --no-dev --optimize-autoloader --no-interaction
php artisan config:cache
php artisan route:cache
php artisan view:cache
# 4. Миграции (осторожно, необратимо)
php artisan migrate --force
# 5. Атомарное переключение
ln -sfn "$RELEASE" "$APP_DIR/current"
# 6. Перезапуск сервисов
php artisan queue:restart
sudo systemctl reload php8.3-fpm
# 7. Чистим старые релизы, оставляем 5
cd "$RELEASES" && ls -1dt */ | tail -n +6 | xargs -r rm -rf
Флаг set -euo pipefail здесь критичен: без него скрипт продолжит выполнение после падения composer install и переключит symlink на битый релиз. Имя сервиса php-fpm (php8.3-fpm) зависит от вашей версии PHP и дистрибутива — проверьте systemctl list-units | grep fpm.
Чего в этом скрипте нет и что придётся дописывать самому: health check после переключения, автоматический откат при провале, уведомления, блокировка одновременных деплоев. Всё это Envoyer и Deployer дают из коробки.
Сравнение
| Критерий | Envoyer | Deployer | Свой скрипт |
|---|---|---|---|
| Стоимость | Подписка (сверяйте на сайте) | Бесплатно, open source | Бесплатно |
| Zero-downtime из коробки | Да | Да | Пишете сами |
| Откат | Кнопка в UI | dep rollback | Пишете сами |
| Health checks / heartbeats | Да | Частично, вручную | Пишете сами |
| Мультисервер | Да | Да | Сложно |
| Конфиг в Git | Нет (в UI) | Да | Да |
| Порог входа | Низкий | Средний | Высокий |
Когда что выбирать
- Envoyer — если хотите нажать кнопку и забыть, готовы платить, а деплой ведёте в основном через веб-интерфейс, а не через CI. Хорош для агентств с десятком клиентских проектов.
- Deployer — если хотите zero-downtime бесплатно и чтобы конфиг деплоя жил в репозитории рядом с кодом. Оптимально для команды, которая деплоит из CI и любит держать всё в Git.
- Свой скрипт — если окружение нестандартное или вы уже вложились в свой пайплайн и лишняя абстракция мешает. Готовьтесь потратить время на откат, health check и блокировки — то, что в готовых инструментах уже отлажено.
Что настроить после первого успешного деплоя
Атомарное переключение — только половина дела. Дальше стоит закрыть три вещи. Первое — откат: убедитесь, что переключение symlink на предыдущий релиз работает и восстанавливает приложение за секунды, и прорепетируйте это до инцидента, а не во время. Второе — необратимые миграции: migrate --force в скрипте деплоя откатить одним symlink нельзя, поэтому опасные миграции (удаление столбцов) разносите по релизам. Третье — health check: после переключёния дёргайте служебный URL и, если он не отвечает 200, откатывайтесь автоматически. Меряйте время полного цикла деплоя и долю пятисотых в минуту выкатки — если оно не ноль, значит переключение всё ещё не атомарно.
Детский психолог: Стратегии воспитания без травм, скрипты при истериках.
Спросить за 12 ₽Источники: Deployer — официальная документация, Laravel Deployment — официальная документация
Частые вопросы
А если у меня другая версия PHP или Laravel?
Что делать, если деплой упал на середине composer install?
Можно ли откатить миграцию базы вместе с откатом кода?
Почему нельзя просто git pull на сервере?
Нужен ли Envoyer, если у меня уже настроен Forge?
Как заблокировать одновременный запуск двух деплоев?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.