Как мы расследовали ошибку 503 в WordPress и локализовали проблему до уровня сервера

Диагностика ошибки 503 Service Unavailable в WordPress и серверных ограничений

Техническая оптимизация
503

Кейс диагностики периодических 503 в WordPress: проверили CloudLinux, NPROC, WP-Cron, Action Scheduler, бот-трафик, PHP-процессы и LiteSpeed/LSAPI, локализовали проблему до серверного уровня, перенесли копию проекта на другой сервер и подтвердили вывод контрольным crawl: 297 из 297 URL получили 200 OK.

Технический кейс · WordPress · 503
503 Service Unavailable: техническое расследование WordPress и серверной инфраструктуры

Периодические 503 невозможно было воспроизвести по команде. Поэтому вместо бессистемного отключения плагинов мы выстроили расследование по времени: CloudLinux, NPROC, Linux fork(), WP-Cron, Action Scheduler, access log, REST API, lsphp, LiteSpeed/LSAPI и внешний бот-трафик. Финальную гипотезу проверили переносом копии сайта на другое серверное окружение и повторным обходом того же набора из 297 URL.

503 подтверждены логами
NPROC Fault зафиксирован
бот-флуд найден
297 / 297 URL → 200 OK
INCIDENT_TRACE / WORDPRESS

503
SERVICE UNAVAILABLE
[LVE] NPROC fault detected
bash: fork: retry: Resource temporarily unavailable
[HTTP] 10 requests / 1 sec
8 → 503
2 → 200
[top -H] 4 threads visible

300%CPU limit
8 GBRAM limit
20Entry Processes
100NPROC limit
100 MB/sI/O limit
1024IOPS

Что было подтверждено фактами

503 была не визуальным сбоем WordPress, а реальным отказом сервера

До поиска причины мы отдельно подтвердили саму природу инцидента. Это исключило ситуацию, когда ошибка существует только в браузере или в одном компоненте административной панели.

Google Search Console
Внешняя проверка URL тоже получила 5xx

Ошибка была видна не только владельцу сайта. Живая проверка URL внешним сервисом также попадала в период серверного отказа.

Access log
503 возникала на разных типах URL

Отказы фиксировались на публичных страницах, wp-login.php, robots.txt, REST/AJAX-запросах. Это не выглядело как поломка одной страницы.

CloudLinux
Fault повторялся именно по NPROC

CPU, RAM, I/O и Entry Processes не показывали аналогичного систематического исчерпания, тогда как NPROC Fault появлялся повторно.

Linux shell
ОС сама сообщила о невозможности создать процесс

bash: fork: retry: Resource temporarily unavailable стало прямым подтверждением процессного ограничения в момент инцидента.

Исходная проблема

Ошибка возникала на несколько секунд — и именно поэтому её было трудно диагностировать

Сайт мог нормально работать десятки минут, после чего кратковременно падала обычная страница, административный запрос, REST API или внешняя проверка. Через несколько секунд всё восстанавливалось.

Почему это сложно

Ошибка исчезала раньше, чем её успевали исследовать

При постоянной 503 можно исследовать сервер прямо в момент отказа. Здесь потребовался непрерывный мониторинг, чтобы поймать короткий сбой и затем сопоставить его с журналами.

Риск ложного вывода

Любой фоновый процесс можно ошибочно объявить виновником

WordPress постоянно выполняет cron, REST-запросы, AJAX и фоновые задачи. Без точной временной корреляции совпадение легко принять за причину.

Схема расследования ошибки 503: WordPress, LiteSpeed, CloudLinux, NPROC Fault и ошибка fork
Схема технического контура: запрос → WordPress → LiteSpeed/LSAPI → CloudLinux/LVE. Иллюстрация показывает направление диагностики, а не заменяет фактические журналы.

Маршрут диагностики

Проверяли не «что может тормозить WordPress», а что происходило именно в секунды 503

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

01

CloudLinux Resource Usage

Сопоставили CPU, RAM, I/O, Entry Processes и NPROC. Повторяющийся Fault обнаружился именно по NPROC.

первая зацепка

02

Linux shell и fork()

Во время инцидента shell вернул bash: fork: retry: Resource temporarily unavailable — прямое сообщение ОС о невозможности создать процесс.

подтверждено системой

03

WP-Cron вынесен в системный cron

