Блог / Статьи

Полезная информация для вашего хостинга

Как автоматизировать настройку WordPress в Nginx через include: полное руководство для хостинг-админов

Как автоматизировать настройку WordPress в Nginx через include: полное руководство для хостинг-админов

Представьте: вы — администратор хостинга. На вашем сервере работают 87 WordPress-сайтов. Каждый из них — от блога пенсионера до корпоративного портала с тысячами посетителей в час. Каждый требует одинаковых настроек: обработка PHP, роутинг ЧПУ, защита от сканирования .env, блокировка PHP в uploads. Вы копировали эти блоки десятки раз. Каждый раз. Потому что «так всегда делали». Пока однажды не поняли: вы не управляете сервером. Вы — его раб.

Однажды вы решили обновить PHP с 8.2 до 8.3. Или поменяли сокет FPM. Или добавили заголовок XSS-защиты. Что произошло? Вы открыли 87 файлов в редакторе. Проверили каждый. Сверяли с предыдущей версией. Потеряли 6 часов. И в одном из сайтов забыли заменить строку. И вот он — сайт-призрак: белый экран, 500 ошибка, клиент в ярости. А вы? Вы уже не помните, где именно вы ошиблись. Потому что дублирование — это не экономия времени. Это инструмент самоуничтожения.

Но есть другой путь. Путь, которым пользуются крупнейшие хостинг-провайдеры, SaaS-платформы и корпоративные инфраструктуры. Путь, где одно изменение применяется ко всем сайтам за 3 секунды. Где новый сайт поднимается за 5 минут, а не за 3 дня. Где вы спите спокойно, зная, что даже если вы забыли что-то — ваш шаблон не забыл.

Этот путь называется include в Nginx. И сегодня мы разберём его так, как никто ещё не разбирал. Не как сухую инструкцию. А как архитектурный шедевр, который превращает хаос в порядок, а рутину — в искусство управления.

Директива include: не просто копирование, а интеллектуальное наследование конфигурации

Многие думают, что include — это просто «вставить текст из другого файла». Это ошибочное представление. include — это механизм наследования конфигурационных правил на уровне процесса загрузки Nginx. Когда сервер стартует, он не просто читает nginx.conf. Он выполняет его, как скрипт. И каждая директива include — это точка, где Nginx временно «переключает контекст»: он открывает указанный файл, читает его содержимое, парсит его как часть основного конфига — и только после этого возвращается к исходному файлу.

Это значит: если в вашем wordpress-common.conf есть блок location ~ \.php$, то после include этот блок становится неотъемлемой частью конфига виртуального хоста. Он обладает теми же приоритетами, теми же правилами совпадения, теми же ограничениями, что и если бы вы написали его прямо в site1.conf. Никаких «внешних» правил. Никаких «дополнительных» слоёв. Только чистая, прозрачная, предсказуемая инъекция.

Зачем это нужно?

  • DRY-принцип в действии: Не пишите одно и то же 87 раз. Напишите один раз — и используйте везде. Это не просто удобство. Это гарантия консистентности. Если вы внесли исправление в защиту от path traversal — оно применится ко всем сайтам. Без исключений.
  • Модульность как стратегия: Вы не обязаны хранить всё в одном файле. Создайте wordpress-security.conf — для защиты от брутфорса и SQL-инъекций. wordpress-cache.conf — для кеширования статики. wordpress-ssl.conf — для настройки HSTS и OCSP stapling. И комбинируйте их как конструктор: для одного сайта — только базовый + безопасный, для другого — базовый + кеширующий + SSL. Всё это — одна строка в каждом конфиге.
  • Централизованный контроль безопасности: Представьте, что обнаружена уязвимость в FastCGI: нужно добавить fastcgi_param HTTP_X_FORWARDED_PROTO $scheme; для корректной работы SSL-прокси. Без include — 87 правок. С ним — одна. И вы можете внедрить исправление за 2 минуты, пока клиенты даже не заметят, что что-то изменилось.

Важно: include работает рекурсивно. Если file1.conf включает file2.conf, а file2.conf включает file3.conf — Nginx прочитает их все в порядке вложенности. Но если file1 включает file2, а file2 включает file1 — вы получите циклическую зависимость и Nginx не запустится. Проверяйте структуру!

Путь к файлам — абсолютный. Не пишите include wordpress-common.conf;. Пишите include /etc/nginx/wordpress-templates/wordpress-common.conf;. Почему? Потому что Nginx может быть запущен из любого рабочего каталога. А ваш скрипт деплоя — из /root. И если вы используете относительный путь — вы рискуете, что в один прекрасный день Nginx не найдёт файл и начнёт отдавать 404 всем сайтам. Не рискуйте. Пишите пути как в файловой системе Linux.

