Jak naprawić błąd 429 Too Many Requests w WordPress

Spis treści

Błąd 429 Too Many Requests blokuje dostęp do strony bez ostrzeżenia. Pojawia się nagle, znika po godzinie i wraca. Większość właścicieli WordPressa myśli, że to atak DDoS. Zwykle to jednak strona ogranicza samą siebie albo ktoś skopiował zbyt ostrą regułę z blogowego poradnika.

W tym artykule pokazuję, jak znaleźć rzeczywistą przyczynę i ją naprawić – na Apache, Nginx i LiteSpeed.

Co oznacza kod 429

Kod 429 oznacza, że serwer ogranicza liczbę żądań. Mówi wprost: zwolnij, wysyłasz ich za dużo. Różni się od 403 (stała blokada) i 503 (serwer przeciążony). To nie awaria, tylko celowa odmowa – serwer miał moc, by przetworzyć żądanie, policzyć je i odpowiedzieć, że nie obsłuży kolejnych.

Kłopot w tym, że nie wiadomo, która warstwa zwraca ten kod. Cloudflare, Nginx na serwerze, wtyczka bezpieczeństwa albo zewnętrzne API, które twoja strona wywołuje – każda wymaga innego podejścia.

Zanim cokolwiek zmienisz, ustal jedno: 429 pojawia się odwiedzającym twoją stronę, czy w logach widzisz, że to twoja strona dostaje 429 od zewnętrznego API? To dwie różne historie.

Jeśli interesuje Cię szersze spojrzenie na optymalizację wydajności WordPress, polecam przeczytać artykuł: Strona WordPress ładuje się bardzo powoli – diagnoza i rozwiązanie, gdzie znajdziesz więcej szczegółów na temat optymalizacji różnych aspektów działania strony.

Diagnostyka – od czego zacząć

Cloudflare

Jeśli używasz Cloudflare, pierwsze podejrzenie zwykle pada na niego. I słusznie – ale nagłówek CF-Ray nie mówi nic o źródle 429. Cloudflare dodaje go do każdej odpowiedzi, niezależnie od tego, czy 429 wygenerował on, czy twój serwer.

Żeby sprawdzić, kto blokuje ruch, wejdź w dashboard → Security → Events. Ustaw filtr na "Action: block" i "Service: Rate limiting". Jeśli widzisz wpisy dla swojego IP, Cloudflare jest winowajcą. Jeśli dashboard jest pusty – 429 pochodzi z serwera.

Druga metoda – curl z ominięciem CDN. Wystarczy wykonać w terminalu polecenie curl z parametrem -sSI i opcją --resolve, wskazując domenę, port 443 i adres IP serwera origin, po czym wywołać adres wp-login.php.

Jeśli origin zwraca 200, a użytkownicy dostawali 429 – wina Cloudflare. Jeśli origin też zwraca 429 – szukaj dalej.

Logi serwera

W logach dostępowych grep po statusie 429 pokaże konkretne endpointy i IP. Wystarczy przefiltrować plik access.log Nginksa poleceniem grep szukającym frazy " 429 ", a następnie posortować wyniki po najczęściej występujących adresach URL.

Jeśli logi nie pokazują 429, ale użytkownicy go dostają – odpowiedź pochodzi z warstwy wyższej (CDN, WAF, reverse proxy). Jeśli logi pokazują 429 – źródłem jest WordPress lub wtyczka.

Wtyczki bezpieczeństwa

Wordfence, iThemes Security, Sucuri, All In One WP Security – wszystkie mają wbudowane ograniczanie żądań, o którym łatwo zapomnieć. Wordfence domyślnie blokuje przy 240 żądaniach na minutę na IP, dla crawlerów przy 120 na minutę.

Podejrzewasz konkretną wtyczkę? Wyłącz ją tymczasowo i sprawdź, czy 429 znika. Potem dostosuj progi – nie zostawiaj wtyczki wyłączonej na stałe.

Ogranicznik żądań w samej wtyczce

To najmniej oczywiste źródło 429. Niektóre wtyczki mają własne ograniczniki żądań, niezależne od pluginów bezpieczeństwa. Znajdziesz je przez grep – wystarczy przeszukać rekurencyjnie katalog wp-content/plugins pod kątem fraz takich jak "rate limit", "too many requests", "429" czy "throttle" w plikach PHP.

