Веб сервер на Oracle Linux 8.4 (Apache, Nginx, PHP, MySQL, phpMyAdmin, Memcached, Redis, ProFTPd, Fail2ban, Postfix)

Веб сервер одна из самых востребованных ролей Linux серверов. В данном примере использована связка двух веб-серверов — Nginx в качестве кэширующего прокси-сервера для Apache, интерпретатора PHP и сервера баз данных MySQL.

Подготовка системы

Обновление системы

dnf update -y

Удаление SELinux

dnf remove -y selinux*

Установка репозитория EPEL и REMI

dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm

dnf install -y https://rpms.remirepo.net/enterprise/remi-release-8.rpm

Установка утилит

dnf install -y wget mc net-tools unzip

Настройка брандмауэра

В качестве межсетевого экрана будет использоваться iptables.

Удаление Firewalld

Остановка сервиса firewalld:

systemctl stop firewalld

Выключение сервиса автозагрузки firewalld:

systemctl disable firewalld

Маскировка сервиса firewalld:

systemctl mask --now firewalld

Удаление firewalld:

dnf remove -y firewalld

Установка и включение iptables

Установка iptables:

dnf install -y iptables-services

Включение сервиса iptables в автозагрузку:

systemctl enable iptables

Запуск сервиса iptables:

systemctl start iptables

Проверка статуса службы iptables:

systemctl status iptables

Перезагрузка ОС:

reboot

Создадим файл настроек iptables в редакторе Midnight Commander:

mcedit iptables.sh

и внесем в него следующее содержимое:

#!/bin/sh
# - Очищаем таблицы
iptables -F
iptables -t nat -F
iptables -t mangle -F
iptables -X
# - Политики по умолчанию
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP
# - Разрешить трафик по петлевому интерфейсу
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
# - Разрешим передавать пакеты, относящиеся к уже установленным соединениям
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# - Разрешить входящий PING
iptables -A INPUT -p icmp -j ACCEPT
# - Разрешить все исходящие
iptables -I OUTPUT 1 -j ACCEPT
# - Доступ по SSH
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# - Разрешить доступ к WEB серверу
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -p tcp --dport 8080 -j ACCEPT
# Разрешить доступ к FTP серверу
iptables -A INPUT -p tcp --dport 20 -j ACCEPT
iptables -A INPUT -p tcp --dport 21 -j ACCEPT
iptables -A INPUT -p tcp --dport 60000:65535 -j ACCEPT
# - Сохранить настройки
service iptables save

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

chmod +x iptables.sh

Выполняем скрипт:

./iptables.sh

Посмотреть список правил iptables можно командой:

iptables --line-numbers -L -v -n

Установка Apache (httpd)

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

dnf install -y httpd

Для настройка Apache работы в связке с Nginx открываем конфигурационный файл:

mcedit /etc/httpd/conf/httpd.conf

Находим параметр:

Listen 80

Меняем значение на:

Listen 8080

Apache будет слушать порт 8080, так как на порту 80 будет работать Nginx

Проверяем синтаксис конфигурационного файла Apache:

apachectl configtest

Включение сервиса Apache в автозагрузку:

systemctl enable httpd

Запуск сервиса Apache:

systemctl start httpd

Проверка статуса сервиса Apache:

systemctl status httpd

