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

В этой статье я поделюсь полным пошаговым руководством по настройке LEMP-стека от чистой установки Linux до полностью готовой к production среды. Мы уделим особое внимание безопасности, производительности и отказоустойчивости — ключевым аспектам любой production-системы.

Настройка production-сервера — это не просто установка компонентов по умолчанию, а тщательно спланированный процесс, учитывающий особенности проекта, ожидаемую нагрузку и требования к безопасности. Инвестиция времени в правильную настройку окупится многократно в будущем.

Данное руководство ориентировано на Ubuntu 22.04 LTS, но большинство команд и принципов применимы и к другим современным дистрибутивам Linux. Для максимальной эффективности рекомендую выполнять каждый шаг последовательно, так как многие настройки взаимосвязаны.

1. Подготовка сервера

Правильная подготовка сервера закладывает фундамент для стабильной и безопасной работы всего LEMP-стека. Начнем с базовой настройки свежеустановленной системы Ubuntu 22.04 LTS.

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

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

# Обновление списка пакетов
sudo apt update

# Установка обновлений
sudo apt upgrade -y

# Перезагрузка сервера при необходимости
sudo reboot

Настройка имени хоста и часового пояса

Установим правильное имя хоста и настроим часовой пояс:

# Установка имени хоста
sudo hostnamectl set-hostname your-server-name

# Настройка часового пояса
sudo timedatectl set-timezone Europe/Moscow  # Замените на ваш часовой пояс

# Проверка настроек времени
timedatectl

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

Для повышения безопасности создадим отдельного пользователя с правами sudo:

# Создание нового пользователя
sudo adduser webadmin

# Добавление пользователя в группу sudo
sudo usermod -aG sudo webadmin

# Проверка доступа
su - webadmin
sudo whoami  # Должно вернуть "root"

Совет

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

# На локальном компьютере (если ключа еще нет)
ssh-keygen -t ed25519 -C "ваш_email@example.com"

# Копирование публичного ключа на сервер
ssh-copy-id webadmin@your_server_ip

# На сервере - отключение парольной аутентификации
sudo nano /etc/ssh/sshd_config
# Установите следующие параметры:
# PasswordAuthentication no
# PubkeyAuthentication yes
# PermitRootLogin no

# Перезапуск SSH-сервера
sudo systemctl restart sshd

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

Установим и настроим UFW (Uncomplicated Firewall) для контроля сетевого доступа:

# Установка UFW, если он еще не установлен
sudo apt install ufw

# Настройка базовых правил
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Разрешение SSH для предотвращения потери доступа
sudo ufw allow ssh

# Разрешение веб-трафика
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Включение брандмауэра
sudo ufw enable

# Проверка статуса
sudo ufw status verbose

Настройка swap-файла

Для серверов с ограниченным объемом RAM полезно настроить swap-пространство:

# Проверка текущего swap
sudo swapon --show

# Создание swap-файла (2GB в данном примере)
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# Настройка автоматического монтирования при загрузке
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

# Настройка оптимальных параметров использования swap
sudo sysctl vm.swappiness=10
sudo sysctl vm.vfs_cache_pressure=50

# Для сохранения настроек при перезагрузке
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
echo 'vm.vfs_cache_pressure=50' | sudo tee -a /etc/sysctl.conf

Важно!

На виртуальных серверах с SSD-дисками вместо fallocate рекомендуется использовать dd для создания swap-файла, чтобы избежать проблем с разреженными файлами:

sudo dd if=/dev/zero of=/swapfile bs=1M count=2048 status=progress

Установка базовых инструментов мониторинга

Установим необходимые утилиты для наблюдения за работой сервера:

# Установка базовых инструментов
sudo apt install -y htop iotop iftop ncdu net-tools dnsutils curl wget unzip

2. Установка и настройка Nginx

Nginx — высокопроизводительный веб-сервер, обратный прокси-сервер и балансировщик нагрузки. Его асинхронная архитектура делает его более эффективным при обработке множества одновременных соединений по сравнению с Apache.

Установка Nginx из официального репозитория

Для получения наиболее свежих версий установим Nginx из официального репозитория:

# Добавление официального репозитория Nginx
sudo apt install -y curl gnupg2 ca-certificates lsb-release ubuntu-keyring
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

# Добавление стабильного репозитория
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" | sudo tee /etc/apt/sources.list.d/nginx.list

# Обновление списка пакетов и установка Nginx
sudo apt update
sudo apt install -y nginx

# Запуск Nginx и включение автозапуска
sudo systemctl start nginx
sudo systemctl enable nginx

# Проверка статуса
sudo systemctl status nginx

Базовая конфигурация Nginx

Настроим основной конфигурационный файл Nginx с оптимальными параметрами для production:

# Создание резервной копии конфигурации
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup

# Редактирование основной конфигурации
sudo nano /etc/nginx/nginx.conf

Заменим содержимое файла на следующую оптимизированную конфигурацию:

user nginx;
worker_processes auto;
pid /var/run/nginx.pid;

# Оптимизация количества одновременных подключений на рабочий процесс
events {
    worker_connections 1024;
    multi_accept on;
    use epoll;
}

http {
    # Основные настройки
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    server_tokens off;
    
    # Размер буфера и таймауты
    client_max_body_size 100M;
    client_body_timeout 12;
    client_header_timeout 12;
    send_timeout 10;

    # Буферизация
    client_body_buffer_size 10K;
    client_header_buffer_size 1k;
    large_client_header_buffers 4 4k;

    # Включаем сжатие для экономии трафика
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_buffers 16 8k;
    gzip_http_version 1.1;
    gzip_min_length 256;
    gzip_types
        application/atom+xml
        application/javascript
        application/json
        application/ld+json
        application/manifest+json
        application/rss+xml
        application/vnd.geo+json
        application/vnd.ms-fontobject
        application/x-font-ttf
        application/x-web-app-manifest+json
        application/xhtml+xml
        application/xml
        font/opentype
        image/bmp
        image/svg+xml
        image/x-icon
        text/cache-manifest
        text/css
        text/plain
        text/vcard
        text/vnd.rim.location.xloc
        text/vtt
        text/x-component
        text/x-cross-domain-policy;

    # Кеш открытых файловых дескрипторов
    open_file_cache max=1000 inactive=20s;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 5;
    open_file_cache_errors on;

    # Логирование
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    # MIME-типы
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # Включение виртуальных хостов
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

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

После внесения изменений важно проверить конфигурацию на наличие ошибок перед перезапуском:

# Проверка синтаксиса конфигурации
sudo nginx -t

# Если ошибок нет, перезапускаем Nginx
sudo systemctl restart nginx

Создание структуры каталогов для сайтов

Подготовим структуру каталогов для наших будущих сайтов:

# Создание основного каталога для веб-сайтов
sudo mkdir -p /var/www/sites

# Создание каталога для стандартного сайта
sudo mkdir -p /var/www/sites/default/public

# Установка корректных прав доступа
sudo chown -R nginx:nginx /var/www/sites
sudo chmod -R 755 /var/www/sites

# Создание тестовой страницы
echo '<!DOCTYPE html>
<html>
<head>
    <title>Welcome to LEMP Stack</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 40px;
            line-height: 1.6;
        }
        h1 {
            color: #336699;
        }
    </style>
</head>
<body>
    <h1>Welcome to your LEMP Stack</h1>
    <p>If you see this page, Nginx is successfully installed and working.</p>
    <p>This is the default test page.</p>
    <p>Server time: <?php echo date("Y-m-d H:i:s"); ?></p>
    <p>PHP Version: <?php echo phpversion(); ?></p>
</body>
</html>' | sudo tee /var/www/sites/default/public/index.php

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

Создадим базовую конфигурацию виртуального хоста:

# Создание конфигурационного файла
sudo nano /etc/nginx/conf.d/default.conf

Содержимое базового конфигурационного файла:

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    
    server_name _;
    root /var/www/sites/default/public;
    index index.php index.html index.htm;

    # Логи для данного виртуального хоста
    access_log /var/log/nginx/default.access.log;
    error_log /var/log/nginx/default.error.log;

    # Настройка для статических файлов
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg)$ {
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }

    # Основная обработка PHP
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass unix:/run/php-fpm/php-fpm.sock; # Будет настроено позже
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_intercept_errors on;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 4 16k;
    }

    # Защита от доступа к скрытым файлам
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }

    # Обработка основных запросов
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
}

Совет

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

Проверим конфигурацию и перезапустим Nginx:

sudo nginx -t
sudo systemctl restart nginx

3. Установка и защита MySQL

MySQL — одна из самых популярных реляционных систем управления базами данных. Она обеспечивает надежное хранение данных для ваших веб-приложений и отлично интегрируется с PHP.

Установка MySQL

Установим MySQL Server из стандартных репозиториев:

# Установка MySQL
sudo apt install -y mysql-server

# Проверка статуса сервиса
sudo systemctl status mysql

# Включение автозапуска
sudo systemctl enable mysql

Безопасная настройка MySQL

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

# Запуск мастера безопасной настройки
sudo mysql_secure_installation

При запуске скрипта вам будет предложено выполнить следующие шаги:

  • Настроить компонент проверки надежности паролей (рекомендуется выбрать политику STRONG)
  • Установить надежный пароль для пользователя root
  • Удалить анонимных пользователей (рекомендуется выбрать "Да")
  • Запретить удаленный вход для пользователя root (рекомендуется выбрать "Да")
  • Удалить тестовую базу данных (рекомендуется выбрать "Да")
  • Перезагрузить таблицы привилегий (рекомендуется выбрать "Да")