Jeśli grep znajdzie plik typu RateLimiter.php, masz winowajcę. Zajrzyj do środka – zobaczysz klasę zliczającą żądania w transients WordPressa, z progiem 10–20 żądań na minutę.

Action Scheduler

W panelu WordPress przejdź do Narzędzia → Zaplanowane akcje. Filtruj po statusie "Nieudane". Jeśli widzisz dziesiątki nieudanych akcji z tym samym hookiem, to twój trop. Hook najczęściej mówi, która wtyczka go wywołuje: hook gla/jobs/update_products to Google Listings & Ads, a wc_helper_subscriptions_refresh to WooCommerce.com Helper.

To obecnie jedna z najczęstszych przyczyn 429 – wtyczka z Action Schedulerem wysyła zapytania na zewnątrz, zewnętrzne API ogranicza żądania per outbound IP, zadanie kończy się niepowodzeniem, Action Scheduler ponawia z wykładniczym opóźnieniem i koło się zamyka.

Jak naprawić 429 – konkretne przypadki

Gdy WordPress ogranicza sam siebie

Zdarza się, że strona wysyła zbyt wiele żądań do zewnętrznego API. Winowajcą jest zwykle wtyczka, która zbyt często odświeża dane – social feed, kurs walut, mapy Google, licencje WooCommerce.

Sprawdź, która wtyczka generuje najwięcej nieudanych zadań w Action Scheduler. Usuń backlog nieudanych akcji. Następnie włącz prawdziwy cron zamiast pseudo-crona, dodając w wp-config.php stałą DISABLE_WP_CRON ustawioną na true, nad komentarzem "That's all, stop editing!".

Potem w panelu hostingowym ustaw prawdziwe zadanie cron uruchamiane co 15 minut, które wywołuje adres wp-cron.php z parametrem doing_wp_cron (np. poleceniem wget w trybie cichym, bez zapisywania wyniku).

Pseudo-cron uruchamia się przy każdej odsłonie strony i na ruchliwych witrynach generuje lawinę równoległych procesów. Przejście na prawdziwy cron często rozwiązuje problem nadmiarowych żądań.

Heartbeat API

WordPress Heartbeat API wysyła POST do admin-ajax.php co 15 sekund na stronach edycji i co 60 sekund na dashboardzie. Jeśli pięciu redaktorów pracuje jednocześnie, łatwo przekroczyć limit.

Wtyczki takie jak Perfmatters, WP Rocket i LiteSpeed Cache mają opcję "Heartbeat Control". Ustaw interwał na 60 sekund dla dashboardu i 30 sekund dla edycji. Na stronie frontowej Heartbeat możesz wyłączyć całkowicie – tylko nieliczne wtyczki go tam potrzebują.

XML-RPC

XML-RPC to stary protokół, który wciąż jest domyślnie włączony w WordPressie. Atakujący używają go do prób logowania i ataków DDoS. Jeśli nie korzystasz z Jetpack (który używa XML-RPC do komunikacji z WordPress.com) ani z aplikacji mobilnych opartych na XML-RPC, wyłącz go całkowicie.

W Nginx wystarczy w bloku location dla ścieżki /xmlrpc.php ustawić deny all, wyłączyć logowanie tych żądań (access_log off, log_not_found off) i zwracać kod 444, który od razu zrywa połączenie bez odpowiedzi.

W Apache ten sam efekt daje dyrektywa Files dla xmlrpc.php z regułą Require all denied.

Jeśli potrzebujesz Jetpack, nie blokuj całego pliku – usuń tylko niebezpieczne metody przez filtr xmlrpc_methods, odpinając z listy dostępnych metod system.multicall oraz pingback.ping i zwracając zmodyfikowaną listę.

Filtr xmlrpc_enabled nie wyłącza nieuwierzytelnionych metod – pingbacki dalej będą działać.

Ataki na stronę logowania

Ataki brute-force na wp-login.php to codzienność. Jeśli 429 pojawia się przy logowaniu, system działa prawidłowo – ale być może próg jest zbyt niski.

W Wordfence przejdź do Firewall → All Firewall Options → Rate Limiting i dostosuj próg. W All In One Security sprawdź Brute Force → Rename Login Page lub Cookie Based Brute Force Prevention.

Możesz też zmienić domyślny URL logowania przez wtyczkę WPS Hide Login. Atakujący przestaną trafiać na wp-login.php, a 429 zniknie, bo nie będzie czego ograniczać.

Rate limiting w Nginx

