Современные сайты часто должны работать в режиме 24x7x365 без остановок на обслуживание. В этих условиях владельцы сайтов готовы инвестировать дополнительные средства в оборудование и программные решения для обеспечения высокой доступности.
Сайт без единой точки отказа становится де-факто требованием в мире, где большинство операций выполняются дистанционным образом. Простои обходятся дорого, особенно, если они происходят в неподходящее время — праздники, выходные, высокий сезон.

В рамках настройки мы рассмотрим следующие проблемы, которые обычно существуют в подобных системах:
- настройка базы данных без единой точки отказа;
- настройка Nginx для обслуживания приложения без единой точки отказа;
- кластеризация статического контента между узлами с помощью GlusterFS;
- репликация сессий между узлами с помощью SyncThing;
- липкая балансировка трафика для избежания потери сессии;
- балансировка трафика между узлами:с помощью DNS;с помощью CDN для быстрого переключения в случае отказа узла;
- с помощью DNS;
- с помощью CDN для быстрого переключения в случае отказа узла;
Для простоты будем считать, что приложение реализовано на PHP, однако, никаких ограничений по средству реализации приложения — будь то, Java (Jetty, Tomcat), Python (Django, Tornado, Turbogears), Ruby (RoR) или использовании другой экосистемы — нет, настройки в большинстве случаев успешно переносятся и в другие среды.
- Топология
- Внутренняя сеть
- Публичная сеть
- DNS
- Установка базового программного обеспечения LEMP
- Репликация сессий
- Использование удаленной синхронизации
- Удаленная репликация с помощью SyncThing
- Настройка мастер-мастер кластера Galera
- Настройка подключения клиентов к кластеру Galera
- Пример проблемы с возникновением обслуживания на разных узлах
- Проксирование соединений к MySQL помощью Nginx
- Настройка балансировки нагрузки между приложениями
- Настройка PHP-FPM
- Настройка Nginx
- Централизованное хранение журналов приложений
- Внешняя балансировка с помощью DNS
- Сертификат SSL для website. com
- Резервное копирование данных
- Требования к серверу
- Требования к DNS
- Базовая настройка компонентов Nginx и получение сертификата
- Установка и настройка MariaDB
- Установка и настройка PHP7
- Настройка виртуального хоста сайта
- Организация доступа к серверу для разработчика
- Подготовка сервера
- Запуск nginx
- Nginx в Docker
- Иерархия каталогов nginx
- Директивы
- Установка и настройка php-fpm
- Конфигурация nginx
- Команды nginx
- Настройка SSL сертификата
Топология
Мы будем настраивать трехузловую конфигурацию, как изображено на следующем рисунке:

Внутренняя сеть
Для успешной настройки все узлы должны быть соединены высоконадежной внутренней сетью. В том случае, если вы используете виртуальные машины, у которых есть только публичная сеть, то вы можете использовать VXLAN, туннели GRE или VPN для организации внутренней сети. В целом, мы предполагаем, что вы как-то свяжете свои серверы между собой, и эта связь будет надежной. От надежности и производительности внутренней сети будет зависеть то, насколько качественно будет работать отказоустойчивая конфигурация.
Если вы используете аппаратные серверы, рекомендуем связать их между собой через свич с поддержкой LACP, а лучше посредством MLAG, через два независимых коммутатора. Если же ваши коммутаторы не поддерживают MLAG, то вы можете использовать протокол OSPF для организации отказоустойчивой внутренней сети, используя Quagga, развернутый на каждом узле.
Если же у вас только один коммутатор, просто воткните три сервера в него и настройте общую частную сеть.
В облаке Cloud2 NetPoint каждая виртуальная машина получает две сети — публичную и приватную, при этом приватная сеть сразу настроена для правильной работы. Если вы клиент NetPoint, вам ничего не надо делать для настройки приватной сети.
Публичная сеть
Публичная сеть в рамках планируемой конфигурации может быть ненадежной. Если вы используете аппаратные серверы, можете взять публичные каналы от нескольких провайдеров, чтобы защититься от аварии инфраструктуры провайдера. В общем случае, к публичной сети требования довольно просты — она должна быть приемлемо надежной и обеспечивать прохождение нужного объема трафика.
Обратите внимание, что в моменты деградации, например, если один из узлов выйдет из строя, трафик перетечет на оставшиеся два узла. Каналы каждого из этих узлов должны выдержать добавление от 1/6 до 1/3 трафика без деградации.
На каждом узле мы установим одну и ту же операционную систему и все прикладное программное обеспечение — Nginx, GlusterFS, MariDB, PHP7 и настроим публичное взаимодействие с этими серверами по безопасному протоколу Let’s Encrypt.
DNS
Будем считать, что наши серверы имеют доменные имена:
- server1.website.com, website.com
- server2.website.com, website.com
- server3.website.com, website.com
Необходимо убедиться, что серверы доступны по этим доменным именам из сети интернет (корректные записи A, AAAA). Доменные имена необходимы для получения сертификатов Let’s Encrypt, которые будут шифровать трафик.
Если вы не планируете использовать для внешней балансировки трафика CDN, необходимо установить корректный TTL для записей website.com A ip. Устанавливайте минимальный, какой позволяет провайдер. Это необходимо, чтобы при отказе сервера вы могли удалить запись для него и быстро исключить его из списка доступных.
Необходимо заметить, что не все провайдеры правильно обрабатывают малые TTL для DNS, поэтому мы бы не рекомендовали использовать этот способ, если есть возможность использовать внешнюю балансировку с помощью CDN.
Если вы планируете отправку почты с напрямую серверов или через внешний SMTP, то для настройки обратитесь к руководствам по настройке дополнительных записей, необходимых для правильной доставки почты — SPF, PTR.
Установка базового программного обеспечения LEMP
Для выполнения дальнейших шагов нам необходимы настроенные LEMP серверы с установленными сертификатами Let’s Encrypt. В зависимости от выбранной ОС, вы можете воспользоваться для настройки одним из руководств, приведенных ниже. При настройке каждого сервера используйте его доменное имя — server1.service-website.com, server2.service-website.com, server3.service-website.com.
Настройку необходимо выполнить на каждом из серверов, который будет входить в отказоустойчивый кластер.
Установка LEMP в CentOS 7 с использованием внешнего репозитория Remi’s Repository для установки PHP 7.2.