Открываем браузер и вводим в адресную строку IP-адрес или DNS имя сервера и добавляем :8080 (http://<IP-адрес нашего сервера>:8080). Откроется тестовая страница.

http://web.dev.mailns.ru:8080

Установка Ngnix

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

dnf install -y nginx

Внесем небольшую корректировку в конфигурационный файл Ngnix:

mcedit /etc/nginx/nginx.conf

В секцию http добавим строку:

server_names_hash_bucket_size 64;

На практике, может встретиться ошибка could not build server_names_hash, you should increase server_names_hash_bucket_size: 32. Она возникает при большом количестве виртуальных серверов или если один из них будет иметь длинное название. Данная строка в конфиге исправит ситуацию.

Включение сервиса Nginx в автозагрузку:

systemctl enable nginx

Запуск сервиса Nginx:

systemctl start nginx

Проверка статуса сервиса Nginx:

systemctl status nginx

Открываем браузер и вводим в адресную строку IP-адрес или DNS имя сервера (http://<IP-адрес нашего сервера>). Должна откроется страница приветствия.

http://web.dev.mailns.ru/

Установка PHP

Вывести список возможных модулей PHP можно следующей командой:

dnf module list php

В данном примере будет установлена PHP 8.0 из репозитория Remi:

dnf module install -y php:remi-8.0

Просмотр установленной версии PHP:

php -v

Установка модулей расширений PHP:

dnf install -y php-{apcu,bcmath,dba,enchant,env,ffi,gd,gearman,geoip,gmp,igbinary,imagick,imap,intl,ldap,libsmbclient,mailparse,mcrypt,memcache,memcached,msgpack,mysqli,mysqlnd,odbc,pdo,pdo_dblib,pdo_firebird,pdo_mysql,pdo_odbc,pdo_pgsql,pdo_sqlite,pgsql,posix,pspell,psr,redis,shmop,smbclient,snmp,soap,sodium,sqlite3,swoole,sysvmsg,sysvsem,sysvshm,tidy,uploadprogress,xmlrpc,yaml,zip,opcache}

Установка MySQL

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

dnf install -y @mysql

Включение сервиса mysql в автозагрузку:

systemctl enable mysqld

Запуск сервиса mysql:

systemctl start mysqld

Проверим статус сервиса mysql:

systemctl status mysqld

Сразу создаем пароль для учетной записи root:

mysqladmin -u root password

Вводим новый пароль, например:

Ekyj6ZfHabq97MvQ64Nc3@

Создание сайта

В директории /var/www/html создаём первый каталог под веб-сайт, и называем его так же, как и доменное имя нашего сайта, чтобы не было путаницы, если сайтов будет несколько.

Создадим директорию для сайта:

mkdir -p /var/www/html/web.dev.mailns.ru

Назначаем владельца директории:

chown -R apache:apache /var/www

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

mcedit /etc/nginx/conf.d/web.dev.mailns.ru.conf

И добавляем следующее содержимое (для HTTP):

server {
listen 80;
server_name web.dev.mailns.ru;
root /var/www/html/web.dev.mailns.ru;
index index.php index.html index.htm;
access_log /var/log/nginx/web.dev.mailns.ru.access.log main;
error_log /var/log/nginx/web.dev.mailns.ru.error.log;

location / {
root /var/www/html/web.dev.mailns.ru;
proxy_pass http://127.0.0.1:8080/;
proxy_redirect     off;
proxy_force_ranges on;
proxy_set_header   Host            $host;
proxy_set_header   X-Real-IP       $remote_addr;
proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cache off;
proxy_cache_key "$request_method|$http_if_modified_since|$http_if_none_match|$host|$request_uri";
proxy_cache_valid 3s;
proxy_cache_min_uses 2;
client_body_buffer_size    128k;
client_max_body_size       1024m;
proxy_connect_timeout      180;
proxy_send_timeout         180;
proxy_read_timeout         180;
send_timeout               180;
proxy_buffer_size          4k;
proxy_buffers              8 32k;
proxy_busy_buffers_size    68k;
proxy_temp_file_write_size 10m;
}

location ~ /\. {
deny all; 
}

}

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

mcedit /etc/httpd/conf.d/web.dev.mailns.ru.conf

Содержимое файла:

<VirtualHost *:8080>
ServerName web.dev.mailns.ru
DocumentRoot /var/www/html/web.dev.mailns.ru
SetEnvIf X-Forwarded-Proto https HTTPS=on
<IFModule proxy_fcgi_module>
ProxyFCGISetEnvIf "true" SCRIPT_FILENAME "/var/www/html/web.dev.mailns.ru%{reqenv:SCRIPT_NAME}"
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost/"
</FilesMatch>
</IFModule>
ErrorLog /var/log/httpd/web.dev.mailns.ru.error.log
CustomLog /var/log/httpd/web.dev.mailns.ru.access.log common
<Directory /var/www/html/web.dev.mailns.ru>
Options Indexes FollowSymLinks Includes ExecCGI
AllowOverride All
Require all granted
</Directory>
</VirtualHost>

Для проверки, создадим файл index.php, с выводом информации о php.

echo '<?php phpinfo(); ?>' > /var/www/html/web.dev.mailns.ru/index.php

Перезапускаем Ngnix:

systemctl restart nginx

Перезапускаем Apache:

systemctl restart httpd

Открываем браузер, и заходим по адресу нашего сайта. Открывается страница с информацией о php.

В данном примере:

http://web.dev.mailns.ru/

Установка Memcached

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

Выполняем установку пакетов:

dnf install -y memcached libmemcached

Создаем или открываем на редактирование конфигурационный файл memcached:

mcedit /etc/sysconfig/memcached

PORT — указываем на каком порту будет слушать сервис кэширования;
USER — пользователь, под которым должен запускаться сервис;
MAXCONN — максимальное число одновременных подключений;
CACHESIZE — размер под кэш в мегабайтах;
OPTIONS — параметры запуска (в данном примере наш сервис будет принимать запросы только с адреса локальной петли).

Включение сервиса memcached в автозагрузку:

systemctl enable memcached

Запуск сервиса memcached:

systemctl start memcached

Проверим статус сервиса memcached:

systemctl status memcached

Чтобы проверить, что модуль memcached работаем создадим файл memcachetest.php:

mcedit /var/www/html/web.dev.mailns.ru/memcachetest.php

со следующим содержимым:

<?php
 
if (!class_exists("Memcache"))  exit("Memcached не установлен");
$memcache = new Memcache;
$memcache->connect('localhost', 11211) or exit("Невозможно подключиться к серверу Memcached");
 
$version = $memcache->getVersion();
echo "Server's version: ".$version."<br/>\n";
 
$tmp_object = new stdClass;
$tmp_object->str_attr = 'test';
$tmp_object->int_attr = 123;
 
$memcache->set('key', $tmp_object, false, 10) or die ("Не получилось оставить запись в Memcached");
echo "Записываем данные в кеш Memcached (данные будут храниться 10 секунд)<br/>\n";
 
$get_result = $memcache->get('key');
echo "Данные, записанные в Memcached:<br/>\n";
 
var_dump($get_result);
 
?>

Открываем браузер, и заходим по адресу нашего сайта с указанием memcachetest.php. Если memcached работает и доступен должна открыться страница со следующим содержимым.

http://web.dev.mailns.ru/memcachetest.php

Установка Redis

Redis (расшифровывается как Remote Dictionary Server) – это быстрое хранилище данных типа «ключ‑значение» в памяти с открытым исходным кодом, Redis используется в качестве базы данных, кэша, брокера сообщений и очереди.

Выполняем установку пакета:

dnf install -y redis

Конфигурационный файл расположен по адресу:

/etc/redis.conf

Включение сервиса redis в автозагрузку:

systemctl enable redis

Запуск сервиса redis:

systemctl start redis

Проверим статус сервиса redis:

systemctl status redis

Пример подключения и выполнения запроса.

Чтобы проверить, что модуль redis работаем создадим файл redistest.php:

mcedit /var/www/html/web.dev.mailns.ru/redistest.php

со следующим содержимым:

<?php
    $redis = new Redis();
     
    $redis->connect('localhost', 6379);
    $redis->auth('password');
     
    $redis->set("test_php_key", "test php value");
    echo $redis->get("test_php_key");
    echo "\r\n";
?>

Открываем браузер, и заходим по адресу нашего сайта с указанием redistest.php. Если redis работает и доступен должна открыться страница со следующим содержимым.

http://web.dev.mailns.ru/redistest.php

Установка и настройка FTP-сервера

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

dnf install -y proftpd

Загружаем скрипт ftpasswd:

wget http://www.castaglia.org/proftpd/contrib/ftpasswd -P /etc/proftpd

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

chmod +x /etc/proftpd/ftpasswd

Создаем виртуального пользователя:

/etc/proftpd/ftpasswd --passwd --file=/etc/proftpd/ftpd.passwd --name=wwwroot --uid=48 --gid=48 --home=/var/www --shell=/sbin/nologin

/etc/proftpd/ftpd.passwd — путь до файла, в котором хранятся пользователи;
wwwroot — имя пользователя (логин);
uid и gid — идентификаторы пользователя и группы системной учетной записи (apache);
/var/www — домашний каталог пользователя;
/sbin/nologin — оболочка, запрещающая локальный вход пользователя в систему.

Изменим права для созданного файла с паролями:

chmod 440 /etc/proftpd/ftpd.passwd

в противном случае, при запуске proftpd мы получим ошибку «…fatal: AuthUserFile: unable to use /etc/proftpd.d/ftpd.passwd: Operation not permitted…»

Открываем на редактирование конфигурационный файл proftpd:

mcedit /etc/proftpd.conf

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

#AuthOrder

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

mcedit /etc/proftpd/conf.d/custom.conf
AuthUserFile /etc/proftpd/ftpd.passwd
IdentLookups off
UseReverseDNS off
RequireValidShell off
AuthPAM off
RootLogin off
DefaultRoot ~
LoadModule mod_auth_file.c
AuthOrder mod_auth_file.c
PassivePorts 60000 65535
UseIPv6 off
ExtendedLog /var/log/proftpd/proftpd.log

Включение сервиса ProFTPd в автозагрузку:

systemctl enable proftpd

Запуск сервиса ProFTPd:

systemctl start proftpd

Проверка статуса сервиса ProFTPd:

systemctl status proftpd

Пробуем подключиться к серверу, использую любые FTP-клиенты, например, FileZilla, Total Commander или тот же браузер.

Установка и настройка Fail2ban

Выполняем установку пакета fail2ban:

dnf install -y fail2ban

Основной конфигурационный файл находится по пути:

/etc/fail2ban/jail.conf

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

/etc/fail2ban/jail.d

SSH

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

mcedit /etc/fail2ban/jail.d/sshd.conf

Содержимое:

[ssh]
enabled = true
bantime = 600
port = ssh
filter = sshd
action = iptables[name=sshd, port=ssh, protocol=tcp]
logpath = /var/log/secure
maxretry = 10
findtime = 3600

ssh — название для правила;
enabled — позволяет быстро включать (true) или отключать (false) правило;
bantime — время, на которое будет блокироваться IP-адрес;
port — порт целевого сервиса. Принимается буквенное или цифирное обозначение;
filter — фильтр (критерий поиска), который будет использоваться для поиска подозрительных действий. По сути, это имя файла из каталога /etc/fail2ban/filter.d без .conf на конце;
action — действие, совершаемое в случае срабатывания правила. В квадратных скобках указаны название для правила, сетевой порт и протокол для блокирования;
logpath — расположение лог-файла, в котором фильтр будет искать подозрительную активность на основе описанных критериев;
maxretry — количество действий, которые разрешено совершить до бана;
findtime — время в секундах, в течение которого учитывается maxretry.

File2ban cо стандартным фильтром для ProFTPd не блокировал подключения пришлось создать для него отдельный фильтр.

ProFTPd

Для создания нового фильтра для ProFTPd необходимо создать конфигурационный файл:

mcedit /etc/fail2ban/filter.d/proftpd-custom.conf

Содержимое файла:

# fail2ban filter for the ProFTPD FTP daemon
[INCLUDES]

before = common.conf

[Definition]

_daemon = proftpd

failregex = \(\S+\[<HOST>\]\)[: -]+ USER \S+: no such user found from \S+ \[[0-9.]+\] to \S+:\S+\s*$
            \(\S+\[<HOST>\]\)[: -]+ USER \S+ \(Login failed\):.*\s+$
            \(\S+\[<HOST>\]\)[: -]+ Maximum login attempts \([0-9]+\) exceeded, connection refused.*\s+$
            \(\S+\[<HOST>\]\)[: -]+ SECURITY VIOLATION: \S+ login attempted\.\s+$
            \(\S+\[<HOST>\]\)[: -]+ Maximum login attempts \(\d+\) exceeded\s+$

ignoreregex =

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

mcedit /etc/fail2ban/jail.d/proftpd.conf

Содержимое файла:

[proftpd]
enabled = true
bantime = 600
port = ftp
filter = proftpd-custom
action = iptables[name=ftp, port=ftp, protocol=tcp]
logpath = /var/log/messages
maxretry = 10
findtime = 3600

Nginx DDoS (req limit)

Для начала, необходимо настроить Nginx:

mcedit /etc/nginx/nginx.conf

В раздел http добавим:

limit_req_zone $binary_remote_addr zone=webdevmailnsru:10m rate=5r/s;

Данная настройка создает зону с интенсивностью запросов в 1 запрос в секунду.

После настраиваем лимит для конкретного виртуального домена в разделе server — location:

mcedit /etc/nginx/conf.d/web.dev.mailns.ru.conf

Добавим:

limit_req zone=webdevmailnsru burst=5 nodelay;

Данная настройка вместе с предыдущей зоной, созданной в секции http, позволит лимитировать запросы — 1 запрос в секунду при всплеске 5 запросов.

Перезапускаем сервис Ngnix:

systemctl reload nginx

Создаем правило в fail2ban:

mcedit /etc/fail2ban/jail.d/nginx-limit-req.conf

Содержимое файла:

[nginx-ddos]
enabled = true
bantime = 600
port = http,https
filter = nginx-limit-req
action = iptables-multiport[name=nginx-ddos, port="http,https", protocol=tcp]
logpath = /var/log/nginx/*.error.log
maxretry = 10
findtime = 3600

Включение сервиса fail2ban в автозагрузку:

systemctl enable fail2ban

Запуск сервиса fail2ban:

systemctl start fail2ban

Проверка статуса сервиса fail2ban:

systemctl status fail2ban

Установка phpMyAdmin

Создадим директорию для сайта:

mkdir -p /var/www/html/phpmyadmin.web.dev.mailns.ru

Создаем новый файл виртуального домена Nginx:

mcedit /etc/nginx/conf.d/phpmyadmin.web.dev.mailns.ru.conf

И добавляем следующее содержимое:

server {
listen 80;
server_name phpmyadmin.web.dev.mailns.ru;
root /var/www/html/phpmyadmin.web.dev.mailns.ru;
index index.php index.html index.htm;
access_log /var/log/nginx/phpmyadmin.web.dev.mailns.ru.access.log main;
error_log /var/log/nginx/phpmyadmin.web.dev.mailns.ru.error.log;

location / {
root /var/www/html/phpmyadmin.web.dev.mailns.ru;
proxy_pass http://127.0.0.1:8080/;
proxy_redirect     off;
proxy_force_ranges on;
proxy_set_header   Host            $host;
proxy_set_header   X-Real-IP       $remote_addr;
proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cache off;
proxy_cache_key "$request_method|$http_if_modified_since|$http_if_none_match|$host|$request_uri";
proxy_cache_valid 3s;
proxy_cache_min_uses 2;
client_body_buffer_size    128k;
client_max_body_size      1024m;
proxy_connect_timeout       180;
proxy_send_timeout          180;
proxy_read_timeout          180;
send_timeout                180;
proxy_buffer_size            4k;
proxy_buffers             8 32k;
proxy_busy_buffers_size     68k;
proxy_temp_file_write_size  10m;
}

location ~ /\. {
deny all; 
}

}

Создаем новый файл виртуального домена Apache:

mcedit /etc/httpd/conf.d/phpmyadmin.web.dev.mailns.ru.conf

Содержимое файла:

<VirtualHost *:8080>
ServerName phpmyadmin.web.dev.mailns.ru
DocumentRoot /var/www/html/phpmyadmin.web.dev.mailns.ru
SetEnvIf X-Forwarded-Proto https HTTPS=on
<IFModule proxy_fcgi_module>
ProxyFCGISetEnvIf "true" SCRIPT_FILENAME "/var/www/html/phpmyadmin.web.dev.mailns.ru%{reqenv:SCRIPT_NAME}"
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost/"
</FilesMatch>
</IFModule>
ErrorLog /var/log/httpd/phpmyadmin.web.dev.mailns.ru.error.log
CustomLog /var/log/httpd/phpmyadmin.web.dev.mailns.ru.access.log common
<Directory /var/www/html/phpmyadmin.web.dev.mailns.ru>
Options Indexes FollowSymLinks Includes ExecCGI
AllowOverride All
Require all granted
</Directory>
</VirtualHost>

Скачиваем phpMyAdmin:

wget -P /var/www/html/phpmyadmin.web.dev.mailns.ru http://files.phpmyadmin.net/phpMyAdmin/5.1.1/phpMyAdmin-5.1.1-all-languages.zip

Переходим в директорию сайта:

cd /var/www/html/phpmyadmin.web.dev.mailns.ru

Распаковываем архив phpMyAdmin:

unzip phpMyAdmin-5.1.1-all-languages.zip

Переносим содержимое распакованного архива в директорию сайта:

mv phpMyAdmin-5.1.1-all-languages/* /var/www/html/phpmyadmin.web.dev.mailns.ru/

Назначаем владельца директории:

chown -R apache:apache /var/www/html/phpmyadmin.web.dev.mailns.ru/

Перезапускаем Nginx:

systemctl restart nginx

Перезапускаем Apache:

systemctl restart httpd

Сгенерируем случайную последовательность символов:

head /dev/urandom | tr -dc A-Za-z0-9 | head -c 32 ; echo ''

Cоздадим файл:

mcedit /var/www/html/phpmyadmin.web.dev.mailns.ru/config.inc.php

Содержимое файла:

<?php
/**
 * phpMyAdmin sample configuration, you can use it as base for
 * manual configuration. For easier setup you can use setup/
 *
 * All directives are explained in documentation in the doc/ folder
 * or at <https://docs.phpmyadmin.net/>.
 */

declare(strict_types=1);

/**
 * This is needed for cookie based authentication to encrypt password in
 * cookie. Needs to be 32 chars long.
 */
$cfg['blowfish_secret'] = 'rdrWuVryamvtwBuwBobs5fW595x9r6Xy'; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */

/**
 * Servers configuration
 */
$i = 0;

/**
 * First server
 */
$i++;
/* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'cookie';
/* Server parameters */
$cfg['Servers'][$i]['host'] = 'localhost';
$cfg['Servers'][$i]['compress'] = false;
$cfg['Servers'][$i]['AllowNoPassword'] = false;

/**
 * phpMyAdmin configuration storage settings.
 */

/* User used to manipulate with storage */
// $cfg['Servers'][$i]['controlhost'] = '';
// $cfg['Servers'][$i]['controlport'] = '';
// $cfg['Servers'][$i]['controluser'] = 'pma';
// $cfg['Servers'][$i]['controlpass'] = 'pmapass';

/* Storage database and tables */
// $cfg['Servers'][$i]['pmadb'] = 'phpmyadmin';
// $cfg['Servers'][$i]['bookmarktable'] = 'pma__bookmark';
// $cfg['Servers'][$i]['relation'] = 'pma__relation';
// $cfg['Servers'][$i]['table_info'] = 'pma__table_info';
// $cfg['Servers'][$i]['table_coords'] = 'pma__table_coords';
// $cfg['Servers'][$i]['pdf_pages'] = 'pma__pdf_pages';
// $cfg['Servers'][$i]['column_info'] = 'pma__column_info';
// $cfg['Servers'][$i]['history'] = 'pma__history';
// $cfg['Servers'][$i]['table_uiprefs'] = 'pma__table_uiprefs';
// $cfg['Servers'][$i]['tracking'] = 'pma__tracking';
// $cfg['Servers'][$i]['userconfig'] = 'pma__userconfig';
// $cfg['Servers'][$i]['recent'] = 'pma__recent';
// $cfg['Servers'][$i]['favorite'] = 'pma__favorite';
// $cfg['Servers'][$i]['users'] = 'pma__users';
// $cfg['Servers'][$i]['usergroups'] = 'pma__usergroups';
// $cfg['Servers'][$i]['navigationhiding'] = 'pma__navigationhiding';
// $cfg['Servers'][$i]['savedsearches'] = 'pma__savedsearches';
// $cfg['Servers'][$i]['central_columns'] = 'pma__central_columns';
// $cfg['Servers'][$i]['designer_settings'] = 'pma__designer_settings';
// $cfg['Servers'][$i]['export_templates'] = 'pma__export_templates';

/**
 * End of servers configuration
 */

/**
 * Directories for saving/loading files from server
 */
$cfg['UploadDir'] = '';
$cfg['SaveDir'] = '';

/**
 * Whether to display icons or text or both icons and text in table row
 * action segment. Value can be either of 'icons', 'text' or 'both'.
 * default = 'both'
 */
//$cfg['RowActionType'] = 'icons';

/**
 * Defines whether a user should be displayed a "show all (records)"
 * button in browse mode or not.
 * default = false
 */
//$cfg['ShowAll'] = true;

/**
 * Number of rows displayed when browsing a result set. If the result
 * set contains more rows, "Previous" and "Next".
 * Possible values: 25, 50, 100, 250, 500
 * default = 25
 */
//$cfg['MaxRows'] = 50;

/**
 * Disallow editing of binary fields
 * valid values are:
 *   false    allow editing
 *   'blob'   allow editing except for BLOB fields
 *   'noblob' disallow editing except for BLOB fields
 *   'all'    disallow editing
 * default = 'blob'
 */
//$cfg['ProtectBinary'] = false;

/**
 * Default language to use, if not browser-defined or user-defined
 * (you find all languages in the locale folder)
 * uncomment the desired line:
 * default = 'en'
 */
//$cfg['DefaultLang'] = 'en';
//$cfg['DefaultLang'] = 'de';

/**
 * How many columns should be used for table display of a database?
 * (a value larger than 1 results in some information being hidden)
 * default = 1
 */
//$cfg['PropertiesNumColumns'] = 2;

/**
 * Set to true if you want DB-based query history.If false, this utilizes
 * JS-routines to display query history (lost by window close)
 *
 * This requires configuration storage enabled, see above.
 * default = false
 */
//$cfg['QueryHistoryDB'] = true;

/**
 * When using DB-based query history, how many entries should be kept?
 * default = 25
 */
//$cfg['QueryHistoryMax'] = 100;

/**
 * Whether or not to query the user before sending the error report to
 * the phpMyAdmin team when a JavaScript error occurs
 *
 * Available options
 * ('ask' | 'always' | 'never')
 * default = 'ask'
 */
//$cfg['SendErrorReports'] = 'always';

/**
 * You can find more configuration options in the documentation
 * in the doc/ folder or at <https://docs.phpmyadmin.net/>.
 */

где ‘rdrWuVryamvtwBuwBobs5fW595x9r6Xy’ — последовательность, которую нам выдала команда head.

И открываем в браузере наш домен, в данном примере, http://phpmyadmin.web.dev.mailns.ru/. Откроется форма для авторизации — вводим логин root и пароль, который мы указали после установки MySQL.

http://phpmyadmin.web.dev.mailns.ru/

Установка Postfix

Выполняем установку пакета postfix:

dnf install -y postfix

Открываем на редактирование файл:

mcedit /etc/postfix/main.cf

Изменяем несколько настроек:

myorigin = $mydomain
...
inet_protocols = ipv4

Добавляем:

smtp_generic_maps = hash:/etc/postfix/generic_map

myorigin — имя домена, которое будет подставляться всем отправляемым сообщениям без явного указания оного;
inet_protocols — задает версию IP, с которой будет работать Postfix;
smtp_generic_maps — указывает на карту с общими правилами пересылки.

Открываем карту пересылки:

mcedit /etc/postfix/generic_map

Добавляем:

@web.dev.mailns.ru reply@web.dev.mailns.ru

данной настройкой мы будем подставлять всем отправляемым письмам без поля FROM адрес reply@web.dev.mailns.ru.

Создаем карту:

postmap /etc/postfix/generic_map

Для применения настроек перезагружаем почтовый сервер postfix:

systemctl restart postfix

Проверка статуса службы postfix:

systemctl status postfix

Получение бесплатного SSL сертификата Let’s Encrypt

Запрашивать сертификат Let’s Encrypt проще всего с веб-сервера, на котором запущен сайт для домена.

Открываем файл виртуального домена Nginx:

mcedit /etc/nginx/conf.d/web.dev.mailns.ru.conf

И добавляем следующее содержимое:

location ~ /.well-known {
root /var/www/html/web.dev.mailns.ru;
allow all;
}

Перезапускаем Nginx

systemctl restart nginx

Выполним установку утилиты для получения сертификата Certbot:

dnf install -y certbot

Создадим директорию .well-known:

mkdir /var/www/html/web.dev.mailns.ru/.well-known

Создадим директорию acme-challenge:

mkdir /var/www/html/web.dev.mailns.ru/.well-known/acme-challenge

Запрос на получение сертификата при использовании веб-сервера Nginx:

certbot certonly --webroot --agree-tos --email admin@mailns.ru --webroot-path /var/www/html/web.dev.mailns.ru/ -d web.dev.mailns.ru

certonly — запрос нового сертификата;
webroot — проверка будет выполняться на основе запроса к корню сайта;
agree-tos — даем согласие на лицензионное соглашение;
email — почтовый адрес администратора домена;
webroot-path — каталог в системе Linux, который является корневым для сайта;
d — перечисление доменов, для которых запрашиваем сертификат.

Как только сертификат SSL будет успешно получен, certbot напечатает следующее сообщение:

Изменим файл виртуального домена Nginx для использования полученных сертификатов:

mcedit /etc/nginx/conf.d/web.dev.mailns.ru.conf

Приведем содержимое к следующему виду:

server {
listen 80;
server_name web.dev.mailns.ru;
return 301 https://$host$request_uri;
}

server {
listen 443 ssl;
# ssl on;
ssl_certificate /etc/letsencrypt/live/web.dev.mailns.ru/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/web.dev.mailns.ru/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/web.dev.mailns.ru/chain.pem;

server_name web.dev.mailns.ru;
index index.php index.html index.htm;
access_log /var/log/nginx/web.dev.mailns.ru.access.log main;
error_log /var/log/nginx/web.dev.mailns.ru.error.log;

location / {
root /var/www/html/web.dev.mailns.ru;
proxy_pass http://127.0.0.1:8080/;
proxy_redirect off;
proxy_force_ranges on;
proxy_set_header Host              $host;
proxy_set_header X-Real-IP         $remote_addr;
proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header HTTPS             $scheme;
proxy_cache off;
proxy_cache_key "$request_method|$http_if_modified_since|$http_if_none_match|$host|$request_uri";
proxy_cache_valid           3s;
proxy_cache_min_uses         2;
client_body_buffer_size   128k;
client_max_body_size     1024m;
proxy_connect_timeout      180;
proxy_send_timeout         180;
proxy_read_timeout         180;
send_timeout               180;
proxy_buffer_size           4k;
proxy_buffers            8 32k;
proxy_busy_buffers_size    68k;
proxy_temp_file_write_size 10m;
}

location ~ /.well-known {
root /var/www/html/web.dev.mailns.ru;
allow all;
}

location ~ /\. {
deny all; 
}

}

Перезапускаем Nginx

systemctl restart nginx

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

https://web.dev.mailns.ru/

Реальный IP-адрес в Apache

Так как все запросы на Apache приходят от Nginx, они воспринимаются как от IP-адреса 127.0.0.1. На практике, это может привести к проблемам, так как некоторым сайтам необходимы реальные адреса посетителей.

Для решения проблемы будем использовать модуль remoteip_module.

Проверяем включен ли модуль remoteip_module, для этого выполним команду:

httpd -M

В конфигурации виртуального домена Nginx должно быть указано:

proxy_set_header X-Forwarded-For $remote_addr;

Проверяем конфигурацию виртульного домена Nginx:

mcedit /etc/nginx/conf.d/web.dev.mailns.ru.conf

Для того, чтобы в логах записывались реальные IP пользователей нужно в основном конфигурационном файле в переменной LogFormat заменить значение %h на %a:

mcedit /etc/httpd/conf/httpd.conf

Создаем конфигурационный файл remoteip_module модуля:

mcedit /etc/httpd/conf.modules.d/remoteip.conf

добавляем в него:

<IfModule remoteip_module>
RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 127.0.0.1/8
</IfModule>

Перезапускаем Apache:

systemctl restart httpd

Для проверки открываем нашу страницу с phpinfo и находим $_SERVER[‘REMOTE_ADDR’] — его значение должно быть равно адресу компьютера, с которого мы открыли страницу.

PHP как модуль Apache (mod_php)

Этот режим предполагает подключение модуля mod_php в настройках веб-сервера Apache. В этом случае каждый процесс веб-сервера будет включать в себя этот модуль.

Так как не установлен модуль mod_php, выполним установку php:

dnf install -y php

Apache по умолчанию настроен на работу с модулем mpm_event, а модуль mod_php поддерживает только модуль mpm_prefork, с другим модулем он работать не будет. Таким образом, чтобы нормально заработал php, надо вместо модуля mpm_event подключить модуль mpm_prefork. Для этого в конфигурационном файле 00-mpm.conf закомментируем подключение mpm_event и раскомментируем mpm_prefork.

mcedit /etc/httpd/conf.modules.d/00-mpm.conf

Если в конфигурации виртуального хоста Apache указано использовать сокет FastCGI, то строки необходимо закоментировать либо удалить.

mcedit /etc/httpd/conf.d/web.dev.mailns.ru.conf
# <IFModule proxy_fcgi_module>
# ProxyFCGISetEnvIf "true" SCRIPT_FILENAME "/var/www/html/web.dev.mailns.ru%{reqenv:SCRIPT_NAME}"
# <FilesMatch \.php$>
# SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost/"
# </FilesMatch>
# </IFModule>

Перезапускаем Apache:

systemctl restart httpd

Теперь в выводе phpinfo можно увидеть изменение настроек.

Ссылки
Полноценный веб-сервер на CentOS 8 — NGINX + Apache (httpd) + MySQL + PHP-FPM (fastCGI) + FTP + PHPMyAdmin + Memcached
Настройка и использование Fail2ban на Linux
Установка и настройка Memcached
Как оптимизировать производительность MySQL при помощи MySQLTuner