[Из песочницы] LEMP стек c PHP 7 на CentOS 7 + Let's Encrypt в Google Cloud для развертывания приложения Symfony 4

Добрый день, уважаемый Хабр! В данном посте я приведу конкретные шаги по установке и настройке связки Nginx + MySQL + PHP7 на CentOS 7. Стоит отметить, что в данной статье будет рассказано про настройку системы для одного домена. В качестве площадки будет использоваться инстанс на Google Cloud Platform, с создания которого и начну:

Создание экземпляра в Google Cloud с генерацией SSH-ключей
Выберем в главном меню выбираем «Compute Engine» и нажимаем «Создать экземпляр». В зависимости от предполагаемой нагрузки выбираем тип машины, но не ниже g1-small, так как Composer для Symfony 4 требователен к оперативной памяти и на f1-micro загрузить зависимости не сможет.

Предлагаемый образ загрузочного диска изменяем на CentOS 7, минимальный объем диска в 10Гб вполне подойдет для развертывания системы, всех необходимых библиотек и зависимостей.

Для доступа к создаваемому серверу по SSH необходимо сгенерировать соответствующий ключ, у пользователей MacOS X или Linux для этого существует команда

ssh-keygen -t rsa -f __FILE__ -C __USER__

где __FILE__ — путь к сохраняемому ключу с именем файла, а __USER__ — имя пользователя под которым вы будете логинититься в систему. При выполнения данной команды система запросит вас указать ключевую фразу, которая будет служить паролем при использовании данного ключа, ее ввод необязателен, для пропуска ничего не вводите и нажмите Enter, далее подтвердите предыдущее действие. После выполнения данной команды система создаст указанный в __FILE__ приватный ключ, а рядом с ним — открытый с именем __FILE__.pub
Последнее, что остается сделать с ключом пользователям MacOS X и Linux — это запретить доступ на запись для всех, кроме владельца ключа, делается это командой
chmod 400 __FILE__ 

Пользователи Windows могут вопользоваться программой PuTTYgen. Откройте программу, нажмите Generate и следуйте инструкциям, установленные по-умолчанию параметры подходит для большинства случаев, однако Google настаивает на 2048-битных ключах, не забудьте установить данный параметр. Поле «Key comment» служит для задания имени пользователя, а для задания ключевой фразы — «Key passphrase». После завершения генерации программа отобразит публичный ключ. Чтобы сохранить приватный ключ с расширением .ppk нажмите «Save private key».

Скопируйте содержимое открытого ключа (из файла __FILE__.pub для MacOS X / Linux или из окна PuTTYgen для Windows) и вставьте его в соответствующее поле на вкладке «Безопасность»:

0nxcbnvsk0zdxh3gpmv4cx7ygc4.png

Не забываем разрешить трафик HTTP и HTTPS, поставив галочки в соответствующих полях. На данном этапе все готово, нажимаем «Создать».

После создания система отобразит присвоенный экземпляру внешний IP-адрес, подключимся к нему по SSH используя приватный ключ:

ssh -i __FILE__ __USER__@__IP__


