Настройка LEMP сервера для работы CMS WordPress
Настройка LEMP сервера для работы CMS WordPress

Во второй части статьи мы рассмотрим настройку LEMP сервера для работы с проектами на примере CMS WordPress. Мы проведем пошаговую настройку, обсудим автоматизацию процесса без использования популярных хостинг-панелей и в качестве бонуса представим улучшения для усиления безопасности WordPress. Это включает настройку виртуального хоста в Nginx и PHP интерпретатора для конкретного сайта. При этом мы не будем рассматривать настройку безопасности всего сервера, так как это тема для отдельной статьи.

В этой статье рассмотрим:

  1. Создание пользователя Linux

  2. Настройка виртуального хоста

  3. Проверка работы PHP

  4. Работа с базой данных MariaDB

  5. Настройка Let's Encrypt

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

Перед прочтением этой статьи рекомендуется ознакомиться с первой частью — Часть 1: Как установить Nginx, MariaDB, PHP-FPM (LEMP) в AlmaLinux 9, RockyLinux 9 и CentOS Stream 9, где был подробно описан пошаговый процесс установки.

Мои рекомендации:

Создание пользователя Linux

Этот скрипт выполняет создание нового пользователя для веб-сервера и настраивает соответствующие параметры для SSH/SFTP подключения.

1. Скопируйте скрипт, показанный ниже:

#!/bin/bash
# Copyright (C) 2024 
# Автор: Крячко Алексей
# Электронная почта: admin@unixweb.info 
# Веб-сайт: https://unixweb.info 
# GitHub: https://github.com/unixweb-info 

# Имя пользователя
username="www-root"

# Проверяем установку пакета curl
if ! command -v curl &> /dev/null; then
    echo "Установка пакета curl..."
    dnf install -y curl
fi

# Создаем пользователя с домашним каталогом и оболочкой
sudo useradd -m -s /bin/bash -d /var/www/$username $username
if [ $? -ne 0 ]; then
    echo "Ошибка при создании пользователя $username."
    exit 1
fi

# Создаем каталог для логов
sudo mkdir -p /var/www/$username/data/logs
if [ $? -ne 0 ]; then
    echo "Ошибка при создании каталога для логов."
    exit 1
fi

# Устанавливаем владельца для каталога пользователя
sudo chown -R $username:$username /var/www/$username
if [ $? -ne 0 ]; then
    echo "Ошибка при установке владельца для каталога пользователя."
    exit 1
fi

# Читаем пароль, не отображая его на экране
read -s -p "Введите пароль: " password
echo -e "\n"

# Устанавливаем пароль для пользователя
echo "$password" | sudo passwd --stdin "$username"
if [ $? -ne 0 ]; then
    echo "Ошибка при установке пароля для пользователя."
    exit 1
fi

