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