NGINX + Apache (httpd) + MariaDB (MySQL) + PHP + PHP-FPM (fastCGI) + FTP + PHPMyAdmin + Postfix на Rocky 9

Обновлено и опубликовано Опубликовано:

Используемые термины: Linux, RockyNGINX, Apache, MySQL, MariaDBPHP-FPMFTPphpMyAdminPostfix.

Веб-сервер, настроенный по данной инструкции можно будет использовать для размещения собственных сайтов в локальной сети или сети Интернет. Данная инструкция проверена для Rocky 9. В результате мы получим:

  • Интерпретатор PHP версии 8.
  • Возможность передачи файлов с помощью FTP.
  • Возможность отправки почты с помощью MTA postfix.
  • СУБД MariaDB и веб-консоль для ее управления PHPMyAdmin.
  • Веб-сервер, который слушает запросы на 80 и 443 портах с помощью nginx и передающий запросы для обработки PHP на fastCGI или Apache.

Содержание:

Общая настройка системы
Установка NGINX
Установка PHP и PHP-FPM
Установка MariaDB или MySQL
Установка phpMyAdmin
Установка и настройка FTP-сервера
Apache (httpd)
Postfix
Тюнинг веб-сервера
Создание первого сайта

Общая настройка системы

Установка пакетов

1. Обновляем Rocky Linux:

dnf update

2. Устанавливаем репозиторий EPEL и дополнительные пакеты для загрузки и распаковки:

dnf install epel-release curl unzip tar

* где:

  • epel-release — расширенный репозиторий для Rocky.
  • curl — программа для отправки http-запросов. С ее помощью мы будем скачивать файлы.
  • unzip — для распаковки zip архивов.
  • tar — распаковки tar архивов.

Время

1. Устанавливаем часовой пояс:

timedatectl set-timezone Europe/Moscow

* данной командой мы установим часовой пояс по московскому времени.

Посмотреть все доступные часовые пояса можно командой:

timedatectl list-timezones

2. Устанавливаем и запускаем службу для автоматической синхронизации времени:

dnf install chrony

systemctl enable chronyd --now

Настройка безопасности

1. Отключаем SELinux:

sed -i "s/SELINUX=enforcing/SELINUX=disabled/" /etc/selinux/config

setenforce 0

* первая команда редактирует конфигурационный файл, чтобы SELinux не запускался автоматически, вторая — отключает его разово. Подробнее читайте статью Как отключить SELinux.

2. Открываем необходимые порты в брандмауэре:

firewall-cmd --permanent --add-service={http,https}

firewall-cmd --permanent --add-port={20,21,60000-65535}/tcp

firewall-cmd --reload

* где:

  • http и https — сервисы для веб-сервера (порты 80 и 443).
  • 20, 21 — нужны для работы FTP.
  • 60000-65535 — также необходимы для работы FTP (динамические порты для пассивного режима);

Читайте подробнее про настройку firewalld.

Установка NGINX

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

dnf install nginx

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

systemctl enable nginx --now

Проверим, что веб-сервер работает. Для этого открываем браузер на другом компьютере, который находится в одной сети и вводим в адресной строке IP-адрес сервера — http://<IP-адрес сервера>.

В итоге мы должны увидеть заголовок «HTTP Server Test Page»:

Стартовая страница NGINX в Rocky 9

* обратите внимание, что данное приветствие может иметь и другой вид.

Установка PHP и PHP-FPM

Устанавливаем PHP и php-fpm следующей командой:

dnf install php php-fpm

* В Rocky Linux 9 будет установлена версия php 8.

Запускаем php-fpm и разрешаем его автозапуск:

systemctl enable php-fpm --now

Настройка связки NGINX + PHP

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

vi /etc/nginx/nginx.conf

В секции server добавляем параметр index со следующими значениями:

server {
    ...
    index index.php index.html index.htm;
    ...
}

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

nginx -t && nginx -s reload

Создаем index.php в каталоге сайта по умолчанию со следующим содержимым:

vi /usr/share/nginx/html/index.php

<?php phpinfo(); ?>

Открываем в браузере IP-адрес нашего сервера. Теперь мы должны увидеть сводную информацию по PHP и его настройкам, например:

Информация о php (phpinfo)

Установка MariaDB / MySQL

В данной статье мы установим MariaDB, но процедура установки и настройки MySQL аналогичная. Все расхождения будут отмечены явно в инструкции.

Устанавливаем MariaDB следующей командой:

dnf install mariadb-server