Оптимизация конфигурации MySQL

Теперь настроим основные параметры производительности MySQL. Создадим конфигурационный файл:

# Создание конфигурационного файла
sudo nano /etc/mysql/conf.d/mysql-optimization.cnf

Содержимое файла оптимизации (параметры подходят для сервера с 4 ГБ RAM):

[mysqld]
# Оптимизация производительности
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_flush_method = O_DIRECT
innodb_flush_log_at_trx_commit = 2
query_cache_type = 1
query_cache_size = 64M
query_cache_limit = 2M
max_connections = 150
table_open_cache = 2000
tmp_table_size = 64M
max_heap_table_size = 64M
join_buffer_size = 4M
read_buffer_size = 3M
read_rnd_buffer_size = 4M
sort_buffer_size = 4M

# Оптимизация для InnoDB
innodb_file_per_table = 1
innodb_buffer_pool_instances = 4
innodb_read_io_threads = 4
innodb_write_io_threads = 4
innodb_io_capacity = 1000

# Настройки журнала
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 2
log_queries_not_using_indexes = 1
log_error = /var/log/mysql/error.log

# Безопасность
max_allowed_packet = 16M
symbolic-links = 0
local_infile = 0

Важно!

Параметры MySQL сильно зависят от доступных ресурсов сервера и характера нагрузки. Указанные значения подойдут для стандартных веб-приложений на сервере с 4 ГБ RAM. Для высоконагруженных проектов или серверов с другими характеристиками необходима дополнительная настройка.

Применим настройки, перезапустив MySQL:

sudo systemctl restart mysql

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

Вместо использования пользователя root, создадим отдельного пользователя для работы с базой данных:

# Подключение к MySQL
sudo mysql

# В командной строке MySQL выполним:
CREATE DATABASE example_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

# Создание пользователя с доступом только с localhost
CREATE USER 'example_user'@'localhost' IDENTIFIED BY 'StrongPassword123!';

# Предоставление привилегий пользователю только для созданной базы данных
GRANT ALL PRIVILEGES ON example_db.* TO 'example_user'@'localhost';

# Применение изменений
FLUSH PRIVILEGES;

# Выход из MySQL
EXIT;

Совет

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

openssl rand -base64 24

Настройка мониторинга производительности

Для отслеживания производительности MySQL установим инструмент MySQLTuner:

# Скачивание MySQLTuner
sudo mkdir -p /opt/mysql-tools
cd /opt/mysql-tools
sudo wget https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl
sudo chmod +x mysqltuner.pl

# Создание символической ссылки для удобства использования
sudo ln -s /opt/mysql-tools/mysqltuner.pl /usr/local/bin/mysqltuner

# Проверка и получение рекомендаций (запускать после нескольких дней работы)
# sudo mysqltuner

4. Установка и оптимизация PHP-FPM

PHP-FPM (FastCGI Process Manager) — это альтернативная реализация PHP FastCGI с дополнительными возможностями, полезными для высоконагруженных сайтов. В отличие от mod_php для Apache, PHP-FPM работает как отдельный процесс и хорошо интегрируется с Nginx.

Установка PHP-FPM и необходимых модулей

Установим PHP 8.1 и основные модули, необходимые для большинства веб-приложений:

# Установка PHP-FPM и основных модулей
sudo apt install -y php8.1-fpm php8.1-mysql php8.1-curl php8.1-gd php8.1-intl php8.1-mbstring php8.1-xml php8.1-zip php8.1-bcmath php8.1-cli

# При необходимости можно установить дополнительные модули
sudo apt install -y php8.1-soap php8.1-ldap php8.1-imagick php8.1-redis php8.1-memcached

# Проверка статуса службы
sudo systemctl status php8.1-fpm

# Включение автозапуска
sudo systemctl enable php8.1-fpm

Оптимизация PHP-FPM

Настроим конфигурацию PHP-FPM для оптимальной производительности:

# Создание резервной копии конфигурации
sudo cp /etc/php/8.1/fpm/pool.d/www.conf /etc/php/8.1/fpm/pool.d/www.conf.backup

# Редактирование конфигурации пула www
sudo nano /etc/php/8.1/fpm/pool.d/www.conf

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

; Изменение пользователя и группы на nginx
user = nginx
group = nginx

; Использование Unix-сокета вместо TCP/IP для большей производительности
listen = /run/php-fpm/php-fpm.sock
listen.owner = nginx
listen.group = nginx
listen.mode = 0660

; Настройка динамического управления процессами
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500

; Логирование
slowlog = /var/log/php-fpm/www-slow.log
request_slowlog_timeout = 10s
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on

; Ограничения ресурсов
php_admin_value[memory_limit] = 256M
php_admin_value[upload_max_filesize] = 50M
php_admin_value[post_max_size] = 50M
php_admin_value[max_execution_time] = 60
php_admin_value[max_input_time] = 60

Настройка PHP.ini

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

# Создание резервной копии конфигурации
sudo cp /etc/php/8.1/fpm/php.ini /etc/php/8.1/fpm/php.ini.backup

# Редактирование конфигурационного файла
sudo nano /etc/php/8.1/fpm/php.ini

Найдите и измените следующие параметры:

; Безопасность
expose_php = Off
display_errors = Off
display_startup_errors = Off
log_errors = On
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
error_log = /var/log/php/error.log

; Производительность
realpath_cache_size = 4M
realpath_cache_ttl = 600
opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 2
opcache.save_comments = 1
opcache.enable_file_override = 1

; Сессии
session.gc_maxlifetime = 1440
session.gc_probability = 1
session.gc_divisor = 1000

; Дата и время
date.timezone = Europe/Moscow

Создание необходимых директорий и настройка прав доступа

Создадим директории для сокета PHP-FPM и логов:

# Создание директорий
sudo mkdir -p /run/php-fpm
sudo mkdir -p /var/log/php-fpm
sudo mkdir -p /var/log/php

# Установка прав доступа
sudo chown nginx:nginx /run/php-fpm
sudo chown nginx:nginx /var/log/php-fpm
sudo chown nginx:nginx /var/log/php

Перезапуск PHP-FPM и проверка работоспособности

Перезапустим службу PHP-FPM для применения всех настроек:

# Перезапуск PHP-FPM
sudo systemctl restart php8.1-fpm

# Проверка статуса
sudo systemctl status php8.1-fpm

# Проверка наличия сокета
ls -la /run/php-fpm/

Совет

В production-среде рекомендуется создавать отдельные пулы PHP-FPM для каждого крупного веб-приложения. Это позволяет более гибко настраивать ресурсы и изолировать приложения друг от друга.

# Создание отдельного пула для приложения
sudo cp /etc/php/8.1/fpm/pool.d/www.conf /etc/php/8.1/fpm/pool.d/example-app.conf

# Редактирование нового пула
sudo nano /etc/php/8.1/fpm/pool.d/example-app.conf

# Измените следующие параметры:
# [www] -> [example-app]
# listen = /run/php-fpm/example-app.sock

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

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

Установка Certbot

Certbot — это клиент Let's Encrypt, который значительно упрощает получение и обновление сертификатов:

# Установка Certbot и плагина для Nginx
sudo apt install -y certbot python3-certbot-nginx

Получение SSL-сертификата

Перед получением сертификата необходимо настроить DNS для вашего домена и убедиться, что он указывает на ваш сервер:

# Получение сертификата с автоматической настройкой Nginx
sudo certbot --nginx -d example.com -d www.example.com

# Или для ручной настройки (только получение сертификата)
sudo certbot certonly --nginx -d example.com -d www.example.com

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

  • Ввести адрес электронной почты для уведомлений об истечении срока действия сертификата
  • Принять условия использования
  • Решить, хотите ли вы делиться своим адресом электронной почты с EFF
  • Выбрать, следует ли перенаправлять HTTP на HTTPS (рекомендуется)

Ручная настройка Nginx для использования SSL

Если вы выбрали режим "certonly", вам потребуется вручную настроить Nginx:

# Создание или редактирование виртуального хоста
sudo nano /etc/nginx/conf.d/example.com.conf

Пример конфигурации с SSL и перенаправлением с HTTP на HTTPS:

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    
    # Перенаправление на HTTPS
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com www.example.com;
    
    # SSL-сертификаты
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
    
    # Настройки SSL
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;
    
    # Настройки OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    
    # Заголовки безопасности
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    add_header X-Content-Type-Options nosniff;
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-XSS-Protection "1; mode=block";
    
    # Корневая директория сайта
    root /var/www/sites/example.com/public;
    index index.php index.html index.htm;
    
    # Логи
    access_log /var/log/nginx/example.com.access.log;
    error_log /var/log/nginx/example.com.error.log;
    
    # Настройка для статических файлов
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg)$ {
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }
    
    # Обработка PHP
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_intercept_errors on;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 4 16k;
    }
    
    # Защита от доступа к скрытым файлам
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }
    
    # Основная обработка запросов
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
}

Настройка автоматического обновления сертификатов

Certbot автоматически устанавливает задание cron для обновления сертификатов. Проверим его наличие и корректность:

# Проверка заданий cron для certbot
systemctl list-timers | grep certbot

# Ручная проверка процесса обновления (без фактического обновления)
sudo certbot renew --dry-run

Важно!

Сертификаты Let's Encrypt действительны только 90 дней. Хотя Certbot настраивает автоматическое обновление, регулярно проверяйте его работоспособность, особенно после обновления операционной системы или Nginx.

Тестирование безопасности SSL-настроек

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