wpnginx05

Шаблон wordpress-common.conf: фундамент, на котором держится ваша инфраструктура

Теперь — к делу. Создадим файл /etc/nginx/wordpress-templates/wordpress-common.conf. Это не просто набор директив. Это архитектурный документ, который определяет, как WordPress будет работать на вашем сервере. Каждая строка здесь — это защита, производительность, надёжность. Мы разберём её по частям, как хирург — по органам.


# =============================================
# БАЗОВЫЕ ПАРАМЕТРЫ ИНДЕКСАЦИИ (ПРИОРИТЕТ ПОДКЛЮЧЕНИЯ)
# =============================================
index index.php index.html index.htm;

# =============================================
# ОСНОВНОЙ РОУТИНГ: ПАТТЕРН FRONT CONTROLLER
# =============================================
location / {
    # Проверяем: существует ли запрошенный файл?
    # Если нет — проверяем, существует ли директория?
    # Если нет — передаём запрос index.php с аргументами
    # Это — ядро ЧПУ WordPress. Без этого — 404 на всех страницах.
    try_files $uri $uri/ /index.php?$args;
}

# =============================================
# ОБРАБОТКА PHP-ЗАПРОСОВ: ПРОЧИТАЙТЕ ЭТО ВНИМАТЕЛЬНО
# =============================================
location ~ \.php$ {
    # КРИТИЧНАЯ НАСТРОЙКА: СОКЕТ PHP-FPM ДОЛЖЕН СООТВЕТСТВОВАТЬ ВЕРСИИ!
    fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;

    # Указываем, что основной файл — index.php
    fastcgi_index index.php;

    # Подключаем стандартные параметры FastCGI от Nginx
    include fastcgi_params;

    # ОБЯЗАТЕЛЬНО: корректное определение пути к скрипту
    # Без этого — 403 или выполнение скриптов из неправильных путей
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

    # КЛЮЧЕВАЯ ЗАЩИТА: разбиваем путь на скрипт и дополнительный путь
    # Предотвращает path traversal: /wp-content/plugins/evil.php/../../../etc/passwd
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;

    # БЛОКИРОВКА НЕСУЩЕСТВУЮЩИХ СКРИПТОВ: предотвращает атаки через поддельные URI
    # Например: /index.php/../../../bin/bash
    if (!-f $document_root$fastcgi_script_name) {
        return 404;
    }
}

# =============================================
# ЗАПРЕТ ДОСТУПА К СКРЫТЫМ ФАЙЛАМ: .htaccess, .env, .git
# =============================================
location ~ /\. {
    # Запрещаем доступ ко всем файлам и директориям, начинающимся с точки
    deny all;

    # Отключаем логирование этих попыток — снижаем нагрузку на диск
    access_log off;
    log_not_found off;
}

# =============================================
# БЛОКИРОВКА ВЫПОЛНЕНИЯ PHP В ПАПКАХ UPLOADS И FILES
# =============================================
location ~* /(?:uploads|files)/.*\.php$ {
    # Директории uploads и files часто имеют права на запись
    # Именно туда закачивают вредоносные скрипты
    # Мы не просто запрещаем — мы полностью блокируем исполнение
    deny all;
}

Глубокий разбор критических блоков

1. try_files $uri $uri/ /index.php?$args;
Это — сердце WordPress. Без него сайт превращается в статический сайт. $uri — запрошенный путь (например, /about). Nginx проверяет: есть ли такой файл? Нет. Есть ли директория? Нет. Тогда — передаём запрос /index.php с аргументами $args (например, ?p=123). Это реализует паттерн Front Controller: все запросы проходят через единую точку входа — index.php. Именно WordPress обрабатывает ЧПУ, редиректы, SEO-страницы. Без этого — всё сломается.

2. fastcgi_split_path_info ^(.+?\.php)(/.*)$;
Это — защита от path traversal. Без неё злоумышленник может отправить запрос вида /wp-content/plugins/evil.php/../../../etc/passwd. Nginx без этого правила может попытаться выполнить evil.php как скрипт, но с путём /etc/passwd как параметром. Это приведёт к утечке данных. fastcgi_split_path_info разбивает строку на две части: script.php и /../../../etc/passwd. WordPress получает только первую часть — и игнорирует вторую. Безопасность на уровне протокола.