Стандартная установка LEMP в Debian 9 Stretch с использованием PHP 7.0
Стандартная установка LEMP в Ubuntu 18.04 Bionic с использованием PHP 7.2
Для обеспечения мгновенной доступности статического контента и упрощения доступа к нему можно использовать различные подходы. Если ваш хостинг-провайдер предлагает высокодоступное хранилище, доступное по протоколу Swift или S3, разумно использовать его, храня данные вне серверов. Если ваш сайт поддерживает такое решение, рекомендуем использовать его. В этом случае вы можете просто пропустить данный раздел.
Если файлы требуется хранить в локальной файловой системе, что может быть обусловлено разными факторами — например, сайт не адаптирован для использования сетевых объектных хранилищ, присутствует специфическая обработка, которую необходимо производить в полноценной файловой системе, то вы можете использовать несколько подходов для реализации доступности файлов на всех узлах.
Синхронизация с помощью rsync, inosync. Методы широко применяются, но имеют основной недостаток, связанный с возможным рассогласованием или потерей файлов, которые на момент отказа еще не были синхронизированы. Кроме того, в зависимости от объемов хранимых данных и типов хранимых файлов, данный подход часто может быть неосуществим практически.
При использования синхронизации ваш сайт должен уметь корректно обрабатывать ситуацию отсутствия файла, который еще не успел скопироваться на узел, где запрашивается.
Высокая доступность с помощью распределенной файловой системы. Этот подход немного сложнее в настройке и управлении, однако гарантирует одинаковую доступность файлов и каталогов.
Мы рассмотрим способ синхронизации для сессий PHP и обеспечение высокой доступности для статических файлов с помощью высокодоступной распределенной системы GlusterFS с трехкратной репликацией данных.
Трехкратная репликация означает, что каждый файл будет содержаться на каждом из узлов нашего кластера, поэтому при потере любого из них файл всегда будет доступен. Когда же сервер восстановится, он синхронизирует изменения, которые возникли с момента отказа.
Трехкратная репликация не отменяет резервное копирование. Вы должны выполнять резервное копирование вне зависимости от надежности хранения текущих данных. Читайте статью о настройке резервного копирования файлов с помощью Duplicity.
При настройке GlusterFS ожидается, что все серверы соединены по внутренней сети 10.0.0.0/24 и имеют адреса 10.0.0.1, 10.0.02, 10.0.03. Если у вас другие адреса, измените настройки, приведенные в инструкции соответствующим образом.