Jeśli masz dostęp do konfiguracji Nginx, możesz ustawić ograniczanie żądań precyzyjnie i skutecznie. Mechanizm opiera się na dwóch dyrektywach: limit_req_zone w bloku http i limit_req w bloku location.

W bloku http definiuje się strefy pamięci dla poszczególnych typów żądań – osobną dla logowania i osobną dla XML-RPC, z limitem odpowiednio 5 i 20 żądań na minutę, kluczowane po adresie IP klienta. W blokach location dla wp-login.php i xmlrpc.php przypisuje się te strefy z dodatkowym buforem (burst) oraz opcją nodelay, a status zwracany po przekroczeniu limitu ustawia się na 429.

Dlaczego 5 żądań na minutę? Człowiek, który pomyli hasło cztery razy, nie przekracza 10 żądań na minutę. Bot wysyłający 50 haseł na sekundę dostanie 429 już po drugiej próbie. Taka zmiana potrafi zredukować ruch botów o 80–95% z dnia na dzień.

Pamiętaj o opcji nodelay. Bez niej Nginx opóźnia odpowiedzi, żeby wygładzić średnią prędkość. Dla przeglądarki wygląda to jak wiszący serwer.

Jeśli używasz Cloudflare, musisz przywrócić prawdziwe IP klienta – inaczej zmienna z adresem IP zawsze będzie pokazywać IP Cloudflare i ogranicznik zablokuje wszystkich jako jednego użytkownika. Służy do tego dyrektywa real_ip_header ustawiona na CF-Connecting-IP wraz z listą zaufanych zakresów adresów Cloudflare podanych przez set_real_ip_from.

Możesz też dodać własną stronę dla kodu 429 z nagłówkiem Retry-After – wystarczy w bloku server ustawić error_page dla 429 wskazujący na osobny plik HTML i dodać do niego nagłówek Retry-After z wartością w sekundach.

Nagłówek Retry-After mówi dobrze wychowanym klientom (Googlebot, biblioteki HTTP), kiedy mogą wrócić.

Rate limiting w Apache

Apache nie ma wbudowanego odpowiednika limit_req z Nginx. Najczęściej używa się mod_evasive, mod_qos lub ModSecurity z regułami OWASP CRS.

mod_evasive monitoruje żądania per IP. W konfiguracji modułu ustawia się m.in. rozmiar tabeli hashującej, maksymalną liczbę żądań do tej samej strony (domyślnie 5) i do całej witryny (domyślnie 50) w zadanym oknie czasowym (1–2 sekundy) oraz czas blokady adresu IP po przekroczeniu limitu (domyślnie 60 sekund).

Pięć żądań do tego samego URI w 2 sekundy lub 50 żądań do całej strony w 1 sekundę powoduje blokadę IP na 60 sekund.

Dla WordPressa można rozważyć ModSecurity z OWASP Core Rule Set. Reguły DOS Protection wykrywają ataki i aplikują tymczasową blokadę.

Jeśli nie chcesz bawić się w ModSecurity, a masz Apache, najprościej postawić Cloudflare przed stroną i ograniczanie żądań ustawić na jego poziomie.

Rate limiting w LiteSpeed

LiteSpeed ma wbudowaną ochronę WordPressa – dyrektywę WordPressProtect, domyślnie włączoną od wersji 5.2.3. Konfiguruje się ją w trybie throttle z limitem, np. 10 punktów.

Każdy POST do wp-login.php lub xmlrpc.php zmniejsza licznik o 1. Gdy licznik spadnie do połowy, IP jest spowalniane. Przy zerze wykonywana jest skonfigurowana akcja – drop, deny, throttle lub captcha. Co (5 minut / limit) sekund bez POSTów licznik rośnie o 1. Z limitem 10 spowalnianie zaczyna się po 5 próbach, blokada po 10.

LiteSpeed umożliwia też sterowanie przez blok connectionControl, w którym ustawia się maksymalną liczbę równoczesnych połączeń per IP (maxConnections), limity żądań dynamicznych i statycznych na sekundę (dynReqPerSec, staticReqPerSec), progi miękki i twardy (softLimit, hardLimit), okres karencji (gracePeriod) oraz czas bana (banPeriod).

Jedno IP może mieć maksymalnie 20 równoczesnych połączeń – strona otwiera zwykle 4–6 połączeń na kartę, więc to rozsądna wartość. Ban na 300 sekund oznacza 5 minut blokady, po których IP jest automatycznie odblokowane. Żądania obsłużone z LSCache nie są liczone do limitu dynReqPerSec, więc caching nie tylko przyspiesza stronę, ale też pomaga nie trafiać w limity.