Встроенный cron отключили через DISABLE_WP_CRON, а запуск wp-cron.php перевели на расписание раз в 5 минут. Сбои продолжились вне его расписания.

не первопричина

04

Action Scheduler

Сопоставили историю фоновых действий с точными проблемными окнами. В нескольких инцидентах Scheduled Actions отсутствовали.

исключено в проверенных окнах

05

Staging WordPress

Проверили дополнительную инсталляцию и её access log. Существенной активности, способной объяснить повторяющиеся Fault, не обнаружили.

исключено

06

Автоматизированный бот-трафик

Один источник примерно за 50 секунд создал около 392 запросов к административным URL WordPress. Источник заблокировали, но 503 полностью не исчезли.

фактор устранён

07

Посекундный top -H

Монитор сохранял процессы и потоки пользователя каждую секунду. Максимально наблюдали 12 потоков, из которых 10 были running.

мониторинг 1 сек.

08

REST API Gutenberg

Редактор WordPress штатно создавал серию параллельных REST-запросов. Это объясняло короткие всплески lsphp, но не NPROC=100.

проверено на практике

09

LiteSpeed / LSAPI / LVE

Установили, что PHP работает через LiteSpeed. Фактический лимит backend workers и состав NPROC на shared-хостинге пользователю не раскрывались.

граница локализована

10

Контрольный перенос и повторный crawl

Копию того же WordPress-проекта направили на другой сервер через локальный файл hosts, не переключая публичный DNS. Тем же Screaming Frog повторно проверили тот же список из 297 URL: все 297 страниц получили 200 OK, массовые 503 не воспроизвелись.

гипотеза подтверждена

Карта диагностики 503: Resource Usage, NPROC, WP-Cron, Action Scheduler, staging, бот-трафик и LiteSpeed LSAPI
Карта расследования показывает, почему одной проверки плагинов было недостаточно: причины исключались по фактическому времени событий.

Что изменили во время диагностики

Каждое изменение использовали как контролируемый эксперимент, а не как случайную «оптимизацию»

Чтобы не потерять причинно-следственную связь, после каждого изменения наблюдали, исчезают ли 503 и NPROC Fault. Если проблема сохранялась, гипотезу не объявляли доказанной.

WP-Cron перевели на системный cron

Встроенный запуск по посещениям отключили и сделали предсказуемый запуск PHP 8.3 каждые 5 минут.

define('DISABLE_WP_CRON', true);

/opt/alt/php83/usr/bin/php -q
/home/ACCOUNT/public_html/wp-cron.php

Проверили и временно отключили фоновую функцию AIOSEO

В Action Scheduler обнаружили хук aioseo_image_sitemap_scan, который выполнялся с частотой Every 1 minute. Связанную функцию AIOSEO временно отключили, чтобы убрать постоянный фоновый фактор из эксперимента. Этот шаг рассматривался как исключение возможной причины, а не как доказательство виновности AIOSEO.

Заблокировали источник бот-флуда

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

Перешли от обычного top к top -H

Мониторинг шёл с шагом в одну секунду и учитывал потоки. Это позволило видеть краткие lsphp-всплески, которые часовые графики усредняют.

top -H -b -d 1 -c -u "$USER"

Синхронизировали время логов и наблюдений

Серверные журналы и локальное время использовали разные часовые пояса. Каждый инцидент сначала приводили к одной временной шкале и только затем сравнивали процессы, HTTP-ответы и Fault.

Отдельно не подменяли факты предположениями. Например, красное сообщение редактора WordPress о недействительном ответе не было автоматически записано в 503: соответствующие REST-запросы в access log получили HTTP 200. Это позволило не смешивать разные классы ошибок.

Реальный усиливающий фактор

Около 392 запросов за ~50 секунд: бот создавал нагрузку, но не объяснял все 503

После блокировки источника крупные всплески снизились. Однако NPROC Fault и отдельные 503 продолжили возникать — значит, расследование нельзя было заканчивать на первой найденной аномалии.

Атаковалась административная поверхность WordPress

В запросах концентрировались wp-login.php, страницы wp-admin и REST API. Блокировка была полезной, но стала только одним из этапов очистки картины.

Схема кратковременного всплеска




обычнобот-всплескпосле блокировки

Ключевое доказательство

10 запросов за секунду дали 8 ответов 503, тогда как top -H показывал всего 4 потока

