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 как надо.