# Используйте онлайн-инструмент SSL Labs
                                    # https://www.ssllabs.com/ssltest/analyze.html?d=example.com
                                    
                                    # Или инструмент командной строки testssl.sh
                                    sudo apt install -y git
                                    git clone --depth 1 https://github.com/drwetter/testssl.sh.git
                                    cd testssl.sh
                                    ./testssl.sh https://example.com

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

Виртуальные хосты позволяют размещать несколько сайтов на одном сервере. Правильная настройка виртуальных хостов — важный шаг для организации production-среды.

Организация файловой структуры

Для каждого сайта рекомендуется использовать следующую структуру каталогов:

# Создание структуры для нового сайта
                                    sudo mkdir -p /var/www/sites/example.com/{public,logs,backup,cache}
                                    
                                    # Настройка прав доступа
                                    sudo chown -R nginx:nginx /var/www/sites/example.com
                                    sudo chmod -R 755 /var/www/sites/example.com

Шаблон конфигурации виртуального хоста

Создадим шаблон для быстрого добавления новых сайтов:

# Создание шаблона
                                    sudo nano /etc/nginx/templates/vhost-template.conf

Содержимое шаблона:

server {
                                        listen 80;
                                        listen [::]:80;
                                        server_name DOMAIN_NAME www.DOMAIN_NAME;
                                        
                                        # Перенаправление на HTTPS
                                        return 301 https://$host$request_uri;
                                    }
                                    
                                    server {
                                        listen 443 ssl http2;
                                        listen [::]:443 ssl http2;
                                        server_name DOMAIN_NAME www.DOMAIN_NAME;
                                        
                                        # SSL-сертификаты
                                        ssl_certificate /etc/letsencrypt/live/DOMAIN_NAME/fullchain.pem;
                                        ssl_certificate_key /etc/letsencrypt/live/DOMAIN_NAME/privkey.pem;
                                        ssl_trusted_certificate /etc/letsencrypt/live/DOMAIN_NAME/chain.pem;
                                        
                                        # Настройки SSL
                                        ssl_protocols TLSv1.2 TLSv1.3;
                                        ssl_prefer_server_ciphers on;
                                        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
                                        ssl_session_timeout 1d;
                                        ssl_session_cache shared:SSL:10m;
                                        ssl_session_tickets off;
                                        
                                        # Настройки OCSP Stapling
                                        ssl_stapling on;
                                        ssl_stapling_verify on;
                                        resolver 8.8.8.8 8.8.4.4 valid=300s;
                                        resolver_timeout 5s;
                                        
                                        # Заголовки безопасности
                                        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
                                        add_header X-Content-Type-Options nosniff;
                                        add_header X-Frame-Options SAMEORIGIN;
                                        add_header X-XSS-Protection "1; mode=block";
                                        
                                        # Корневая директория сайта
                                        root /var/www/sites/DOMAIN_NAME/public;
                                        index index.php index.html index.htm;
                                        
                                        # Логи
                                        access_log /var/www/sites/DOMAIN_NAME/logs/access.log;
                                        error_log /var/www/sites/DOMAIN_NAME/logs/error.log;
                                        
                                        # Настройка для статических файлов
                                        location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
                                            expires 30d;
                                            add_header Cache-Control "public, no-transform";
                                        }
                                        
                                        # Обработка PHP
                                        location ~ \.php$ {
                                            try_files $uri =404;
                                            fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
                                            fastcgi_index index.php;
                                            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                                            include fastcgi_params;
                                            fastcgi_intercept_errors on;
                                            fastcgi_buffer_size 16k;
                                            fastcgi_buffers 4 16k;
                                        }
                                        
                                        # Защита от доступа к скрытым файлам
                                        location ~ /\. {
                                            deny all;
                                            access_log off;
                                            log_not_found off;
                                        }
                                        
                                        # Отключение доступа к чувствительным файлам
                                        location ~* \.(env|log|git|htaccess|tpl|twig|ini|sql)$ {
                                            deny all;
                                            return 404;
                                        }
                                        
                                        # Основная обработка запросов
                                        location / {
                                            try_files $uri $uri/ /index.php?$query_string;
                                        }
                                    }

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

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

# Создание скрипта
                                    sudo nano /usr/local/bin/create-vhost.sh

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

#!/bin/bash
                                    
                                    # Проверка наличия доменного имени
                                    if [ -z "$1" ]; then
                                        echo "Не указано доменное имя!"
                                        echo "Использование: create-vhost.sh example.com"
                                        exit 1
                                    fi
                                    
                                    DOMAIN=$1
                                    TEMPLATE_FILE="/etc/nginx/templates/vhost-template.conf"
                                    CONFIG_FILE="/etc/nginx/conf.d/${DOMAIN}.conf"
                                    
                                    # Проверка существования шаблона
                                    if [ ! -f "$TEMPLATE_FILE" ]; then
                                        echo "Файл шаблона не найден: $TEMPLATE_FILE"
                                        exit 1
                                    fi
                                    
                                    # Создание структуры каталогов
                                    echo "Создание структуры каталогов для $DOMAIN..."
                                    mkdir -p /var/www/sites/${DOMAIN}/{public,logs,backup,cache}
                                    chown -R nginx:nginx /var/www/sites/${DOMAIN}
                                    chmod -R 755 /var/www/sites/${DOMAIN}
                                    
                                    # Создание тестовой страницы
                                    echo "<!DOCTYPE html>
                                    <html>
                                    <head>
                                        <title>Welcome to ${DOMAIN}</title>
                                        <style>
                                            body {
                                                font-family: Arial, sans-serif;
                                                margin: 40px;
                                                line-height: 1.6;
                                            }
                                            h1 {
                                                color: #336699;
                                            }
                                        </style>
                                    </head>
                                    <body>
                                        <h1>Welcome to ${DOMAIN}</h1>
                                        <p>This is the default page for ${DOMAIN}.</p>
                                        <p>Server time: <?php echo date('Y-m-d H:i:s'); ?></p>
                                        <p>PHP Version: <?php echo phpversion(); ?></p>
                                    </body>
                                    </html>" > /var/www/sites/${DOMAIN}/public/index.php
                                    
                                    # Создание конфигурации виртуального хоста
                                    echo "Создание конфигурации виртуального хоста..."
                                    cp $TEMPLATE_FILE $CONFIG_FILE
                                    sed -i "s/DOMAIN_NAME/${DOMAIN}/g" $CONFIG_FILE
                                    
                                    # Проверка синтаксиса конфигурации
                                    echo "Проверка синтаксиса конфигурации Nginx..."
                                    nginx -t
                                    
                                    if [ $? -eq 0 ]; then
                                        echo "Конфигурация успешно проверена."
                                        echo "Перезапуск Nginx..."
                                        systemctl reload nginx
                                        
                                        echo "Получение SSL-сертификата..."
                                        certbot --nginx -d ${DOMAIN} -d www.${DOMAIN}
                                        
                                        echo "Виртуальный хост для ${DOMAIN} успешно создан!"
                                        echo "Теперь вы можете загрузить ваши файлы в /var/www/sites/${DOMAIN}/public/"
                                    else
                                        echo "Ошибка в конфигурации Nginx. Виртуальный хост не активирован."
                                    fi

Сделаем скрипт исполняемым:

sudo chmod +x /usr/local/bin/create-vhost.sh

Совет

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

sudo create-vhost.sh example.com

Скрипт создаст все необходимые каталоги, настроит виртуальный хост и запросит SSL-сертификат.

Настройка специализированных виртуальных хостов

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

Пример конфигурации для WordPress

# Дополнительные настройки для WordPress
                                    location / {
                                        try_files $uri $uri/ /index.php?$args;
                                    }
                                    
                                    # Защита файлов WordPress
                                    location ~* wp-config.php|wp-admin/includes {
                                        deny all;
                                    }
                                    
                                    # Кеширование статических файлов
                                    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
                                        expires max;
                                        log_not_found off;
                                    }

Пример конфигурации для Laravel

# Laravel настройки
                                    location / {
                                        try_files $uri $uri/ /index.php?$query_string;
                                    }
                                    
                                    # Защита от доступа к .env и другим критичным файлам
                                    location ~ \.env {
                                        deny all;
                                        return 404;
                                    }
                                    
                                    # Кеширование для Laravel Mix (собранные ресурсы)
                                    location ~* \.(?:css|js|jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
                                        expires 1M;
                                        access_log off;
                                        add_header Cache-Control "public";
                                    }

7. Оптимизация производительности

Оптимизация производительности LEMP-стека позволяет сайтам работать быстрее и обрабатывать больше запросов без необходимости в дополнительных ресурсах.

Настройка кеширования Nginx

Правильно настроенное кеширование может значительно снизить нагрузку на сервер:

# Создание директории для кеша
                                    sudo mkdir -p /var/cache/nginx
                                    
                                    # Настройка прав доступа
                                    sudo chown -R nginx:nginx /var/cache/nginx
                                    sudo chmod -R 755 /var/cache/nginx
                                    
                                    # Создание конфигурации кеширования
                                    sudo nano /etc/nginx/conf.d/cache.conf

Содержимое конфигурационного файла кеширования:

# Определение зон кеширования
                                    proxy_cache_path /var/cache/nginx/proxy_cache levels=1:2 keys_zone=proxy_cache:10m max_size=1g inactive=60m;
                                    fastcgi_cache_path /var/cache/nginx/fastcgi_cache levels=1:2 keys_zone=fastcgi_cache:10m max_size=1g inactive=60m;
                                    
                                    # Настройка параметров FASTCGI кеширования
                                    fastcgi_cache_key "$scheme$request_method$host$request_uri";
                                    fastcgi_cache_use_stale error timeout invalid_header http_500;
                                    fastcgi_ignore_headers Cache-Control Expires Set-Cookie;