# Получаем IP-адрес на интерфейсе eth0
#IP_ADDRESS=$(ip -o -4 addr show | awk '!/127.0.0.1/ {print $4}' | cut -d/ -f1) # Функция не актуальна если сервер работает за NAT
# Получаем IP-адрес ервера с помощью команды curl http://ident.me.
IP_ADDRESS=$(sudo -u www-root curl -s http://ident.me)

# Получаем номер порта SSH из файла конфигурации
SSH_PORT=$(awk '/^\s*Port\s+[0-9]+/ {print $2}' /etc/ssh/sshd_config | head -1)

# Если порт не найден (пустое значение), попробуем найти закомментированный порт
if [ -z "$SSH_PORT" ]; then
    SSH_PORT=$(awk '/^\s*#?\s*Port\s+[0-9]+/ {print $2}' /etc/ssh/sshd_config | head -1)
fi

# Проверяем, что переменная не пуста
if [ -z "$SSH_PORT" ]; then
    echo "Ошибка: Не удалось получить номер порта SSH."
    exit 1
fi
echo -e "Пользователь $username успешно добавлен! \nПожалуйста, сохраните данные для SSH/SFTP подключения:\n- IP-адрес: $IP_ADDRESS\n- SSH/SFTP порт: $SSH_PORT\n- Пользователь: $username\n- Пароль: $password"
  1. Сохраните файл, например, под именем create_user.sh, предварительно скопировав содержимое скрипта и выйдите из редактора.

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

chmod +x ./create_user.sh && sudo ./create_user.sh

Важно сохранить введённые данные, так как они понадобятся для подключения к сайту через протокол SFTP.

[unixweb@localhost ~]# sudo ./create_user.sh
useradd: warning: the home directory /var/www/www-root already exists.
useradd: Not copying any file from skel directory into it.
Creating mailbox file: File exists
Введите пароль: 
Changing password for user www-root.
passwd: all authentication tokens updated successfully.
Пользователь www-root успешно добавлен! 
Пожалуйста, сохраните данные для SSH/SFTP подключения:
- IP-адрес: 1.2.3.4
- SSH/SFTP порт: 22
- Пользователь: www-root
- Пароль: !Your Password!
[unixweb@localhost ~]#

Действия, выполняемые скриптом:

  1. Установка пакетов: Сначала скрипт проверяет наличие пакета curl. Если пакет не установлен, функция устанавливает его.

  2. Создание нового пользователя:
    Определяет имя пользователя www-root.
    Создает пользователя с домашним каталогом /var/www/www-root, оболочкой /bin/bash, используя команду useradd.
    Если команда завершится с ошибкой, скрипт прекращает выполнение и выводит сообщение об ошибке.

  3. Создание каталога для логов:
    Создает каталог для логов /var/www/www-root/data/logs.
    Если команда завершится с ошибкой, скрипт прекращает выполнение и выводит сообщение об ошибке.

  4. Установка владельца для каталога пользователя:
    Устанавливает владельца и группу для каталога /var/www/www-root в соответствии с пользователем www-root.
    Если команда завершится с ошибкой, скрипт прекращает выполнение и выводит сообщение об ошибке.

  5. Установка пароля для нового пользователя:
    Считывает пароль, не отображая его на экране.
    Устанавливает пароль для пользователя www-root с помощью команды passwd.
    Если команда завершится с ошибкой, скрипт прекращает выполнение и выводит сообщение об ошибке.

  6. Получение IP-адреса:
    Получение IP-адреса сервера с помощью команды curl http://ident.me.

  7. Получение номера порта SSH:
    Извлекает номер порта SSH из файла конфигурации /etc/ssh/sshd_config с помощью команды awk.
    Если номер порта не найден (пустое значение), пробует найти закомментированный порт.
    Если порт не найден после обоих попыток, скрипт прекращает выполнение и выводит сообщение об ошибке.

  8. Вывод информации о новом пользователе:
    Выводит информацию о новом пользователе, включая IP-адрес, порт SSH/SFTP, имя пользователя и пароль.

Настройка виртуального хоста

Создание виртуального хоста и настройка php-fpm за три простых шага

Теперь необходимо настроить Nginx для работы с PHP, создать виртуальный хост и настроить php-fpm. Внимательно изучите содержимое этого скрипта.

1. Скопируйте скрипт, показанный ниже:

#!/bin/bash
# Copyright (C) 2024 
# Автор: Крячко Алексей
# Электронная почта: admin@unixweb.info 
# Веб-сайт: https://unixweb.info 
# GitHub: https://github.com/unixweb-info 

# Настройка SELinux — это важная и сложная тема, которая заслуживает отдельной публикации.
# Переключаем SELinux в режим permissive. 
setenforce 0

# Переменная domain задает название вашего домена, например, example.com, замените значение на имя вашего домена. 
domain="example.com" 

# Переменная username задает имя пользователя, например, www-root, ранее мы создавали этого пользователя.
username="www-root"

# Переменная php_version задает версию PHP интерпретатора, установленного в системе (например, PHP 8.1), задаем 81
php_version="81"

# Проверяем, существует ли каталог /etc/nginx/sites-available
[ ! -d "/etc/nginx/sites-available" ] && \
# Если каталог не существует, создаем его
mkdir "/etc/nginx/sites-available"

# Проверяем, существует ли каталог /etc/nginx/sites-enabled
[ ! -d "/etc/nginx/sites-enabled" ] && \
# Если каталог не существует, создаем его
mkdir "/etc/nginx/sites-enabled"

# Настройка виртуального хоста Nginx
cat << EOF | tee "/etc/nginx/sites-available/${domain}.conf"
server {
    listen 80;
    listen [::]:80;
    server_name ${domain};

    add_header Last-Modified \$date_gmt;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Xss-Protection "1; mode=block" always;
    add_header Content-Security-Policy "default-src 'self' https: data: 'unsafe-inline' 'unsafe-eval';" always;

    access_log /var/www/${username}/data/logs/${domain}-access.log;
    error_log /var/www/${username}/data/logs/${domain}-error.log;

    charset off;
    gzip on;
    gzip_proxied expired no-cache no-store private auth;
    gzip_types text/css text/xml application/javascript text/plain application/json image/svg+xml image/x-icon;
    gzip_comp_level 6;

    set \$root_path /var/www/${username}/data/www/${domain};
    root \$root_path;
    disable_symlinks if_not_owner from=\$root_path;

# Предоставляем доступ к файлу robots.txt
location ~ /robots.txt {allow all;}

# Закрываем доступ ко всем расширениям, файлам и каталогам, которые могут быть использованы для компрометации WordPress.
location ~ /*\.(json|ini|log|md|txt|sql)|LICENSE {
    allow 1.2.3.4; # Замените на фактический IP администратора
    deny all;
    }
location ~ /\. {
    allow 1.2.3.4; # Замените на фактический IP администратора
    deny all;
    }

location ~* /(?:uploads|wflogs|w3tc-config|files)/.*\.php$ {
    allow 1.2.3.4; # Замените на фактический IP администратора
    deny all;
    access_log off;
    log_not_found off;
    }

location ~* /wp-includes/.*.php$ {
    allow 1.2.3.4; # Замените на фактический IP администратора
    deny all;
    access_log off;
    log_not_found off;
    }

location ~* /wp-content/.*.php$ {
    allow 1.2.3.4; # Замените на фактический IP администратора
    deny all;
    access_log off;
    log_not_found off;
    }

location ~* /themes/.*.php$ {
    allow 1.2.3.4; # Замените на фактический IP администратора
    deny all;
    access_log off;
    log_not_found off;
    }

location ~* /plugins/.*.php$ {
    allow 1.2.3.4; # Замените на фактический IP администратора
    deny all;
    access_log off;
    log_not_found off;
    }

    location = /xmlrpc.php {
    allow 1.2.3.4; # Замените на фактический IP администратора
    deny all;
    access_log off;
    log_not_found off;
    }

   # Безопасность для раздела администратора WordPress
    location ~* ^/(wp-admin/|wp-login\.php) {
        # Замените IP 1.2.3.4 на свой реальный IP, а затем удалите комментарии, чтобы заблокировать доступ к административному разделу сайта для посторонних.
        #allow 1.2.3.4;
        #deny all;
        try_files \$uri \$uri/ /index.php?\$args;
    location ~ \.php\$ {
        fastcgi_pass unix:/var/opt/remi/php$php_version/run/php-fpm/$domain.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
        fastcgi_param SCRIPT_NAME \$fastcgi_script_name;
        include /etc/nginx/fastcgi_params;
    }
    }

    location / {
        index index.php index.html;
        try_files \$uri \$uri/ /index.php?\$args;
    }
    location ~ \.php\$ {
        include /etc/nginx/fastcgi_params;
        fastcgi_pass unix:/var/opt/remi/php${php_version}/run/php-fpm/${domain}.sock;
        fastcgi_param SCRIPT_FILENAME \$realpath_root\$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT \$realpath_root;
     }

    location ~* ^.+\.(jpg|jpeg|gif|png|svg|js|css|mp3|ogg|mpeg|avi|zip|gz|bz2|rar|swf|ico|7z|doc|docx|map|ogg|otf|pdf|tff|tif|txt|wav|webp|woff|woff2|xls|xlsx|xml)\$ {
        try_files \$uri \$uri/ /index.php?\$args;
        expires 30d;
    }

    location @fallback {
        fastcgi_pass unix:/var/opt/remi/php${php_version}/run/php-fpm/${domain}.sock;
        fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
        include /etc/nginx/fastcgi_params;
    }
}
server {
    listen 80;
    listen [::]:80;
    server_name www.${domain};
    return 301 http://${domain}\$request_uri;
    access_log /var/www/${username}/data/logs/${domain}-access.log;
    error_log /var/www/${username}/data/logs/${domain}-error.log;
}
EOF

ln -s "/etc/nginx/sites-available/${domain}.conf" "/etc/nginx/sites-enabled/${domain}.conf"

nginx -t

# Настройка php-fpm для работы виртуального хоста

mkdir -p "/var/www/${username}/data/tmp"
chown "${username}:${username}" "/var/www/${username}/data/tmp"
mkdir -p "/var/www/${username}/data/www/${domain}"
chown "${username}:${username}" "/var/www/${username}/data/www/${domain}"

cat << EOF | tee "/etc/opt/remi/php${php_version}/php-fpm.d/${domain}.conf"
[${domain}]
user = ${username}
group = ${username}
listen = /var/opt/remi/php${php_version}/run/php-fpm/${domain}.sock
listen.owner = ${username}
listen.group = apache
listen.mode = 0660

pm = dynamic
pm.max_children = 20
pm.min_spare_servers = 6
pm.max_spare_servers = 10
pm.max_requests = 1000


php_admin_value[cgi.fix_pathinfo] = "Off"
php_admin_value[expose_php] = "Off"
php_admin_value[allow_url_include] = "Off"
php_admin_value[allow_url_fopen] = "Off"
php_admin_value[disable_functions] = "eval,system,shell_exec,passthru,proc_open,popen,expect_popen,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_signal_get_handler,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,exec,pcntl_exec,pcntl_getpriority,pcntl_setprioritypcntl_async_signals,pcntl_unshare"
php_admin_value[display_errors] = "Off"
php_admin_value[log_errors] = "On"
php_admin_value[date.timezone] = "Europe/Moscow"
php_admin_value[mail.add_x_header] = "On"
php_admin_value[max_execution_time] = "3600"
php_admin_value[max_input_time] = "3600"
php_admin_value[memory_limit] = "512M"
php_admin_value[max_input_vars] = "100000"
php_admin_value[opcache.blacklist_filename] = "opcache.blacklist_filename=/etc/opt/remi/php${php_version}/php.d/opcache*.blacklist"
php_admin_value[opcache.max_accelerated_files] = "100000"
php_admin_value[open_basedir] = "/var/www/${username}/data/www/${domain}:/var/www/${username}/data/tmp"
php_admin_value[output_buffering] = "4096"
php_admin_value[post_max_size] = "100M"
php_admin_value[sendmail_path] = "/usr/sbin/sendmail -t -i -f 'admin@${domain}'"
php_admin_value[session.save_path] = "/var/www/${username}/data/tmp"
php_admin_value[short_open_tag] = "On"
php_admin_value[upload_max_filesize] = "100M"
php_admin_value[upload_tmp_dir] = "/var/www/${username}/data/tmp"

catch_workers_output = no
access.format = "%{REMOTE_ADDR}e - [%t] \"%m %r%Q%q %{SERVER_PROTOCOL}e\" %s %{kilo}M \"%{HTTP_REFERER}e\" \"%{HTTP_USER_AGENT}e\""
access.log = /var/www/${username}/data/logs/${domain}-backend.access.log

php_admin_value[error_log] = /var/www/${username}/data/logs/${domain}-backend.error.log

EOF

# Перезапуск службы PHP-FPM
systemctl restart "php${php_version}-php-fpm.service"

# Команда gpasswd -a apache ${username} добавляет пользователя ${username} в группу apache. 
gpasswd -a apache ${username}

# Изменение прав доступа к каталогам, chmod g+x /var/www/${username} устанавливает права на выполнение для группы для каталога пользователя ${username}.
chmod g+x /var/www
chmod g+x /var/www/${username}
chmod g+x /var/www/${username}/data
chmod g+x /var/www/${username}/data/www
chmod g+x /var/www/${username}/data/www/${domain}

# Перезапуск службы Nginx
systemctl restart nginx.service
  1. Сохраните файл, например, под именем create_site.sh, предварительно скопировав содержимое скрипта и выйдите из редактора.

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

chmod +x ./create_site.sh && sudo ./create_site.sh

В данном скрипте реализована конфигурация для защиты файлов и каталогов WordPress. Хочу поделиться с вами своими наработками.

Вы также можете ознакомиться с официальной документацией WordPress по этой теме, перейдя по ссылке: https://developer.wordpress.org/advanced-administration/server/web-server/nginx/ 

Содержание скрипта:

1. Переключение SELinux в режим permissive:

setenforce 0

Это необходимо для предотвращения проблем с доступом при настройке.

2. Определение переменных:

domain="example.com"
username="www-root"
php_version="81"
  • domain: Название вашего домена.

  • username: Имя пользователя.

  • php_version: Версия PHP интерпретатора.

3. Создание каталогов конфигурации Nginx:

[ ! -d "/etc/nginx/sites-available" ] && mkdir "/etc/nginx/sites-available"
[ ! -d "/etc/nginx/sites-enabled" ] && mkdir "/etc/nginx/sites-enabled"

Проверяет наличие и создаёт каталоги /etc/nginx/sites-available и /etc/nginx/sites-enabled.

4. Настройка виртуального хоста Nginx:

   Создаёт файл конфигурации для домена и заполняет его настройками:

cat << EOF | tee "/etc/nginx/sites-available/${domain}.conf"
server {
       ...
}
server {
       ...
}
EOF

Конфигурационный файл Nginx обеспечивает усиленную безопасность для сайта на CMS WordPress. Ограничивает доступ к различным типам файлов и каталогов, которые могут быть использованы для компрометации:

  • Запрещает доступ ко всем файлам с расширениями .json, .ini, .log, .md, .txt, .sql и файлу LICENSE, за исключением IP-адреса администратора.

  • Блокирует доступ к скрытым файлам и каталогам.

  • Запрещает выполнение PHP-файлов в определенных каталогах: uploads, wflogs, w3tc-config, files.

  • Ограничивает доступ к PHP-файлам в каталогах wp-includes, wp-content, themes, plugins.

  • Запрещает доступ к файлу xmlrpc.php.

  • Предоставляет дополнительную безопасность для раздела администратора WordPress, разрешая доступ только с определенного IP-адреса.

Важно! Обратите внимание, что в текущей версии конфигурационного файла доступ к административному разделу CMS WordPress открыт. Пожалуйста, ознакомьтесь с комментариями в скрипте для дальнейших инструкций по его настройке.

5. Создание символической ссылки для активации виртуального хоста:

ln -s "/etc/nginx/sites-available/${domain}.conf" "/etc/nginx/sites-enabled/${domain}.conf"

6. Проверка конфигурации и перезапуск Nginx:

nginx -t
systemctl restart nginx.service

7. Настройка PHP-FPM для виртуального хоста:

   Создаёт необходимые каталоги и настраивает PHP-FPM:

mkdir -p "/var/www/${username}/data/tmp"
chown "${username}:${username}" "/var/www/${username}/data/tmp"
mkdir -p "/var/www/${username}/data/www/${domain}"
chown "${username}:${username}" "/var/www/${username}/data/www/${domain}"

Создаёт файл конфигурации PHP-FPM:

cat << EOF | tee "/etc/opt/remi/php${php_version}/php-fpm.d/${domain}.conf"
[${domain}]
...
EOF

Важно! Эти настройки PHP для обеспечения безопасности:

cgi.fix_pathinfo = "Off":
Отключает поддержку исправления путей в CGI-скриптах.
Это предотвращает возможные атаки, связанные с обработкой путей к файлам.

expose_php = "Off":
Скрывает информацию о версии PHP в заголовках ответов сервера.
Это помогает снизить риск атак, связанных с известными уязвимостями PHP.

allow_url_include = "Off":
Запрещает использование функций, которые загружают файлы по URL (например, include и require).
Это предотвращает возможные уязвимости, связанные с удаленной загрузкой кода.

allow_url_fopen = "Off":
Запрещает использование функции fopen для открытия файлов по URL.
Это уменьшает риск выполнения вредоносного кода из удаленных источников.

disable_functions:
Перечисляет запрещенные функции, которые не могут быть вызваны из PHP-скриптов.
В данном случае, запрещены опасные функции, такие как eval, system, shell_exec и другие.

display_errors = "Off":

  • Отключает вывод ошибок PHP на экран. Это предотвращает случайное раскрытие конфиденциальной информации.

  1. Перезапуск PHP-FPM:

systemctl restart "php${php_version}-php-fpm.service"

9. Команда  ‘gpasswd -a apache ${username}’ используется добавления пользователя ${username} в группу Apache. Это позволяет пользователю получить доступ к ресурсам и правам, предоставляемым этой группой:

gpasswd -a apache ${username}

10. Изменение прав доступа к каталогам:

chmod g+x /var/www
chmod g+x /var/www/${username}
chmod g+x /var/www/${username}/data
chmod g+x /var/www/${username}/data/www
chmod g+x /var/www/${username}/data/www/${domain}

11. Перезапуск службы Nginx:

systemctl restart nginx.service

Этот скрипт автоматически настроит виртуальный хост Nginx и PHP-FPM для указанного домена, обеспечивая необходимые параметры безопасности и производительности.

Проверка работы PHP

Для получения подробного списка параметров PHP рекомендуется использовать функцию phpinfo(). Это особенно полезно для отладки настроек сайта после его размещения на сервере. Замените значение "example.com" на ваш домен.

Для начала создадим файл info.php в каталоге вашего сайта, например, /var/www/www-root/data/www/example.com/, чтобы проверить работу PHP:

sudo touch /var/www/www-root/data/www/example.com/info.php
sudo bash -c 'echo "<?php phpinfo(); ?>" > /var/www/www-root/data/www/example.com/info.php'
sudo chown www-root:www-root /var/www/www-root/data/www/example.com/info.php

Теперь, для просмотра полного списка параметров PHP на вашем сервере, перейдите по ссылке вида http://example.com/info.php.

Проверка работы PHP интепритатора на сервере
Проверка работы PHP интепритатора на сервере

Важно! Не забудьте удалить этот файл после проверки. Оставление его в открытом доступе может позволить злоумышленникам получить доступ к информации о вашем сервере и использовать её для атак.

Для удаления файла info.php выполните следующую команду:

sudo rm /var/www/www-root/data/www/example.com/info.php

Настройка LEMP завершена, теперь можно приступать к настройке вашего сайта.

Работа с базой данных MariaDB

Автоматизация процесса настройки базы данных и управления пользователями является важной частью администрирования серверов. Данный скрипт предназначен для упрощения создания базы данных и пользователя в MariaDB, что является стандартной задачей при настройке серверов для веб-приложений. 

Создание пользователя и базы данных в три простых шага

1. Скопируйте скрипт, показанный ниже:

#!/bin/bash
# Copyright (C) 2024 
# Автор: Крячко Алексей
# Электронная почта: admin@unixweb.info 
# Веб-сайт: https://unixweb.info 
# GitHub: https://github.com/unixweb-info 

# Установка параметров по умолчанию
DB_CHARSET="utf8mb4"
DB_NAME="exampledb"
DB_USER="exampleuser"
DB_PASSWORD="!Example^Password!"

# Создание базы данных с указанным набором символов
/usr/bin/mariadb -u root -e "CREATE DATABASE $DB_NAME CHARACTER SET $DB_CHARSET;"

# Создание пользователя с заданным паролем
/usr/bin/mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASSWORD';"

# Предоставление всех привилегий пользователю на созданной базе данных
/usr/bin/mariadb -u root -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost';"

# Применение изменений привилегий
/usr/bin/mariadb -u root -e "FLUSH PRIVILEGES;"

# Отображение списка баз данных
echo "List of databases:"
/usr/bin/mariadb -u root -e "SHOW DATABASES;"

# Отображение списка пользователей
echo "List of users:"
/usr/bin/mariadb -u root -e "SELECT User, Host FROM mysql.user;"
  1. Сохраните файл, например, под именем create_db_user_and_database.sh, предварительно скопировав содержимое скрипта и выйдите из редактора.

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

chmod +x ./create_db_user_and_database.sh && sudo ./create_db_user_and_database.sh

Описание скрипта

Этот скрипт предназначен для автоматизации создания базы данных и пользователя в MariaDB. Он выполняет следующие действия:

  1. Установка параметров по умолчанию:
    DB_CHARSET="utf8mb4": Устанавливает кодировку символов для базы данных.
    DB_NAME="exampledb": Устанавливает имя базы данных.
    DB_USER="exampleuser": Устанавливает имя пользователя.
    DB_PASSWORD="!Example^Password!": Устанавливает пароль для пользователя.

  2. Создание базы данных:

  • Выполняет команду для создания базы данных с указанным именем и кодировкой символов:

/usr/bin/mariadb -u root -e "CREATE DATABASE $DB_NAME CHARACTER SET $DB_CHARSET;"
  • Создание пользователя:Выполняет команду для создания пользователя с заданным именем и паролем:

/usr/bin/mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASSWORD';"
  1. Предоставление привилегий:

  • Выполняет команду для предоставления всех привилегий пользователю на созданной базе данных:

/usr/bin/mariadb -u root -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost';"
  1. Применение изменений привилегий:

  • Выполняет команду для обновления привилегий, чтобы они вступили в силу:

/usr/bin/mariadb -u root -e "FLUSH PRIVILEGES;"
  1. Отображение списка баз данных:

  • Выполняет команду для отображения всех баз данных на сервере:

/usr/bin/mariadb -u root -e "SHOW DATABASES;"
  1. Отображение списка пользователей:

  • Выполняет команду для отображения всех пользователей и их хостов на сервере:

/usr/bin/mariadb -u root -e "SELECT User, Host FROM mysql.user;"

Результат работы скрипта:

[unixweb@localhost ~]# sudo ./create_db_user_and_database.sh
List of databases:
+--------------------+
| Database       	|
+--------------------+
| exampledb      	|
| information_schema |
| mysql          	|
| performance_schema |
| sys            	|
+--------------------+
List of users:
+-------------+-----------+
| User    	| Host  	|
+-------------+-----------+
| PUBLIC  	|       	|
| exampleuser | localhost |
| mariadb.sys | localhost |
| mysql   	| localhost |
| root    	| localhost |
+-------------+-----------+

Пользователь и база данных успешно созданы.

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

Настройка Let's Encrypt

Автоматизированная настройка Let's Encrypt предоставляет сценарий по установке и настройке Let's Encrypt для получения бесплатных SSL/TLS сертификатов на вашем веб-сервере. Представляю скрипт для автоматизации настройки SSL/TLS сертификатов Let's Encrypt.

1. Скопируйте скрипт, показанный ниже:

#!/bin/bash
# Copyright (C) 2024 
# Автор: Крячко Алексей
# Электронная почта: admin@unixweb.info 
# Веб-сайт: https://unixweb.info 
# GitHub: https://github.com/unixweb-info 
# Пожалуйста, перед выполнением скрипта замените example.com на ваш домен и admin@example.com на ваш email.
DOMAIN="example.com"
EMAIL="admin@example.com"

# Проверяем установку пакетов certbot, python3-certbot-nginx, curl и bind-utils
if ! command -v certbot &> /dev/null || ! rpm -q --quiet python3-certbot-nginx || ! command -v curl &> /dev/null || ! command -v dig &> /dev/null; then
    echo "Установка пакетов certbot, python3-certbot-nginx, curl и bind-utils..."
    dnf install -y certbot python3-certbot-nginx curl bind-utils
else
    echo "Пакеты certbot, python3-certbot-nginx, curl и bind-utils уже установлены."
fi

# Путь к файлу конфигурации certbot
CERTBOT_CONFIG_FILE="/etc/sysconfig/certbot"

# Проверяем существование файла и наличие строки POST_HOOK=""
if [ -f "$CERTBOT_CONFIG_FILE" ]; then
    # Проверяем, содержит ли файл строку POST_HOOK=""
    if grep -q "^POST_HOOK=\"\"" "$CERTBOT_CONFIG_FILE"; then
        # Заменяем строку POST_HOOK="" на POST_HOOK="--post-hook 'systemctl restart nginx'"
        sed -i "s|^POST_HOOK=\"\"|POST_HOOK=\"--post-hook 'systemctl restart nginx'\"|g" "$CERTBOT_CONFIG_FILE"
        echo "Обновлена переменная POST_HOOK в файле $CERTBOT_CONFIG_FILE."
    else
        echo "Переменная POST_HOOK уже установлена или не найдена в файле $CERTBOT_CONFIG_FILE, пропускаем."
    fi
else
    echo "Файл $CERTBOT_CONFIG_FILE не найден."
fi

# Включаем и запускаем таймер для автоматического обновления сертификатов
systemctl enable --now certbot-renew.timer

# Запрос A-записи для вашего домена
A_RECORD_DOMAIN=$(sudo -u www-root dig @8.8.8.8 A "$DOMAIN" +short)

# Запрос A-записи для www вашего домена
A_RECORD_WWW_DOMAIN=$(sudo -u www-root dig @8.8.8.8 A "www.$DOMAIN" +short)

# Запрос AAAA-записи для вашего домена
AAAA_RECORD_DOMAIN=$(sudo -u www-root dig @8.8.8.8 AAAA "$DOMAIN" +short)

# Запрос AAAA-записи для www вашего домена
AAAA_RECORD_WWW_DOMAIN=$(sudo -u www-root dig @8.8.8.8 AAAA "www.$DOMAIN" +short)

# Узнать внешний IP сервера, проверка в случае если ваш сервер находится за NAT сетью
EXTERNAL_IP=$(sudo -u www-root curl -4 -s http://ident.me)

# Узнать внешний IPv6 адрес сервера, проверка в случае если ваш сервер находится за NAT сетью
EXTERNAL_IPV6=$(sudo -u www-root curl -6 -s http://ident.me)

# Проверяем, что A-записи и AAAA-записи совпадают с внешним IP
if [[ ("$A_RECORD_DOMAIN" == "$EXTERNAL_IP" || "$AAAA_RECORD_DOMAIN" == "$EXTERNAL_IPV6") && ("$A_RECORD_WWW_DOMAIN" == "$EXTERNAL_IP" || "$AAAA_RECORD_WWW_DOMAIN" == "$EXTERNAL_IPV6") ]]; then
    echo "A и AAAA-записи корректно настроены. Выпускаем сертификат..."
    certbot --nginx --non-interactive --agree-tos --domains "$DOMAIN,www.$DOMAIN" --email "$EMAIL"
else
    echo "Настройте корректно A и AAAA-записи $DOMAIN и www.$DOMAIN на IP-адрес $EXTERNAL_IP или $EXTERNAL_IPV6 вашего сервера."
fi


# Показываем список всех таймеров
echo "Список таймеров для Let's Encrypt с помощью certbot:"

systemctl list-timers --all | grep certbot
  1. Сохраните файл, например, под именем install_certbot.sh, предварительно скопировав содержимое скрипта и выйдите из редактора.

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

chmod +x ./install_certbot.sh && sudo ./install_certbot.sh

Этот скрипт предназначен для автоматической настройки Let's Encrypt на вашем сервере. Давайте разберемся с его функциональностью:

  1. Установка необходимых пакетов: Сначала скрипт проверяет наличие пакетов certbot, python3-certbot-nginx, curl и bind-utils. Если какого-либо из них нет, он устанавливает их.

  2. Настройка POST_HOOK: Скрипт проверяет, что переменная POST_HOOK пуста. Если она пуста, он добавляет команду перезапуска сервиса nginx.

  3. Обновление таймера: Скрипт включает и запускает таймер certbot-renew.timer, который автоматически обновляет сертификаты Let's Encrypt.

  4. Проверка A-записей: Скрипт запрашивает A-записи для вашего домена и www-домена, а также определяет внешний IP-адрес вашего сервера. Если A-записи совпадают с внешним IP, выпускается сертификат.

  5. Вывод списка таймеров: В конце скрипт выводит список всех таймеров, связанных с Let's Encrypt.

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

Fail2Ban — это мощный инструмент для защиты серверов от атак посредством автоматического блокирования IP-адресов, которые пытаются слишком часто подключаться к сервисам, таким как SSH. Ниже приведен скрипт для автоматизации установки и настройки Fail2Ban на сервере с операционной системой, поддерживающей управление пакетами через DNF (например, AlmaLinux 9, RockyLinux 9, CentOS Stream 9).

Установка и настройка Fail2ban в три простых шага

1. Скопируйте скрипт, показанный ниже:

#!/bin/bash
# Copyright (C) 2024 
# Автор: Крячко Алексей
# Электронная почта: admin@unixweb.info 
# Веб-сайт: https://unixweb.info 
# GitHub: https://github.com/unixweb-info 

# Обновляем все пакеты на сервере
dnf update -y

# Устанавливаем Fail2Ban, если не установлен
if ! rpm -qa | grep -q '^fail2ban-'; then
    dnf install fail2ban -y
fi

# Проверяем, есть ли уже настройка [sshd]\nenabled=true в файле /etc/fail2ban/jail.d/00-firewalld.conf
if ! grep -q "^\[sshd\]" /etc/fail2ban/jail.d/00-firewalld.conf; then
    # Если настройки нет, добавляем её в файл
    echo -e "\n[sshd]\nenabled=true\nmaxretry=2" | tee -a /etc/fail2ban/jail.d/00-firewalld.conf >/dev/null
else
    # Если настройка уже есть, выводим сообщение
    echo "Config [sshd] already exists in /etc/fail2ban/jail.d/00-firewalld.conf"
fi

# Выводим сообщение об успешной установке и настройке Fail2Ban
echo -e "\nFail2Ban was successfully installed and configured."

# Включаем и запускаем сервис Fail2Ban
systemctl enable fail2ban

# Перезапускаем сервис Fail2Ban
systemctl restart fail2ban
sleep 1
# Проверяем статус Fail2Ban
echo -e "\nFail2Ban status:"
fail2ban-client status
  1. Сохраните файл, например, под именем install_and_setting_fail2ban.sh, предварительно скопировав содержимое скрипта и выйдите из редактора.

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

chmod +x ./install_and_setting_fail2ban.sh && sudo ./install_and_setting_fail2ban.sh

Описание скрипта

Этот скрипт предназначен для автоматизации установки и базовой настройки Fail2Ban на сервере с операционной системой, использующей менеджер пакетов DNF. Вот подробное описание каждого шага:

  1. Обновление пакетов на сервере:

dnf update -y

Эта команда обновляет все установленные пакеты на сервере до последних доступных версий.

  1. Установка Fail2Ban:

if ! rpm -qa | grep -q '^fail2ban-'; then
       dnf install fail2ban -y
fi

Проверяет, установлен ли уже Fail2Ban (rpm -qa | grep -q '^fail2ban-'). Если он не установлен (!), то выполняется установка Fail2Ban из репозитория EPEL.

  1. Добавление настройки для SSH в файл конфигурации Fail2Ban:

if ! grep -q "^\[sshd\]" /etc/fail2ban/jail.d/00-firewalld.conf; then
    echo -e "\n[sshd]\nenabled=true\nmaxretry=2" | tee -a /etc/fail2ban/jail.d/00-firewalld.conf >/dev/null
else
    echo "Config [sshd] already exists in /etc/fail2ban/jail.d/00-firewalld.conf"
fi

Проверяет наличие настройки [sshd] в файле конфигурации Fail2Ban (/etc/fail2ban/jail.d/00-firewalld.conf). Если настройки нет, она добавляется в конец файла.

  1. Включение и запуск сервиса Fail2Ban:

systemctl enable --now fail2ban

Включает и немедленно запускает сервис Fail2Ban. Опция --now указывает на необходимость немедленного запуска сервиса.

  1. Перезапуск сервиса Fail2Ban:

systemctl restart fail2ban

Перезапускает сервис Fail2Ban, чтобы применить новые настройки.

  1. Проверка статуса Fail2Ban:

echo -e "\nFail2Ban status:"
fail2ban-client status

Выводит текущий статус работы Fail2Ban, показывая, активен ли сервис и количество заблокированных IP-адресов.

Этот скрипт полезен для быстрой и удобной установки Fail2Ban с предварительной настройкой для защиты SSH. Он автоматизирует установку, настройку и запуск Fail2Ban, что существенно сокращает время и упрощает процесс обеспечения безопасности сервера.

Для глубокого погружения в тему рекомендуется внимательно изучить официальную документацию по Fail2ban.

Подведение итогов

В этом руководстве из двух частей мы прошли через все этапы установки и настройки стека LEMP (Linux, Nginx, MySQL/MariaDB, PHP)

Важно отметить, что этот набор инструкций создает базовую конфигурацию LEMP-стека. Для продакшн-среды может потребоваться дополнительная настройка и оптимизация, включая:

  • Дополнительная оптимизация производительности необходима, так как сделанного недостаточно для высоконагруженных проектов

  • Настройка резервного копирования интернет проекта и базы данных

  • Реализация дополнительных мер безопасности

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

Этот гайд, разделенный на две части, предоставляет прочную основу для развертывания веб-приложений на базе LEMP-стека, но помните, что каждый проект может иметь свои нюансы, которые могут потребовать дополнительной настройки.

Комментарии (2)


  1. Thomas_Hanniball
    15.07.2024 17:35
    +6

    Немного странно в 2024 году видеть настройку LEMP через bash-скрипты, когда всё прогрессивное человечество использует для этих целей Ansible или его аналоги.


    1. unixweb Автор
      15.07.2024 17:35

      можно и так и так сделать