Настройка сервера Linux Nginx, PHP 7, MySQL (LEMP) с поддержкой сертификата Let’s Encrypt в Ubuntu Linux 18.04 Bionic

Закончив чтение данного руководства, вы научитесь самостоятельно настраивать минималистичный 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 со следующей конфигурацией, которая будет основой нашей будущей конфигурации сайта:

server {
        listen 80;
        listen [::]:80;
        server_name website.com;
}


server {
        listen 443 ssl;
        listen [::]:443 ssl;

        server_name website.com;

        root /var/www/website.com;
        index index.html;

        location / {
                try_files $uri $uri/ =404;
        }
}

Заменим website.com на имя вашего домена:

sudo sed -i "s/website.com/$WEBSITE_NAME/g" /etc/nginx/sites-available/$WEBSITE_NAME

Создайте символическую ссылку для активации виртуального хоста:

sudo ln -s /etc/nginx/sites-{available,enabled}/$WEBSITE_NAME

# проверьте корректность конфигурации Nginx

sudo nginx -t

Теперь закажем сертификат для этого виртуального хоста с помощью certbot. После запуска скрипт попросит вас указать ряд параметров:

  • адрес электронной почты, с которой будет ассоциирован сертификат;
  • домен из списка найденных в настройках Nginx доменов для которого сертификат будет получаться;
  • необходимо ли настроить автоматическое перенаправление пользователей с HTTP на HTTPS (здесь надо указать Yes).
sudo certbot --nginx

В итоге в файле /etc/nginx/sites-enabled/$WEBSITE_NAME должна появиться дополнительная конфигурация, сгенерированная certbot:

server {
    if ($host = website.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    listen 80;
    listen [::]:80;
    server_name website.com;


}


server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name website.com;

    root /var/www/website.com;
    index index.html;

    location / {
		try_files $uri $uri/ =404;
    }
    
    ssl_certificate /etc/letsencrypt/live/website.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/website.com/privkey.pem; # managed by Certbot

}

Перезапустите nginx для активации изменений:

sudo nginx -t && sudo service nginx restart

Для проверки работы SSL проведем эксперимент. Создадим файл index.html и проверим работу сертификата:

sudo mkdir -p /var/www/$WEBSITE_NAME
sudo sh -c "echo 'Hello, world' > /var/www/$WEBSITE_NAME/index.html"

curl https://$WEBSITE_NAME/

Hello, world

Теперь, если вы откроете в браузере http://website.com, то Nginx должен вас перебросить на https://website.com и отобразить текст Hello, world.

Настройка автопродления сертификата. Сертификаты Let’s Encrypt надо продлевать раз в 90 дней, иначе они устаревают. Добавим в CRON задачу вызова автопродления. Для этого в каталоге /etc/cron.monthly создайте скрипт по имени le-renew следующего содержания:

#/bin/bash
certbot renew

Выдайте ему права на исполнение и протестируйте:

sudo chmod 755 /etc/cron.monthly/le-renew
sudo /etc/cron.monthly/le-renew

На этом пока что настройку Nginx закончим и установим оставшиеся компоненты.

Установка и настройка MariaDB

Произведем базовую установку MariaDB 10.3, рекомендованную поставщиком для Ubuntu Linux 18.04:

sudo apt-get install software-properties-common
sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
sudo add-apt-repository 'deb [arch=amd64,arm64,ppc64el] http://sfo1.mirrors.digitalocean.com/mariadb/repo/10.3/ubuntu bionic main'

sudo apt update
sudo apt install -y mariadb-server apg

Проверьте корректность установки, соединившись с MariaDB с помощью клиента командной строки:

mysql -uroot -e 'SELECT version();'
+--------------------------------------------+
| version()                                  |
+--------------------------------------------+
| 10.3.13-MariaDB-1:10.3.13+maria~bionic-log |
+--------------------------------------------+

Соединение работает, если вы получили вывод похожий на приведенный выше.

Если ваш сервер располагает внушительным запасом RAM и ядрами, а сайт будет работать под существенной нагрузкой, вы должны выполнить дополнительные настройки MySQL, чтобы оптимизировать его призводительность, однако, в рамках данной статьи эти настройки не рассматриваются.

Создадим базу данных для сайта и настроим доступ пользователя к ней. В настройке используется пользователь siteuser с паролем secret. Вы должны задать безопасный пароль, который можете сгенерировать с помощью команды apg.

export DB_NAME=website
export DB_USER=siteuser
export DB_PASSWORD=secret

mysql -uroot -e "CREATE DATABASE IF NOT EXISTS $DB_NAME;"

mysql -uroot -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASSWORD'";                                                                                    

mysql -uroot -e "FLUSH PRIVILEGES;"

mysql -u$DB_USER -p$DB_PASSWORD $DB_NAME -e 'select version();'
+--------------------------------------------+
| version()                                  |
+--------------------------------------------+
| 10.3.14-MariaDB-1:10.3.14+maria~bionic-log |
+--------------------------------------------+

Запомните выбранные имя пользователя, пароль и название базы данных, чтобы не забыть. На этом настройка 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, а новую конфигурацию заполним данными из листинга ниже:

sudo mv /etc/php/7.2/fpm/pool.d/www.{conf,conf.orig} 
sudo nano /etc/php/7.2/fpm/pool.d/www.conf
[www]
user = www-data
group = www-data
listen = /run/php/php7.2-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0666
pm = ondemand
pm.max_children = 5
pm.process_idle_timeout = 10s
pm.max_requests = 200
chdir = /

Теперь перезапустим PHP-FPM для активации изменений:

sudo service php7.2-fpm restart

Настройка виртуального хоста сайта

Настройку начнем с того, что завершим конфигурацию Nginx для работы с PHP-FPM. Для этого изменим конфигурационный файл сайта /etc/nginx/sites-available/$WEBSITE_NAME.

Добавим перед секцией server следующий фрагмент конфигурации, который задает способ связи с PHP-FPM:

upstream php {
        server unix:/run/php/php7.2-fpm.sock;
}

# то, что ниже не добавлять в настройку, 
# приведено для примера куда вставить секцию
# upstream
#
server {
        listen 443 ssl;
        listen [::]:443 ssl;

...

Удалим следующие строки конфигурации:

       index index.html;

       location / {
                try_files $uri $uri/ =404;
       }

Добавим следующие строки конфигурации вместо них:

        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;

        index index.php;

        location = /favicon.ico {
                log_not_found off;
                access_log off;
        }

        location = /robots.txt {
                allow all;
                log_not_found off;
                access_log off;
        }

        location / {
                try_files $uri $uri/ /index.php?$args;
        }

        location ~ .php$ {
                include fastcgi.conf;
                fastcgi_intercept_errors on;
                fastcgi_pass php;
        }

        location ~* .(js|css|png|jpg|jpeg|gif|ico)$ {
                expires max;
                log_not_found off;
        }

Пример полной конфигурации:

server {
    if ($host = website.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


        listen 80;
        listen [::]:80;
        server_name website.com;


}

upstream php {
        server unix:/run/php/php7.2-fpm.sock;
}

server {
	listen 443 ssl;
	listen [::]:443 ssl;

	server_name website.com;

	root /var/www/example.com;

        ssl_certificate /etc/letsencrypt/live/website.com/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/website.com/privkey.pem; # managed by Certbot

        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;

        index index.php;

        location = /favicon.ico {
                log_not_found off;
                access_log off;
        }

        location = /robots.txt {
                allow all;
                log_not_found off;
                access_log off;
        }

        location / {
                try_files $uri $uri/ /index.php?$args;
        }

        location ~ .php$ {
                include fastcgi.conf;
                fastcgi_intercept_errors on;
                fastcgi_pass php;
        }

        location ~* .(js|css|png|jpg|jpeg|gif|ico)$ {
                expires max;
                log_not_found off;
        }
}

Проверим корректность настроек Nginx и перезапустим его:

sudo nginx -t && sudo service nginx restart

Убедимся, что PHP-скрипты работают корректно. Для этого создадим файл index.php в пути /var/www/$WEBSITE_NAME/index.php со следующим содержимым:

<?php 
echo "Hello\n";

Проверим работоспособность скрипта:

# локально
php /var/www/$WEBSITE_NAME/index.php
Hello

# через web
curl https://$WEBSITE_NAME/index.php
Hello

# удалим скрипт
sudo rm /var/www/$WEBSITE_NAME/index.{php,html}

Настройка сервера 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:

sudo useradd -o -u 33 -d /var/www/$WEBSITE_NAME -g www-data developer
sudo passwd developer

Проверим, что пользователь может нормально войти в систему по ssh с локальной машины:

ssh developer@$WEBSITE_NAME

Если вход получилось осуществить, то пользователь успешно добавлен, а базовая настройка сервера завершена. Для большей безопасности рекомендуем настроить вход в SSH с использованием ключа SSH, а не пароля.

Резервное копирование данных

Важно настроить резервное копирование сразу же, как только вы настроили сервер, не откладывая это действие на потом. Воспользуйтесь нашим пошаговым руководством по настройке инкрементного резервного копирования файлов и баз данных для MySQL и PostgreSQL с помощью Duplicity.