Это был особенно показательный эпизод: внешний поток был небольшим, а пользовательский монитор процессов не показывал ничего близкого к NPROC=100.

Небольшая пачка запросов — массовый отказ

В одну секунду сервер получил десять HEAD-запросов к главной странице.

10HTTP-запросов за 1 секунду
8×503и только 2×200

зафиксированоCloudLinuxNPROC Fault
зафиксированоLinux shellfork: Resource temporarily unavailable
в ту же секундуtop -HThreads: 4 total / 2 running / 2 sleeping
установленоPHP SAPIlitespeed

100

Заявленный лимит NPROC, при достижении которого CloudLinux фиксировал Fault.

4–12

Порядок количества потоков, видимых пользователю в top -H во время наблюдений.

10 HTTP запросов за секунду, 8 ответов 503, 2 ответа 200 и 4 видимых потока при NPROC 100
Ключевое противоречие: сервер массово отказывает запросам при небольшом входящем потоке и малом количестве процессов, видимых обычному пользователю.

Что удалось исключить

Не подгоняли каждую найденную аномалию под заранее выбранную версию

Даже ошибка редактора WordPress с сообщением о недействительном ответе не была автоматически записана в 503: соответствующие REST-запросы в access log получили HTTP 200.

×

CPU

Систематических CPU Fault в исследованных эпизодах не подтвердилось.

×

RAM

Память оставалась далеко от установленного лимита.

×

I/O и Entry Processes

Эти показатели не повторяли картину NPROC Fault.

×

WP-Cron

После переноса в системное расписание сбои продолжились вне запусков cron.

×

Action Scheduler

В нескольких проверенных проблемных окнах фоновых действий не было.

Бот-трафик

Реальный фактор нагрузки найден и устранён, но первопричину он не исчерпал.

Дополнительные проверки

Что ещё проверили, чтобы не принять технический шум за причину 503

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

Action Scheduler
Async runner не объявляли источником 503

Один запрос к admin-ajax.php?action=as_async_request_queue_runner получил 503 уже после отказа публичной страницы. Поэтому его рассматривали как возможную жертву дефицита ресурса, а не автоматически как источник нагрузки.

AIOSEO
Отделили фоновое сканирование от доказанной причины

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

error_log
Не стали строить вывод на старых ошибках

В старом error log обнаруживались записи, не совпадавшие с актуальными инцидентами. Их сознательно не использовали как доказательство причины текущих 503.

LSAPI / LVE
Проверили границу доступных пользователю метрик

PHP_SAPI подтвердил LiteSpeed, но backend children и полный состав LVE-процессов из shared-аккаунта получить было нельзя. Утилиты уровня lveps/lvetop требовали доступа администратора сервера.

Контрольная проверка после основного расследования

Повторный инцидент подтвердил: 503 возникает и без заметной внешней нагрузки

После основного этапа диагностики удалось зафиксировать ещё один особенно показательный эпизод.
Он позволил повторно проверить уже сделанные выводы и глубже исследовать поведение веб-сервера
непосредственно после ошибки 503.

503 / LOW TRAFFIC

Ошибка произошла практически без внешней нагрузки

В момент инцидента обычный запрос к административной странице WordPress:
GET /wp-admin/post.php?... → 503.
За всю соответствующую минуту в access log было всего
6 запросов от 6 разных IP-адресов.
Ни один внешний адрес не создавал заметного потока запросов.

TRAFFIC CORRELATION

Большая серия запросов появилась уже после 503

Позднее в журнале было обнаружено 187 запросов с IP рабочей сессии.
Однако временная корреляция показала, что сама 503 произошла в
13:19:45, а основная серия запросов началась только около
13:20:51.
Следовательно, эта нагрузка не могла вызвать конкретный отказ 503.

TEMPORARY 403

После восстановления сервер внезапно начал запрещать ресурсы

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


13:20:51 → 79 × 304
13:20:52 → 21 × 304
13:20:52 → 77 × 403
13:20:53 → 9 × 403

AH01797

Причину 403 зафиксировал центральный журнал веб-сервера

В cPanel для этих запросов появилась серверная запись:
AH01797: client denied by server configuration.
При этом блокировался не один конкретный файл, а разные типы ресурсов:
JPG и PNG из /uploads/, JavaScript и SVG AIOSEO,
а также REST API WordPress.

REST API

Один и тот же endpoint работал до и после кратковременного запрета