Cloudflare – najczęstsze błędy w konfiguracji

Cloudflare nie ogranicza WordPressa domyślnie. Jeśli dostajesz 429 z Cloudflare, ktoś stworzył regułę, która odpaliła. Najczęściej to zbyt ostra reguła na ścieżkę wp-json (domyślny próg to 10 żądań na 10 sekund), reguła na wp-login.php blokująca monitorowanie lub własne IP, Bot Fight Mode zbyt agresywnie challenge'ujący automatyczne boty albo reguła skopiowana z bloga bez dostosowania progów.

Używaj challenge zamiast block tam, gdzie fałszywe trafienie kosztuje – finalizacja zamówienia, logowanie. POST limituj ostrzej niż GET. Ludzie przeglądają, boty wysyłają.

Gdy hosting jest źródłem 429

Niektórzy dostawcy hostingu stosują ograniczanie żądań na poziomie serwera, niezależnie od CDN i wtyczek. To najtrudniejszy przypadek – nie pojawia się w logach WordPressa, bo jest obsługiwane poniżej warstwy aplikacji.

Jeśli podejrzewasz hosting, skontaktuj się z supportem. Przygotuj wcześniej dokładny URL zwracający 429, timestamp ze strefą czasową, informację, czy 429 jest przychodzący czy wychodzący, linijki z access loga i error loga, informację o Cloudflare oraz listę aktywnych wtyczek – szczególnie zmienianych w ostatnich 48 godzinach.

Na współdzielonym hostingu jedno IP outbound jest dzielone przez wiele stron. Jeśli jedna z nich wysyła dużo żądań do tego samego API, ty też możesz dostać 429, nawet jeśli twoja wtyczka działa prawidłowo. Rozwiązaniem jest migracja na VPS z dedykowanym IP lub zmiana dostawcy.

Jak odróżnić 429 z Cloudflare od 429 z serwera

Objaw Cloudflare Origin
Strona błędu Z brandingiem Cloudflare Plain text
Nagłówek server cloudflare nginx / apache
Security Events Wpis w Security → Events Brak wpisu
curl --resolve origin zwraca 200 origin też zwraca 429

Wpływ na SEO

Gdy Googlebot trafia na 429, ogranicza crawl rate. Jeśli błąd utrzymuje się dłużej, indeksowanie strony może zostać wstrzymane nawet na 90 dni.

W Wordfence możesz ustawić opcję "Verified Google crawlers are not rate limited". Na poziomie serwera nagłówek Retry-After pomaga Googlebotowi zrozumieć, kiedy wrócić.

Lista kontrolna

  1. Określ kierunek – dostajesz 429 czy wysyłasz?
  2. Sprawdź Cloudflare Security Events
  3. Sprawdź logi serwera (grep " 429 ")
  4. Wyłącz wtyczki bezpieczeństwa jedną po drugiej
  5. Sprawdź Action Scheduler
  6. Zgrepuj wtyczki po "rate.limit" i "429"
  7. Sprawdź, czy nie blokujesz samego siebie zbyt ostrą regułą
  8. Włącz prawdziwy cron
  9. Ogranicz Heartbeat API
  10. Jeśli nic nie pomaga – skontaktuj się z hostingiem

Zamiast na ślepo podnosić limity

Błąd 429 to sygnał, nie awaria. Coś w łańcuchu między użytkownikiem a twoją stroną uznało, że żądań jest za dużo. Znajdź to coś, zamiast na oślep podnosić limity.

Obecnie najczęstszą przyczyną 429 nie są ataki, ale źle skonfigurowane wtyczki wysyłające za dużo żądań do zewnętrznych API oraz reguły przepisane z bloga bez zrozumienia. W obu przypadkach naprawa sprowadza się do jednego – wiedzieć, gdzie szukać.

Zmagasz się z błędem 429 Too Many Requests na swojej stronie WordPress? Chętnie pomożemy Ci zdiagnozować rzeczywistą przyczynę – niezależnie od tego, czy leży ona w Cloudflare, wtyczce, Action Schedulerze czy konfiguracji serwera – i wdrożyć rate limiting, który nie blokuje prawdziwych użytkowników. Skontaktuj się z nami, aby uzyskać profesjonalne wsparcie techniczne.