* подробнее про развертывание СУБД читайте в инструкции Установка MariaDB-server на Rocky Linux или Ubuntu.

Для установки mysql выполняем команду:

dnf install mysql

Разрешаем автозапуск и запускаем СУБД:

systemctl enable mariadb --now

* для работы с mysql меняем mariadb на mysql.

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

mysql

Чтобы выйти из SQL-оболочки, вводим:

> quit

PHP + MariaDB (MySQL)

Для возможности подключаться к базе данных скриптами PHP необходимо установить следующие модули:

dnf install php-mysqli

После перезагружаем php-fpm:

systemctl restart php-fpm

Проверяем, что поддержка mysql теперь есть в PHP:

php -i | grep mysql

Мы должны увидеть:

...
mysqlnd
mysqlnd => enabled
Version => mysqlnd 8.0.30
...

* нас не должно смущать, что установили мы mariadb, а заголовок mysql.

Установка phpMyAdmin

Устанавливаем phpMyAdmin командой:

dnf install phpmyadmin

Готово. Так как в процессе установки были также установлены компоненты PHP и добавлен конфигурационный файл для NGINX, перезапускаем сервисы:

systemctl reload nginx php-fpm

Чтобы мы могли войти в MySQL в phpMyAdmin, задаем пароль root-пользователю СУБД:

mysqladmin -u root password

Придумываем и дважды вводим пароль.

Открываем браузер и переходим по адресу http://<IP-адрес сервера>/phpMyAdmin. — откроется окно входа в MariaDB. Вводим логин root и пароль, который мы задали. Мы должны попасть в базу данных.

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

В качестве FTP-сервера будем использовать ProFTPd, так как он позволяет авторизоваться под uid системных учетных записей.

Нам нужен будет репозиторий CodeReady Linux Builder (CRB):

dnf config-manager --set-enabled crb

Теперь ProFTPd и набор утилит для работы с ним можно установить командой:

dnf install proftpd proftpd-utils

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

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