3. if (!-f $document_root$fastcgi_script_name) { return 404; }
Это — последний рубеж. Представьте, что атакующий отправляет запрос /wp-login.php/../../../bin/bash. Даже если fastcgi_split_path_info сработал, Nginx может попытаться выполнить /bin/bash как PHP-скрипт — если он не проверит его существование. Этот блок проверяет физическое наличие файла на диске. Если его нет — сразу 404. Никаких попыток выполнения. Никаких логов. Никаких ошибок. Только тишина.

4. location ~ /\. { deny all; }
~\. — это регулярное выражение, означающее «любой символ, за которым следует точка». То есть: .htaccess, .env, .git, .user.ini. Эти файлы содержат логины, ключи API, пароли баз данных. Доступ к ним — полный компромет сервера. Запрет — это не опция. Это обязательное условие безопасности.

5. location ~* /(?:uploads|files)/.*\.php$
~* — регистронезависимое регулярное выражение. (?:uploads|files) — незахватывающая группа. То есть: любая директория, называющаяся uploads или files (в любом регистре!), и любой файл с расширением .php внутри. Это — стандартная точка входа для веб-шеллов. Многие вредоносные скрипты загружаются именно сюда. Мы их не удаляем — мы их не даём исполняться. Лучшая защита — это не обнаружение, а невозможность запуска.

ВАЖНО: ТЕСТИРУЙТЕ ВСЕГДА!
Перед перезагрузкой Nginx — ВСЕГДА проверяйте синтаксис:

sudo nginx -t -c /etc/nginx/nginx.conf

Если вы видите test is successful — вы в безопасности. Если нет — не перезагружайте сервер. Исправьте ошибку. Иначе — все сайты упадут.

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

Теперь — самое красивое. Вы создали шаблон. Теперь — как его использовать?

Ваш конфиг виртуального хоста /etc/nginx/sites-available/example.ru должен выглядеть так:

server {
    listen 80;
    listen [::]:80;
    
    # УНИКАЛЬНЫЕ ПАРАМЕТРЫ — ТОЛЬКО ЗДЕСЬ
    server_name example.ru www.example.ru;
    root /var/www/example.ru/public_html;
    
    # ВАЖНО: КАСТОМНЫЕ LOCATION ДО include!
    location /wp-admin {
        auth_basic "Admin Area";
        auth_basic_user_file /etc/nginx/.htpasswd;
        
        # Дополнительные ограничения по IP
        allow 192.168.1.100;
        deny all;
    }
    
    # КЛЮЧЕВАЯ СТРОКА: ПОДКЛЮЧЕНИЕ ШАБЛОНА
    include /etc/nginx/wordpress-templates/wordpress-common.conf;
    
    # ДОПОЛНИТЕЛЬНЫЕ НАСТРОЙКИ ПОСЛЕ include (если нужны)
    # Например: логи для этого сайта
    access_log /var/log/nginx/example.ru-access.log combined;
    error_log /var/log/nginx/example.ru-error.log warn;
}

Ключевые принципы интеграции

1. Порядок имеет значение — и это критично
Nginx обрабатывает location-блоки по приоритету:

  1. Точное совпадение: location = /
  2. Префиксный с модификатором ^~: location ^~ /images/
  3. Регулярные выражения: location ~ \.php$
  4. Префиксный без модификатора: location /

Ваш include вставляет регулярные выражения и префиксы. Поэтому все кастомные location-блоки, которые вы хотите сохранить — ДОЛЖНЫ БЫТЬ ПЕРЕД include! Если вы напишете:

include /etc/nginx/wordpress-templates/wordpress-common.conf;
location /wp-admin { ... }

— то ваш /wp-admin будет проигнорирован, потому что в шаблоне уже есть location /, который имеет более низкий приоритет, чем регулярные выражения. Но если в шаблоне есть location ~ \.php$ — он будет переопределён только если вы объявите более точное регулярное выражение до include.

2. Как переопределить правило из шаблона?
Допустим, на одном сайте вы хотите использовать PHP 8.2 вместо 8.3. Вы не можете просто изменить fastcgi_pass в шаблоне — это сломает все остальные сайты. Что делать?

Создайте новый location с более высоким приоритетом — но перед include:

server {
    listen 80;
    server_name legacy-site.ru;
    root /var/www/legacy-site.ru/public_html;
    
    # ПЕРЕОПРЕДЕЛЕНИЕ: СПЕЦИАЛЬНЫЙ СОКЕТ ДЛЯ PHP 8.2
    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        if (!-f $document_root$fastcgi_script_name) {
            return 404;
        }
    }
    
    # ТЕПЕРЬ МОЖНО ВКЛЮЧИТЬ ШАБЛОН — ОН НЕ ПЕРЕОПРЕДЕЛИТ НАШ БЛОК!
    include /etc/nginx/wordpress-templates/wordpress-common.conf;
}