Добавление кеширования в конфигурацию виртуального хоста (пример для WordPress):

# Настройка FASTCGI-кеширования (добавить в server блок)
                                    set $skip_cache 0;
                                    
                                    # Пропуск кеша для админки, входа, авторизованных пользователей и т.д.
                                    if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
                                        set $skip_cache 1;
                                    }
                                    if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
                                        set $skip_cache 1;
                                    }
                                    
                                    # В location блоке для PHP добавить:
                                    location ~ \.php$ {
                                        try_files $uri =404;
                                        fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
                                        fastcgi_index index.php;
                                        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                                        include fastcgi_params;
                                        
                                        # Настройки кеширования
                                        fastcgi_cache fastcgi_cache;
                                        fastcgi_cache_valid 200 60m;
                                        fastcgi_cache_bypass $skip_cache;
                                        fastcgi_no_cache $skip_cache;
                                        fastcgi_cache_background_update on;
                                        
                                        # Добавление заголовка для отладки
                                        add_header X-Cache $upstream_cache_status;
                                    }

Установка и настройка Redis для кеширования сессий и данных

Redis — быстрое хранилище данных в памяти, которое можно использовать для кеширования и хранения сессий:

# Установка Redis
                                    sudo apt install -y redis-server php8.1-redis
                                    
                                    # Настройка Redis
                                    sudo nano /etc/redis/redis.conf

Основные настройки для Redis:

# Базовая настройка безопасности
                                    protected-mode yes
                                    port 6379
                                    bind 127.0.0.1 ::1
                                    
                                    # Производительность
                                    maxmemory 256mb
                                    maxmemory-policy allkeys-lru
                                    
                                    # Персистентность (если нужна)
                                    save 900 1
                                    save 300 10
                                    save 60 10000

Настройка PHP для использования Redis:

# Редактирование php.ini
                                    sudo nano /etc/php/8.1/fpm/php.ini
                                    
                                    # Добавить настройки для Redis
                                    session.save_handler = redis
                                    session.save_path = "tcp://127.0.0.1:6379"

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

sudo systemctl restart redis-server
                                    sudo systemctl restart php8.1-fpm

Оптимизация баз данных MySQL

Для оптимизации производительности баз данных:

# Создание скрипта для автоматической оптимизации
                                    sudo nano /usr/local/bin/optimize-mysql.sh

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

#!/bin/bash
                                    
                                    # Файл для логов
                                    LOG_FILE="/var/log/mysql/optimization.log"
                                    
                                    # Дата выполнения
                                    DATE=$(date +"%Y-%m-%d %H:%M:%S")
                                    
                                    # Запись начала в лог
                                    echo "[$DATE] Starting MySQL optimization" >> $LOG_FILE
                                    
                                    # Получение списка баз данных
                                    DATABASES=$(mysql -B -N -e "SHOW DATABASES;" | grep -v "information_schema" | grep -v "performance_schema" | grep -v "mysql" | grep -v "sys")
                                    
                                    # Перебор баз данных
                                    for DB in $DATABASES; do
                                        echo "[$DATE] Optimizing database: $DB" >> $LOG_FILE
                                        
                                        # Получение списка таблиц
                                        TABLES=$(mysql -B -N -e "SHOW TABLES FROM \`$DB\`;")
                                        
                                        # Перебор таблиц
                                        for TABLE in $TABLES; do
                                            echo "[$DATE] Optimizing table: $DB.$TABLE" >> $LOG_FILE
                                            
                                            # Анализ таблицы
                                            mysql -e "ANALYZE TABLE \`$DB\`.\`$TABLE\`;" >> $LOG_FILE 2>&1
                                            
                                            # Оптимизация таблицы
                                            mysql -e "OPTIMIZE TABLE \`$DB\`.\`$TABLE\`;" >> $LOG_FILE 2>&1
                                        done
                                    done
                                    
                                    echo "[$DATE] MySQL optimization completed" >> $LOG_FILE

Сделаем скрипт исполняемым и добавим его в планировщик cron:

# Установка прав на исполнение
                                    sudo chmod +x /usr/local/bin/optimize-mysql.sh
                                    
                                    # Добавление задания в cron для выполнения каждое воскресенье в 3:00
                                    echo "0 3 * * 0 root /usr/local/bin/optimize-mysql.sh" | sudo tee -a /etc/cron.d/mysql-optimization

Настройка мониторинга производительности

Установим простой инструмент для мониторинга производительности — Netdata:

# Установка зависимостей
                                    sudo apt install -y autoconf automake gcc make git python3 python3-pip
                                    
                                    # Установка Netdata
                                    bash <(curl -Ss https://my-netdata.io/kickstart.sh)
                                    
                                    # Проверка статуса
                                    sudo systemctl status netdata

После установки Netdata доступен через веб-интерфейс по адресу http://ваш_сервер:19999. Для повышения безопасности рекомендуется настроить базовую HTTP-аутентификацию или проксирование через Nginx с SSL.

Совет

Для максимальной производительности в production-среде также рассмотрите:

  • Использование CDN (Content Delivery Network) для статического контента
  • Настройку HTTP/2 для всех сайтов
  • Применение WebP и оптимизацию изображений
  • Минификацию и объединение CSS/JavaScript файлов
  • Внедрение отложенной загрузки (lazy loading) для изображений

8. Повышение безопасности

Production-сервер требует особого внимания к безопасности. Рассмотрим дополнительные меры для защиты LEMP-стека от распространенных угроз.

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

Fail2ban помогает защититься от брутфорс-атак, блокируя IP-адреса после определенного количества неудачных попыток:

# Установка Fail2ban
                                    sudo apt install -y fail2ban
                                    
                                    # Создание конфигурационного файла
                                    sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
                                    sudo nano /etc/fail2ban/jail.local

Основные настройки для Fail2ban:

[DEFAULT]
                                    # Время бана в секундах (24 часа)
                                    bantime = 86400
                                    
                                    # Время в секундах, за которое отслеживаются попытки (10 минут)
                                    findtime = 600
                                    
                                    # Количество попыток до бана
                                    maxretry = 5
                                    
                                    # Игнорирование локальных IP
                                    ignoreip = 127.0.0.1/8 ::1
                                    
                                    # Настройка для SSH
                                    [sshd]
                                    enabled = true
                                    port = ssh
                                    filter = sshd
                                    logpath = /var/log/auth.log
                                    maxretry = 3
                                    
                                    # Настройка для Nginx (защита от сканирования сайта)
                                    [nginx-http-auth]
                                    enabled = true
                                    filter = nginx-http-auth
                                    port = http,https
                                    logpath = /var/log/nginx/*error.log
                                    
                                    # Настройка для защиты PHP-FPM от брутфорса
                                    [php-url-fopen]
                                    enabled = true
                                    port = http,https
                                    filter = php-url-fopen
                                    logpath = /var/log/nginx/*error.log

Создание дополнительного фильтра для обнаружения атак на веб-приложения:

# Создание фильтра для обнаружения сканирования уязвимостей
                                    sudo nano /etc/fail2ban/filter.d/nginx-scanners.conf

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

[Definition]
                                    failregex = ^<HOST> .* "(?:GET|POST|HEAD) (?:/\.env|/wp-login\.php|/administrator|/admin/|/wp-content/|/phpMyAdmin|/phpmyadmin|/myadmin|/mysql|/mysqladmin|/sqladmin|/MyAdmin|/pma/|/PMA/|/joomla/|/wordpress/) .*$
                                    ignoreregex =

Добавление нового фильтра в конфигурацию:

# Добавить в /etc/fail2ban/jail.local
                                    [nginx-scanners]
                                    enabled = true
                                    port = http,https
                                    filter = nginx-scanners
                                    logpath = /var/log/nginx/access.log
                                    maxretry = 2
                                    bantime = 86400

Запуск и включение автозапуска Fail2ban:

sudo systemctl start fail2ban
                                    sudo systemctl enable fail2ban
                                    
                                    # Проверка статуса
                                    sudo fail2ban-client status

Настройка ModSecurity WAF

ModSecurity — это межсетевой экран веб-приложений (WAF), который обеспечивает защиту от распространенных атак на веб-приложения:

# Установка зависимостей
                                    sudo apt install -y git build-essential libpcre3-dev libxml2-dev libyajl-dev liblmdb-dev libgeoip-dev libcurl4-openssl-dev libmaxminddb-dev
                                    
                                    # Клонирование репозитория ModSecurity
                                    cd /opt
                                    sudo git clone --depth 1 -b v3/master --single-branch https://github.com/SpiderLabs/ModSecurity
                                    
                                    # Компиляция ModSecurity
                                    cd ModSecurity
                                    sudo git submodule init
                                    sudo git submodule update
                                    sudo ./build.sh
                                    sudo ./configure
                                    sudo make
                                    sudo make install
                                    
                                    # Клонирование коннектора для Nginx
                                    cd /opt
                                    sudo git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git
                                    
                                    # Определение версии Nginx
                                    NGINX_VERSION=$(nginx -v 2>&1 | sed 's/^nginx version: nginx\///g')
                                    
                                    # Загрузка исходников Nginx той же версии
                                    cd /opt
                                    sudo wget http://nginx.org/download/nginx-$NGINX_VERSION.tar.gz
                                    sudo tar zxvf nginx-$NGINX_VERSION.tar.gz
                                    
                                    # Компиляция и установка модуля
                                    cd /opt/nginx-$NGINX_VERSION
                                    sudo ./configure --with-compat --add-dynamic-module=/opt/ModSecurity-nginx
                                    sudo make modules
                                    sudo cp objs/ngx_http_modsecurity_module.so /etc/nginx/modules/
                                    
                                    # Создание директории для правил ModSecurity
                                    sudo mkdir -p /etc/nginx/modsecurity
                                    cd /etc/nginx/modsecurity
                                    
                                    # Клонирование OWASP Core Rule Set
                                    sudo git clone https://github.com/coreruleset/coreruleset.git
                                    sudo cp coreruleset/crs-setup.conf.example coreruleset/crs-setup.conf
                                    
                                    # Настройка базовой конфигурации ModSecurity
                                    sudo cp /opt/ModSecurity/modsecurity.conf-recommended /etc/nginx/modsecurity/modsecurity.conf
                                    
                                    # Редактирование конфигурации
                                    sudo sed -i 's/SecRuleEngine DetectionOnly/SecRuleEngine On/' /etc/nginx/modsecurity/modsecurity.conf
                                    
                                    # Создание основного конфигурационного файла включения
                                    sudo nano /etc/nginx/modsecurity/main.conf

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

Include /etc/nginx/modsecurity/modsecurity.conf
                                    Include /etc/nginx/modsecurity/coreruleset/crs-setup.conf
                                    Include /etc/nginx/modsecurity/coreruleset/rules/*.conf

Настройка Nginx для использования ModSecurity:

# Редактирование nginx.conf
                                    sudo nano /etc/nginx/nginx.conf

Добавьте в начало блока http следующие строки:

load_module modules/ngx_http_modsecurity_module.so;
    
    http {
        # Настройки ModSecurity
        modsecurity on;
        modsecurity_rules_file /etc/nginx/modsecurity/main.conf;

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

sudo nginx -t
    sudo systemctl restart nginx

Важно!

ModSecurity может вызывать ложные срабатывания и блокировать легитимный трафик. Рекомендуется сначала запустить его в режиме обнаружения (SecRuleEngine DetectionOnly) и тщательно проанализировать логи перед включением в производственной среде.

Защита важных файлов и каталогов

Настройка защиты для критически важных файлов системы:

# Настройка защиты критических файлов
    sudo chattr +i /etc/passwd
    sudo chattr +i /etc/shadow
    sudo chattr +i /etc/group
    sudo chattr +i /etc/gshadow
    
    # Для временного редактирования этих файлов используйте:
    # sudo chattr -i /etc/passwd
    # ... внесите изменения ...
    # sudo chattr +i /etc/passwd

Установка и настройка Maldet (Linux Malware Detect)

Maldet — это инструмент для обнаружения вредоносного ПО в Linux:

# Загрузка и установка Maldet
    cd /opt
    sudo wget http://www.rfxn.com/downloads/maldetect-current.tar.gz
    sudo tar -xzf maldetect-current.tar.gz
    cd maldetect-*
    sudo ./install.sh
    
    # Настройка Maldet
    sudo nano /usr/local/maldetect/conf.maldet

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

# Включение e-mail уведомлений
    email_alert="1"
    email_addr="your-email@example.com"
    
    # Автоматическое сканирование каталогов
    autoupdate_signatures="1"
    autoupdate_version="1"
    
    # Карантин для зараженных файлов
    quarantine_hits="1"
    
    # Сканирование оперативной памяти
    scan_user_access="1"

Создание задания для регулярного сканирования:

# Создание скрипта для еженедельного сканирования
    echo '#!/bin/bash
    /usr/local/maldetect/maldet -b -r /var/www /home /tmp /var/tmp /var/log' | sudo tee /etc/cron.weekly/maldet-scan
    sudo chmod +x /etc/cron.weekly/maldet-scan

Аудит безопасности с помощью Lynis

Lynis — инструмент для аудита безопасности и проверки соответствия стандартам:

# Установка Lynis
    sudo apt install -y lynis
    
    # Запуск аудита безопасности
    sudo lynis audit system
    
    # Создание еженедельного отчета
    echo '#!/bin/bash
    REPORT_FILE="/var/log/security-audit-$(date +%Y%m%d).log"
    echo "Security Audit Report - $(date)" > $REPORT_FILE
    echo "===================================" >> $REPORT_FILE
    echo "" >> $REPORT_FILE
    lynis audit system --quiet >> $REPORT_FILE
    echo "" >> $REPORT_FILE
    echo "Recommendations:" >> $REPORT_FILE
    echo "===================================" >> $REPORT_FILE
    lynis show suggestions >> $REPORT_FILE
    echo "" >> $REPORT_FILE
    echo "Warnings:" >> $REPORT_FILE
    echo "===================================" >> $REPORT_FILE
    lynis show warnings >> $REPORT_FILE
    
    # Отправка отчета на email
    mail -s "Security Audit Report for $(hostname) - $(date +%Y-%m-%d)" your-email@example.com < $REPORT_FILE' | sudo tee /etc/cron.weekly/security-audit
    sudo chmod +x /etc/cron.weekly/security-audit

Совет

Регулярно проверяйте отчеты аудита безопасности и внедряйте рекомендуемые меры. Безопасность — это непрерывный процесс, а не одноразовое мероприятие.

9. Мониторинг и логирование

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

Настройка централизованного логирования

Объединение логов в одном месте упрощает их анализ и поиск проблем:

# Установка rsyslog
    sudo apt install -y rsyslog
    
    # Настройка централизованного хранения логов
    sudo mkdir -p /var/log/centralized
    sudo chown syslog:adm /var/log/centralized
    
    # Конфигурация rsyslog
    sudo nano /etc/rsyslog.d/30-centralized.conf

Содержимое конфигурационного файла:

# Nginx логи
    $InputFileName /var/log/nginx/access.log
    $InputFileTag nginx-access:
    $InputFileStateFile stat-nginx-access
    $InputFileSeverity info
    $InputFileFacility local6
    $InputRunFileMonitor
    
    $InputFileName /var/log/nginx/error.log
    $InputFileTag nginx-error:
    $InputFileStateFile stat-nginx-error
    $InputFileSeverity error
    $InputFileFacility local6
    $InputRunFileMonitor
    
    # PHP-FPM логи
    $InputFileName /var/log/php-fpm/www-error.log
    $InputFileTag php-error:
    $InputFileStateFile stat-php-error
    $InputFileSeverity error
    $InputFileFacility local5
    $InputRunFileMonitor
    
    # MySQL логи
    $InputFileName /var/log/mysql/error.log
    $InputFileTag mysql-error:
    $InputFileStateFile stat-mysql-error
    $InputFileSeverity error
    $InputFileFacility local4
    $InputRunFileMonitor
    
    # Шаблон для сохранения логов
    $template CentralizedLogs,"/var/log/centralized/%$YEAR%/%$MONTH%/%$DAY%/%syslogfacility-text%-%syslogseverity-text%.log"
    
    # Правила для записи логов
    local4.* -?CentralizedLogs
    local5.* -?CentralizedLogs
    local6.* -?CentralizedLogs

Перезапуск rsyslog:

sudo systemctl restart rsyslog

Настройка ротации логов

Правильная ротация логов предотвращает заполнение диска старыми логами:

# Настройка logrotate для всех компонентов LEMP
    sudo nano /etc/logrotate.d/lemp

Содержимое файла конфигурации ротации:

# Nginx логи
    /var/log/nginx/*.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 0640 nginx adm
        sharedscripts
        postrotate
            [ -s /run/nginx.pid ] && kill -USR1 `cat /run/nginx.pid`
        endscript
    }
    
    # PHP-FPM логи
    /var/log/php-fpm/*.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 0640 nginx adm
        sharedscripts
        postrotate
            [ -s /run/php-fpm/php-fpm.pid ] && kill -USR1 `cat /run/php-fpm/php-fpm.pid`
        endscript
    }
    
    # MySQL логи
    /var/log/mysql/*.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 0640 mysql adm
        sharedscripts
        postrotate
            [ -s /run/mysqld/mysqld.pid ] && kill -USR1 `cat /run/mysqld/mysqld.pid`
        endscript
    }

Установка и настройка Prometheus и Grafana

Для комплексного мониторинга всего стека настроим Prometheus (сбор метрик) и Grafana (визуализация):

# Создание пользователя для Prometheus
    sudo useradd --no-create-home --shell /bin/false prometheus
    
    # Создание директорий
    sudo mkdir -p /etc/prometheus
    sudo mkdir -p /var/lib/prometheus
    sudo chown prometheus:prometheus /var/lib/prometheus
    
    # Загрузка и установка Prometheus
    cd /tmp
    wget https://github.com/prometheus/prometheus/releases/download/v2.40.0/prometheus-2.40.0.linux-amd64.tar.gz
    tar -xvf prometheus-2.40.0.linux-amd64.tar.gz
    cd prometheus-2.40.0.linux-amd64
    sudo cp prometheus /usr/local/bin/
    sudo cp promtool /usr/local/bin/
    sudo chown prometheus:prometheus /usr/local/bin/prometheus
    sudo chown prometheus:prometheus /usr/local/bin/promtool
    sudo cp -r consoles/ /etc/prometheus
    sudo cp -r console_libraries/ /etc/prometheus
    sudo chown -R prometheus:prometheus /etc/prometheus/consoles
    sudo chown -R prometheus:prometheus /etc/prometheus/console_libraries
    
    # Настройка конфигурации Prometheus
    sudo nano /etc/prometheus/prometheus.yml

Базовая конфигурация Prometheus:

global:
      scrape_interval: 15s
    
    scrape_configs:
      - job_name: 'prometheus'
        scrape_interval: 5s
        static_configs:
          - targets: ['localhost:9090']
    
      - job_name: 'node_exporter'
        scrape_interval: 5s
        static_configs:
          - targets: ['localhost:9100']
    
      - job_name: 'mysql_exporter'
        scrape_interval: 5s
        static_configs:
          - targets: ['localhost:9104']
    
      - job_name: 'nginx_exporter'
        scrape_interval: 5s
        static_configs:
          - targets: ['localhost:9113']

Создание systemd-сервиса для Prometheus:

sudo nano /etc/systemd/system/prometheus.service

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

[Unit]
    Description=Prometheus
    Wants=network-online.target
    After=network-online.target
    
    [Service]
    User=prometheus
    Group=prometheus
    Type=simple
    ExecStart=/usr/local/bin/prometheus \
        --config.file /etc/prometheus/prometheus.yml \
        --storage.tsdb.path /var/lib/prometheus/ \
        --web.console.templates=/etc/prometheus/consoles \
        --web.console.libraries=/etc/prometheus/console_libraries
    
    [Install]
    WantedBy=multi-user.target

Установка экспортеров для сбора метрик:

# Node Exporter для системных метрик
    cd /tmp
    wget https://github.com/prometheus/node_exporter/releases/download/v1.4.0/node_exporter-1.4.0.linux-amd64.tar.gz
    tar -xvf node_exporter-1.4.0.linux-amd64.tar.gz
    cd node_exporter-1.4.0.linux-amd64
    sudo cp node_exporter /usr/local/bin/
    sudo useradd --no-create-home --shell /bin/false node_exporter
    sudo chown node_exporter:node_exporter /usr/local/bin/node_exporter
    
    # Сервис для Node Exporter
    sudo nano /etc/systemd/system/node_exporter.service

Содержимое файла сервиса Node Exporter:

[Unit]
    Description=Node Exporter
    Wants=network-online.target
    After=network-online.target
    
    [Service]
    User=node_exporter
    Group=node_exporter
    Type=simple
    ExecStart=/usr/local/bin/node_exporter
    
    [Install]
    WantedBy=multi-user.target

Установка и настройка Grafana:

# Установка зависимостей
    sudo apt install -y apt-transport-https software-properties-common
    
    # Добавление GPG ключа Grafana
    wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
    
    # Добавление репозитория Grafana
    echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list
    
    # Установка Grafana
    sudo apt update
    sudo apt install -y grafana
    
    # Запуск и включение автозапуска
    sudo systemctl start grafana-server
    sudo systemctl enable grafana-server

Запуск всех служб мониторинга:

sudo systemctl daemon-reload
    sudo systemctl start prometheus
    sudo systemctl enable prometheus
    sudo systemctl start node_exporter
    sudo systemctl enable node_exporter

Совет

После настройки откройте Grafana (http://ваш_сервер:3000) и импортируйте готовые дашборды для мониторинга. Рекомендуемые ID дашбордов:

  • 1860 — Node Exporter Full
  • 7362 — MySQL Overview
  • 9614 — NGINX Exporter Dashboard

Настройка оповещений

Создание системы оповещений о критических событиях:

# Установка Alertmanager
    cd /tmp
    wget https://github.com/prometheus/alertmanager/releases/download/v0.24.0/alertmanager-0.24.0.linux-amd64.tar.gz
    tar -xvf alertmanager-0.24.0.linux-amd64.tar.gz
    cd alertmanager-0.24.0.linux-amd64
    sudo cp alertmanager /usr/local/bin/
    sudo cp amtool /usr/local/bin/
    sudo useradd --no-create-home --shell /bin/false alertmanager
    sudo chown alertmanager:alertmanager /usr/local/bin/alertmanager
    sudo chown alertmanager:alertmanager /usr/local/bin/amtool
    sudo mkdir -p /etc/alertmanager
    sudo chown alertmanager:alertmanager /etc/alertmanager
    
    # Конфигурация Alertmanager
    sudo nano /etc/alertmanager/alertmanager.yml

Базовая конфигурация Alertmanager:

global:
      resolve_timeout: 5m
      smtp_from: 'alerts@example.com'
      smtp_smarthost: 'smtp.example.com:587'
      smtp_auth_username: 'alerts@example.com'
      smtp_auth_password: 'your-password'
      smtp_require_tls: true
    
    route:
      group_by: ['alertname', 'instance', 'severity']
      group_wait: 30s
      group_interval: 5m
      repeat_interval: 4h
      receiver: 'email-notifications'
    
    receivers:
      - name: 'email-notifications'
        email_configs:
          - to: 'admin@example.com'
            send_resolved: true

Создание systemd-сервиса для Alertmanager:

sudo nano /etc/systemd/system/alertmanager.service

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

[Unit]
    Description=Alertmanager
    Wants=network-online.target
    After=network-online.target
    
    [Service]
    User=alertmanager
    Group=alertmanager
    Type=simple
    ExecStart=/usr/local/bin/alertmanager \
      --config.file=/etc/alertmanager/alertmanager.yml \
      --storage.path=/var/lib/alertmanager
    
    [Install]
    WantedBy=multi-user.target

Запуск Alertmanager:

sudo systemctl daemon-reload
    sudo systemctl start alertmanager
    sudo systemctl enable alertmanager

10. Автоматизация обслуживания

Автоматизация рутинных задач позволяет экономить время и снижает риск человеческих ошибок. Рассмотрим автоматизацию основных процессов обслуживания LEMP-стека.

Автоматизация резервного копирования

Создадим скрипт для полного резервного копирования всех компонентов LEMP-стека:

# Создание скрипта для резервного копирования
    sudo nano /usr/local/bin/lemp-backup.sh

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

#!/bin/bash
    
    # Настройки
    BACKUP_DIR="/var/backups/lemp"
    MYSQL_USER="root"
    MYSQL_PASSWORD=""  # Если используется аутентификация через socket
    DATE=$(date +"%Y-%m-%d_%H-%M-%S")
    LOG_FILE="/var/log/lemp-backup.log"
    KEEP_DAYS=7  # Количество дней хранения резервных копий
    
    # Создание директории для резервных копий
    mkdir -p $BACKUP_DIR
    mkdir -p $BACKUP_DIR/databases
    mkdir -p $BACKUP_DIR/websites
    mkdir -p $BACKUP_DIR/config
    
    # Логирование начала процесса
    echo "$(date): Начало процесса резервного копирования" >> $LOG_FILE
    
    # Резервное копирование MySQL базы данных
    echo "$(date): Резервное копирование баз данных MySQL" >> $LOG_FILE
    databases=$(mysql -u $MYSQL_USER --skip-column-names -e "SHOW DATABASES;" | grep -v "information_schema" | grep -v "performance_schema" | grep -v "mysql" | grep -v "sys")
    
    for db in $databases; do
        echo "$(date): Копирование базы данных $db" >> $LOG_FILE
        mysqldump -u $MYSQL_USER --single-transaction --quick --lock-tables=false $db | gzip > $BACKUP_DIR/databases/$db-$DATE.sql.gz
        if [ $? -eq 0 ]; then
            echo "$(date): База данных $db успешно скопирована" >> $LOG_FILE
        else
            echo "$(date): Ошибка при копировании базы данных $db" >> $LOG_FILE
        fi
    done
    
    # Резервное копирование веб-сайтов
    echo "$(date): Резервное копирование веб-сайтов" >> $LOG_FILE
    for website_dir in /var/www/sites/*; do
        if [ -d "$website_dir" ]; then
            website_name=$(basename $website_dir)
            echo "$(date): Копирование сайта $website_name" >> $LOG_FILE
            tar -czf $BACKUP_DIR/websites/$website_name-$DATE.tar.gz -C /var/www/sites $website_name
            if [ $? -eq 0 ]; then
                echo "$(date): Сайт $website_name успешно скопирован" >> $LOG_FILE
            else
                echo "$(date): Ошибка при копировании сайта $website_name" >> $LOG_FILE
            fi
        fi
    done
    
    # Резервное копирование конфигурации
    echo "$(date): Резервное копирование конфигурационных файлов" >> $LOG_FILE
    tar -czf $BACKUP_DIR/config/nginx-config-$DATE.tar.gz /etc/nginx
    tar -czf $BACKUP_DIR/config/php-config-$DATE.tar.gz /etc/php
    tar -czf $BACKUP_DIR/config/mysql-config-$DATE.tar.gz /etc/mysql
    
    # Удаление старых резервных копий
    echo "$(date): Удаление устаревших резервных копий (старше $KEEP_DAYS дней)" >> $LOG_FILE
    find $BACKUP_DIR -type f -name "*.gz" -mtime +$KEEP_DAYS -delete
    
    # Установка прав доступа
    chown -R root:root $BACKUP_DIR
    chmod -R 600 $BACKUP_DIR
    
    echo "$(date): Процесс резервного копирования завершен" >> $LOG_FILE
    
    # Опционально: отправка уведомления о завершении
    # mail -s "LEMP Backup Completed on $(hostname)" your-email@example.com < $LOG_FILE

Настройка прав доступа и добавление задания в cron:

# Установка прав на исполнение
    sudo chmod +x /usr/local/bin/lemp-backup.sh
    
    # Добавление задания в cron для ежедневного резервного копирования в 2:00
    echo "0 2 * * * root /usr/local/bin/lemp-backup.sh" | sudo tee -a /etc/cron.d/lemp-backup

Автоматизация обновлений безопасности

Настроим автоматические обновления безопасности для системы:

# Установка пакета unattended-upgrades
    sudo apt install -y unattended-upgrades apt-listchanges
    
    # Настройка автоматических обновлений
    sudo nano /etc/apt/apt.conf.d/50unattended-upgrades

Основные настройки для автоматических обновлений:

Unattended-Upgrade::Allowed-Origins {
        "${distro_id}:${distro_codename}";
        "${distro_id}:${distro_codename}-security";
        "${distro_id}ESMApps:${distro_codename}-apps-security";
        "${distro_id}ESM:${distro_codename}-infra-security";
    };
    
    Unattended-Upgrade::Package-Blacklist {
    };
    
    Unattended-Upgrade::Automatic-Reboot "true";
    Unattended-Upgrade::Automatic-Reboot-Time "02:00";

Включение автоматических обновлений:

sudo nano /etc/apt/apt.conf.d/20auto-upgrades

Содержимое конфигурационного файла:

APT::Periodic::Update-Package-Lists "1";
    APT::Periodic::Download-Upgradeable-Packages "1";
    APT::Periodic::AutocleanInterval "7";
    APT::Periodic::Unattended-Upgrade "1";

Скрипт для проверки состояния LEMP-стека

Создадим скрипт для комплексной проверки работоспособности всего стека:

# Создание скрипта
    sudo nano /usr/local/bin/check-lemp-stack.sh

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

#!/bin/bash
    
    # Файл для логов
    LOG_FILE="/var/log/lemp-health-check.log"
    
    # Очистка лог-файла
    echo "LEMP Stack Health Check - $(date)" > $LOG_FILE
    echo "=====================================" >> $LOG_FILE
    echo "" >> $LOG_FILE
    
    # Проверка состояния Nginx
    echo "Проверка состояния Nginx:" >> $LOG_FILE
    if systemctl is-active --quiet nginx; then
        echo "✅ Nginx работает" >> $LOG_FILE
        nginx -v >> $LOG_FILE 2>&1
    else
        echo "❌ Nginx не запущен!" >> $LOG_FILE
    fi
    
    # Проверка синтаксиса конфигурации Nginx
    echo "" >> $LOG_FILE
    echo "Проверка конфигурации Nginx:" >> $LOG_FILE
    nginx -t >> $LOG_FILE 2>&1
    
    # Проверка состояния MySQL
    echo "" >> $LOG_FILE
    echo "Проверка состояния MySQL:" >> $LOG_FILE
    if systemctl is-active --quiet mysql; then
        echo "✅ MySQL работает" >> $LOG_FILE
        mysql --version >> $LOG_FILE 2>&1
    else
        echo "❌ MySQL не запущен!" >> $LOG_FILE
    fi
    
    # Проверка подключения к MySQL
    echo "" >> $LOG_FILE
    echo "Проверка соединения с MySQL:" >> $LOG_FILE
    if mysql -e "SELECT 1;" &>/dev/null; then 
    echo "✅ Соединение с MySQL успешно" >> $LOG_FILE
else
    echo "❌ Ошибка соединения с MySQL!" >> $LOG_FILE
fi

# Проверка состояния PHP-FPM
echo "" >> $LOG_FILE
echo "Проверка состояния PHP-FPM:" >> $LOG_FILE
if systemctl is-active --quiet php8.1-fpm; then
    echo "✅ PHP-FPM работает" >> $LOG_FILE
    php-fpm8.1 -v >> $LOG_FILE 2>&1
else
    echo "❌ PHP-FPM не запущен!" >> $LOG_FILE
fi

# Проверка доступности сокета PHP-FPM
echo "" >> $LOG_FILE
echo "Проверка сокета PHP-FPM:" >> $LOG_FILE
if [ -S /run/php-fpm/php-fpm.sock ]; then
    echo "✅ Сокет PHP-FPM доступен" >> $LOG_FILE
else
    echo "❌ Сокет PHP-FPM отсутствует!" >> $LOG_FILE
fi

# Проверка использования диска
echo "" >> $LOG_FILE
echo "Проверка использования диска:" >> $LOG_FILE
df -h / >> $LOG_FILE
DISK_USAGE=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//g')
if [ "$DISK_USAGE" -gt 90 ]; then
    echo "❌ Предупреждение! Использование диска превышает 90%" >> $LOG_FILE
else
    echo "✅ Использование диска в норме ($DISK_USAGE%)" >> $LOG_FILE
fi

# Проверка использования памяти
echo "" >> $LOG_FILE
echo "Проверка использования памяти:" >> $LOG_FILE
free -h >> $LOG_FILE
MEM_USAGE=$(free | awk 'NR==2 {print int($3*100/$2)}')
if [ "$MEM_USAGE" -gt 90 ]; then
    echo "❌ Предупреждение! Использование памяти превышает 90%" >> $LOG_FILE
else
    echo "✅ Использование памяти в норме ($MEM_USAGE%)" >> $LOG_FILE
fi

# Проверка загрузки системы
echo "" >> $LOG_FILE
echo "Проверка загрузки системы:" >> $LOG_FILE
uptime >> $LOG_FILE
LOAD=$(uptime | awk -F'[a-z]:' '{ print $2}' | awk -F',' '{print $1}' | tr -d ' ')
CORES=$(nproc)
LOAD_PER_CORE=$(echo "$LOAD / $CORES" | bc -l)
if (( $(echo "$LOAD_PER_CORE > 1.5" | bc -l) )); then
    echo "❌ Предупреждение! Высокая загрузка системы" >> $LOG_FILE
else
    echo "✅ Загрузка системы в норме" >> $LOG_FILE
fi

# Проверка виртуальных хостов Nginx
echo "" >> $LOG_FILE
echo "Проверка виртуальных хостов Nginx:" >> $LOG_FILE
for config in /etc/nginx/conf.d/*.conf; do
    if [ -f "$config" ]; then
        SERVER_NAME=$(grep -E '^\s*server_name' "$config" | head -1 | sed 's/server_name//g' | sed 's/;//g' | tr -d ' ' | cut -d' ' -f1)
        if [ ! -z "$SERVER_NAME" ]; then
            echo "  - $SERVER_NAME ($(basename $config))" >> $LOG_FILE
        fi
    fi
done

# Проверка SSL-сертификатов
echo "" >> $LOG_FILE
echo "Проверка SSL-сертификатов:" >> $LOG_FILE
for cert in /etc/letsencrypt/live/*/cert.pem; do
    if [ -f "$cert" ]; then
        DOMAIN=$(echo "$cert" | sed -E 's/.*live\/([^/]+)\/cert.pem/\1/')
        EXPIRY_DATE=$(openssl x509 -enddate -noout -in "$cert" | cut -d= -f2)
        EXPIRY_EPOCH=$(date -d "$EXPIRY_DATE" +%s)
        CURRENT_EPOCH=$(date +%s)
        DAYS_LEFT=$(( ($EXPIRY_EPOCH - $CURRENT_EPOCH) / 86400 ))
        
        if [ "$DAYS_LEFT" -lt 10 ]; then
            echo "❌ $DOMAIN: Сертификат истекает через $DAYS_LEFT дней ($EXPIRY_DATE)" >> $LOG_FILE
        else
            echo "✅ $DOMAIN: Сертификат действителен ($DAYS_LEFT дней до истечения)" >> $LOG_FILE
        fi
    fi
done

# Проверка сетевых соединений
echo "" >> $LOG_FILE
echo "Активные сетевые соединения:" >> $LOG_FILE
netstat -tulpn | grep -E '(nginx|mysql|php)' >> $LOG_FILE

# Сбор метрик производительности
echo "" >> $LOG_FILE
echo "Метрики производительности:" >> $LOG_FILE
echo "  - Nginx Active Connections: $(curl -s http://localhost/nginx_status 2>/dev/null | grep "Active connections" | awk '{print $3}' || echo "N/A")" >> $LOG_FILE
echo "  - PHP-FPM Active Processes: $(ps aux | grep php-fpm | grep -v master | grep -v grep | wc -l)" >> $LOG_FILE
echo "  - MySQL Active Connections: $(mysql -e "SHOW STATUS LIKE 'Threads_connected';" 2>/dev/null | tail -1 | awk '{print $2}' || echo "N/A")" >> $LOG_FILE

# Отправка отчета на email (опционально)
#mail -s "LEMP Health Check Report - $(hostname) - $(date +"%Y-%m-%d")" your-email@example.com < $LOG_FILE

# Вывод пути к файлу отчета
echo "" >> $LOG_FILE
echo "Отчет сохранен в $LOG_FILE"
echo "Отчет сохранен в $LOG_FILE"

Настройка прав доступа и добавление в cron:

# Установка прав на исполнение
sudo chmod +x /usr/local/bin/check-lemp-stack.sh

# Добавление задания в cron для ежедневной проверки в 8:00
echo "0 8 * * * root /usr/local/bin/check-lemp-stack.sh" | sudo tee -a /etc/cron.d/lemp-health-check

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

Создадим скрипт для автоматического развертывания проектов на базе LEMP-стека:

# Создание скрипта
sudo nano /usr/local/bin/deploy-project.sh

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

#!/bin/bash

# Проверка аргументов
if [ "$#" -lt 3 ]; then
    echo "Использование: $0   "
    echo "Поддерживаемые типы проектов: wordpress, laravel, php-static"
    exit 1
fi

DOMAIN=$1
PROJECT_TYPE=$2
GIT_REPO=$3
WWW_DIR="/var/www/sites/$DOMAIN"
WWW_PUBLIC="$WWW_DIR/public"
LOG_FILE="/var/log/project-deploy-$DOMAIN.log"

# Запись начала процесса
echo "Начало развертывания проекта $DOMAIN ($(date))" > $LOG_FILE

# Создание директории для проекта
echo "Создание директории проекта..." >> $LOG_FILE
sudo mkdir -p $WWW_DIR
sudo mkdir -p $WWW_PUBLIC
sudo mkdir -p $WWW_DIR/logs
sudo mkdir -p $WWW_DIR/backup

# Клонирование репозитория
echo "Клонирование репозитория $GIT_REPO..." >> $LOG_FILE
git clone $GIT_REPO $WWW_PUBLIC 2>> $LOG_FILE

# Настройка прав доступа
echo "Настройка прав доступа..." >> $LOG_FILE
sudo chown -R nginx:nginx $WWW_DIR
sudo chmod -R 755 $WWW_DIR

# Создание виртуального хоста
echo "Создание виртуального хоста..." >> $LOG_FILE
sudo create-vhost.sh $DOMAIN

# Настройка в зависимости от типа проекта
case $PROJECT_TYPE in
    wordpress)
        echo "Настройка WordPress..." >> $LOG_FILE
        
        # Создание базы данных и пользователя
        DB_NAME=$(echo ${DOMAIN/./_} | sed 's/-/_/g')
        DB_USER=$(echo ${DOMAIN/./_} | sed 's/-/_/g' | cut -c 1-12)
        DB_PASS=$(openssl rand -base64 12 | tr -d "=+/")
        
        echo "Создание базы данных $DB_NAME и пользователя $DB_USER..." >> $LOG_FILE
        mysql -e "CREATE DATABASE IF NOT EXISTS $DB_NAME CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
        mysql -e "CREATE USER IF NOT EXISTS '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
        mysql -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost';"
        mysql -e "FLUSH PRIVILEGES;"
        
        # Создание wp-config.php
        cd $WWW_PUBLIC
        if [ -f wp-config-sample.php ]; then
            cp wp-config-sample.php wp-config.php
            sed -i "s/database_name_here/$DB_NAME/" wp-config.php
            sed -i "s/username_here/$DB_USER/" wp-config.php
            sed -i "s/password_here/$DB_PASS/" wp-config.php
            
            # Генерация ключей безопасности
            for i in $(seq 1 8); do
                key=$(openssl rand -base64 48 | tr -d "=+/" | cut -c 1-64)
                sed -i "/AUTH_KEY/,/NONCE_SALT/ s/'put your unique phrase here'/'$key'/1" wp-config.php
            done
            
            # Настройка дополнительных параметров
            echo "/** Настройки для повышения безопасности */" >> wp-config.php
            echo "define('DISALLOW_FILE_EDIT', true);" >> wp-config.php
            echo "define('WP_AUTO_UPDATE_CORE', true);" >> wp-config.php
            echo "define('WP_POST_REVISIONS', 5);" >> wp-config.php
        else
            echo "ОШИБКА: Файл wp-config-sample.php не найден. Возможно, это не проект WordPress." >> $LOG_FILE
        fi
        ;;
        
    laravel)
        echo "Настройка Laravel..." >> $LOG_FILE
        
        # Создание базы данных и пользователя
        DB_NAME=$(echo ${DOMAIN/./_} | sed 's/-/_/g')
        DB_USER=$(echo ${DOMAIN/./_} | sed 's/-/_/g' | cut -c 1-12)
        DB_PASS=$(openssl rand -base64 12 | tr -d "=+/")
        
        echo "Создание базы данных $DB_NAME и пользователя $DB_USER..." >> $LOG_FILE
        mysql -e "CREATE DATABASE IF NOT EXISTS $DB_NAME CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
        mysql -e "CREATE USER IF NOT EXISTS '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
        mysql -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost';"
        mysql -e "FLUSH PRIVILEGES;"
        
        # Настройка Laravel
        cd $WWW_PUBLIC
        cp .env.example .env
        sed -i "s/DB_DATABASE=laravel/DB_DATABASE=$DB_NAME/" .env
        sed -i "s/DB_USERNAME=root/DB_USERNAME=$DB_USER/" .env
        sed -i "s/DB_PASSWORD=/DB_PASSWORD=$DB_PASS/" .env
        
        # Установка зависимостей и настройка приложения
        composer install --no-interaction --no-dev --optimize-autoloader
        php artisan key:generate
        php artisan storage:link
        php artisan config:cache
        php artisan route:cache
        php artisan view:cache
        
        # Миграция базы данных
        php artisan migrate --force
        
        # Настройка прав доступа для Laravel
        sudo chown -R nginx:nginx $WWW_DIR/storage
        sudo chown -R nginx:nginx $WWW_DIR/bootstrap/cache
        ;;
        
    php-static)
        echo "Настройка статического PHP проекта..." >> $LOG_FILE
        # Для статических сайтов дополнительная настройка не требуется
        ;;
        
    *)
        echo "ОШИБКА: Неизвестный тип проекта: $PROJECT_TYPE" >> $LOG_FILE
        exit 1
        ;;
