Web-сервер Nginx — пошагово

Web-сервер Nginx — пошагово

В этой инструкции пошагово разберём установку и настройку LEMP — стека для организации web-сервера на системе CentOS 7.

Будет сделано:

  • первоначальная настройка CentOS
  • установка и конфигурирование Nginx + php-fpm
  • установка и настройка MariaDB
  • установка PHP
  • создание двух тестовых сайтов, установка WordPress
  • автоматический Backup баз данных
  • поддержка HTTPS с помощью Let’s Encrypt

Итак, мы находимся в только что установленном CentOS:


Выполняем обновление системы:

sudo yum clean all
sudo yum update
sudo yum autoremove

Устанавливаем текстовый редактор nano, файловый менеджер mc и инструменты для работы с сетью, программу для скачивания:

sudo yum install mc nano net-tools wget -y

Назначение имени компа:

sudo nano /etc/sysconfig/network
1
HOSTNAME=_имя_компьютера_
sudo hostnamectl set-hostname _имя_компьютера_

Назначение статического IP:

с помощью программулины:
 sudo nmtui
либо в рукопашку:
sudo nano /etc/sysconfig/network-scripts/ifcfg-eth0
1
2
3
4
5
6
7
8
9
BOOTPROTO="none"
IPADDR="192.168.2.203"
GATEWAY="192.168.2.254"
DNS1="192.168.2.254"
DNS2="8.8.8.8"
# Disable ipv6 #
IPV6INIT="no"
# Subnet #
PREFIX=24
Перезапуск сети:
sudo systemctl restart network

Настройка времени:

Написано здесь


Редактируем правила фаервола:

Смотрим работает ли фаервол:

firewall-cmd --state

Смотрим правила:

firewall-cmd --permanent --list-all

Убираем dhcpv6-client:

firewall-cmd --permanent --zone=public --remove-service=dhcpv6-client

Разрешаем http:

firewall-cmd --permanent --zone=public --add-service=http

Перезагружаем правила:

firewall-cmd --reload

Ещё про фаервол: здесь


Установка Nginx:

Добавляем CentOS 7 EPEL репозиторий:

sudo yum install epel-release

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

sudo yum install nginx

Запускаем его:

sudo systemctl start nginx

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

sudo systemctl enable nginx

Можно смотреть в браузер


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

Запускаем и добавляем в автозагрузку:

sudo yum install mariadb mariadb-server -y
sudo systemctl start mariadb
sudo systemctl enable mariadb

Проверяем порт 3306:

netstat -tulpn

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

mysql_secure_installation

Делаем отдельную базу данных для будущего сайта и отдельного пользователя для этой базы:

mysql -u root -p

create database tst105db;

Создаем пользователя для локального подключения:

CREATE USER 'tst105dbuser'@'localhost' IDENTIFIED BY 'mypassword';

Дать полные права на базу tst105db пользователю tst105dbuser:

grant all on tst105db.* to 'tst105dbuser'@'localhost';

Если нужно, разрешаем удаленное подключение к БД:

Добавляем правило в фаерволл:

firewall-cmd --permanent --zone=public --add-port=3306/tcp
firewall-cmd --reload

Разрешаем подключения извне:

mysql -u root -p

Показать пользователей БД:

SELECT Host, User, plugin FROM mysql.user;

создать сетевого пользователя:

CREATE USER 'remoteuser'@'%' IDENTIFIED BY 'mypassword';

Дать полные права на базу tst105db пользователю remoteuser:

grant all on tst105db.* to 'remoteuser'@'%';
exit;

Установка и настройка PHP:

установим PHP7.2 из репозитория REMI:

yum install http://rpms.remirepo.net/enterprise/remi-release-7.rpm yum-utils -y

yum-config-manager --enable remi-php72

yum install php php-common php-opcache php-mcrypt php-cli php-gd php-curl php-mysqlnd -y

Проверяем:

php -v

—————————————
Конфигурирование PHP 7.x для работы с Nginx:

В отличае от Apache, Nginx не имеет встроенной поддержки PHP файлов, поэтому нам нужно установить PHP FPM пакет:

sudo yum install php-fpm

По-умолчанию PHP FPM запускается под пользователем apache на порту 9000. Мы изменим пользователя на nginx:

sudo cp /etc/php-fpm.d/www.conf /etc/php-fpm.d/www.conf-original
sudo nano /etc/php-fpm.d/www.conf
1
2
3
4
5
6
7
...
user = nginx
...
group = nginx
...
listen.owner = nginx
listen.group = nginx

К тому же под строкой listen = 127.0.0.1:9000 нужно добавить следующее:

1
listen = /var/run/php-fpm/php-fpm.sock

Убедитесь что папка /var/lib/php имеет необходимые права доступа (ls -l):

sudo chown -R root:nginx /var/lib/php

Запускаем и добавляем в автозагрузку PHP FPM сервис:

sudo systemctl start php-fpm
sudo systemctl enable php-fpm

Для того чтобы Nginx мог обрабатывать PHP файлы:

sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf-original
sudo nano /etc/nginx/nginx.conf
1
2
3
4
5
6
7
8
9
10
server {
# . . . other code
location ~ \.php$ {
#fastcgi_pass localhost:9000;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME
$document_root$fastcgi_script_name;
include fastcgi_params;
}
}

Перечитываем конфиг:

sudo nginx -t
sudo nginx -s reload

Кстати, вот команда для полного перезапуска Nginx (если вдруг понадобится):

sudo systemctl restart nginx

Сейчас по http отдается страница из /usr/share/nginx/html,
что в директиве root файла /etc/nginx/nginx.conf

Можно проверить работает ли php, создав рядом файл test.php со следующим содержимым:

<?php
 phpinfo();
 ?>

Для этого выполните команду

sudo nano /usr/share/nginx/html/test.php

Откройте его в браузере (не заабудьте сделать DNS-перенаправление имени домена на IP вашего сервера, например, с помощью файла hosts)

Проверяем работает ли php + mariadb:

sudo nano /usr/share/nginx/html/index2.php

Вставляем, заменяя пароль от рута базы данных:

<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>

Открываем в браузере http://…/index2.php


Создаём свои сайты. Создавать их будем в папке /var/www

cd /var/www
sudo mkdir tst104.1gb.ru
cd tst104.1gb.ru
sudo nano index.html

Итак, я создал 2 сайта:

/var/www/tst104.1gb.ru/public_html/index.html

/var/www/tst105.1gb.ru/public_html/index.php

Директивы server в файле файла /etc/nginx/nginx.conf я оставил такие:

#Если открывается tst104.1gb.ru или www.tst104.1gb.ru
server{
        listen 80;
        server_name     tst104.1gb.ru   www.tst104.1gb.ru;
        root /var/www/tst104.1gb.ru/public_html;

        location / {
            index   index.html index.php;
        }

        location ~* \.(gif|jpg|png)$ {
            expires 30d;
        }

        location ~ \.php$ {
            fastcgi_pass  localhost:9000;
            fastcgi_param SCRIPT_FILENAME
                          $document_root$fastcgi_script_name;
            include       fastcgi_params;
        }

    }

#Если открывается tst105.1gb.ru или www.tst105.1gb.ru
server{
        listen 80;
        server_name     tst105.1gb.ru   www.tst105.1gb.ru;
        root /var/www/tst105.1gb.ru/public_html;

        location / {
            index   index.html index.php;
        }

        location ~* \.(gif|jpg|png)$ {
            expires 30d;
        }

        location ~ \.php$ {
            fastcgi_pass  localhost:9000;
            fastcgi_param SCRIPT_FILENAME
                          $document_root$fastcgi_script_name;
            include       fastcgi_params;
        }

    }
    