Для /wp-json/aioseo/v1/ping в журнале было обнаружено
28 ответов 200 и только один 403.
После проблемного события тот же endpoint снова ответил 200.
Это не похоже на постоянный запрет AIOSEO или WordPress REST API.

STATIC FILES

Те же физические файлы позднее снова стали доступны

Один из JPG-файлов из /wp-content/uploads/,
получивший во время проблемного окна 403, позднее был проверен напрямую
и ответил 200.
Аналогичный результат был получен для JavaScript-файла AIOSEO.

.HTACCESS CHECK

Доступные правила сайта не объяснили временную блокировку

Были проверены корневой .htaccess,
правила внутри uploads и wp-includes,
родительские каталоги и IP Blocker.
Постоянного правила, которое могло бы одновременно запрещать JPG, JS, SVG и REST API,
обнаружено не было.

FILE TIMESTAMPS

.htaccess не изменялся в момент инцидента

Время модификации доступных файлов конфигурации было проверено отдельно.
Ни корневой .htaccess, ни правила в uploads
и wp-includes в момент возникновения 503/403 не переписывались.

PHP ERROR LOG

На уровне PHP в этот момент ошибок не зарегистрировано

PHP/WordPress error_log был проверен с учётом различий часовых поясов.
В точный интервал 503 и последующей волны 403 записей не обнаружено.
При этом центральный журнал веб-сервера фиксировал
client denied by server configuration.

CONTROL TEST

Гипотеза о постоянном лимите «100 запросов» не подтвердилась

Первоначально последовательность выглядела подозрительно:
после 100 успешных запросов начались 403.
Для проверки редактор повторно загрузили с отключённым браузерным кэшем.
Контрольный результат:
105 запросов → 105 × 200 → 0 × 403.

Почему этот эпизод важен для итогового вывода.

Повторная проверка дополнительно показала, что бот-трафик не является обязательным условием
возникновения 503. Одновременно была зафиксирована кратковременная серверная блокировка ресурсов,
которой нет в доступной конфигурации WordPress и пользовательских .htaccess.

При этом 503 и последующая волна 403
не объединяются в одну причину без доказательств:
между событиями существует временной разрыв.
Они рассматриваются как отдельные признаки нестабильности серверного окружения,
требующие проверки конфигурации веб-сервера на административном уровне.

503

возникла при минимальном входящем трафике и не сопровождалась ошибкой PHP.

+
403

кратковременно появилась позже с сообщением
client denied by server configuration,
после чего доступ восстановился самостоятельно.

Граница расследования

На этом этапе дальнейшая диагностика требовала уже root-доступа к серверу

Shared-хостинг позволял видеть пользовательские процессы и часть CloudLinux-метрик, но не показывал, какие именно PID/TID сформировали NPROC=100 и какие ограничения действовали внутри LSAPI.

Что проверили со стороны сайта

  • CloudLinux Resource Usage.
  • Access log по секундам.
  • WP-Cron и системный cron.
  • Action Scheduler.
  • Staging WordPress.
  • REST API Gutenberg.
  • top / top -H / lsphp.
  • бот-трафик.

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

  • lveps / lvetop в момент Fault.
  • фактический состав NPROC.
  • LSAPI backend children.
  • Max Connections.
  • server-side spawn / fork errors.
  • журналы LiteSpeed/LSAPI.
  • лимит PHP workers.
  • LVE process accounting.
Профессиональный вывод: техническая диагностика не обязана заканчиваться «нашли плохой плагин». Иногда её задача — доказательно установить границу между приложением и инфраструктурой.

Было → стало

Из хаотичной ошибки получили технически понятную картину

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

Было

  • 503 возникает непредсказуемо.
  • Через несколько секунд сайт снова работает.
  • Неясно: WordPress, бот или сервер.
  • Общее объяснение «превышены ресурсы».
  • Риск бессистемно менять плагины и настройки.

Стало

  • NPROC Fault подтверждён.
  • Получено системное сообщение fork().
  • Проверены cron, фоновые механизмы и REST API.
  • Найден и заблокирован бот-флуд, но 503 не исчезли полностью.
  • 503 пойманы при небольшой внешней нагрузке.
  • Граница проблемы локализована до серверного окружения LVE/LSAPI.
  • Копия проекта перенесена на другой сервер для контрольной проверки.
  • Тот же список из 297 URL повторно просканирован Screaming Frog.
  • 297 из 297 URL получили 200 OK, массовые 503 не воспроизвелись.