esac

# Запись информации о проекте
echo "Сохранение информации о проекте..." >> $LOG_FILE
cat > $WWW_DIR/project-info.txt << EOF
Домен: $DOMAIN
Тип проекта: $PROJECT_TYPE
Репозиторий: $GIT_REPO
Дата развертывания: $(date)
EOF

if [ $PROJECT_TYPE == "wordpress" ] || [ $PROJECT_TYPE == "laravel" ]; then
    cat >> $WWW_DIR/project-info.txt << EOF
База данных: $DB_NAME
Пользователь БД: $DB_USER
Пароль БД: $DB_PASS
EOF
fi

# Защита файла с информацией
sudo chmod 600 $WWW_DIR/project-info.txt
sudo chown root:root $WWW_DIR/project-info.txt

echo "Проект успешно развернут!" >> $LOG_FILE
echo ""
echo "Проект $DOMAIN успешно развернут!"
echo "Тип проекта: $PROJECT_TYPE"
echo "Информация о проекте сохранена в $WWW_DIR/project-info.txt"
echo "Лог установки: $LOG_FILE"

Установка прав на исполнение:

sudo chmod +x /usr/local/bin/deploy-project.sh

Совет

Использование скрипта очень простое:

sudo deploy-project.sh example.com wordpress https://github.com/username/wordpress-project.git