Почему это работает? Потому что два location-блока с одинаковым типом (регулярное выражение) — конфликтуют. Nginx выбирает тот, который объявлен первым. Мы объявляем свой блок до include — и он «перекрывает» тот, что приходит из шаблона.

3. Как проверить, что всё подключилось правильно?
Используйте команду:

sudo nginx -T | grep -A 50 "server_name example.ru"

Эта команда выводит итоговый конфиг после всех include. Вы увидите, как ваш шаблон «вплетается» в конфиг. Вы увидите, какие location-блоки действительно работают. Это — ваша «диагностика» перед перезагрузкой. Используйте её как ритуал перед каждым деплоем.

Защита шаблона: как сделать ваш wordpress-common.conf неприкосновенным

Вы создали шаблон. Он работает. Он прекрасен. И теперь он — самый важный файл на вашем сервере. Потому что если он сломается — сломаются все сайты. Это не просто конфиг. Это ядро вашей инфраструктуры.

1. Ограничьте доступ на чтение и запись

sudo chown root:root /etc/nginx/wordpress-templates/wordpress-common.conf
sudo chmod 644 /etc/nginx/wordpress-templates/wordpress-common.conf

Это означает: только root может изменить файл. Все остальные — только читать. Даже если злоумышленник получит доступ к веб-интерфейсу или FTP-аккаунту — он не сможет изменить ваш шаблон.

2. Используйте Git как систему контроля версий
Вы не можете просто «сделать бэкап». Вам нужна история изменений. Кто, когда, зачем внес изменения? Почему вчера добавили заголовок? Почему убрали кеширование для одного сайта?

Инициализируйте репозиторий в директории /etc/nginx:


cd /etc/nginx
sudo git init
sudo git config --local user.email "Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript."
sudo git config --local user.name "Server Admin"
sudo git add .
sudo git commit -m "INIT: Base Nginx config with WordPress templates"

# После каждого изменения:
sudo git add .
sudo git commit -a -m "FIX: Added X-Frame-Options header to wordpress-common.conf"
Теперь вы можете:
  • Откатиться на предыдущую версию одним git checkout HEAD~1
  • Сравнить изменения между версиями: git diff HEAD~1 HEAD
  • Создать ветку для тестирования новых правил: git checkout -b feature/xss-protection

Это — стандарт промышленного DevOps. И это делает вас не админом, а архитектором.

3. Создайте скрипт проверки перед перезагрузкой
Создайте файл /usr/local/bin/check-nginx.sh:

#!/bin/bash
echo "🔍 Проверка конфигурации Nginx..."
if sudo nginx -t -c /etc/nginx/nginx.conf; then
    echo "✅ Конфигурация корректна. Можно перезагружать."
    exit 0
else
    echo "❌ ОШИБКА В КОНФИГУРАЦИИ! НЕ ПЕРЕЗАГРУЖАТЬ!"
    exit 1
fi

Сделайте его исполняемым:

sudo chmod +x /usr/local/bin/check-nginx.sh

Теперь перед любой перезагрузкой — вы запускаете check-nginx.sh. И если он выдаёт ошибку — вы не трогаете сервер. Это — ваша последняя линия обороны.

wpnginx02

Оптимизация шаблона: как превратить Nginx в гиперскоростной двигатель

Безопасность — это основа. Оптимизация — это мощность. И шаблон wordpress-common.conf — идеальное место для внедрения производительностных настроек, которые работают на всех сайтах.

1. Кеширование статики: снизьте нагрузку на сервер на 70%

Добавьте в ваш шаблон этот блок — и вы забудете, что такое «высокая нагрузка на диск»:

# =============================================
# КЕШИРОВАНИЕ СТАТИКИ: CSS, JS, IMG, FONTS
# =============================================
location ~* \.(?:css|js|jpg|jpeg|gif|png|ico|webp|woff2|svg|eot|ttf)$ {
    expires 30d;  # Браузер кеширует 30 дней
    add_header Cache-Control "public, immutable, max-age=2592000";
    access_log off;  # Отключаем логи — экономим диск
    tcp_nodelay off; # Улучшает передачу больших файлов
    # Дополнительно: включаем Gzip для статики (если не включён глобально)
    gzip on;
    gzip_vary on;
}

