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

в 7:20, , рубрики: Google Cloud Platform, lemp, mysql, nginx, symfony

Добрый день, уважаемый Хабр! В данном посте я приведу конкретные шаги по установке и настройке связки 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) и вставьте его в соответствующее поле на вкладке «Безопасность»:

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

Не забываем разрешить трафик 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=<domain.name>

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

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

# hostname <domain.name>

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

# /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 <domain.name>/public
$ cd <domain.name>/public
$ nano index.php

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

<html>
<head>
    <h2>LEMP test</h2>
</head>
    <body>
    <?php echo '<p>Hello!</p>';

    $host = "localhost";
    $username = "root";
    $password = "__YOUR_ROOT_PASSWORD__";

    $connection = mysqli_connect($host, $username, $password);

    if (!$connection) 
        print '<p>DB connect failed with error: ' .  mysqli_connect_error() . '</p>';
    else
        print '<p>DB connection established</p>';
    ?>
</body>
</html>

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

# nano /etc/nginx/nginx.conf

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

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

server {
    server_name <domain.name> www.<domain.name>;

    root /home/__USER__/<domain.name>/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/<domain.name>.error.log;
    access_log /var/log/nginx/<domain.name>.access.log;
}

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

# systemctl restart nginx

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

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

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

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

# nano /etc/nginx/nginx.conf

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

server {
       listen 443 ssl;
       server_name <domain.name>;
   
       ssl_certificate /etc/letsencrypt/live/<domain.name>/fullchain.pem;
       ssl_certificate_key /etc/letsencrypt/live/<domain.name>/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__/<domain.name>/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/<domain.name>.error.log;
       access_log /var/log/nginx/<domain.name>.access.log;
   }
   
   server {
       listen 443 ssl;
       server_name www.<domain.name>;

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

       return 301 https://<domain.name>$request_uri;
   }
   
   server {
       server_name <domain.name> www.<domain.name>;
       return 301 https://<domain.name>$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/

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

Автор: iAmWeb

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js