Скрипт автоматически создаст виртуальный хост, базу данных, настроит права доступа и выполнит базовую настройку проекта в зависимости от его типа.

Заключение

Настройка и оптимизация LEMP-стека для production-среды — это многогранный процесс, который требует внимания ко множеству аспектов от безопасности до производительности. В этой статье мы прошли полный путь от чистой установки Linux до полностью настроенного стека, готового для размещения высоконагруженных веб-приложений.

Мы рассмотрели:

  1. Подготовку сервера — базовую настройку безопасности системы
  2. Установку и оптимизацию Nginx — настройку веб-сервера для максимальной производительности
  3. Настройку MySQL — оптимизацию базы данных и обеспечение ее безопасности
  4. Установку PHP-FPM — настройку интерпретатора PHP для эффективной работы с Nginx
  5. Настройку SSL/TLS — защиту передаваемых данных с помощью шифрования
  6. Настройку виртуальных хостов — организацию размещения нескольких сайтов на одном сервере
  7. Оптимизацию производительности — повышение скорости работы всех компонентов стека
  8. Повышение безопасности — защиту от распространенных угроз и атак
  9. Мониторинг и логирование — отслеживание работы системы и выявление проблем
  10. Автоматизацию обслуживания — минимизацию рутинных операций с помощью скриптов

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

