SearXNG błąd 429: jak naprawić limity i blokady IP
Błąd 429 w SearXNG wynika z lokalnego limitera lub blokady IP przez wyszukiwarki. Sprawdź logi loggera searxng, aby odróżnić te przyczyny i uniknąć błędnej konfiguracji serwera.
Dlaczego SearXNG zwraca błędy 429
Własna instancja SearXNG zwraca błędy 429 z dwóch niezależnych powodów, a limit, który wymaga korekty, zazwyczaj nie jest tym, o którym myślisz. Pierwszy powód jest lokalny: wbudowany mechanizm ograniczania SearXNG uznał żądanie za pochodzące od bota i odpowiedział Too Many Requests statusem 429. Drugi powód jest zewnętrzny: wyszukiwarka odrzuciła adres IP Twojego serwera, co dociera do użytkowników jako strona wyników z brakującymi elementami, a nie jako błąd 429.
Oba przypadki wymagają innych działań. Mechanizm ograniczający jest Twój, więc możesz go skonfigurować. Blokada zewnętrzna występuje po stronie Google, więc żadna zmiana w Twoim settings.yml jej nie usunie. Dziennik zdarzeń pozwala zidentyfikować przyczynę w około minutę, więc od tego należy zacząć.
Ten przewodnik zakłada instalację kontenerową opisaną w własna instancja SearXNG na własnym VPS. Każda nazwa ustawienia poniżej pochodzi z aktualnej dokumentacji źródłowej, zweryfikowanej w sierpniu 2026.
Przeanalizuj logi przed zmianą ustawień
Odtwórz problem przy otwartym oknie z logami.
cd ./searxng/
docker compose logs -f searxng-coreKomunikaty ogranicznika pochodzą z loggera o nazwie searx.limiter i zawierają adres IP. Trafienie na czarną listę jest oznaczone jako BLOCK 203.0.113.10: matched BLOCKLIST, a trafienie na białą listę jako PASS 203.0.113.10: matched PASSLIST. Jeśli ogranicznik nie może uzyskać dostępu do magazynu liczników, w logu pojawia się komunikat The limiter requires Valkey, please consult the documentation, co oznacza, że zliczanie nie odbywa się w ogóle.
Każda pojedyncza weryfikacja bota jest rejestrowana na poziomie debug, więc domyślnie nie będzie widoczna. Włącz tryb debug na czas testu w settings.yml:
general:
debug: trueLog doda wówczas linie w formacie NOT OK (http_accept_language) obok sieci klienta, wskazując nazwę nieudanej weryfikacji. Po zakończeniu testu wyłącz tę opcję, ponieważ zalecenia producenta odradzają uruchamianie wdrożonej instancji z aktywnym trybem debug.
Awarie silnika wyglądają inaczej. Wskazują nazwę silnika zamiast adresu IP, a najczęstszą przyczyną jest przekroczenie limitu czasu (timeout):
HTTP requests timeout (search duration : 3.1 s, timeout: 3.0 s)Dostępna jest również strona poświęcona temu zagadnieniu. Przy ustawieniu enable_metrics na wartość domyślną true, instancja rejestruje błędy silnika w /stats/errors, a /preferences wyświetla listę silników, które aktualnie odpowiadają. Jeśli /stats/errors jest pełne, a log nie zawiera linii searx.limiter, problem nie leży po stronie ogranicznika.
Ustal wersję przed rozpoczęciem debugowania
Konfiguracja kontenera typu upstream składa się z dwóch plików.
mkdir -p ./searxng/core-config/
cd ./searxng/
curl -fsSL \
-O https://raw.githubusercontent.com/searxng/searxng/master/container/docker-compose.yml \
-O https://raw.githubusercontent.com/searxng/searxng/master/container/.env.example
cp -i .env.example .envPlik compose pobiera docker.io/searxng/searxng:${SEARXNG_VERSION:-latest}. Niezdefiniowana zmienna oznacza latest, a latest powoduje, że instancja zmienia się w sposób niekontrolowany przy kolejnym docker compose pull, przez co ustawienie działające w zeszłym tygodniu może przestać być zgodne z kodem, który je odczytuje. Tagi SearXNG zawierają datę oraz skrót commitu. Przykładowy tag w upstream .env.example na sierpień 2026 to 2026.3.25-541c6c3cb, dlatego należy ustawić konkretną wartość w .env:
SEARXNG_VERSION=2026.3.25-541c6c3cbSprawdź opublikowane tagi i przypnij wersję, która została faktycznie przetestowana, a następnie przeprowadź debugowanie w odniesieniu do ustalonego celu. Ten sam plik .env przechowuje klucz tajny, dlatego przed zatwierdzeniem zmian w tym katalogu zapoznaj się z sposobem działania plików env i sekretów w Docker Compose.
Ogranicznik wymaga Valkey, w przeciwnym razie nie uruchomi się
Ogranicznik zlicza żądania na klienta, a te dane muszą być współdzielone między procesami roboczymi. Magazynem tym jest Valkey, utrzymywany fork Redis. Starsze poradniki do SearXNG określają to ustawienie jako redis:. Bieżące wydania używają valkey:, dlatego należy skopiować nazwę klucza z aktualnej dokumentacji, a nie ze starszych wpisów.
use_default_settings: true
server:
secret_key: "change-this-value"
limiter: true
public_instance: false
valkey:
url: valkey://searxng-valkey:6379/0Dostarczony plik compose uruchamia już usługę searxng-valkey na obrazie docker.io/valkey/valkey:9-alpine, więc ta nazwa hosta jest rozpoznawana wewnątrz sieci compose. Tę samą wartość można ustawić za pomocą zmiennej środowiskowej SEARXNG_VALKEY_URL, a adres URL gniazda Unix (unix:///path/to/socket.sock?db=0) działa, gdy SearXNG i Valkey współdzielą hosta.
To, co dzieje się w przypadku braku magazynu, zależy od innego klucza. Przy public_instance: false ogranicznik loguje błąd Valkey i rezygnuje, więc instancja kontynuuje działanie bez żadnego ograniczania szybkości. Przy public_instance: true proces wywołuje sys.exit(1), ponieważ otwarta instancja z niedziałającą ochroną przed botami zbiera CAPTCHA (całkowicie zautomatyzowany publiczny test Turinga do odróżniania komputerów od ludzi) z każdego silnika w ciągu jednego dnia. Kontener, który restartuje się w pętli zaraz po ustawieniu public_instance: true, cierpi na ten problem, a ostatnia linia przed każdym wyjściem wskazuje na Valkey.
Co faktycznie zlicza ogranicznik
The data behind this chart
[
{
"label": "Burst, normal client",
"max_requests": 15,
"window": "20 seconds"
},
{
"label": "Burst, flagged client",
"max_requests": 2,
"window": "20 seconds"
},
{
"label": "Sustained, normal client",
"max_requests": 150,
"window": "10 minutes"
},
{
"label": "Sustained, flagged client",
"max_requests": 10,
"window": "10 minutes"
},
{
"label": "Any non-HTML format",
"max_requests": 4,
"window": "1 hour"
},
{
"label": "Flagged requests before block",
"max_requests": 3,
"window": "30 days"
}
]Standardowy klient otrzymuje 15 żądań w oknie 20-sekundowego burstu oraz 150 w oknie 10-minutowym. Gdy żądanie zostanie oznaczone jako podejrzane, ten sam klient zostaje ograniczony do 2 na okno burstu. Ostatni wiersz jest najbardziej restrykcyjny: po 3 oznaczonych żądaniach w oknie 30-dniowym, dany adres jest przekierowywany na stronę startową zamiast do wyszukiwarki, a w dzienniku pojawia się wpis BLOCK: too many request from ... in SUSPICIOUS_IP_WINDOW (redirect to /).
Wartości te są stałymi w searx/botdetection/ip_limit.py. Nie są to ustawienia, a limiter.toml ich nie udostępnia, więc ich zmiana wymaga edycji kodu źródłowego. To, co /etc/searxng/limiter.toml kontroluje, to prefiksy adresów używane do grupowania klientów, lista zaufanych proxy, opcjonalna weryfikacja tokena linku oraz listy dozwolonych i zablokowanych adresów.
Żądanie jest oznaczane jako podejrzane na podstawie weryfikacji nagłówków, a każda kontrola posiada nazwę widoczną w dzienniku debugowania:
http_accept: nagłówekAcceptnie zawieratext/html.http_accept_encoding: nagłówekAccept-Encodingnie wskazuje anigzip, anideflate.http_accept_language: brak nagłówkaAccept-Language.http_connection: nagłówekConnectionjest ustawiony naclose.http_user_agent: nagłówekUser-Agentjest nieobecny lub pasuje do znanego wzorca bota.http_sec_fetch: nagłówekSec-Fetch-ModelubSec-Fetch-Destnie jest zgodny z tym, co wysyła przeglądarka.
Przeglądarka wysyła wszystkie te nagłówki. Zwykłe wywołanie curl nie wysyła niemal żadnego z nich, dlatego ręcznie przygotowane żądanie testowe jest oznaczane już przy pierwszej próbie, podczas gdy to samo wyszukiwanie działa poprawnie w karcie przeglądarki. Z tego powodu sytuacja, w której „w przeglądarce działa, a skrypt otrzymuje 429”, jest typowym zachowaniem, a nie zagadką.
Za reverse proxy ogranicznik blokuje wszystkich jednocześnie
Jest to najczęstsza przyczyna awarii działającej instancji. SearXNG pobiera adres klienta z pierwszego niezaufanego adresu IP w X-Forwarded-For, przechodzi do X-Real-IP, a następnie do adresu, który nawiązał połączenie. O tym, czy nagłówki te są uznawane, decyduje trusted_proxies w limiter.toml.
Jeśli adres Twojego proxy nie znajduje się na tej liście, nagłówki są ignorowane, a każdy odwiedzający jest identyfikowany adresem proxy. Wszyscy użytkownicy współdzielą jeden licznik, więc cała witryna zostaje zablokowana, gdy łączna liczba żądań przekroczy 150 w ciągu 10 minut. Jeden użytkownik odświeżający stronę wyników kilka razy powoduje zablokowanie wszystkich.
Nadmierne zaufanie jest jeszcze gorsze. Jeśli na liście znajdzie się publiczny zakres adresów, każdy odwiedzający może wysłać własny nagłówek X-Forwarded-For i przyjmować nową tożsamość przy każdym żądaniu, co wyłącza ogranicznik dla każdego, kto o tym wie. Należy umieszczać wyłącznie adres, z którego łączy się własne proxy. W Docker jest to zazwyczaj sieć typu bridge wewnątrz 172.16.0.0/12, a ta linia jest domyślnie zakomentowana.
[botdetection]
ipv4_prefix = 32
ipv6_prefix = 48
trusted_proxies = [
'127.0.0.0/8',
'::1',
'172.16.0.0/12',
]Proxy również musi przesyłać odpowiednie nagłówki. Nginx nie dodaje ich automatycznie:
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header Connection $http_connection;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}Caddy i Traefik ustawiają nagłówki przekierowania automatycznie, więc w ich przypadku należy wykonać tylko część zadań związanych z trusted_proxies. Zalety i wady poszczególnych rozwiązań opisano w wybór reverse proxy dla usługi self-hosted. Aby zweryfikować konfigurację, należy włączyć debug, wykonać jedno wyszukiwanie z telefonu przy użyciu danych mobilnych i sprawdzić w dzienniku, czy adres sieciowy odpowiada adresowi telefonu, a nie proxy.
Twój agent otrzymuje cztery żądania API na godzinę
Wyjście JSON jest domyślnie wyłączone, więc agent wymaga jego dodania:
search:
formats:
- html
- jsonTeraz ponownie przeanalizuj wiersz wykresu. Każde żądanie wymagające formatu innego niż HTML jest zliczane w ramach własnego okna: 4 żądań na 1 hour, na adres. Agent badawczy wyczerpuje ten limit w jednym zadaniu, a każde kolejne wywołanie zwraca błąd 429. Zwiększenie limitu nie jest możliwe, ponieważ wartość ta jest zakodowana w źródłach.
Poprawnym rozwiązaniem jest poinformowanie ogranicznika, że ten klient nie jest obcy. Dodaj jego adres do listy przepuszczania w limiter.toml:
[botdetection.ip_lists]
block_ip = []
pass_ip = [
'10.8.0.0/24',
]
pass_searxng_org = truepass_ip ma priorytet nad każdą inną metodą, więc klient z listy dozwolonych pomija również sprawdzanie nagłówków, dzięki czemu zwykłe wywołanie curl działa poprawnie. Utrzymuj zakres jako możliwie najmniejszy i preferuj podsieć VPN lub sieć kontenerową zamiast czegokolwiek routowalnego. Drugim poprawnym rozwiązaniem jest całkowite odizolowanie agenta od ścieżki publicznej: skieruj go na adres kontenera w sieci wewnętrznej, gdzie proxy i jego ogranicznik nie widzą ruchu. Konfiguracja tego połączenia została opisana w nadawanie agentowi AI umiejętności wyszukiwania SearXNG.
Opcją, której należy unikać, jest kierowanie agenta na publiczną instancję utrzymywaną przez kogoś innego. Jest to najszybszy sposób na zablokowanie adresu IP wolontariusza przez silniki nadrzędne i właśnie dlatego format JSON jest domyślnie wyłączony.
Gdy wyszukiwarki blokują dostęp
The data behind this chart
[
{
"label": "SearxEngineTooManyRequests",
"suspended_seconds": 3600,
"roughly": "1 hour"
},
{
"label": "SearxEngineAccessDenied",
"suspended_seconds": 86400,
"roughly": "1 day"
},
{
"label": "SearxEngineCaptcha",
"suspended_seconds": 86400,
"roughly": "1 day"
},
{
"label": "recaptcha_SearxEngineCaptcha",
"suspended_seconds": 604800,
"roughly": "7 days"
},
{
"label": "cf_SearxEngineCaptcha",
"suspended_seconds": 1296000,
"roughly": "15 days"
}
]Gdy wyszukiwarka odpowiada kodem 429 lub stroną z CAPTCHA, SearXNG zgłasza nazwany wyjątek i na pewien czas przestaje wysyłać zapytania do tego silnika. Odpowiedź o zbyt dużej liczbie żądań powoduje zawieszenie na 3600 sekund. Zwykła strona CAPTCHA lub odmowa dostępu zawiesza silnik na 1 day. CAPTCHA serwowana przez Cloudflare powoduje zawieszenie na 15 days, co stanowi najdłuższy domyślny czas w zestawieniu, ponieważ taka odpowiedź oznacza blokadę na poziomie brzegu sieci i ponawianie prób nie przyniesie efektu.
Typowe błędy korzystają z innych ustawień. Przekroczenie czasu oczekiwania lub błąd parsowania zawiesza silnik na krótki czas wynikający z search.ban_time_on_fail, którego domyślna wartość wynosi 5 sekund, a maksymalna wartość ograniczona jest przez search.max_ban_time_on_fail do 120 sekund. Dzięki temu wolny silnik odzyskuje sprawność samodzielnie w ciągu kilku minut, podczas gdy zablokowany silnik pozostaje niedostępny przez wiele godzin. Ta różnica wyjaśnia objaw zgłaszany przez użytkowników jako losowy: wyniki są poprawne, a następnie wyniki z jednego silnika znikają do końca popołudnia.
Przed szukaniem winnych warto naprawić problemy z przekroczeniem czasu oczekiwania. Domyślna wartość request_timeout wynosi 2.0 sekundy, co jest wartością restrykcyjną dla małego VPS znajdującego się daleko od najbliższego serwera brzegowego wyszukiwarki.
outgoing:
request_timeout: 3.0
max_request_timeout: 10.0
engines:
- name: bing
timeout: 5.0request_timeout to wartość domyślna dla każdego silnika, max_request_timeout to górny limit, a pojedynczy silnik może posiadać własne ustawienie timeout. Zwiększenie tych wartości poprawia stabilność kosztem opóźnienia strony, dlatego należy wprowadzać zmiany co pół sekundy i obserwować /stats/errors, zamiast od razu ustawiać wartość 10.
W przypadku silnika, który faktycznie blokuje Twój adres IP, należy go usunąć. Każde wyszukiwanie czeka na najwolniejszy silnik, więc utrzymywanie trwale zawieszonego silnika zwiększa opóźnienia i nie zwraca żadnych wyników.
use_default_settings:
engines:
remove:
- googleZastosuj zmiany za pomocą docker compose restart searxng-core, a następnie wykonaj kilka wyszukiwań i przeładuj /stats/errors. Pusta strona po pięciu minutach rzeczywistego użytkowania oznacza, że zmiana zadziałała.
Adres IP centrum danych będzie traktowany jako bot
Adres Twojego VPS należy do puli adresowej dostawcy hostingu, a duże wyszukiwarki klasyfikują takie zakresy jako źródła automatyzacji. Niektóre z nich serwują CAPTCHA przy każdym żądaniu z takiego adresu, niezależnie od poprawności nagłówków czy częstotliwości zapytań. Żadne ustawienie w settings.yml nie zmieni tej oceny.
Można natomiast zmienić wybór wyszukiwarek oraz zdecydować, czy instancja ma być publicznie dostępna. Instancja prywatna, używana przez jedno gospodarstwo domowe, rzadko wywołuje blokady. Instancja publiczna działająca na adresie IP hostingu będzie otrzymywać zawieszenia od najbardziej restrykcyjnych wyszukiwarek; jest to normalne zachowanie oprogramowania, a nie błąd w konfiguracji. SearXNG może kierować zapytania do wyszukiwarek przez proxy przy użyciu outgoing.proxies lub outgoing.using_tor_proxy, co przenosi ruch na inny adres. Węzły wyjściowe (exit nodes) oraz tanie pule proxy są oceniane gorzej niż zakresy hostingowe, dlatego należy się spodziewać, że takie rozwiązanie pogorszy jakość wyników.
Monitorowanie instancji w celu szybkiego wykrywania awarii
SearXNG odpowiada na swoim porcie nawet wtedy, gdy wszystkie silniki są wstrzymane, więc test dostępności sprawdzający wyłącznie kod statusu pozostaje zielony, mimo że instancja nie zwraca wyników. Należy sprawdzać zawartość: trzeba wykonać rzeczywiste wyszukiwanie i dopasować słowo oczekiwane w treści odpowiedzi. Monitorowanie słów kluczowych w Uptime Kuma realizuje to zadanie bez dodatkowych narzędzi. Należy również monitorować /stats/errors po każdej aktualizacji wersji, ponieważ silniki zmieniają swój kod HTML, co powoduje awarię parsera niezależnie od limitów zapytań.
FAQ
Dlaczego SearXNG zwraca błąd 429 każdemu użytkownikowi po umieszczeniu go za reverse proxy?
Ponieważ mechanizm ograniczający (limiter) traktuje proxy jako klienta. SearXNG odczytuje X-Forwarded-For tylko wtedy, gdy adres połączenia znajduje się na liście trusted_proxies w pliku /etc/searxng/limiter.toml. Jeśli adres nie jest wymieniony, wszyscy użytkownicy współdzielą jeden licznik i wspólnie przekraczają limit 150 żądań na 10 minut. Należy dodać adres, z którego łączy się proxy (w przypadku Docker jest to zazwyczaj zakres sieci bridge 172.16.0.0/12) oraz upewnić się, że proxy przesyła nagłówki X-Real-IP i X-Forwarded-For. Nigdy nie należy dodawać zakresu, nad którym nie sprawuje się kontroli, ponieważ zaufana sieć pozwala każdemu użytkownikowi na ustawienie tego nagłówka i podszycie się pod inną tożsamość w każdym żądaniu.
Ile żądań API na godzinę pozwala wykonać limiter SearXNG?
Cztery na adres IP w ciągu godziny. Każde żądanie formatu innego niż HTML jest liczone w osobnej godzinnej puli, a limit ten jest zdefiniowany w searx/botdetection/ip_limit.py, a nie w limiter.toml, więc nie można go zwiększyć poprzez plik konfiguracyjny. Agent lub skrypt wykonuje to w ramach jednego zadania. Należy dodać adres klienta do pass_ip w pliku limiter.toml lub łączyć się z instancją przez sieć wewnętrzną, gdzie limiter nie widzi żądań.
Dlaczego wyniki wyszukiwania są puste, mimo braku błędu 429?
Wyszukiwarki odrzucają żądania z Twojego serwera, a nie od Twoich użytkowników. Otwórz /stats/errors na własnej instancji: zawiera ona listę wyszukiwarek, które zawiodły, wraz z przyczyną. Komunikat o CAPTCHA lub odmowie dostępu oznacza, że wyszukiwarka zablokowała adres IP Twojego serwera. SearXNG zawiesza wtedy daną wyszukiwarkę na godzinę w przypadku zbyt dużej liczby żądań lub na dobę w przypadku CAPTCHA. Żadne ustawienie lokalne nie zniesie blokady nałożonej przez dostawcę zewnętrznego, dlatego należy usunąć wyszukiwarki blokujące Twój adres i pozostawić te, które odpowiadają poprawnie.
Czy należy włączać limiter na prywatnej instancji?
Jeśli do instancji nie dociera żaden ruch poza Twoim, pozostaw limiter: false. Włączenie limitera dodaje zależność od Valkey, blokuje własne skrypty i chroni przed ruchem, którego nie otrzymujesz. Włącz go w momencie, gdy instancja uzyska publiczny adres, wraz z public_instance: true. Ta para ustawień jest celowa: przy public_instance: true i niedziałającym Valkey, proces kończy się statusem 1 zamiast działać bez ochrony.