* где

  • /etc/proftpd/ftpd.passwd — путь до файла, в котором хранятся пользователи;
  • ftpwww — имя пользователя (логин); 
  • uid и gid — идентификаторы пользователя и группы учетной записи apache (можно сверить командой id 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:

vi /etc/proftpd.conf

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

#AuthOrder ...

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

vi /etc/proftpd/conf.d/custom.conf

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

UseIPv6 off
IdentLookups off
PassivePorts 60000 65535

RequireValidShell off
AuthUserFile /etc/proftpd/ftpd.passwd
AuthPAM off
LoadModule mod_auth_file.c
AuthOrder mod_auth_file.c

* где 60000 - 65535 — диапазон динамических портов для пассивного режима.

Разрешаем автозапуск FTP-серверу и запускаем его:

systemctl enable proftpd --now

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

Это базовая и самая простая настройка ProFTPd, но если необходимо настроить TLS или хранить виртуальных пользователей в базе MySQL, читайте подробнее инструкцию по настройке ProFTPd на CentOS.

Apache (httpd)

Несмотря на то, что мы установили и настроили PHP-FPM, Apache нам понадобится, как минимум, по двум причинам. Во-первых, многие сайты используют файл .htaccess, который читает Apache. Во-вторых, последний включает большое число модулей, которые может использовать портал.

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

И так, устанавливаем httpd:

dnf install httpd

Заходим в настройки:

vi /etc/httpd/conf/httpd.conf

И редактируем следующее:

Listen 8080

* наш веб-сервер будет слушать на порту 8080, так как на 80 уже работает NGINX.

<IfModule dir_module>
    DirectoryIndex index.php index.html
</IfModule>

* если не указан конкретный скрипт, сначала веб-сервер пытается найти и запустить index.php, затем index.html

Добавляем:

<Directory /var/www/*/www>
    AllowOverride All
    Options Indexes ExecCGI FollowSymLinks
    Require all granted
</Directory>

* где Directory — разрешенные каталоги для запуска из apache; Options — разрешенные опции; Require — с каких IP-адресов можно открывать сайты, определенные в данном каталоге. Итого, мы разрешаем все каталоги в /var/www, но только если следующий каталог будет www; разрешаем опции Indexes (возвращает список файлов, если нет индексного файла, например, index.php), ExecCGI (разрешены сценарии CGI), FollowSymLinks (включены символические ссылки в этом каталоге); доступ для данных каталогов разрешен со всех адресов (all granted).

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

apachectl configtest

И если получаем ответ:

...
Syntax OK

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

systemctl enable httpd --now

Создаем php-файл со следующим содержимым:

vi /var/www/html/index.php

<?php phpinfo(); ?>

Вводим команду для отправки http-запроса веб-серверу Apache:

curl -s http://127.0.0.1:8080 | grep SERVER_SOFTWARE

Мы должны получить что-то на подобие:

<tr><td class="e">$_SERVER['SERVER_SOFTWARE']</td><td class="v">Apache/2.4.57 (Rocky Linux)</td></tr>

NGINX + Apache

Ранее нами была настроена связка nginx + php-fpm. Теперь проверяем совместную работу первого с apache.

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

vi /etc/nginx/nginx.conf

В раздел server добавляем location:

        ...
        location ~ \.php$ {
            proxy_pass     http://127.0.0.1:8080;
            proxy_redirect off;

            proxy_set_header  Host              $host;
            proxy_set_header  X-Forwarded-Proto $scheme;
            proxy_set_header  X-Real-IP         $remote_addr;
            proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
        }
        ...

Проверяем и перезапускаем nginx:

nginx -t && nginx -s reload

Пробуем снова открыть в браузере адрес http://<IP-адрес нашего сервера> — должна открыться страница phpinfo, а в переменной $_SERVER['SERVER_SOFTWARE'] должно быть значение Apache:

Страницу с phpinfo загрузил Apache

Apache Real IP

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

Для решения проблемы будем использовать модуль mod_rpaf. Устанавливаем набор разработчика для apache:

dnf install httpd-devel gcc unzip redhat-rpm-config

Переходим в каталог /usr/local/src:

cd /usr/local/src

Скачиваем модуль:

curl -sLO https://github.com/gnif/mod_rpaf/archive/stable.zip

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

unzip stable.zip

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

cd mod_rpaf-stable/

Собираем модуль и устанавливаем его:

make

make install

* при возникновении ошибки ./apxs.sh: line 15: -c: command not found, необходимо поставить which командой dnf install which.

Создаем конфигурационный файл со следующим содержимым:

vi /etc/httpd/conf.d/mod_rpaf.conf

LoadModule              rpaf_module modules/mod_rpaf.so
RPAF_Enable             On
RPAF_ProxyIPs           127.0.0.1
RPAF_SetHostName        On
RPAF_SetHTTPS           On
RPAF_SetPort            On
RPAF_ForbidIfNotProxy   Off

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

systemctl restart httpd

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

Реальный IP-адрес при обращении к Apache

Postfix

Устанавливаем postfix командой:

dnf install postfix

Теперь нам необходимо сделать несколько простых настроек:

vi /etc/postfix/main.cf

Редактируем: 

...
myorigin = $mydomain
...
inet_protocols = ipv4
...

Добавляем:

smtp_generic_maps = hash:/etc/postfix/generic_map

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

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

vi /etc/postfix/generic_map

И добавляем:

@dmosk.local    no-reply@dmosk.local

* данной настройкой мы будем подставлять всем отправляемым письмам без поля FROM адрес no-reply@dmosk.local.

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

postmap /etc/postfix/generic_map

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

systemctl restart postfix

Тюнинг веб-сервера

PHP

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

vi /etc/php.ini

И правим следующее:

upload_max_filesize = 512M
...
post_max_size = 512M
...
short_open_tag = On
...
date.timezone = "Europe/Moscow"

Перезапускаем php-fpm и httpd:

systemctl restart php-fpm

systemctl restart httpd

NGINX

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

vi /etc/nginx/nginx.conf

И внутри секции http добавляем:

client_max_body_size 512M;

После перезапускаем nginx:

systemctl restart nginx

Подробнее про тюнинг NGINX в статье Практические советы по тюнингу веб-сервера NGINX.

Postfix

Чтобы отправляемая почта меньше попадала в СПАМ, необходимо выполнить следующие шаги:

  1. Прописать PTR-запись.
  2. Создать запись SPF.
  3. Настроить DKIM

Создание первого сайта

Задаем переменную, значение которой будет домен сайта:

TMP_SITE=site1

* где site1 — имя домена. Нам будет намного удобнее копировать и вставлять команды с переменной (не придется править после копипасты).

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

vi /etc/nginx/conf.d/$TMP_SITE.conf

* обязательно на конце должен быть .conf, так как только такие файлы веб-сервер подгружает в конфигурацию.

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

Для HTTP:

server {
    listen       80;
    server_name  site1.local www.site1.local;
    set $root_path /var/www/site1/www;

    access_log /var/www/site1/log/nginx/access_log;
    error_log /var/www/site1/log/nginx/error_log;
    
    gzip  on;
    gzip_disable "msie6";
    gzip_min_length 1000;
    gzip_vary on;
    gzip_proxied    expired no-cache no-store private auth;
    gzip_types      text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;

    root   $root_path;

    location / {
        proxy_pass http://127.0.0.1:8080/;
        proxy_redirect     off;
        proxy_set_header   Host             $host;
        proxy_set_header   X-Forwarded-Proto $scheme;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
    }
    
    location ~* ^.+\.(jpg|jpeg|gif|png|css|zip|tgz|gz|rar|bz2|doc|docx|xls|xlsx|exe|pdf|ppt|tar|wav|bmp|rtf|js)$ {
            expires modified +1w;
    }
}

* где site1.local — домен, для которого создается виртуальный домен; /var/www/site1 — каталог, в котором будет размещаться сайт.
** все запросы будут переводиться на локальный сервер, порт 8080, на котором работает apache, кроме обращений к статическим файла (jpg, png, css и так далее).
*** обратите внимание на выделения полужирным — здесь нужно подставить свои данные.

Для HTTPS:

server {
    listen 80;
    server_name site1.local www.site1.local;
    return 301 https://$host$request_uri;
}

server {
    listen       443 ssl;
    ssl on;
    ssl_certificate /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/cert.key;

    server_name  site1.local www.site1.local;
    set $root_path /var/www/site1/www;

    access_log /var/www/site1/log/nginx/access_log;
    error_log /var/www/site1/log/nginx/error_log;
    
    gzip  on;
    gzip_disable "msie6";
    gzip_min_length 1000;
    gzip_vary on;
    gzip_proxied    expired no-cache no-store private auth;
    gzip_types      text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;

    root   $root_path;

    location / {
        proxy_pass http://127.0.0.1:8080/;
        proxy_redirect     off;
        proxy_set_header   Host             $host;
        proxy_set_header   X-Forwarded-Proto $scheme;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
    }
    
    location ~* ^.+\.(jpg|jpeg|gif|png|css|zip|tgz|gz|rar|bz2|doc|docx|xls|xlsx|exe|pdf|ppt|tar|wav|bmp|rtf|js)$ {
            expires modified +1w;
    }
}

* в первой секции server мы перенаправляем все запросы по незащищенному http на https.
** ssl_certificate и ssl_certificate_key — пути к публичному и приватному ключам соответственно.
*** для получения бесплатного сертификата читайте статью Получение бесплатного SSL сертификата Let's Encrypt.

Теперь настроим виртуальный домен в Apache:

vi /etc/httpd/conf.d/$TMP_SITE.conf

<VirtualHost *:8080>
    Define root_domain site1.local
    Define root_path /var/www/site1

    ServerName ${root_domain}
    ServerAlias www.${root_domain}
    DocumentRoot ${root_path}/www

    ErrorLog     ${root_path}/log/apache/error_log
    TransferLog  ${root_path}/log/apache/access_log
</VirtualHost>

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

mkdir -p /var/www/$TMP_SITE/{www,tmp}

mkdir -p /var/www/$TMP_SITE/log/{nginx,apache}

Создаем индексный файл со следующим содержимым:

vi /var/www/$TMP_SITE/www/index.php

<?php echo "<h1>Hello from site1</h1>"; ?>

Задаем права на папки:

chown -R apache:apache /var/www/$TMP_SITE

chmod -R 775 /var/www/$TMP_SITE

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

nginx -t

apachectl configtest

Перезапускаем веб-сервер:

systemctl reload nginx

systemctl reload httpd

Открываем сайт в браузере.

Не забываем, что обращаться к сайту нужно по его доменному имени. Например, если мы создали сайт site1.local, то нужно в браузере набрать http://site1.local. При этом, данное имя должно разрешаться в IP-адрес с помощью DNS или локального файла hosts.

При необходимости, создаем базу данных.

mysql -uroot -p

> CREATE DATABASE site1 DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;

> GRANT ALL PRIVILEGES ON site1.* TO dbuser@localhost IDENTIFIED BY 'password' WITH GRANT OPTION;

* данными sql-командами мы создаем базу данных site1 и предоставляем к ней доступ для учетной записи dbuser с паролем password. При желании сделать соединение более безопасным, можно убрать WITH GRANT OPTION.

# MySQL # NGINX # Rocky Linux # Интернет # Серверы
Дмитрий Моск — частный мастер
Была ли полезна вам эта инструкция?

Да            Нет