Приступим непосредственно к установке LEMP. Все приведенные действия выполняются от суперпользователя (#), если явно не указано иное ($).

Обновляем систему и удаляем «осиротевшие» пакеты:

# yum clean all
# yum update
# yum autoremove


Добавляем поддержку репозиториев Fedora:

# yum install epel-release


Устанавливаем текстовый редактор nano:

# yum install nano


Устанавливаем утилиту wget для возможности получения файлов с удаленных серверов:

# yum install wget


Для развертывания приложений на Symfony (и не только), я использую клонирование git-репозитория, для реализации данного метода установим поддержку git:

# yum install git-core


Также Symfony необходима поддержка zip:

# yum install zip unzip


Нужно указать корректное имя хоста, для этого отредактируем конфигурационный файл сети:

# nano /etc/sysconfig/network


Добавьте в содержимое строку

HOSTNAME=

где , здесь и далее, необходимо заменить на корректное имя хоста.

Сохраняем файл и устанавливаем его же с помощью утилиты hostname:

# hostname 


и перезапускаем сетевую службу:

# /etc/init.d/network restart


Устанавливаем nginx:

# yum install nginx


Запускаем nginx:

# systemctl start nginx


Добавляем nginx в автозагрузку:

# systemctl enable nginx


Устанавливаем MySQL, запускаем и добавляем в автозагрузку:

# yum install mariadb mariadb-server
# systemctl start mariadb
# systemctl enable mariadb


Проведем начальную настройку MySQL, на все вопросы скрипта ответьте «Y» и укажите пароль суперпользователя:

# mysql_secure_installation


Добавим поддержку Let’s Encrypt:

# yum install certbot


Так как к моменту написания данной статьи PHP 7 нет ни в репозиториях CentOS, ни в Fedora, его мы установим из репозитория REMI:

# wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm
# rpm -Uvh remi-release-7.rpm
# yum install yum-utils
# yum-config-manager --enable remi-php72
# yum --enablerepo=remi,remi-php72 install php-fpm
# yum --enablerepo=remi,remi-php72 install php-common php-opcache php-cli php-pear php-pdo php-mysqlnd php-gd php-mcrypt php-xml php-zip


Весь необходимый софт установлен, перейдем к его настройке, первоначально отредактируем конфигурационный файл php-fpm:

# nano /etc/php-fpm.d/www.conf


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

user = __USER__
group = __USER__
listen.owner = __USER__
listen.group = __USER__


Далее, укажем сокет — необходимо под строкой ; listen = 127.0.0.1:9000 добавить следующее:
listen = /var/run/php-fpm/php-fpm.sock

Сохраните изменения, затем запустите и добавьте php-fpm в автозагрузку:

# systemctl start php-fpm
# systemctl enable php-fpm


Отключим SELINUX:

# setenforce 0


Данной командой вы отключаете SELINUX только в текущем сеансе пользователя, чтобы после перезагруки настройки сохранились необходимо отредактировать его конфигурационный файл:

# nano /etc/selinux/config


где указать SELINUX=disabled

Сохраните изменения и выйдете из режима суперпользователя. Далее мы создадим директорию для проекта в домашней директории и поместим туда индексный файл — заглушку для проверки работоспособности создаваемого стека:

$ cd ~
$ mkdir -p /public
$ cd /public
$ nano index.php


Пусть содержимое файла будет следующим (замените __YOUR_ROOT_PASSWORD__ на пароль суперпользователя MySQL, указанный при его настройке):



    

LEMP test

Hello!

'; $host = "localhost"; $username = "root"; $password = "__YOUR_ROOT_PASSWORD__"; $connection = mysqli_connect($host, $username, $password); if (!$connection) print '

DB connect failed with error: ' . mysqli_connect_error() . '

'; else print '

DB connection established

'; ?>


Снова авторизуемся под правами суперпользователя и откроем на редактирование конфигурационный файл nginx:

# nano /etc/nginx/nginx.conf


Изменим имя пользователя подобно конфигурации php-fpm:
user __USER__;

Конфигурацию директивы server, созданную по-уполчанию, измените следующим образом:

server {
    server_name  www.;

    root /home/__USER__//public;

    location / {
        # try to serve file directly, fallback to index.php
        try_files $uri /index.php$is_args$args;
    }

    location ~ ^/index\.php(/|$) {
        fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;

        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;

        internal;
    }

    location ~ \.php$ {
        return 404;
    }

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


Сохраните изменения и перезапустите nginx:

# systemctl restart nginx


По доменному имени должна открываться созданная нами страница — заглушка.

Приступим к созданию сертификата:

# openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
# certbot certonly --webroot -w /home/__USER__//public -d 
# certbot certonly --webroot -w /home/__USER__//public -d www.


После генерации ключей, изменим конфигурацию nginx для поддержки HTTPS, в данной конфигурации «главным» идет домен без www и настроено перенаправление на защищенное соединение. И так:

# nano /etc/nginx/nginx.conf


Меняем созданную нами 2 шага назад директиву server на следующие:

server {
       listen 443 ssl;
       server_name ;
   
       ssl_certificate /etc/letsencrypt/live//fullchain.pem;
       ssl_certificate_key /etc/letsencrypt/live//privkey.pem;
   
       ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
       ssl_prefer_server_ciphers on;
       ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
       ssl_ecdh_curve secp384r1;
       ssl_session_cache shared:SSL:10m;
       ssl_session_tickets off;
       ssl_stapling on;
       ssl_stapling_verify on;
       resolver 8.8.8.8 8.8.4.4 valid=300s;
       resolver_timeout 5s;
       add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
       add_header X-Frame-Options DENY;
       add_header X-Content-Type-Options nosniff;
   
       ssl_dhparam /etc/ssl/certs/dhparam.pem;
   
       root /home/__USER__//public;
   
       location / {
           # try to serve file directly, fallback to index.php
           try_files $uri /index.php$is_args$args;
       }
   
       location ~ ^/index\.php(/|$) {
           fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
           fastcgi_split_path_info ^(.+\.php)(/.*)$;
           include fastcgi_params;
           
           fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
           fastcgi_param DOCUMENT_ROOT $realpath_root;
           
           internal;
       }
   
       location ~ \.php$ {
           return 404;
       }
   
       error_log /var/log/nginx/.error.log;
       access_log /var/log/nginx/.access.log;
   }
   
   server {
       listen 443 ssl;
       server_name www.;

       ssl_certificate /etc/letsencrypt/live/www./fullchain.pem;
       ssl_certificate_key /etc/letsencrypt/live/www./privkey.pem;
       ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

       return 301 https://$request_uri;
   }
   
   server {
       server_name  www.;
       return 301 https://$request_uri;
   }


Сохраняем результат и перезапускаем nginx:

# systemctl restart nginx


Так как Let’s Encrypt необходимо обновлять раз в три месяца, настроим автоматическое продление в планировщике, к примеру так, в ночь на понедельник

# crontab -e


15 4 * * 1 /usr/bin/certbot renew --quiet
18 4 * * 1 /usr/bin/systemctl reload nginx

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

# chown -R __USER__:__USER__ /var/lib/nginx
# chown -R __USER__:__USER__ /var/lib/php/session/


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

© Habrahabr.ru