WordPress: ускоряем Nginx + PHP-FPM до TTFB меньше 300 мс
Пошаговая настройка OPcache и fastcgi_cache для WordPress 6.x на VPS (Nginx + PHP-FPM). Снижаем TTFB до 300 мс и нагрузку CPU. Конфиги, проверка, типичные ошибки.
Требования
- WordPress 6.x
- PHP 8.2
- Доступ к VPS (root)
WordPress: ускоряем Nginx + PHP-FPM до TTFB меньше 300 мс
Если wordpress долго загружается nginx php-fpm, TTFB 2–5 секунд, CPU стабильно загружен, а плагинов немного — проблема почти всегда в конфигурации PHP-FPM, OPcache и отсутствии fastcgi_cache.
После настройки:
- TTFB меньше 300 мс
- CPU без перегруза
- OPcache реально работает
- Nginx кеширует анонимный трафик
Без Docker. Обычный VPS в prod.
Сниппеты по статье: OPcache для WordPress (php.ini) · PHP-FPM pool (pm dynamic) · Nginx fastcgi_cache для WordPress · Проверка TTFB (curl)
В чём проблема
Симптомы:
- Страница открывается 2–5 секунд
curl -w "%{time_starttransfer}"показывает TTFB 1.8–3.5 сек- CPU 70–100%
topпоказывает php-fpm в топе процессов- Кеш-плагинов нет или они не решают проблему
Проверка TTFB (сниппет: curl TTFB):
curl -o /dev/null -s -w "TTFB: %{time_starttransfer}\n" https://example.com
Если видите:
TTFB: 2.341221
— PHP генерирует страницу каждый раз. Nginx не кеширует. OPcache либо отключён, либо настроен плохо.
Причины обычно такие:
- OPcache выключен или память 64MB.
- PHP-FPM работает с 5 процессами при 8 ядрах.
- Нет fastcgi_cache.
- Неправильно настроен bypass для админки.
Как отличить от других причин: если отключить все плагины (переименовать папку wp-content/plugins) и TTFB всё равно высокий — дело в стеке (Nginx/PHP-FPM/OPcache), а не в коде темы или плагинах. Если после отключения плагинов стало быстро — оптимизируйте тяжёлые плагины или кеш на уровне приложения. Здесь разбираем именно случай «плагинов немного, но стек не настроен».
WordPress сам по себе не медленный. Медленный — стек. Если после настройки появятся 502/504 — смотрите Nginx и PHP-FPM: ошибки 502, 504. Конфиг виртуальных хостов — в настройке server blocks для нескольких проектов.
Рабочее решение
1️⃣ Настраиваем OPcache (PHP 8.2)
Готовый блок с пояснениями: сниппет «OPcache для WordPress (php.ini)». Ниже — кратко.
Файл:
/etc/php/8.2/fpm/php.ini
Ищем блок OPcache и приводим к нормальному виду:
opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=256
opcache.interned_strings_buffer=32
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.fast_shutdown=1
Почему так:
- 256MB — минимум для продакшена
- validate_timestamps=0 — без постоянной проверки файлов
- 20 000 файлов — WordPress + плагины легко съедают 10k+
Путь к php.ini может отличаться: на Debian/Ubuntu это обычно /etc/php/8.2/fpm/php.ini, на CentOS/Rocky — /etc/php.ini или отдельный файл в /etc/php.d/. Убедитесь, что правите именно конфиг FPM, а не CLI: php -i | grep "Loaded Configuration" покажет активный файл для CLI, для FPM смотрите конфиг пула.
Перезапуск:
systemctl restart php8.2-fpm
Проверка:
php -i | grep opcache.enable
Ожидаем:
opcache.enable => On => On
2️⃣ Настройка PHP-FPM (CPU не должен кипеть)
Полный вариант с проверкой памяти: сниппет «PHP-FPM pool (pm dynamic)». Ниже — ключевые параметры.
Файл:
/etc/php/8.2/fpm/pool.d/www.conf
Меняем pm режим:
pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 4
pm.max_spare_servers = 8
pm.max_requests = 500
pm.max_requests — после скольких запросов воркер перезапускается; снижает риск утечек памяти в долгоживущих процессах. 500–1000 нормально для WordPress.
Как считать:
- max_children ≈ RAM / 60MB
- Если 2GB RAM → ~30 процессов максимум
Проверка нагрузки:
ps --no-headers -o "rss,cmd" -C php-fpm8.2 | awk '{ sum+=$1 } END { print sum/1024 " MB" }'
3️⃣ Включаем fastcgi_cache в Nginx
Это ключевой момент. Готовый конфиг с bypass для админки: сниппет «Nginx fastcgi_cache для WordPress».
Файл:
/etc/nginx/nginx.conf
Добавляем в http:
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=WORDPRESS:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
Создаём директорию:
mkdir -p /var/cache/nginx
chown -R www-data:www-data /var/cache/nginx
Размер зоны keys_zone=WORDPRESS:100m — это не место на диске, а объём ключей в памяти. 100m хватает на десятки тысяч URL. Реальный кеш лежит в /var/cache/nginx; убедитесь, что на разделе достаточно места (гигабайт и больше для активного сайта). Параметр inactive=60m — удалять ключ из кеша, если к нему не обращались 60 минут.
4️⃣ Настройка server для WordPress
Файл сайта:
/etc/nginx/sites-available/example.com
В location ~ .php$ добавляем:
set $skip_cache 0;
if ($request_method = POST) {
set $skip_cache 1;
}
if ($query_string != "") {
set $skip_cache 1;
}
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-login.php") {
set $skip_cache 1;
}
if ($http_cookie ~* "wordpress_logged_in") {
set $skip_cache 1;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_cache WORDPRESS;
fastcgi_cache_valid 200 60m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
add_header X-FastCGI-Cache $upstream_cache_status;
}
Перезапуск:
systemctl restart nginx
Проверка результата
Проверка TTFB
curl -I https://example.com
В заголовках должно быть:
X-FastCGI-Cache: MISS
Повторный запрос:
X-FastCGI-Cache: HIT
Проверка времени:
curl -o /dev/null -s -w "TTFB: %{time_starttransfer}\n" https://example.com
Ожидаемый результат:
TTFB: 0.112341
CPU должен упасть минимум в 2–4 раза.
Краткий чеклист:
- OPcache:
php -i | grep opcache.enable→ On - PHP-FPM: в
pool.d/www.confстоитpm = dynamic,pm.max_childrenпо памяти - Nginx: в ответе есть заголовок
X-FastCGI-Cache, при повторном запросе — HIT - TTFB: для закешированной главной — меньше 0,3 сек (лучше 0,05–0,15)
Если хотя бы один пункт не выполняется — возвращайтесь к соответствующему шагу выше. На проде после любых изменений конфига делайте nginx -t перед systemctl reload nginx.
Если не работает
1️⃣ Нет заголовка X-FastCGI-Cache → location блок не применяется.
Проверь:
nginx -T | grep fastcgi_cache
2️⃣ Всегда BYPASS → Cookie не даёт кешировать.
Проверь:
curl -I https://example.com | grep Set-Cookie
3️⃣ OPcache не даёт прироста → validate_timestamps включён.
Проверь:
php -i | grep validate_timestamps
Должно быть 0 в проде. После деплоя кода делайте systemctl reload php8.2-fpm, чтобы OPcache подхватил новые файлы.
4️⃣ Кеш не создаётся (всегда MISS) → путь к кешу неверный или нет прав.
Проверь:
ls -la /var/cache/nginx
Владелец должен быть www-data (или пользователь nginx). Если директории нет — создай и выдай права, как в шаге 3 выше, затем systemctl restart nginx.
Типичные ошибки
❌ OPcache 64MB Причина: дефолт Debian Решение: минимум 256MB
❌ pm = ondemand Причина: экономия памяти Проблема: запуск процессов под нагрузкой Решение: dynamic
❌ Кеширование админки Причина: нет bypass Решение: skip_cache условия
❌ Кеш не чистится при деплое Причина: validate_timestamps=0 Решение: после деплоя:
systemctl reload php8.2-fpm
Где применять
- Production VPS
- Nginx + PHP-FPM
- Без Docker
- CI/CD с деплоем через git pull
- WordPress 6.x
Если используешь Docker — логика та же, но путь к сокету другой. Основы Nginx — в Nginx: основы веб-сервера. Дальнейшая оптимизация фронта (LCP, INP, кеш) — WordPress и Core Web Vitals.
После обновления кода или темы
При opcache.validate_timestamps=0 OPcache не перечитывает файлы сам. После деплоя (git pull, загрузка обновлённой темы или плагинов) выполните:
systemctl reload php8.2-fpm
Так PHP-FPM перезапустит воркеры и подхватит новый код. При необходимости сбросьте fastcgi_cache: удалите содержимое /var/cache/nginx или перезапустите Nginx. Для инвалидации только части кеша в Nginx нужна отдельная настройка (например, purge по ключу).
Итог
Если wordpress долго загружается nginx php-fpm, проблема почти никогда не в “тяжёлом WordPress”.
Проблема в:
- выключенном OPcache
- неправильном pm
- отсутствии fastcgi_cache
После этих трёх шагов:
- TTFB меньше 300 мс
- CPU стабилен
- Сайт ощущается быстрым
WordPress может работать быстро. Просто стек должен быть настроен как прод, а не как shared-хостинг 2012 года. Следуйте шагам по порядку и проверяйте результат после каждого этапа.



Комментарии