Один файл вместо сотни правок: рассказываем, как упростить управление множеством WordPress-сайтов на Nginx с помощью директивы include. В статье — создание базового шаблона конфига и интеграция с виртуальным хостом.
Введение
Управление множеством WordPress-сайтов на Nginx часто превращается в кошмар. Представьте сервер с виртуальными хостами — несколькими, десятками или даже сотнями, — где каждый конфиг содержит идентичные блоки настроек: обработку PHP через FastCGI, правила роутинга для ЧПУ, защиту скрытых файлов и базовые параметры индексации. Изначально копирование этих секций кажется безобидным, но любое изменение требует ручной правки всех файлов.
При этом вероятность опечатки или пропущенного конфига растёт пропорционально количеству сайтов. Со временем конфиги начинают отличаться друг от друга всё больше: в одних файлах остались устаревшие параметры, а в других — уже новые. И главное, это огромные трудозатраты: простое изменение одного параметра (например, fastcgi_pass при переходе с PHP 8.2 на 8.3) превращается в многочасовой «поиск и замену».
Однако вместо дублирования блоков кода можно создать единый шаблон /etc/nginx/wordpress-common.conf, содержащий универсальные настройки, и подключать его в виртуальных хостах директивой include — так изменения в шаблоне автоматически применятся ко всем сайтам. Для продакшена это означает:
- правки на всех сайтах выполняются за минуты вместо часов;
- все сайты работают на идентичных настройках;
- новый сайт добавляется в три строки: server_name, root и include;
- и 50, и 500 сайтов требуют одинаковых усилий.
Как работает include в Nginx
Директива include в Nginx — это полноценная инъекция содержимого одного файла в другой на этапе загрузки конфигурации. Когда Nginx парсит конфиги, он фактически подставляет содержимое включаемого файла на место директивы include. Это происходит до применения любых других правил обработки, что делает механизм предсказуемым и стабильным.
Зачем это нужно в продакшене:
- Принцип DRY (Don't Repeat Yourself, не повторяйся). Вместо дублирования одних и тех же блоков (обработки PHP, настройки статики и т. д.) в каждом виртуальном хосте, мы выносим их в отдельный файл. Это особенно важно при массовом хостинге: например, нужно изменить параметр fastcgi_read_timeout для 100+ сайтов, и без include придётся править каждый конфиг вручную, а с ним — только один шаблон.
- Гибкость конфигурации. Можно создавать специализированные шаблоны под разные задачи:
- wordpress-common.conf — базовая обработка PHP и маршрутизация;
- wordpress-security.conf — защита от подбора паролей и SQL-инъекций;
- wordpress-cache.conf — настройки кеширования.
Затем комбинировать их в нужных сочетаниях для конкретных сайтов.
- Безопасность и контроль. Централизованное хранение критичных правил (например, запрет доступа к .env) снижает риск ошибок. Если обнаруживается уязвимость в конфигурации (допустим, нужно экранировать $ в FastCGI-параметрах), исправление в одном файле обновит все сайты.
Рекомендуемая организация конфигов для WordPress:
/etc/nginx/
├── sites-available/ # Индивидуальные конфиги хостов
│ └── site1.conf # Основные параметры сайта (server_name, root)
├── wordpress-templates/ # Общие шаблоны
│ ├── wordpress-common.conf # Базовая обработка запросов
│ ├── wordpress-security.conf # Защита от эксплойтов
│ └── wordpress-optimization.conf # Настройки производительности
Как Nginx обрабатывает include:
- Директивы include выполняются рекурсивно в порядке их объявления. Если файл A.conf включает B.conf, а B.conf включает C.conf, то в итоге выполнение будет выглядеть как A → B → C.
- Также важно соблюдать контекст включаемых правил. Например, блок location нельзя поместить вне server, а fastcgi_param — вне location ~ \.php$.
- Пути в include интерпретируются относительно файла, в котором вызван include, в данном случае — относительно nginx.conf. Лучше использовать абсолютные пути:
include /etc/nginx/wordpress-templates/wordpress-common.conf;
Ограничения и подводные камни:
- Циклические зависимости. Если file1.conf включает file2.conf, а file2.conf включает file1.conf, Nginx завершится с ошибкой.
- Переопределение переменных. Переменные (например, set $root_path /var/www) из включаемого файла переносятся в основной конфиг. Это может привести к конфликтам имён.
- Проверка синтаксиса. Команда nginx -t проверяет всю конфигурацию, включая подгружаемые файлы. Но если шаблон используется только в некоторых виртуальных хостах, ошибка в нём может проявиться не сразу.
Создание базового шаблона wordpress-common.conf
Создадим файл /etc/nginx/wordpress-templates/wordpress-common.conf с минимально необходимым содержимым для работы WordPress:
# Базовые настройки индексации
index index.php index.html;
# Обработка статики и маршрутизация запросов
location / {
try_files $uri $uri/ /index.php?$args;
}
# Обработка PHP
location ~ \.php$ {
# Сокет PHP-FPM (версия должна соответствовать продакшену)
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
# Критичные параметры
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# Защита от path traversal
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
# Блокировка выполнения несуществующих скриптов
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
}
# Защита скрытых файлов (.htaccess, .env, .git)
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
# Блокировка доступа к PHP в uploads
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
Разбор критических директив:
- try_files в location / — стандартный механизм роутинга WordPress. Проверяется существование запрошенного файла ($uri), затем директории ($uri/), и если оба варианта не найдены — управление передаётся index.php с аргументами ($args). Это реализация паттерна Front Controller, где все запросы обрабатываются через единую точку входа.
- fastcgi_split_path_info — защита от path traversal-атак. Директива разделяет путь на две части: основной скрипт (script.php) и дополнительную информацию пути (/malicious/path). Без этого параметра злоумышленник может попытаться выполнить произвольный код через конструкции вида /legit-script.php/../evil.php.
- Проверка if (!-f ...) — блокирует выполнение PHP-файлов, которых нет в файловой системе. Предотвращает атаки через поддельные пути (такие как /index.php/../../../bin/bash).
- location ~ /\. — запрещает доступ ко всем файлам и директориям, начинающимся с точки (.htaccess, .git, .env). Утечка этих данных может раскрыть конфиденциальную информацию или логины. Параметры access_log off и log_not_found off снижают нагрузку на диск.
- Блокировка PHP в uploads — дополнительная защита от выполнения загруженных скриптов: директория uploads часто имеет права на запись, что делает её мишенью для атак. Регулярное выражение ~* /(?:uploads|files)/.*\.php$ полностью запрещает выполнение любых PHP-файлов в этих каталогах.
Ошибка в шаблоне заблокирует все сайты — поэтому всегда тестируйте конфиг перед применением:
sudo nginx -t -c /etc/nginx/nginx.conf
Интеграция с виртуальными хостами
Пример конфигурации для сайта example.ru (/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 /wp-admin {
# Кастомные настройки
}
# Подключаем шаблон WordPress
include /etc/nginx/wordpress-templates/wordpress-common.conf;
# Уникальный блок правил для административной зоны
}
Ключевые моменты интеграции:
Относительные пути в include ищутся относительно nginx.conf. Абсолютный путь предотвращает ошибки, если Nginx запущен с другим рабочим каталогом, поэтому для кросс-серверной совместимости рекомендуется абсолютный путь.
Nginx обрабатывает location-блоки в порядке приоритета:
- точные совпадения имеют высший приоритет (location = /path);
- префиксные (location ^~ /images);
- регулярные выражения (location ~ \.php$);
- стандартные префиксные (location /).
Для блоков одинакового типа имеет значение порядок объявления.
Nginx применяет принцип «первого совпадения» для regex-блоков. Шаблон wordpress-common.conf содержит общие регулярные выражения, поэтому кастомные location-блоки в хосте (такие как /wp-admin) должны быть объявлены до include, иначе они будут переопределены общими правилами.
Чтобы изменить правила шаблона для конкретного сайта:
- добавьте location с более высоким приоритетом:
# Переопределение обработки PHP для специфичного каталога
location ~ ^/custom-dir/.*\.php$ {
fastcgi_pass unix:/var/run/php/php8.2-fpm-alt.sock;
include fastcgi_params;
}
- или используйте location @name для кастомных обработчиков:
location /protected-area {
try_files $uri @custom_handler;
}
location @custom_handler {
proxy_pass http://special-backend;
}
Команда диагностики, которая выведет итоговый конфиг после всех include:
nginx -T | grep -A 30 "server_name example.ru"
Важно: при переопределении правил из шаблона дублируйте все защитные директивы (fastcgi_split_path_info и другие), иначе создадите уязвимость.
Безопасность и оптимизация шаблона
Защита шаблона
Шаблон /etc/nginx/wordpress-common.conf является критической частью инфраструктуры — его повреждение выведет из строя все сайты. Поэтому ограничим его редактирование только привилегированными пользователями:
sudo chown root:root /etc/nginx/wordpress-common.conf
sudo chmod 644 /etc/nginx/wordpress-common.conf # -rw-r--r--
Это предотвратит случайное изменение через веб-панели или неуполномоченными пользователями.
Перед каждым применением проверяем целостность:
sudo nginx -t -c /etc/nginx/nginx.conf
Для контроля версий инициализируем Git-репозиторий в /etc/nginx:
cd /etc/nginx
sudo git init
sudo git config --local user.email "admin@example.ru"
sudo git config --local user.name "Server Admin"
sudo git add .
sudo git commit -m "Initial config"
После изменений фиксируем правки:
sudo git commit -a -m "Update: Added XSS protection headers"
Оптимизация
Шаблон — хорошее место для правил, влияющих на производительность. Добавляем в шаблон блок для кеширования статики, уменьшающий нагрузку на сервер:
location ~* \.(?:css|js|jpg|jpeg|gif|png|ico|woff2|svg)$ {
expires 30d; # Браузеры хранят файлы 30 дней
add_header Cache-Control "public, immutable";
access_log off; # Снижаем нагрузку на диск
tcp_nodelay off;
}
Оптимизируем передачу текстового контента (сжатие gzip):
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types
text/plain
text/css
application/json
application/javascript
text/xml
application/xml
image/svg+xml;
gzip_min_length 1024; # Не сжимать маленькие файлы
Буферизация FastCGI (в секции location ~ \.php$):
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_busy_buffers_size 256k;
Важно
Никогда не размещайте в шаблоне секреты (SSL-ключи, пароли). Используйте env-переменные или отдельные защищенные файлы.
Читайте в блоге:
- Интеграция WordPress с Nginx и MariaDB на Ubuntu 24.04: от базы данных до SSL
- Хостинг сайта на Ubuntu 24.04 LTS: NGINX, SSL и WordPress
- Резко возросла нагрузка на хостинг в WordPress: причины и решение