10этапов последовательной диагностики и контрольной проверки
392запроса в найденном бот-всплеске
8/10503 в показательном секундном эпизоде старого сервера
1 сек.шаг мониторинга процессов и потоков
297/297HTTP 200 на контрольном обходе нового сервера
0массовых 503 в повторном crawl того же набора URL

Финальное решение

Перенос использовали не как догадку, а как контрольный эксперимент

Название прежнего провайдера намеренно не указывается: важен не бренд, а проверяемый технический результат. Когда диагностика дошла до LVE/LSAPI, а административные журналы shared-сервера оставались недоступны, гипотезу решили проверить сменой серверного окружения.

Сначала локализовали границу, затем проверили её на другом сервере

В поддержку были переданы конкретные интервалы 503, NPROC Fault, системное сообщение fork(), результаты top -H, access log и сведения о входящем трафике.

Углублённая проверка LVE/LSAPI на shared-сервере предоставлена не была. Вместо дальнейшей бесконечной настройки WordPress копию проекта перенесли на другое серверное окружение и повторили тот же тест.

Старое серверное окружение
массовые 503

При обходе того же набора страниц Screaming Frog значительная часть URL отвечала 503 Service Unavailable, хотя вручную страницы открывались.

VS
Новое серверное окружение
297 / 297

Тот же список URL завершил crawl со статусом 200 OK для всех 297 страниц. Массовые 503 не воспроизвелись.

Что оставили неизменным

WordPress-проект, содержимое страниц, набор из 297 URL и инструмент проверки — Screaming Frog SEO Spider.

Что изменили

Серверное окружение. Тестовую копию направили на новый сервер локально через файл hosts, не переключая публичный DNS для посетителей.

Почему такой тест показателен.
На время проверки публичный домен для обычных посетителей и поисковых роботов продолжал работать через прежний DNS. Только тестовый компьютер разрешал домен в IP нового сервера через локальный hosts. Это позволило проверить одну и ту же копию сайта на другом сервере без публичного переключения проекта.
Контрольный скан 297 страниц Screaming Frog после переноса копии WordPress на другой сервер
Контрольный crawl на новом сервере: 297 URL обработаны полностью, все проверенные HTML-страницы отвечают 200 OK. Адрес сайта на иллюстрации скрыт.

Итог расследования

Гипотеза о серверной природе 503 получила практическое подтверждение

Контрольный перенос не раскрывает, какой именно внутренний PID, LSAPI worker или механизм LVE формировал NPROC Fault на прежнем shared-сервере — для этого по-прежнему нужен административный доступ. Но он позволяет проверить главный технический вывод: проблема была связана не с содержимым 297 страниц и не с самим набором WordPress-материалов, а с прежним серверным окружением.

Полный путь расследования
От случайной 503 до контрольного подтверждения на другой инфраструктуре
503
NPROC Fault
fork()
исключение WordPress-факторов
граница LVE / LSAPI
контрольный перенос
297 / 297 → 200 OK

Что подтверждено: на прежнем серверном окружении один и тот же проект воспроизводил массовые 503 при SEO-обходе, а на новом окружении тот же список из 297 URL прошёл полностью без массовых серверных отказов.

Что не утверждается без root-доступа: конкретный скрытый процесс или точная внутренняя настройка LVE/LSAPI, которая создавала NPROC=100 на старом shared-сервере.

Практический вывод: если WordPress уже проверен на уровне cron, фоновых задач, REST API, бот-трафика и пользовательских процессов, а сервер продолжает кратковременно отдавать 503, контрольный перенос на другое окружение может стать корректным способом проверить инфраструктурную гипотезу вместо бесконечной замены плагинов и настроек CMS.

Связанные кейсы

Диагностика 503 связана с другими направлениями оптимизации сайта

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

Связанные услуги

Какие направления работают вместе с технической стабильностью сайта

Рубрики кейсов выше ведут на выполненные работы. Ниже восстановлена перелинковка на профильные услуги и экспертные направления, которая была в более ранней версии страницы.

Сайт периодически отдаёт 500, 502 или 503, а причина неочевидна?

В таких ситуациях нужна не серия случайных отключений, а корреляция логов, фоновых процессов, cron, REST API и серверных лимитов.

Обсудить диагностику