Гайд по деплою web-приложений для новичков. Часть 2. VPS и настройка окружения
Привет, коллеги! 👋
Это статья - вторая часть небольшого сериала о деплое web-приложений в поддержку сервиса по деплою приложений onFriday.
Вот ссылка на первую часть - деплой проекта на Laravel на shared-хостинге с использованием GitHub. Вкратце содержание:
Содержание статьи
- создание приватного репозитория на GitHub и его "связь" с локальным репозиторием- пуш проекта на GitHub
- клонирование репозитория с GitHub на shared-хостинг
- настройка символических ссылок (необходимо для Laravel приложений)
- настройка Composer
- работа с базой данных- настройка .env, выполнение миграций, компиляция ассетов и рестарт очередей
Если в прошлой статье мы "ютились" в отдельном каталоге на shared-хостинге, то в этой части статьи мы будем работать на выделенном сервере (физическом или виртуальном).
Что же такое VPS? VPS (англ. virtual private server) - выделенный виртуальный сервер. Простыми словами это просто удаленный компьютер, который вам временно предоставили. Технически, каждый VPS представляет собой отдельно запущенную виртуальную машину на физическом сервере, но с точки зрения конечного пользователя, такой сервер ничем не отличается по своему функционалу и управлению от выделенного сервера.
На старте у нас будет неподготовленный сервер, и мы с нуля "накатим" операционную систему и необходимые инструменты для того, чтобы наше Laravel-приложение работало. Это называется настроить окружение.
В этой статье установим и настроим:
- Nginx. Бесплатный и мощный веб-сервер с открытым исходным кодом. Nginx - это приложение, которое может принимать входящие запросы от пользователей (обычно через веб-браузер) и отвечать на них, отправляя запрошенные веб-страницы или другие данные.
- Система управления базами данных. Будем использовать MySQL.
- Для работы Laravel нам нужен PHP (PHP-FPM).
- Далее поставим Composer.
- Чтобы корректно работала frontend часть нам понадобится Node/npm.
- Ну и Git.
Про Nginx, CGI и PHP-FPM
Nginx сам по себе не умеет обрабатывать PHP, и если вы направите его на index.php, то в респонсе получите содержимое скрипта. Nginx может обслуживать статические файлы, такие как HTML, CSS и JavaScript, а для обработки PHP-скриптов ему нужна помощь.
CGI (Common Gateway Interface) - один из первых сценариев обработки php-скриптов сервером. В этом режиме каждый php-запрос выполняется отдельным процессом. Производительность сайта невысокая, так как на обработку скриптов требуется много ресурсов. Сейчас он используется редко и считается устаревшим.
Развитием CGI стал FastCGI. Была учтена медленная скорость CGI и применили циклическую обработку нескольких запросов одним процессом. FastCGI — экономит ресурсы сервера за счет сокращения количества запущенных процессов.
PHP-FPM (FastCGI Process Manager), "Менеджер процессов FastCGI". Это уже не протокол или интерфейс, а исполняемая программа, Linux пакет. Это компонент, который реализует протокол FastCGI и соединяет Nginx с нашим Laravel приложением.
По сути, PHP-FPM это балансировщик нагрузки, распределяющий работу между множеством интрефейсов (FastCGI).
Что у нас есть на старте
Кроме непреодолимого желания, у нас есть выделенный сервер и доступы к нему:
- ip-адрес
- логин (в моём случае root)
- пароль
Проект для разворачивания как и в предыдущей статье - демо админ-панели для проектов на Laravel - MoonShine.
Git репозитории: локальный и удаленный (приватный) на GitHub уже настроены и связаны (как это делали).
Установка операционной системы
Смотрим, есть ли операционная система на сервере. В моём случае это Ubuntu 20.04.
У моего провайдера есть возможность выбрать операционную систему через панель управления, возможно у вашего провайдера придется ставить операционную систему самостоятельно или брать дополнительную услугу. Можно приступать! Копируем папку с проектом на сервер (шутка).
Открываем терминал и подключаемся к серверу. Вводим:
Вводим пароль. Видим, что приглашение для ввода поменялось - мы авторизованы.
Создаём отдельного пользователя под проект
Хорошей практикой с точки зрения безопасности и управления доступом будет создание отдельного пользователя для каждого проекта что обеспечит изоляцию проектов на одном сервере.
Создадим пользователя localadmin и настроим ему директорию:
Установим пароль для пользователя localadmin:
Создадим для пользователя директорию .ssh и файл authorized_keys:
Настроим владельца директорий и файлов (папку с проектом создадим позднее, тогда и установим права на неё):
Настроим права доступа:
Чтобы Linux не запрашивал каждый раз пароль при выполнении команд от имени суперпользователя (sudo), выполним команду:
Входим в систему под созданным пользователем:
Настройка подключения по SSH
Более удобно в дальнейшем подключаться к серверу по SSH:
1. Создадим SSH ключи на локальной машине:
- выполните команду ssh-keygen в терминале
- следуйте инструкциям для создания новой пары ключей (публичного и приватного)
- по умолчанию ключи будут сохранены в директории:
Windows - С://Users/username/.ssh/id_rsa (или другой диск, на котором установлена Windows)
Linux - /home/username/.ssh/id_rsa
MacOS - /Users/username/.ssh/id_rsa
2. Добавим публичный ключ (*.pub) на сервер:
- отобразите содержимое публичного ключа на локальном рабочем месте:
- скопируйте содержимое публичного ключа
- на сервере откройте файл ~/.ssh/authorized_keys с помощью текстового редактора
- вставьте скопированный публичный ключ в конец файла authorized_keys. Убедитесь, что каждый ключ находится на новой строке.
Также можно отключить вход на сервер по паролю и разрешить только аутентификацию через SSH. Для этого нужно отредактировать файл конфигурации SSH на сервере:
Продолжаем. На старте у нас чистая система и нужно все установить и настроить окружение с нуля.
Обновим все пакеты в системе. Нужно держать в актуальном состоянии компоненты операционной системы, чтобы её работа была безопасной и стабильной. Сначала обновляем список доступных пакетов:
Затем можно обновить до последней версии все пакеты в системе:
Nginx
Теперь можно переходить к установке веб-сервера Nginx:
Проверим, правильно ли установлен Nginx - перейдём в браузере на ip адрес сервера:
Отлично, появилась стандартная страница Nginx. Чуть позднее разберемся как это работает.
Устанавливаем MySQL
Выполняем команду:
Видим, что MySQL 8 версии установлен.
MySQL поставляется с скриптом mysql_secure_installation, который помогает установить некоторые настройки безопасности по умолчанию: установку пароля root, удаление анонимных пользователей, удаление тестовой базы данных и т.д.:
Запускается диалог, в котором быстро настраивается СУБД:
- Validate password component. Можно его не настраивать, но помним что пароль должен быть надёжным - длинный, буквы в разном регистре и т.д.
- Remove anonymous users? Удаляем.
- Disallow root login remotely? Соглашаемся - запрещаем удаленный вход в систему MySQL от имени пользователя root. Это является хорошей практикой безопасности. Пользователь root в MySQL обладает максимальными привилегиями и может выполнять любые операции с базой данных. Если злоумышленник получит доступ к учетной записи root, он может с нашей базой делать всё что захочет.
- Remove test database and access to it? Удаляем тестовую базу данных.
- Reload privilege tables now? Перезагружаем чтобы изменения применились
Создадим нового пользователя для базы данных проекта. В целях безопасности всегда нужно создавать отдельного пользователя для базы данных каждого проекта. Заходим в MySQL под root:
и вводим пароль текущего пользователя системы. Вошли, проверяем, что приглашение изменилось на mysql>.
Создаём пользователя:
имя_пользователя и пароль устанавливаем свои!
Проверим, создан ли пользователь:
Теперь создаем базу данных для проекта:
И даём пользователю доступ к базе:
Заканчивая работу по настройке MySQL, необходимо перезагрузить привилегии, чтобы все сделанные изменения вступили в силу. Не забывайте каждый раз перезагружать привилегии после внесения изменений:
База данных подготовлена.
В целях безопасности базы данных можно выполнить еще несколько настроек.
Дополнительные настройки безопасности:
- Отключение удалённого подключения. В файле конфигурации MySQL (обычно my.cnf или my.ini) можно указать параметр bind-address и установить его значение на localhost или 127.0.0.1. Это ограничит доступ к MySQL только с локального сервера, и удаленное подключение будет невозможно.
- Использование брандмауэра. Настройте брандмауэр на сервере, где установлен MySQL, чтобы блокировать входящие соединения на порт MySQL (обычно 3306) с удаленных IP-адресов.
Переходим к PHP-FPM.
Установка и настройка PHP-FPM
PHP-FPM ставим чтобы наш веб-сервер мог обрабатывать большое количество запросов одновременно.
Приложение, которое мы будем разворачивать, работает на Laravel 11 - нам понадобиться PHP 8.3 (самая свежая версия PHP на момент публикации статьи, или другую версию, в зависимости от вашего проекта):
Проверьте установленную версию PHP:
В ответ вы должны увидеть информацию о версии PHP
И статус службы PHP-FPM:
Служба должна быть активной (запущенной)
Установка Git
Переходим к Git:
Проверяем:
Видим версию git. C git всё достаточно легко, не так ли?
Установка Composer
Выполняем команду для загрузки установочного скрипта Composer:
Проверяем что установщик не поврежден и не модифицирован всякими безобразниками:
Если всё ок и хэш совпал с эталонным, то появится сообщение - Installer verified, значит, установочный файл можно использовать. Устанавливаем Composer:
Проверим:
Удаляем файл composer-setup.php :
Устанавливаем Node.js и npm
Выполняем:
Проверяем:
Ставим расширения для PHP
Для каждого проекта ставится свой набор расширений для PHP.
Вот самые популярные:
php-mysql — позволяет PHP взаимодействовать с базами данных MySQL. Предоставляет функции и классы для подключения к MySQL, выполнения запросов и обработки результатов.
php-curl — обеспечивает интеграцию с библиотекой cURL. cURL (Client URL) — это инструмент для работы с URL-адресами, который позволяет выполнять HTTP-запросы, обращаться к веб-серверам, загружать файлы и многое другое. Модуль php-curl позволяет PHP-скриптам использовать функциональность cURL для взаимодействия с внешними ресурсами, такими как API, веб-сервисы и другие серверы.
php-dom — позволяет взаимодействовать с XML-документами через DOM API. Оно предоставляет функции и классы для работы с иерархической структурой дерева узлов.
php-zip — позволяет читать/записывать сжатые ZIP-архивы и файлы внутри них.
php-intl— предоставляет поддержку интернационализации (i18n) и локализации (l10n). Это расширение включает в себя библиотеку ICU (International Components for Unicode), которая обеспечивает мощные инструменты для работы с различными языками, региональными настройками и кодировками.
php-mbstring — предоставляет поддержку многобайтовых строк (multibyte strings). Многобайтовые строки используются для представления символов, которые не могут быть закодированы в одном байте, таких как символы азбуки Морзе, китайские иероглифы, японские каны и многие другие.
php-soap — обеспечивает поддержку для работы с SOAP (Simple Object Access Protocol). SOAP — это протокол для обмена структурированными информационными сообщениями в распределенной среде, использующий XML в качестве формата сообщений.
php-bcmath — для произведения арифметических операций с произвольной точностью. Laravel использует эту библиотеку для генерации и проверки CSRF-токенов, а также для работы с денежными и другими числовыми значениями.
php-cli — предоставляет возможность запускать PHP скрипты из командной строки. В контексте Laravel, может использоваться для выполнения команд Laravel Artisan.
php-common — является одним из основных пакетов расширений PHP, который включает в себя общие и основные функции и библиотеки, необходимые для работы с PHP.
php-fpm — альтернативный способ запуска PHP скриптов на веб-сервере, является отдельным процессом, который управляет выполнением PHP скриптов и обеспечивает более эффективное управление процессами PHP на сервере.
php-gd — (Graphics Draw) для работы с изображениями. Позволяет создавать, редактировать и обрабатывать изображения в различных форматах, таких как JPEG, PNG, GIF и другие.
php-opcache — для улучшения производительности PHP приложений путем кэширования скомпилированного PHP кода в памяти сервера. Это позволяет уменьшить время выполнения PHP скриптов, так как PHP код не нужно компилировать заново при каждом запросе.
php-readline — делает работу с командной строкой более удобной и эффективной (автодополнение и история команд, перемещение курсора и т.д.)
php-xml — для работы с XML (Extensible Markup Language) - создание XML документов, их парсинг, преобразование в другие форматы данных и т.д.
Я установил следующие:
В вашем случае список модулей может отличаться. Если вы не уверены, какие модули уже установлены, выполнить команду php -m .
Расширения для PHP будут установлены для той версии, которая используется на вашем сервере
Каталог проекта и настройка прав доступа
Давайте создадим директорию для проекта который будем деплоить:
Для того чтобы веб-сервер Nginx мог корректно работать с файлами и директориями нашего проекта на Laravel, он должен иметь правильные права доступа, чтобы обеспечить как безопасность, так и работоспособность приложения. При установке Nginx создаётся пользователь www-data или nginx (проверить можно в файле с конфигурацией /etc/nginx/nginx.conf, директива user). В моём случае пользователь Nginx - www-data.
Общий подход настройки прав доступа для директории проекта заключается в том, чтобы установить владельца (пользователя и группу localadmin) для полного контроля и дать права Nginx на чтение.
Делаем localadminвладельцем директории проекта:
Теперь настроим для Nginx. Владельца оставляем localadmin, а группу установим www-data:
Установим права на директорию проекта:
- для директорий: 755 (чтение и выполнение для всех, запись для владельца)
- для файлов: 644 (чтение и запись для владельца, чтение для остальных)
Наконец, отдельно для директорий storage и bootstrap/cache устанавливаем права доступа:
- для директорий: 775 (чтение и выполнение для всех, запись для членов группы владельца)
- для файлов: 664 (чтение и запись для членов группы владельца, чтение для остальных)
Теперь у Nginx есть право записывать данные в эти директории, что необходимо для кэширования и логирования.
Настройка Nginx
Если вы не знаете как работает Nginx, то предлагаю краткий экскурс.
Nginx сейчас выводит свою дефолтную страницу, давайте научимся влиять на поведение Nginx!
Nginx у нас "живет" в каталоге ../etc/nginx :
Его конфиг по умолчанию находится в /sites-available. Объясню отдельные строки конфига:
Создадим в каталоге проекта /var/www/moonshinedemo файл для тестирования - index.php:
Теперь откроем этот файл с помощью редактора nano:
Давайте что-нибудь оригинальное тут изобразим. Пусть будет
Жмем ctrl+s (сохраняет файл) и ctrl+x (закрыть редактор nano).
Теперь надо указать Nginx чтобы он искал проект в папке moonshinedemo. Внесем изменения в конфиг:
Редактируем следующие строки:
"Учим" Nginx как работать с php файлами. Раскомментируем строки:
Чтобы изменения в конфигурацию применились, надо Nginx перезапустить:
И проверяем работу, вводим ip-адрес:
Всё работает, файл index.php в /var/www/moonshinedemo можно удалить.
Клонируем проект из GitHub
Напоминаю, что мы работаем с приватным проектом, который настраивали в прошлой статье, для работы с ним нужно сгенерировать SSH-ключи на сервере и на локальном компьютере и указать публичные ключи в настройках GitHub репозитория. Если не знаете, как это делать, посмотрите в первой части статьи.
Переходим в каталог /var/www/ и клонируем проект из GitHub репозитория в каталог moonshinedemo:
Проверим:
Всё ок, мы склонировали проект на сервер.
Остальные телодвижения
Обновляем зависимости:
Создаём .env из шаблона:
Генерируем APP_KEY, вносим настройки для работы с базой данных, переводим в прод, указываем APP_URL , (смотрим как это делать в первой статье). После запускаем миграции:
Пересобираем ассеты:
Создаем символическую ссылку для папки хранилища в публичной директории вашего проекта Laravel. Это позволяет обращаться к файлам, хранящимся в хранилище, через URL-адреса:
После того, как символическая ссылка создана, она не требует обновления при каждом деплое. Заново создать символическую ссылку нужно только если произошли изменения в структуре файлов или директорий, связанных с хранением файлов (например, изменение пути к директории storage).
В настройках Nginx указываем параметры из документации Laravel (Тейлор всё протестировал). Не забудьте поменять путь к проекту (root):
Инструкция location / с директивой try_files $uri $uri/ /index.php?query_string; в конфигурации Nginx для приложения на Laravel используется для обработки маршрутов и перенаправления всех запросов на index.php, где происходит дальнейшая обработка маршрутов приложения Laravel.
Эта конфигурация позволяет обеспечить правильную маршрутизацию запросов в приложении Laravel, так как все запросы будут направлены на точку входа - index.php, где фреймворк Laravel может обработать их и вернуть соответствующий ответ.
Перезагружаем Nginx:
Готово. Можно проверять!
Дополнительные работы по Supervisor и Cron
Для продвинутых пользователей добавил информацию по установке и настройке Supervisor и Cron на ваш сервер. Полезные инструменты!
Supervisor
Зачем нам нужен Supervisor?
Очереди - неотъемлемая часть любого Laravel приложения. Не будем затрагивать тему как они работают, все это есть в документации. А Supervisor я добавил в статью при деплой потому, что если мы без него будем использовать queue:work (обработчик очередей, который обрабатывает задачи, помещенные в очередь), то при перезапуске или сбое приложения обработчик перестанет работать! Тут нам и поможет Supervisor, это менеджер процессов, который работает в фоновом режиме (демон) и управляет другими процессами, такими как queue:work. Supervisor который контролирует рабочие процессы и их количество, а также перезапустит процессы в случае сбоя.
Давайте установим Supervisor:
Для настройки Supervisor необходимо создать конфигурационный файл для каждого процесса, которым вы хотите управлять. Перейдем в директорию Supervisor (обычно это /etc/supervisor/conf.d/) и создадим конфигурационный файл для обработчика очередей Laravel - laravel-worker.conf :
Обновите Supervisor, чтобы он прочитал новый конфигурационный файл:
Запустите обработчика очередей с помощью Supervisor:
Теперь Supervisor будет управлять процессом обработки очередей Laravel и обеспечивать его непрерывную работу.
Сron
Cron - это стандартный инструмент в операционных системах Unix, который позволяет запускать задачи по расписанию. Эти задачи могут выполняться автоматически в определенное время или с определенной периодичностью.
В Laravel есть мощный функционал для планирования задач по расписанию, который называется scheduler. Также не буду перегружать статью про то как он работает, всё хорошо описано в документации.
Мы же с помощью Cron настроим чтобы каждую минуту выполнялась консольная команда Laravel schedule:run, которая под капотом будет искать задачи, которые нужно выполнить прямо сейчас. Создаётся команда так:
При этом создается файл команды - app/Console/Commands/ResetCommand.php
Давайте разберем пример. На демо-проекте админки MoonShine - работает команда, которая ресетит базу данных и чистит пользовательские файлы чтобы они не копились. Демо проект размещен чтобы любой желающий мог попробовать MoonShine в деле и в том числе добавить свои пользовательские данные (создать статьи, добавить изображения и т.д.). Чтобы база данных не разрасталась, сделана команда по очистке:
Чтобы команда выполнялась её нужно добавить в файле routes/console.php с указанием периодичности выполнения. Приготовлены такие функции, как ->daily(), ->hourly(), ->everyFifteenMinutes() и т. д.:
Переходим на сервер. На Ubuntu 20.04 Сron обычно уже предустановлен по умолчанию. Вы можете проверить, установлен ли cron, с помощью следующих команд:
Если Cron не установлен выполняем команду:
После установки Cron будет автоматически запущен. Проверяем его статус с помощью команды:
Настроим автозапуск Crone при загрузке системы:
Добавляем планировщика задач Laravel в Cron. Выполните команду crontab -e, которая откроет файл редактирования текущих задач:
Готово. Теперь Cron будет следить что планировщик задач Laravel (scheduler) запускается каждую минуту. А планировщик, в свою очередь, запускает команду для очистки базы данных каждые 15 минут.
Выводы
Деплой на VPS сервер выполнен! Этот процесс не сложнее деплоя на shared-хостинг, если делать всё пошагово, то проблем обычно не возникает. В среднем процесс создания окружения занимает минут 40-50. Сам в работе использую только VPS серверы, разной конфигурации, в зависимости от решаемых задач.
Для вашего комфорта подготовил шпаргалку с командами по настройке окружения, чтобы ничего не забыть, и не листать статью в поисках нужной строчки.
Что дальше?
Варианты деплоя на самые популярные виды хостинга мы рассмотрели. В следующей статье будем разбираться, как можно (и нужно) автоматизировать деплой. Подписывайтесь на мой блог, чтобы не пропустить! К первой части статьи было достаточно много комментариев, в том числе по дополнению статьи, так что жду активную обратную связь и в этот раз.
Данил Щуцкий, автор проекта CutCode.
Для node лучше использовать nvm
С Хабра выгнали? ;)
нет. все доступные ресурсы подключаю