Основные принципы работы с production-средой

Документирование — ведите подробную документацию по всем настройкам и изменениям
Тестирование — проверяйте изменения в тестовой среде перед применением в production
Мониторинг — отслеживайте все аспекты работы системы в режиме реального времени
Резервное копирование — обеспечьте надежное резервное копирование и проверяйте возможность восстановления
Автоматизация — минимизируйте ручные операции для уменьшения риска ошибок

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

Заключительный совет

Сохраните все скрипты и команды из этого руководства в личном репозитории. Это позволит вам быстро восстановить настроенную среду в случае необходимости или развернуть аналогичную конфигурацию на новых серверах. В идеале перейдите к полностью автоматизированному развертыванию инфраструктуры с помощью таких инструментов, как Ansible, Chef или Terraform.

Похожие статьи

Прочитать статью о безопасности MySQL

Безопасность и аудит баз данных MySQL

28 января 2025 Читать →
Прочитать статью о методах отладки Linux-серверов

Методы отладки Linux-серверов: от простого к сложному

1 февраля 2025 Читать →

Масштабирование веб-приложений на LEMP-стеке

15 февраля 2025 Скоро →

Комментарии

Оставить комментарий

3 комментария

М

Максим Орлов

27 января 2025

Потрясающая статья! Я уже давно занимаюсь администрированием веб-серверов, но нашел здесь множество полезных советов, о которых раньше не задумывался. Особенно понравился раздел по автоматизации - скрипты очень удобные и практичные.

E

Elena Martinez

28 января 2025

Спасибо за подробное руководство! Только что настроила production-сервер по вашей инструкции. Всё работает просто отлично! Теперь чувствую себя намного увереннее с настройкой LEMP-стека. Особенно полезен раздел по мониторингу – Grafana и Prometheus дают отличную визуализацию происходящего на сервере.

А

Александр Иванов

30 января 2025

Статья очень помогла мне при миграции с Apache на Nginx. Интересно, планируете ли вы написать продолжение о том, как интегрировать Docker в эту инфраструктуру? Было бы здорово узнать, как лучше настраивать контейнеры для такого стека. А еще хорошо бы охватить тему балансировки нагрузки и масштабирования.