Почему это работает? Потому что браузеры больше не запрашивают ваши 2 МБ CSS-файлы каждый раз. Они кешируют их. Это снижает нагрузку на Nginx, на сеть, на CPU. Это — экономия 10–30% трафика и 50–70% I/O операций.

2. Gzip-сжатие текстового контента

Добавьте в nginx.conf (в блок http) или в ваш шаблон (если он включается в http-контекст):

gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_types
    text/plain
    text/css
    application/json
    application/javascript
    text/xml
    application/xml
    application/rss+xml
    application/atom+xml
    image/svg+xml
    text/html
    application/xhtml+xml;

Это сжимает HTML, CSS, JS, JSON — на 70–80%. Браузеры получают файлы быстрее. SEO-скорость растёт. А ваш сервер — дышит.

3. Оптимизация FastCGI: ускорьте обработку PHP в 2–3 раза

Добавьте в блок location ~ \.php$ следующие параметры:

fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 60s;
fastcgi_read_timeout 60s;

Почему это важно? PHP-FPM отвечает не мгновенно. Если клиент медленно загружает данные — Nginx ждёт. Если ответ от FPM большой — он не помещается в буфер. Эти параметры:

  • fastcgi_buffers — сколько буферов выделять (16 буферов по 16 КБ = 256 КБ)
  • fastcgi_buffer_size — размер первого буфера для заголовков (32 КБ — достаточно для WordPress)
  • fastcgi_busy_buffers_size — сколько буферов можно использовать для отправки ответа клиенту

Без этих настроек — Nginx начинает писать временные файлы на диск. Это — смерть для производительности. С ними — всё в памяти. Быстро. Чисто. Надёжно.

4. Дополнительно: защита от DDoS и брутфорса

Добавьте в шаблон (в блок server, до include):

# Ограничение частоты запросов
limit_req_zone $binary_remote_addr zone=wp_login:10m rate=10r/m;
limit_req_zone $binary_remote_addr zone=general:20m rate=30r/s;

# Применяем к wp-login.php
location = /wp-login.php {
    limit_req zone=wp_login burst=20 nodelay;
    include /etc/nginx/wordpress-templates/wordpress-common.conf;
}

Это ограничивает попытки входа в админку: максимум 10 запросов в минуту. При превышении — 503. Это — мощная защита от брутфорса. И это — общее правило. Применяется ко всем сайтам.

Что НЕЛЬЗЯ делать в шаблоне: табу, которые разрушат вашу инфраструктуру

Несмотря на то, что шаблон — это универсальное решение, есть абсолютные табу. Их нарушение — прямой путь к катастрофе.

  • Никогда не вставляйте секреты: SSL-ключи, пароли баз данных, API-ключи, токены. Их нужно хранить в отдельных файлах, доступных только root, и подключать через include /etc/nginx/secrets/ssl.conf; или через переменные окружения.
  • Никогда не используйте переменные в шаблоне, которые должны быть уникальными: set $root_path /var/www/site1; — это ошибка. Каждый сайт имеет свой root. Это — должно быть в виртуальном хосте.
  • Никогда не включайте блоки, не относящиеся к WordPress: не вставляйте настройки для WooCommerce, не вставляйте правила для WooCommerce REST API — если они не универсальны. Специфика — в отдельных файлах.
  • Никогда не меняйте шаблон без тестирования. Даже если вы «просто добавили один заголовок». Всегда: nginx -tcheck-nginx.shgit commitreload.

wpnginx03

Заключение: от хаоса к архитектуре — ваш путь к свободе

Вы больше не админ, который копирует конфиги. Вы — архитектор. Вы создали систему, где одно изменение применяется ко всем. Где новый сайт поднимается за 5 минут. Где вы спите спокойно, зная, что даже если вы забыли что-то — ваш шаблон не забыл. Где вы можете обновить PHP, добавить защиту от новых уязвимостей, улучшить кеширование — и сделать это за 10 минут, а не за 3 дня.

Это — не «хитрость». Это — стандарт профессионалов. Это — то, что делает разницу между «я управляю сервером» и «я управляю инфраструктурой».

Ваш шаблон — это не файл. Это — ваша философия управления. И она работает. Потому что она проста. Потому что она надёжна. Потому что она — автоматизирована.

Сегодня вы не просто настроили Nginx. Вы создали систему, которая будет работать годами. Без вас. Без ошибок. Без паники.

Теперь — возьмите свой первый сайт. Удалите все дублированные блоки. Подключите шаблон. Проверьте. Перезагрузите. И почувствуйте — как тяжесть снимается с ваших плеч.

Вы больше не раб. Вы — архитектор.