#Если открывается без разницы какой сайт, кроме тех двух
server {
        listen       80 default_server;
        server_name _;
        root         /usr/share/nginx/html;

        location / {
        }
        
        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }

Не забываем перечитать конфиг:

sudo nginx -t
sudo nginx -s reload

Теперь при открытии соответствующих сайтов (при условии наличия соответствующих DNS направлений) в первом случае откроется html файл, во втором — php. В любом другом случае — страница nginx.

Про настройки этого файла можно почитать в официальной русской документации здесь: http://nginx.org/ru/docs/http/request_processing.html


Ставим вордпресс:

Если установить Вордпресс Вам что-то мешает, то вот хардкордный рецепт:
Используйте это если у Вас появились проблемы с установкой:

Отключим SELINUX:

setenforce 0

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

nano /etc/selinux/config

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

reboot

Качаем zip с официального сайта и распаковываем все его файлы в папку с нашим сайтом.

Переходим в папку сайта

cd /var/www/tst105.1gb.ru/public_html

Качаем (возьмите последнюю версию отсюда: https://ru.wordpress.org/download/):

sudo wget https://ru.wordpress.org/latest-ru_RU.tar.gz

Распаковываем:

sudo tar -xzvf latest-ru_RU.tar.gz

Удаляем файл:

sudo rm latest-ru_RU.tar.gz

Переносим всё содержимое папки public_html/wordpress в public_html:

cd ..
sudo mv -v public_html/wordpress/* public_html/

Удаляем папку wordpress:

sudo rmdir public_html/wordpress

Проверяем, что владелец всех файлов сайта — nginx и у группы есть права на запись (ls -l), если это не так, делаем

chown -R nginx:nginx tst104.1gb.ru
chmod -R 775 tst104.1gb.ru

Чтобы добавить пользователя в группу, выполните команду:

Добавляем пользователя admin2 в группу nginx

sudo usermod -a -G nginx admin2

Проверка принадлежности группам пользователя admin2:

id admin2

Открываем браузер и делаем первый запуск Вордпресса с указанием доступа к БД.

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

Вообще говоря, у WordPress есть мануал насчёт Nginx’а: https://codex.wordpress.org/Nginx, где предлагается несколько иное содержимое файла nginx.conf


Настроим архивация MySQL с помощью automysqlbackup:

Заходим на сайт https://sourceforge.net/projects/automysqlbackup/files/AutoMySQLBackup/ и берём ссылку на свежую версию, заменяя пробелы на %20.

Подготавливаем папку:

sudo mkdir /opt/automysqlbackup
cd /opt/automysqlbackup

Скачиваем:

sudo wget http://downloads.sourceforge.net/project/automysqlbackup/AutoMySQLBackup/AutoMySQLBackup%20VER%203.0/automysqlbackup-v3.0_rc6.tar.gz

Распаковываем:

sudo tar zxvf automysqlbackup-v3.0_rc6.tar.gz

Удаляем файл архива:

sudo rm automysqlbackup-v3.0_rc6.tar.gz

Запускаем скрипт установки (global configuration directory и directory for the executable не меняем):

sudo ./install.sh

Редактируем конфиг:

sudo nano /etc/automysqlbackup/automysqlbackup.conf

Расскоментируйте и установите следующие директивы конфигурации

CONFIG_mysql_dump_username='_пользовательБД_'
CONFIG_mysql_dump_password='_пароль_пользователя_'
CONFIG_mysql_dump_host='localhost'
CONFIG_backup_dir='/var/www/backups/db'
CONFIG_do_monthly="01"
CONFIG_do_weekly="5"
CONFIG_rotation_daily=6
CONFIG_rotation_weekly=35
CONFIG_rotation_monthly=150
CONFIG_mysql_dump_port=3306
CONFIG_mysql_dump_compression='gzip'
CONFIG_db_exclude=( 'information_schema' 'performance_schema' )

Создаем папку для бакапов:

sudo mkdir /var/www/backups
sudo mkdir /var/www/backups/db

Можете проверить архивацию, выполнив:

sudo /usr/local/bin/automysqlbackup

Добавим задание в Cron:

sudo nano /etc/crontab
0 2 * * * root /usr/local/bin/automysqlbackup

Вызов automysqlbackup будет производиться каждый день в 2 часа ночи

После редактирования данного файла службу перезапускать не нужно. Она сама обнаруживает изменения. Можете проверить в логах:

Логи Cron находятся здесь: /var/log/cron

UPD:

Теперь сделаем архивацию файлов

В папке /var/www/backups создадим файл do_backup_now.sh:

cd /var/www/backupssudo nano do_backup_now.sh

И поместим примерно следующее содержимое:

#!/bin/sh
cd /var/www

#File naming
DATE=`date +"%Y-%m-%d_%Hh%Mm"`

#Creating list of site dirrectories on this pattern .*\.\w{1,4} (must ends with .abcd)
LIST=`ls | grep -E ".*\.\w{1,4}"`

#Create directory if not exists
test ! -d /var/www/backups/files_of_sites/`date +%Y`/`date +%m` && { mkdir -p /var/www/backups/files_of_sites/`date +%Y`/`date +%m` ; }

#Cicle of site dirrectories
for ELEMENT in $LIST
 do

 tar -zcvpf /var/www/backups/files_of_sites/`date +%Y`/`date +%m`/$ELEMENT-$DATE.tar.gz /var/www/$ELEMENT --exclude=backup --exclude=managed_cache --exclude=stats --exclude=resize_cache >> /dev/null 2> /var/www/backups/start_backup_files.sh.errors.log

 done
 
#Run mysql backup:
/usr/local/bin/automysqlbackup

exit 0

Дадим на него права:

sudo chmod 770 do_backup_now.sh

Теперь при вызове

sudo ./do_backup_now.sh

будет создататься архив файлов + архив баз в /var/www/backups

Теперь в Cron’е вместо

0 2 * * * root /usr/local/bin/automysqlbackup

укажем

0 2 * * * root /var/www/backups/do_backup_now.sh

Можно не использовать automysqlbackup, а прописать все в файле. Например, так:

 #!/bin/sh
cd /var/www

#File naming
DATE=`date +"%Y-%m-%d_%Hh%Mm"`

#Creating list of site dirrectories on this pattern .*\.\w{1,4} (must ends with .abcd)
LIST=`ls | grep -E ".*\.\w{1,4}"`

#Create directory if not exists
test ! -d /var/www/backups/files_of_sites/`date +%Y`/`date +%m` && { mkdir -p /var/www/backups/files_of_sites/`date +%Y`/`date +%m` ; }

#Cicle of site dirrectories
for ELEMENT in $LIST
 do

 tar -zcvpf /var/www/backups/files_of_sites/`date +%Y`/`date +%m`/$ELEMENT-$DATE.tar.gz /var/www/$ELEMENT --exclude=backup --exclude=managed_cache --exclude=stats --exclude=resize_cache >> /dev/null 2> /var/www/$

 done

#Run mysql backup:
#/usr/local/bin/automysqlbackup

USER="логин пользователя, имеющего доступ ко всем базам данных"
PASSWORD="пароль пользователя, имеющего доступ ко всем базам данных"
OUTPUT="/var/www/backups/db_of_sites/`date +%Y`/`date +%m`" #директория для хранения резервных копий

#Create directory if not exists
test ! -d $OUTPUT && { mkdir -p $OUTPUT ; }


databases=`mysql --user="$USER" --password="$PASSWORD" -e "SHOW DATABASES;" | tr -d "| " | grep -v Database`

for db in $databases; do
    if [[ "$db" != "information_schema" ]] && [[ "$db" != "performance_schema" ]] && [[ "$db" != "mysql" ]] && [[ "$db" != "sys" ]]  ; then
        #echo "Dumping database: $db"
        mysqldump --force --opt --user="$USER" --password="$PASSWORD" --databases $db > $OUTPUT/$db-$DATE.sql
        gzip $OUTPUT/$db-$DATE.sql
    fi
done

exit 0

Настройка HTTPS:

Instructions:

https://www.nginx.com/blog/using-free-ssltls-certificates-from-lets-encrypt-with-nginx/

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

yum install certbot -y

Важное отступление в том, что к этому моменту в вас должен быть доменное имя ссылающееся на данный сайт на сервере. Иначе сертификат не получится получить

UPD: Также можно использовать способ выпуска сертификата через верификацию по DNS, а также выпуск wildcard на весь домен и его поддомены. Для этого использую команду:

certbot certonly --manual --preferred-challenges=dns --server https://acme-v02.api.letsencrypt.org/directory --agree-tos -d knasys.ru -d *.knasys.ru

Для верификации, нужно будет у регистратора доменного имени добавить поддомен _acme-challenge и для него создать требуемую TXT запись. Проверить можно здесь https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.knasys.ru

openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

certbot certonly --webroot -w /var/www/tst104.1gb.ru -d tst104.1gb.ru

certbot certonly --webroot -w /var/www/tst104.1gb.ru -d www.tst104.1gb.ru

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

Если у вас возникает ошибка типа

http://tst104.1gb.ru/.well-known/acme-challenge/eqPo2nLyj7GXUVOuZwGZfDIduAsUrOlMU_j0:
 "<!doctype html>\n<html lang=\"ru-RU\">\n<head>\n<meta
 charset=\"UTF-8\">\n<meta name=\"viewport\"
 content=\"width=device-width, initial-sca"

, проверьте правильность вот этого пути: certbot certonly —webroot -w /var/www/tst104.1gb.ru -d tst104.1gb.ru. В своё время я целый день потерял меняя насторйки nginx, создавая перенаправления на .well-known/acme-challenge, но оказалось нужно было просто дописать /public_html 🙂

Меняем настройки nginx для поддержки HTTPS:

sudo nano /etc/nginx/nginx.conf

В соответствующем server — вместо

listen 80;

пишем (будем использовать путь без www):

listen 443 ssl;    
ssl_certificate /etc/letsencrypt/live/tst104.1gb.ru/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/tst104.1gb.ru/privkey.pem;

А также заменяем

server_name     tst104.1gb.ru   www.tst104.1gb.ru;

на

server_name     tst104.1gb.ru;

Потому что сертификат годен только для него.

Сохраняем и проверяем конфигурацию:

sudo nginx -t

Если всё ок, то

sudo nginx -s reload

Проверяем прослушку 443 порта:

netstat -tulpn

Пробуем открыть в браузере https://tst104.1gb.ru и о чудо :)) работает!

Однако останось несколько неразрешенных моментов:

https://www.tst104.1gb.ru
http://tst104.1gb.ru
http://www.tst104.1gb.ru
Итак, по порядку:
Добавляем другие сертификаты + перенаправление с https://www.tst104.1gb.ru на  https://tst104.1gb.ru:

server {
       listen 443 ssl;
       server_name www.tst104.1gb.ru;

       ssl_certificate /etc/letsencrypt/live/www.tst104.1gb.ru/fullchain.pem;
       ssl_certificate_key /etc/letsencrypt/live/www.tst104.1gb.ru/privkey.pem;

       return 301 https://tst104.1gb.ru$request_uri;
   }

Перенаправление с HTTP на HTTPS для www и без него:

server {
       server_name tst104.1gb.ru www.tst104.1gb.ru;
       return 301 https://tst104.1gb.ru$request_uri;
   }

Сертификаты годны 90 дней, поэтому добавляем задачу в Cron на автообновление:

 sudo nano /etc/crontab
0 0 1 * * root /usr/bin/certbot renew --quiet
1 0 1 * * root systemctl restart nginx

Задача будет запускаться каждое 1 число месяца в 0 часов ночи. Команда проверяет, истекает ли сертификат на сервере в течение следующих 30 дней, и обновляет его, если это так. Директива —quiet просит certbot не генерировать output.

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

Полезные статьи:


Настройка функции mail() на php

За основу взял статью https://hd.zp.ua/nastrojka-msmtp-dlya-otpravki-pisem-php-mail-cherez-servisy-gmail-i-yandex/ с некоторыми уточнениями и важным замечанием

Итак, мы не будем поднимать postfix и т.д. Мы будем слать почту через SMTP с помощью msmtp.

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

sudo yum install msmtp -y

Правим конфиг:

sudo nano /etc/msmtprc

Вносим данные только что зарегистрированной почты на Яндексе:

account yandex
logfile /var/log/msmtp.log
host smtp.yandex.ru
port 587
from YOUR_LOGIN@yandex.ru
keepbcc on
auth on
user YOUR_LOGIN@yandex.ru
password YOUR_PASSWORD
tls on
tls_starttls on
tls_certcheck off

Создадим файл для логов:

sudo touch /var/log/msmtp.log
sudo chown root:nginx /var/log/msmtp.log
sudo chmod 770 /var/log/msmtp.log

Проверяем.

Создаем дирректорию для тестов (в последствии можете её удалить):

sudo mkdir /var/www/msmtp
sudo chmod 777 /var/www/msmtp

cd /var/www/msmtp

Создаем тестовое письмо

echo -e «From: YOUR_LOGIN@yandex.ru \n\
To: YOUR_OWN_EMAIL@mail.ru \n\
Subject: Hello World \n\
\n\
This email was sent using MSMTP» >> sample_email.txt

В поле From укажите зарегистрированную на Яндексе почту (хотя, можете указать совершенно лефую и письмо придет якобы я неё 🙂 )

В поле To укажите почту куда будете слать письмо.

Делаем отправку из консоли:

Дебаг, но улетит в спам и будет пустое

sudo cat sample_email.txt | msmtp --debug -a yandex YOUR_OWN_EMAIL@mail.ru

Без дебага, но всё будет как надо
sudo cat sample_email.txt | msmtp  -a yandex YOUR_OWN_EMAIL@mail.ru

Теперь вы можете создать файл 1.php в корне вашего сайта с таким содержанием:

<?php
   if (mail("YOUR_OWN_EMAIL@mail.ru", "theme", "message", "From: YOUR_LOGIN@yandex.ru")){
      echo "success";
   }else{
      echo "error";
   } 
?>

Однако, при открытии через браузер этого файла, почта не будет отправляться, но из консоли при выполнении команды:

sudo php /var/www/YOUR_SITE/1.php

будет. Здесь проблема в правах. И тут мы подошли к моменту, который немного вынес мне мозг:

Внимание! Очень важно чтобы владелец файла /etc/msmtprc был пользователь, под которым запущен web-сервер (у меня это nginx)
Особенно важно чтобы права на файл /etc/msmtprc были Чтение/Запись только для владельца! Не больше, не меньше! Иначе Вы не сможете отправлять письма и сломаете голову почему! Ещё раз повторю, что даже большие права на этот файл не дадут отправляться письмам. Права должны быть 600, а владелец — пользователь, под которым стартует web-сервер!

ls -l /etc/msmtprc

sudo chmod 600 /etc/msmtprc
sudo chown nginx /etc/msmtprc
sudo chgrp nginx /etc/msmtprc

ls -l /etc/msmtprc

Нужно сказать php через что слать письма:

sudo cp /etc/php.ini /etc/php.ini.original
sudo nano /etc/php.ini

Параметру sendmail_path присваиваем значение:

sendmail_path = "/usr/bin/msmtp -C /etc/msmtprc --logfile /var/log/msmtp.log -a yandex -t"

Перезагружаем php-fpm:

sudo systemctl reload php-fpm

Теперь письма полетят с помощью функции mail() — php как надо.

(Просмотрено 1 451 раз, 1 раз за сегодня)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *