Быстрое развертывание стэка ПО на web-серверах для запуска Laravel приложений
Артур Хайбуллин
Артур Хайбуллин 13 апр 2026, 00:18
Снимок экрана 2026-04-16 103916.png

Если у тебя всего один сайт и один сервер, всё выглядит элементарно: подключился по SSH, поставил nginx, PHP, подправил конфиги - и готово.
Но как только проектов становится больше, эта рутина начинает съедать время и порождать ошибки.

Я постоянно ловил себя на том, что повторяю одни и те же шаги:

  • ставлю nginx из официального репозитория (а не из пакетов дистрибутива, чтобы всегда иметь свежую версию)

  • создаю отдельный PHP-FPM пул под каждый сайт с собственным Unix-сокетом

  • настраиваю OPcache, лимиты, таймауты

  • прописываю виртуальные хосты nginx с корректными заголовками безопасности

  • ставлю Composer, Node.js, Yarn

  • создаю структуру директорий под Laravel

  • добавляю cron для artisan schedule:run

И всё это - вручную. Каждый раз. И каждый раз есть шанс что-то забыть или сделать иначе, чем на предыдущем сервере.

Почему Ansible, а не Docker?

ansible-1024x683-1-4034155887.png

Вопрос логичный. Docker действительно удобен, когда нужна изоляция и переносимость.
Но в реальности часто встречаются ситуации, когда контейнеры - лишняя сложность:

  • VDS с ограниченными ресурсами

  • хостинг без поддержки Docker

  • проекты, где нужен прямой доступ к системе

  • обслуживание legacy-серверов

Ansible же работает с любым Linux-сервером через SSH. Никаких агентов, никакой дополнительной инфраструктуры - только Python на целевой машине.

Что получилось в итоге

Я собрал роль nginx_laravel, которая разворачивает полноценную среду для Laravel одной командой:

ansible-playbook site.yml

Что делает роль:

  • устанавливает nginx из официального репозитория nginx.org

  • автоматически определяет последнюю стабильную ветку (1.26.x, 1.28.x и т.д.)

  • ставит PHP 8.4 (или любую >= 8.2) из ondrej/php или Remi

  • создаёт отдельный PHP-FPM пул для каждого сайта

  • поддерживает список сайтов - роль сама создаёт нужные конфиги

  • добавляет сайт по умолчанию (catch-all) с информацией о сервере

  • включает базовые заголовки безопасности

  • защищает .env, .git, vendor

  • интегрируется с GitLab CI/CD

CI/CD: автоматизация, которая экономит время

Я хотел добиться простого принципа: любое изменение в репозитории должно быть проверено автоматически, а деплой выполняется только если всё прошло успешно.

Снимок экрана 2026-04-16 104015.png

Пайплайн состоит из трёх стадий: validate → deploy → verify.

validate ──────────────────────────────────────────────────────┐
  yaml-lint   ──┐                                              │
  lint          ├── все три параллельно                        │
  syntax-check ─┘                                              │
                                                               ▼
deploy ────────────────────────────────────────────────────────┐
  deploy:production  (только если validate прошёл)             │
                                                               ▼
verify ────────────────────────────────────────────────────────┘
  verify:sites  (только если deploy прошёл)

Validate

Запускается на каждый push и merge request.
Состоит из трёх параллельных задач:

  • yaml-lint - проверяет синтаксис YAML

  • ansible-lint - анализирует плейбуки на ошибки и антипаттерны

  • syntax-check - проверяет структуру плейбука без подключения к серверу

yamllint --config-file .yamllint.yml --format colored $(find . -name '*.yml' -o -name '*.yaml')

ansible-playbook site.yml --syntax-check --inventory inventory/hosts.yml

Deploy

Запускается только при пуше в main.
Использует resource_group: production, чтобы не было параллельных деплоев.

Что происходит:

  1. Поднимается ssh-agent, загружается ключ

  2. При необходимости расшифровываются секреты ansible-vault

  3. Запускается плейбук с флагом --diff, чтобы в логах CI было видно изменения

Verify

После деплоя запускается проверка всех сайтов:

  • проверяется дефолтный сайт

  • проверяются именованные сайты через Host-заголовок

  • для HTTPS используется отключённая проверка сертификата (поддержка self-signed)

Если хоть один сайт не отвечает или возвращает 4xx/5xx - пайплайн падает.

Почему это важно

До внедрения пайплайна типичная ситуация выглядела так:

  • сделал изменение

  • запушил

  • через 10 минут проверяешь - сайт лежит

Теперь:

  • syntax-check ловит ошибки до деплоя

  • verify ловит проблемы сразу после деплоя

  • весь цикл занимает 3-4 минуты

Что мне кажется важным в дизайне

Конфигурация как данные, а не код. Вся конфигурация сайтов — это просто YAML в инвентаре:

laravel_sites:
  - domain: "myapp.ru www.myapp.ru"
    root: "/var/www/myapp"
    ssl_enabled: true
    ssl_email: "admin@myapp.ru"
    env: production
Снимок экрана 2026-04-13 001232.png

Добавить сайт - просто добавить элемент в список.

Идемпотентность

Роль можно запускать сколько угодно раз - она не ломает уже настроенный сервер.

Несколько доменов на один сайт

Первый домен используется для сокета, логов и сертификата, остальные обслуживаются nginx.

Кроссплатформенность

Изначально роль была только под Debian/Ubuntu. Потом добавил поддержку AlmaLinux - достаточно было вынести OS-специфичные переменные в vars/.

Что ещё предстоит сделать

  • автоматический HTTPS через Let's Encrypt

  • опциональная установка PostgreSQL/MySQL

  • мониторинг через php-fpm status

  • автоматический деплой кода из репозитория (возможно через webhook)

Итог

Эта роль не заменяет понимание nginx и PHP-FPM, но отлично снимает рутину и делает настройку серверов предсказуемой и воспроизводимой.
Если у тебя несколько Laravel-проектов на VDS и ты всё ещё настраиваешь серверы вручную - попробуй. В худшем случае просто посмотри код - уверен, найдёшь что-то полезное.

Исходники: GitOps / ansible-web-server · GitLab

0
62
Комментарии (0)
Комментировать
Пока нет комментариев

Станьте первым, кто прокомментирует эту запись