Для дальнейшей настройки GlusterFS перейдите в наше руководство по настройке для трехузлового кластера. В руководстве приведены инструкции для CentOS 7, Debian 9, Ubuntu 16.04 или 18.04.
После успешного завершения настройки GlusterFS создайте каталог /var/www/webiste.com/assets и добавьте в /etc/fstab запись вида:
/mnt/gluster /var/www/website.com/assets none bind,_netdev,default 0 0
В общем случае, мы не рекомендуем размещать сам код сайта в распределенной файловой системе. Специфические системные вызовы, которые используют движки, могут снизить производительность для таких сред, которые на лету автоматически определяют изменения и применяют их — например, PHP-FPM. С другой стороны, если после чтения кода обращение к файловой системе не происходит, можно легко использовать хранение кода в GlusterFS.
Всеми силами избегайте использования файловых блокировок на распределенных файловых системах — это существенно снизит производительность работы с файлами. Если вам нужны распределенные блокировки, рассмотрите вариант использования Apache Zookeeper вместо файловых блокировок.
Репликация сессий
Если вы используете MySQL для хранения сессий, то этот раздел можно пропустить, поскольку мы будем использовать кластерный вариант MySQL, который обеспечит доступность сессий на всех узлах. Аналогично обстоят дела, если вы храните сессии в Redis.
Настройка высокодоступного кластера Redis на 3х узлах рассматривается в отдельной статье из-за объемности.
Лайфхак. В последнее время разработчики часто выбирают хранение сессий в зашифрованном виде на стороне клиента, а не на сервере. При этом сервер хранит только ключ симметричного шифрования, сами же зашифрованные данные всегда передаются через Cookie. Если вы планируете использовать такой подход, можете пропустить оставшуюся часть раздела.
Использование удаленной синхронизации
Далее рассмотрим как реализовать асинхронную репликацию сессий с помощью инструментов на основе удаленной синхронизации, которая подходит для многих, но не всех сайтов.
Важное замечание: если сессия хранит информацию, утрата которой является проблемой, данный подход использовать нельзя.
Удаленная репликация с помощью SyncThing
Преимущества SyncThing состоят в том, что это программное обеспечение использует пиринговый протокол, что особенно удобно в случае группы, состоящей из более чем 2х узлов. Для настройки SyncThing воспользуйтесь нашим руководством, которое показывает как настроить трехузловой кластер для синхронизации сессий между узлами.
В качестве альтернативы SyncThing вы можете рассмотреть и Resilio, однако, это коммерческий инструмент, для поддержки некоторых функций требуется приобрести PRO-лицензию.
Теперь, когда мы разобрались с файлами и каталогами, пришло время решить вопрос с высокодоступным сервером СУБД.
Настройка мастер-мастер кластера Galera
В приложениях без единой точки отказа доступность СУБД — особо важный аспект. В рамках MySQL уже несколько лет существует продвинутая система для организации мульти-master репликации, которая реализуется с помощью Galera. В отличие от способов обеспечения отказоустойчивости MySQL, которые применялись ранее и являлись асинхронными или почти синхронными, кластер Galera позволяет реализовать самую настоящую синхронную репликацию MySQL, которая может смело применяться в продуктовой среде.
Настройка кластера MySQL Galera для операционных систем Ubuntu 16.04, Ubuntu 18.04, Debian 9, CentOS 7 приведена в отдельной статье нашего блога. После выполнения инструкций, приведенных в ней, вы получите полноценный отказоустойчивый кластер MySQL без единой точки отказа.
Настройка подключения клиентов к кластеру Galera
Из-за ограничений Galera вы можете столкнуться с тем, что все серверы приложений должны работать с кластером данных через один определенный сервер MySQL до его выхода из строя, после чего переключиться на другой доступный.
Внимание. Не используйте HAProxy, Nginx, если вам необходимо всегда обслуживать все операции MySQL на одном и том же сервере. Несмотря на то, что в некоторых случаях все будет работать, ряд ситуаций приведет к тому, что соединения будут обслуживаться разными серверами.
Пример проблемы с возникновением обслуживания на разных узлах
Рассмотрим пример балансировки соединений с помощью Nginx, который приводит к возникновению ошибки.
Данный фрагмент конфигурации Nginx делает следующее:
Nginx будет слушать соединения по протоколу TCP на порту 33306 текущего сервера и перенаправлять их на сервер 10.0.0.1:3306, если он не доступен, то на сервер 10.0.0.2:3306, в случае его отказа на 10.0.0.3:3306. Эта конфигурация Nginx активируется на всех серверах, где будут выполняться приложения.
Приложения будут соединяться с MySQL по адресу 127.0.0.1:33306, который будет проксировать запросу на нужный сервер MySQL.
Сначала все серверы MySQL работают, появляются клиенты, проксируемые соединения устанавливаются с сервером 10.0.0.1:

Сервер MySQL 1 выходит из строя, клиенты получают сообщение о потере соединения и инициализируют повторное соединение, в результате чего они переключаются на сервер 10.0.0.2:

Пока что все отлично, новые клиенты, которые будут появляться будут отправляться на сервер 10.0.0.2:

Теперь сервер 10.0.0.1 опять появляется в сети, и появляется клиент 5:

Поскольку Nginx обнаружил, что сервер 10.0.0.1 снова доступен, он подключил клиента нему. В результате возникла ситуация обслуживания на различных серверах.
Этот пример показывает, что при наличии требования обслуживания на одном сервере СУБД, которое продиктовано ограничениями кластера Galera, возникающими при использовании ряда операций блокировок, использование проксирования соединений не является возможным способом решения проблемы. Оно позволяет бороться с ситуацией выхода серверов из строя, но автоматический ввод серверов обратно приведет к некорректной обработке запросов.
В том случае, если нет требования обработки на одном сервере, проксирование соединений с помощью Nginx будет прекрасно работать. Рассмотрим эту настройку подробнее.
Проксирование соединений к MySQL помощью Nginx
Как мы уже выяснили ранее, подобная схема может успешно использоваться, если нет требования обработки на одном сервере.
Настройка Nginx. Добавьте в файл /etc/nginx/nginx.conf следующий фрагмент:
Проверьте, что конфигурация Nginx корректна и перезапустите его:
sudo nginx -t
sudo systemctl restart nginx
Настройка пользователя MySQL. Вам необходимо создать пользователя MySQL, который может соединяться с базой данных с любого из ваших серверов через проксированное соединение:
Проверьте, что созданный пользователь может соединяться с СУБД через прокси:
На этом настройка завершена. Теперь движок вашего сайта может соединяться с любым из доступных серверов MySQL через единый адрес 127.0.0.1:33306.
Настройка балансировки нагрузки между приложениями
В этом разделе мы настроим механизм отказоустойчивой обработки с помощью распределения обработки между локальным движком сайта и удаленными, которые размещаются на двух других серверах. Для простоты будем считать, что используется PHP-FPM, хотя принципиальной разницы нет. Топология обработки запросов приведена на следующем изображении:

Запрос от пользователя, который поступил на сервер 1, обрабатывается Nginx следующим способом:
- если возможно исполнение на локальном PHP-FPM, запрос исполняется на нем;
- если локальный PHP-FPM недоступен, запрос передается на один из доступных серверов напрямую в PHP-FPM (мимо Nginx, который на них тоже выполняется).
В приведенной выше схеме обработки предполагается, что приложение размещено в безопасной локальной сети. В случае взаимодействия через публичную инфраструктуру лучше организовать резервный путь обработки через Nginx с сертификатом SSL и выделенным портом для обработки трафика приложения. В этом руководстве мы рассматриваем только настройку отказоустойчивой обработки в безопасной сети.
Предполагается, что вы уже выполнили настройку серверов LEMP по руководству, приведенному ранее. К этому момент у вас должны быть развернуты три сервера с Nginx и PHP-FPM.
Настройка PHP-FPM
CentOS. В файле /etc/opt/remi/php72/php-fpm.d/www.conf измените listen = /var/run/php72-fpm.sock на listen = 10.0.0.X:20000, где X — 1, 2, 3 в зависимости от сервера. После внесения изменений перезапустите PHP-FPM командой sudo systemctl restart php72-php-fpm.
Если вы установили из репозитория Remi другую версию PHP, сделайте замену аналогичным способом с учетом именования.
Debian 9. В файле /etc/php/7.0/fpm/pool.d/www.conf измените listen = /run/php/php7.0-fpm.sock на listen = 10.0.0.X:20000, где X — 1, 2, 3 в зависимости от сервера. После внесения изменений перезапустите PHP-FPM командой sudo service php7.0-fpm restart.
Ubuntu 18. В файле /etc/php/7.2/fpm/pool.d/www.conf измените listen = /run/php/php7.2-fpm.sock на listen = 10.0.0.X:20000, где X — 1, 2, 3 в зависимости от сервера. После внесения изменений перезапустите PHP-FPM командой sudo service php7.2-fpm restart.
Настройка Nginx
Замените в конфигурации Nginx фрагмент:
где X — октет, соответствующий локальному адресу, например, для сервера 10.0.0.1 — 1, а Y, Z — октеты адресов двух оставшихся серверов в случайном порядке, например, для сервера 10.0.0.1:
Проверьте настройки Nginx и перезапустите его:
sudo nginx -t && systemctl restart nginx
Централизованное хранение журналов приложений
access_log /var/log/nginx/access-10.0.0.1.log;
error_log /var/log/nginx/error-10.0.0.1.log;
Не забудьте организовать ротацию журналов — в общем каталоге это сделать несколько сложнее. Другой способ организации централизованного хранения записей журналов — отправлять их в общее хранилище, например, в Elasticsearch с помощью Filebeat и анализировать их в Kibana.
Организация централизованного хранения журналов особенно важна для реализации масштабируемых, отказоустойчивых приложений, поскольку их отладка более сложна. Для понимания ситуации администратору важно одновременном наблюдать журналы со всех узлов, поскольку заранее неизвестно на каком из них происходила обработка запроса.
Внешняя балансировка с помощью DNS
К настоящему моменту у вас должно быть настроено 3 сервера LEMP, при этом ваш сайт должен быть доступен по трем доменным именам — server1.website.com, server2.website.com, server3.website.com по протоколу HTTPS: https://serverX.website.com/. Как мы говорил ранее, у вас так же есть настроенный домен website.com, для которого созданы три записи типа A/AAAA:
- website.com A server1-ip;
- website.com A server2-ip;
- website.com A server3-ip.
К сожалению, вы пока что не можете открыть сайт по безопасному протоколу HTTPS по адресу https://website.com/, поскольку сертификат для данного домена еще не установлен.
Сертификат SSL для website. com
Если вы используете купленный сертификат, то все, что вам необходимо сделать — копировать виртуальный хост Nginx, созданный для serverX.website.com, заменить в нем serverX.website.com на website.com, а сертификат Let’s Encrypt на приобретенный вами.
Если вы планируете для сайта https://website.com использовать сертификат Let’s Encrypt, то, опять же, скопируйте виртуальный хост Nginx, получите для него SSL-сертификат точно так же, как было описано в инструкции по настройке LEMP-сервера.
На этом опциональном шаге вы можете дополнить систему с помощью отказоустойчивой балансировки трафика пользователей между доступными серверами с помощью CDN. Вышедшие из строя серверы автоматически будут исключаться из балансировки. Итоговая схема высокой доступности станет выглядеть как изображено на картинке:

Выполнение этого шага не только обеспечивает автоматическое отключение вышедших из строя серверов, но и позволяет обеспечить защиту кластера от DDoS.
Резервное копирование данных
Важно настроить резервное копирование сразу же, как только вы настроили серверы, не откладывая это действие на потом. Воспользуйтесь нашим пошаговым руководством по настройке инкрементного резервного копирования файлов и баз данных для MySQL и PostgreSQL с помощью Duplicity.
Поскольку серверы используют GlusterFS и кластер Galera, вам достаточно выполнять резервное копирование для этих данных только на одном из серверов. Что же касается системных каталогов, для них рекомендуем настроить резервное копирование на каждом из серверов.
Закончив чтение данного руководства, вы научитесь самостоятельно настраивать минималистичный LEMP (Linux, Nginx, MySQL, PHP 7) сервер для сайта без лишних компонентов. Ваш сайт будет доступен по защищенному протоколу HTTPS с поддержкой бесплатного сертификата Let’s Encrypt.
Ubuntu версии 18.04 LTS. Мы рекомендуем использовать данный дистрибутив Ubuntu, так как он будет поддерживаться до 2023 года, что позволит поддерживать сервер в актуальном состоянии и устанавливать на него обновления безопасности из стандартных источников.
MariaDB. Альтернативная реализация сервера MySQL, которая обладает лучшей производительностью и при этом полностью с ним совместима.
Требования к серверу
Для нормальной работы сайта с более-менее приличной нагрузкой вам понадобится сервер с одним или двумя ядрами, 1 GB RAM и 10 GB хранилища. Мы предполагаем, что вы уже располагаете такими или большими ресурсами и готовы приступить к установке.
Требования к DNS
Мы предполагаем, что вы уже имеете доменное имя, которое указывает на IP-сервера. Далее, будем считать, что сайт будет использовать доменное имя website.com. Везде, где фигурирует website.com вы должны сделать замену на имя своего домена. Мы будем использовать переменную WEBSITE_NAME для упрощения настройки:
# если hostname —fqdn отдает правильное доменное имя, то используйте
#
export WEBSITE_NAME=$(hostname —fqdn)
# в противном случае
export WEBSITE_NAME=mycooldomain.com
Базовая настройка компонентов Nginx и получение сертификата
Nginx. Установка выполняется стандартным для Ubuntu способом:
sudo apt update && sudo apt install -y nginx
Получение сертификата Let’s Encrypt. Для установки сертификата Let’s Encrypt установим требуемое программное обеспечение:
sudo add-apt-repository -y ppa:certbot/certbot && sudo apt install -y python3-certbot-nginx
Теперь вы можете сгенерировать сертификат Let’s Encrypt для сервера. Для этого в Nginx необходимо добавить секцию для виртуального хоста, который будет описывать ваш сайт.
Создайте файл /etc/nginx/sites-available/$WEBSITE_NAME со следующей конфигурацией, которая будет основой нашей будущей конфигурации сайта:
Заменим website.com на имя вашего домена:
sudo sed -i «s/website.com/$WEBSITE_NAME/g» /etc/nginx/sites-available/$WEBSITE_NAME
Создайте символическую ссылку для активации виртуального хоста:
Теперь закажем сертификат для этого виртуального хоста с помощью certbot. После запуска скрипт попросит вас указать ряд параметров:
- адрес электронной почты, с которой будет ассоциирован сертификат;
- домен из списка найденных в настройках Nginx доменов для которого сертификат будет получаться;
- необходимо ли настроить автоматическое перенаправление пользователей с HTTP на HTTPS (здесь надо указать Yes).
sudo certbot —nginx
В итоге в файле /etc/nginx/sites-enabled/$WEBSITE_NAME должна появиться дополнительная конфигурация, сгенерированная certbot:
Перезапустите nginx для активации изменений:
sudo nginx -t && sudo service nginx restart
Для проверки работы SSL проведем эксперимент. Создадим файл index.html и проверим работу сертификата:
Теперь, если вы откроете в браузере http://website.com, то Nginx должен вас перебросить на https://website.com и отобразить текст Hello, world.
Настройка автопродления сертификата. Сертификаты Let’s Encrypt надо продлевать раз в 90 дней, иначе они устаревают. Добавим в CRON задачу вызова автопродления. Для этого в каталоге /etc/cron.monthly создайте скрипт по имени le-renew следующего содержания:
Выдайте ему права на исполнение и протестируйте:
sudo chmod 755 /etc/cron.monthly/le-renew
sudo /etc/cron.monthly/le-renew
На этом пока что настройку Nginx закончим и установим оставшиеся компоненты.
Установка и настройка MariaDB
Произведем базовую установку MariaDB 10.3, рекомендованную поставщиком для Ubuntu Linux 18.04:
Проверьте корректность установки, соединившись с MariaDB с помощью клиента командной строки:
Соединение работает, если вы получили вывод похожий на приведенный выше.
Если ваш сервер располагает внушительным запасом RAM и ядрами, а сайт будет работать под существенной нагрузкой, вы должны выполнить дополнительные настройки MySQL, чтобы оптимизировать его призводительность, однако, в рамках данной статьи эти настройки не рассматриваются.
Запомните выбранные имя пользователя, пароль и название базы данных, чтобы не забыть. На этом настройка MariaDB завершена.
Установка и настройка PHP7
PHP версии 7.2 присутствует в стандартной поставке Ubuntu Linux 18.04. Установим пакеты из репозитория:
sudo apt install -y php7.2-common php7.2-readline php7.2-fpm php7.2-cli php7.2-gd php7.2-mysql php7.2-curl php7.2-mbstring php7.2-opcache php7.2-json php7.2-xml php7.2-zip
# поправим настройки PHP для режима FPM
sudo sed -i «s/memory_limit = .*/memory_limit = 256M/» /etc/php/7.2/fpm/php.ini
sudo sed -i «s/upload_max_filesize = .*/upload_max_filesize = 128M/» /etc/php/7.2/fpm/php.ini
sudo sed -i «s/zlib.output_compression = .*/zlib.output_compression = on/» /etc/php/7.2/fpm/php.ini
sudo sed -i «s/max_execution_time = .*/max_execution_time = 18000/» /etc/php/7.2/fpm/php.ini
Менеджер процессов PHP-FPM может работать в трех режимах — статическом, динамическом и «по требованию». По умолчанию, используется динамический режим. Мы изменим режим на режим «по требованию». Для этого мы перенесем базовую конфигурацию в файл www.conf.orig, а новую конфигурацию заполним данными из листинга ниже:
Теперь перезапустим PHP-FPM для активации изменений:
Настройка виртуального хоста сайта
Настройку начнем с того, что завершим конфигурацию Nginx для работы с PHP-FPM. Для этого изменим конфигурационный файл сайта /etc/nginx/sites-available/$WEBSITE_NAME.
Добавим перед секцией server следующий фрагмент конфигурации, который задает способ связи с PHP-FPM:
Удалим следующие строки конфигурации:
Добавим следующие строки конфигурации вместо них:
Пример полной конфигурации:
Проверим корректность настроек Nginx и перезапустим его:
Убедимся, что PHP-скрипты работают корректно. Для этого создадим файл index.php в пути /var/www/$WEBSITE_NAME/index.php со следующим содержимым:
Проверим работоспособность скрипта:
Настройка сервера LEMP завершена. Теперь вы можете выполнить развертывание сайта в каталоге /var/www/$WEBSITE_NAME и начать его использование, открыв в браузере https://$WEBSITE_NAME/.
Организация доступа к серверу для разработчика
Если настраиваемый сервер планируется для разработки, возможно, требуется настроить FTP-сервер для работы с файлами сайта.
Для настройки мы воспользуемся возможностью Linux создавать нескольких пользователей с одним и тем же UID. В этом случае все учетные записи являются синонимами, но им можно назначать разные пароли и оболочки.
Дело в том, что файлы, которые обслуживаются Nginx хранятся под пользователем www-data. Если мы создадим нового уникального пользователя, то придется для установить на файлы и каталоги широкие права для того, чтобы он мог манипулировать файлами Nginx, кроме того, вероятно, будет возникать путаница с правами и периодическая недоступность ресурсов, связанная с этим.
Вместо этого, мы создадим пользователя developer с таким же UID как и у www-data, соответственно, он сможет получить нормальный доступ к файлам и права будут корректными.
Сначала узнаем UID www-data:
id www-data
uid=33(www-data) gid=33(www-data) группы=33(www-data)
Теперь добавим нового пользователя с повторяющимся UID:
Если вход получилось осуществить, то пользователь успешно добавлен, а базовая настройка сервера завершена. Для большей безопасности рекомендуем настроить вход в SSH с использованием ключа SSH, а не пароля.
Важно настроить резервное копирование сразу же, как только вы настроили сервер, не откладывая это действие на потом. Воспользуйтесь нашим пошаговым руководством по настройке инкрементного резервного копирования файлов и баз данных для MySQL и PostgreSQL с помощью Duplicity.
В данной статье описана установка и настройка высокопроизводительного современного веб-сервера nginx на примере облачной платформы Selectel. Все действия актуальны для ОС Ubuntu 20.04 LTS 64-bit.
Nginx — это веб-сервер с открытым исходным кодом, созданный работать под высокой нагрузкой, чаще всего используемый для отдачи статического контента, например, html страниц, медиафайлов, документов, архивов, картинок и т.д.
Подготовка сервера

Откроется оснастка создания сервера, где необходимо задать понятное для дальнейшей работы имя сервера, в примере это «WebSrv01». Регион и зону можно оставить без изменения. Для выбора операционной системы необходимо нажать кнопку «Выбрать другой источник».

Откроется меню «Выбор источника».

В поле «Операционные системы», выбираем Ubuntu, в левом поле появится список всех доступных образов операционных систем на базе данной ОС, выбираем «Ubuntu 20.04 LTS 64-bit» и нажимаем кнопку «Выбрать».
Перемещаемся вниз по странице. В нашем примере используется только «Локальный диск», флажок установлен, в поле «Сетевые диски» нажимаем кнопку «Удалить диск».

В поле «Сеть», поскольку это наш первый сервер выбираем «Приватная подсеть + 1 плавающий IP», после выбора значение в поле сменится на «Новый плавающий IP адрес».
Необходимо скопировать «Пароль для root», он понадобиться для первоначальной настройки сервера через SSH протокол.

Нажимаем кнопку «Создать», сервер будет доступен примерно через 1 минуту. Переходим в меню «Облачная платформа» — «Серверы».

В списке появится сервер с именем, что задали ранее, его IP адрес, который будем использовать для удаленного подключения, на скриншоте в области с цифрой 3, статус сервера ALIVE, означает готовность сервера. Подключаемся к серверу, используя любой SSH-клиент.
Проведем небольшую первоначальную настройку сервера. Обновим информацию о доступных пакетах из подключенных репозиториев:
Открываем конфигурационный файл SSH-сервера:
В открывшемся текстовом файле ищем строку #Port 22 и удаляем в начале строки символ комментария #, стандартный номер порта 22 рекомендуется сменить в целях безопасности, пускай это будет 22100. В конечном итоге строка должна выглядеть следующим образом:
Переходим к строке PermitRootLogin yes, меняем значение на no, тем самым запретив вход пользователя root напрямую:
Находясь в редакторе, нажимаем комбинацию клавиш Ctrl+O, внизу появится строка подтверждения: File Name to Write: /etc/ssh/sshd_config, нажимаем ENTER для сохранения изменений, затем Ctrl+X для выхода из редактора.
После изменений файла конфигурации SSH сервера, необходимо выполнить его перезапуск для того, чтобы изменения вступили в силу:
service sshd restart
Установка сервера nginx может быть выполнена как непосредственно на машину, так и в виде docker контейнера. У каждого метода есть свои преимущества и недостатки, описание которых выходит за рамки данной статьи. Мы посмотрим оба варианта.
Начнем с непосредственной установки на сервер:
apt install nginx
Дожидаемся окончания процесса установки.
Разрешим автозапуск сервера:
systemctl enable nginx
systemctl is-enabled nginx
Если в ответ получили «enabled», значит nginx успешно добавлен в автозагрузку.
Запуск nginx
Стартуем наш веб-сервер:
service nginx start
service nginx status
Если в статусе присутствует строка Active: active (running), значит сервер работает. Также в этом можно убедиться, набрав в адресной строке браузера IP адрес сервера, будет отображено приветственное сообщение от nginx, которое выглядит так:

Nginx в Docker
Для установки Docker, нужно подготовить систему. Устанавливаем необходимые пакеты:
apt install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
Добавляем GPG ключ официального репозитория Docker в систему:
В следующей строке появится надпись OK, добавляем репозиторий Docker:
Теперь необходимо обновить информацию о пакетах:
Проверим, что установка Docker будет происходить из его репозитория:
apt-cache policy docker-ce
В ответ должны получить много строк, среди которых должен присутствовать адрес репозитория, добавленный ранее, в нашем примере это:
Ставим сам Docker:
apt install docker-ce
Дожидаемся окончания процесса установки. После docker будет автоматически запущен и добавлен в автозагрузку. Проверим:
systemctl status docker
В выводе команды должна присутствовать строка Active: active (running), значит процесс-демон работает.
systemctl is-enabled docker
В ответе увидели «enabled», значит docker успешно добавлен в автозагрузку. На этом установка Docker завершена, переходим к запуску в контейнере веб-сервера nginx.
Устанавливаем и запускаем nginx в Docker одной командой:
Docker скачает официальный образ nginx с Docker Hub, сконфигурирует и запустит контейнер.
- nginx_myproject – имя контейнера, создаваемого на базе образа nginx.
- Конструкция –p 8080:80 выполняет проброс портов, с порта 8080 локальной машины на порт 80 контейнера.
Проверяем, работает ли контейнер:
Вывод команды должен быть примерно следующим:
Стоит обратить внимание на столбец NAMES, где обнаруживаем имя созданного ранее контейнера nginx_myproject, колонка STATUS, в которой отображается состояние контейнера, в данном случае он работает уже 7 часов. Если набрать в адресной строке браузера IP адрес сервера и через двоеточие порт, используемый контейнером 8080, т.е. конструкцию вида 123.123.123.123:8080, то в ответ получим:
«Hello from NGINX in Docker!»
Мы научились запускать веб-сервер nginx в контейнере!
Проброс портов, папок, а так же многий другой функционал, предоставляемый контейнеризацией, должен быть использован исходя из поставленных задач, разнообразие которых выходит за рамки данной статьи. Дальнейшее описание работы с nginx рассматривается в рамках работы непосредственно на сервере, без контейнеризации.
Иерархия каталогов nginx
Администрирование сервера nginx в основном заключается в настройке и поддержке его файлов конфигурации, которые находятся в папке /etc/nginx. Рассмотрим подробнее:
- /etc/nginx/nginx.conf – главный файл конфигурации nginx.
- /etc/nginx/sites-available – каталог с конфигурациями виртуальных хостов, т.е. каждый файл, находящийся в этом каталоге, содержит информацию о конкретном сайте – его имени, IP адресе, рабочей директории и многое другое.
- /etc/nginx/sites-enabled – в этом каталоге содержаться конфигурации сайтов, обслуживаемых nginx, т.е. активных, как правило, это символические ссылки sites-available конфигураций, что очень удобно для оперативного включения и отключения сайтов.
Рассмотрим главный конфигурационный файл nginx — /etc/nginx/nginx.conf. По умолчанию он выглядит следующим образом:
Конфигурационный файл состоит из директив. О них и пойдет речь дальше.
Директивы
В конфигурационных файлах nginx допустимо пользоваться встроенными переменными. Преимущественно это переменные, представляющие собой поля заголовка запроса клиента, такие как $remote_addr, $server_name. Все переменные начинаются со знака $, с полным перечнем можно ознакомиться в документации, на официальном сайте.
Установка и настройка php-fpm
Для работы веб приложений, написанных на языке PHP необходимо установить php-fpm в качестве бэкэнда:
apt install php-fpm php-mysql
После установки сервис будет автоматически запущен и добавлен в автозагрузку. Создаем файл пула для конкретного сайта sampledomain.ru:
Создаем следующую конфигурацию:
Нажимаем комбинацию клавиш Ctrl+O, внизу появится строка подтверждения: File Name to Write: /etc/php/7.4/fpm/pool.d/sampledomain.ru.conf, нажимаем ENTER для сохранения изменений, затем Ctrl+X для выхода из редактора.
Перезагружаем сервис php-fpm, чтобы он мог перечитать файлы конфигураций:
service php7.4-fpm restart
Проверяем, что сервис перезапустился корректно и наша новая конфигурация sampledomain.ru обслуживается:
service php7.4-fpm status
О том, что сервис запущен, свидетельствует наличие строки Active: active (running), чуть ниже список обслуживаемых конфигураций в виде дерева, где можно увидеть php-fpm: pool sampledomain.ru, значит все работает.
Конфигурация nginx
У нас имеется главный конфигурационный файл, содержимое которого оставляем неизменным для примера. Создадим файл виртуального хоста:
Заполняем его следующим содержимым:
Нажимаем комбинацию клавиш Ctrl+O, внизу появится строка подтверждения: File Name to Write: /etc/nginx/sites-available/sampledomain.ru.conf, нажимаем ENTER для сохранения изменений, затем Ctrl+X для выхода из редактора.
Создаем символическую ссылку на данный виртуальный хост из директории /etc/nginx/sites-available в директорию /etc/nginx/sites-enabled, чтобы nginx его обслуживал:
ln -s /etc/nginx/sites-available/sampledomain.ru.conf /etc/nginx/sites-enabled/
Необходимо создать структуру каталогов веб проекта:
Создаем файл для тестирования работы связки nginx и php-fpm:
Задаем владельца каталогов и находящихся внутри файлов:
Конфиги написаны, директории созданы, перезапускаем nginx для того, чтобы он перечитал файлы конфигураций:
Переходим в браузере по адресу http://sampledomain.ru и должны увидеть такую картину:

Все настроили правильно.
Команды nginx
Если все хорошо, в результате получим сообщение:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
В случае обнаружения ошибок, сервер уведомит об этом. Чтобы узнать используемую версию сервера, нужно ввести:
Можно получить расширенную информацию об nginx – его версию, параметры конфигурации сборки:
Когда существует необходимость оперативно, но аккуратно перезапустить веб-сервер, чтобы пользователи на данный момент, работающие с ним, не потеряли соединение, но в то же время, вновь подключившиеся уже работали с учетом последних изменений конфигурации. В таком случае, вместо restart необходимо использовать команду reload:
service nginx reload
Настройка SSL сертификата
apt install certbot python3-certbot-nginx
Запрашиваем сертификат у Certbot:
Появится вопрос о передаче вашего адреса электронной почты компании партнеру: (Y)es/(N)o:Жмем Y, потом ENTER.
Сертификат успешно получен, если появилось сообщение:
IMPORTANT NOTES:
— Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/sampledomain.ru/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/sampledomain.ru/privkey.pem
Your cert will expire on 2021-05-27. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
«certbot renew»
— Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
— If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let’s Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Сертификат действителен 90 дней. Теперь необходимо позаботиться об автоматическом продлении сертификатов, открываем файл:
Приводим его к следующему виду:
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
0 */12 * * * root test -x /usr/bin/certbot -a ! -d /run/systemd/system && perl -e ‘sleep int(rand(43200))’ && certbot -q renew —renew-hook «systemctl reload nginx»
Нажимаем комбинацию клавиш Ctrl+O, внизу появится строка подтверждения: File Name to Write: /etc/cron.d/certbot, нажимаем ENTER для сохранения изменений, затем Ctrl+X для выхода из редактора.
Дважды в день будет происходить проверка необходимости обновления сертификатов на сервере, если какому-либо осталось 30 дней и меньше до истечения срока действия – он будет обновлен, а nginx перезагружен.
Протестируем процесс обновления без внесения изменений:
certbot renew —dry-run
Ждем около полминуты, на экран будет выведен подробный отчет. Если присутствует строка Congratulations, all renewals succeeded – значит все настроено правильно. Если когда-либо в процессе обновления произойдет сбой – Let’s Encrypt уведомит о приближающимся конце срока действия сертификата по электронной почте, указанной при первом запросе.

