SearXNG 429 fouten oplossen: rate limits en blokkades
Krijgt u 429 fouten in SearXNG? Ontdek of uw eigen limiter de boosdoener is of dat zoekmachines uw IP blokkeren. Analyseer uw logs en los het probleem direct en gericht op.
Waarom SearXNG 429-fouten retourneert
Een zelfgehoste SearXNG-instantie retourneert 429-fouten om twee ongerelateerde redenen, en de rate limit die u moet aanpassen is meestal niet degene die u vermoedt. De eerste reden is lokaal: de eigen limiter van SearXNG heeft besloten dat een verzoek van een bot kwam en antwoordde Too Many Requests met status 429. De tweede reden is upstream: een zoekmachine heeft het IP-adres van uw server geweigerd, wat uw gebruikers bereikt als een resultatenpagina waar informatie ontbreekt, niet als een 429.
Voor beide gevallen is geen gezamenlijke oplossing. De limiter is van u, dus u kunt deze wijzigen. Upstream-blokkades vinden plaats aan de kant van Google, dus niets in uw settings.yml zal deze opheffen. Het logboek vertelt u binnen een minuut met welke situatie u te maken heeft, dus begin daar.
Deze handleiding gaat uit van de containerinstallatie zoals beschreven in een zelfgehoste SearXNG-instantie op uw eigen VPS. Elke instellingsnaam hieronder is afkomstig uit de huidige upstream-documentatie en broncode, gecontroleerd in augustus 2026.
Lees het logbestand voordat u een instelling wijzigt
Reproduceer het probleem terwijl u een logvenster open heeft staan.
cd ./searxng/
docker compose logs -f searxng-coreLimiter-berichten zijn afkomstig van de logger genaamd searx.limiter en vermelden een IP-adres. Een treffer in de blocklist wordt weergegeven als BLOCK 203.0.113.10: matched BLOCKLIST, en een treffer in de allowlist als PASS 203.0.113.10: matched PASSLIST. Als de limiter de telleropslag niet kan bereiken, geeft het logbestand The limiter requires Valkey, please consult the documentation aan; dit betekent dat er helemaal niets wordt geteld.
Elke individuele bot-controle wordt gelogd op debug-niveau, waardoor u deze standaard niet ziet. Schakel debug in voor één test in settings.yml:
general:
debug: trueHet logbestand voegt vervolgens regels toe in de vorm van NOT OK (http_accept_language) naast het clientnetwerk, met de naam van de controle die is mislukt. Schakel dit daarna weer uit, omdat de upstream-documentatie adviseert om een geïmplementeerde instantie niet met debug ingeschakeld te draaien.
Engine-fouten zien er anders uit. Deze vermelden een engine in plaats van een IP-adres, en de meest voorkomende is een time-out:
HTTP requests timeout (search duration : 3.1 s, timeout: 3.0 s)Er is ook een pagina hiervoor. Met enable_metrics op de standaardwaarde true, registreert uw instantie engine-fouten op /stats/errors, en /preferences toont welke engines momenteel antwoorden. Als /stats/errors vol is en het logbestand bevat geen searx.limiter-regels, dan is de limiter niet het probleem.
Zet de versie vast voordat u begint met debuggen
De upstream container-setup bestaat uit twee bestanden.
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 .envHet compose-bestand haalt docker.io/searxng/searxng:${SEARXNG_VERSION:-latest} op. Een niet-ingestelde variabele betekent latest, en latest betekent dat de instantie onder uw handen verandert bij de volgende docker compose pull. Hierdoor kan een instelling die vorige week werkte, niet langer overeenkomen met de code die deze leest. SearXNG-tags bevatten een datum en een commit. De voorbeeldtag in de upstream .env.example is per augustus 2026 2026.3.25-541c6c3cb, dus stel een concrete waarde in in .env:
SEARXNG_VERSION=2026.3.25-541c6c3cbControleer de gepubliceerde tags en zet de release vast die u daadwerkelijk heeft getest; debug vervolgens tegen een vast doel. Hetzelfde .env-bestand bevat uw geheime sleutel, dus lees hoe env-bestanden en secrets werken in Docker Compose voordat u die map ergens commit.
De limiter vereist Valkey om te kunnen functioneren
De limiter telt verzoeken per client en deze aantallen moeten worden gedeeld tussen worker-processen. Deze opslag is Valkey, de onderhouden fork van Redis. Oudere SearXNG-handleidingen noemen deze instelling redis:. Huidige releases lezen valkey:, dus kopieer de sleutelnaam uit de actuele documentatie in plaats van uit een ouder bericht.
use_default_settings: true
server:
secret_key: "change-this-value"
limiter: true
public_instance: false
valkey:
url: valkey://searxng-valkey:6379/0Het upstream compose-bestand draait al een searxng-valkey-service op de docker.io/valkey/valkey:9-alpine-image, waardoor die hostnaam binnen het compose-netwerk wordt omgezet. Dezelfde waarde kan worden ingesteld met de SEARXNG_VALKEY_URL-omgevingsvariabele, en een Unix socket URL (unix:///path/to/socket.sock?db=0) werkt wanneer SearXNG en Valkey dezelfde host delen.
Wat er gebeurt als de opslag ontbreekt, hangt af van één andere sleutel. Bij public_instance: false logt de limiter de Valkey-fout en geeft het op, waardoor de instantie blijft draaien zonder enige rate limiting. Bij public_instance: true roept het proces in plaats daarvan sys.exit(1) aan, omdat een open instantie met defecte bot-bescherming binnen een dag CAPTCHAs (completely automated public turing test to tell computers and humans apart) van elke engine verzamelt. Een container die in een lus herstart direct nadat u public_instance: true heeft ingesteld, is hiervan het gevolg, en de laatste regel voor elke exit noemt Valkey.
Wat de limiter daadwerkelijk telt
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"
}
]Een normale client krijgt 15 verzoeken binnen een burst-venster van 20 seconden en 150 binnen een venster van 10 minuten. Zodra een verzoek als verdacht wordt gemarkeerd, valt dezelfde client terug naar 2 per burst-venster. De laatste rij is het strengst: na 3 gemarkeerde verzoeken binnen een venster van 30 dagen, wordt dat adres omgeleid naar de startpagina in plaats van dat er gezocht kan worden, en het logbestand vermeldt BLOCK: too many request from ... in SUSPICIOUS_IP_WINDOW (redirect to /).
Deze getallen zijn constanten in searx/botdetection/ip_limit.py. Het zijn geen instellingen en limiter.toml stelt ze niet bloot, dus het wijzigen ervan vereist het aanpassen van de broncode. Wat /etc/searxng/limiter.toml wel beheert, zijn de adresprefixen die worden gebruikt om clients te groeperen, de lijst met vertrouwde proxy's, de optionele link-tokencontrole, en de toegestane en geblokkeerde lijsten.
Een verzoek wordt als verdacht gemarkeerd door header-controles, en elke controle heeft een naam die u in het debug-logbestand zult zien:
http_accept: deAcceptheader bevat niettext/html.http_accept_encoding: deAccept-Encodingheader noemt nochgzip, nochdeflate.http_accept_language: er is geenAccept-Languageheader aanwezig.http_connection: deConnectionheader is ingesteld opclose.http_user_agent: deUser-Agentontbreekt of komt overeen met een bekend bot-patroon.http_sec_fetch: deSec-Fetch-ModeofSec-Fetch-Destheader is niet wat een browser verstuurt.
Een browser verstuurt al deze headers. Een standaard curl-aanroep verstuurt er bijna geen, waardoor een handgeschreven testverzoek bij de eerste poging wordt gemarkeerd, terwijl dezelfde zoekopdracht wel werkt in een browsertabblad. Daarom is "het werkt in mijn browser, maar mijn script krijgt 429" het normale resultaat en geen mysterie.
Achter een reverse proxy blokkeert de limiter iedereen tegelijk
Dit is de meest voorkomende manier om een werkende instantie onbruikbaar te maken. SearXNG haalt het clientadres uit het eerste niet-vertrouwde IP-adres in X-Forwarded-For, valt terug op X-Real-IP, en valt daarna terug op het adres dat de verbinding heeft geopend. Of deze headers überhaupt worden vertrouwd, wordt bepaald door trusted_proxies in limiter.toml.
Als het adres van uw proxy niet in die lijst staat, worden de headers genegeerd en komt elke bezoeker binnen met het adres van de proxy. Zij delen dan één teller, waardoor de hele site wordt geblokkeerd zodra het totaal de 150 verzoeken in 10 minuten overschrijdt. Eén gebruiker die een resultatenpagina een paar keer ververst, haalt iedereen offline.
Te veel vertrouwen is echter gevaarlijker. Als een publiek bereik wordt vermeld, kan elke bezoeker zijn eigen X-Forwarded-For-header sturen en voor elk verzoek een nieuwe identiteit kiezen, wat de limiter uitschakelt voor iedereen die weet hoe dit moet. Vermeld alleen het adres van waaruit uw eigen proxy verbinding maakt. In Docker is dat meestal een bridge-netwerk binnen 172.16.0.0/12, en die regel wordt standaard uitgeschakeld (gecommentarieerd) geleverd.
[botdetection]
ipv4_prefix = 32
ipv6_prefix = 48
trusted_proxies = [
'127.0.0.0/8',
'::1',
'172.16.0.0/12',
]De proxy moet de headers ook meesturen. Nginx voegt deze niet uit zichzelf toe:
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 en Traefik stellen de forwarded headers automatisch in, dus bij die software hoeft u alleen het trusted_proxies-gedeelte van de configuratie uit te voeren. De afwegingen worden besproken in het kiezen van een reverse proxy voor een self-hosted service. Om een van beide opstellingen te verifiëren, zet u debug aan, voert u één zoekopdracht uit vanaf uw telefoon via mobiele data, en controleert u of het netwerk in de logregel het adres van uw telefoon is in plaats van dat van de proxy.
Uw agent ontvangt vier API-verzoeken per uur
De JSON-uitvoer is standaard uitgeschakeld, dus een agent heeft deze toevoeging nodig:
search:
formats:
- html
- jsonLees nu de tabelrij opnieuw. Elk verzoek dat om een ander formaat dan HTML vraagt, wordt geteld in zijn eigen venster: 4 verzoeken per 1 hour, per adres. Een onderzoeksagent verbruikt dit in één taak, en elke aanroep daarna resulteert in een 429-foutmelding. Het verhogen van de limiet is geen optie, omdat het getal in de broncode is vastgelegd.
De juiste oplossing is om de limiter te laten weten dat deze client geen onbekende is. Voeg het adres toe aan de pass-lijst in limiter.toml:
[botdetection.ip_lists]
block_ip = []
pass_ip = [
'10.8.0.0/24',
]
pass_searxng_org = truepass_ip heeft voorrang op elke andere methode, dus een client op de allowlist slaat ook de header-controles over en een kale curl-aanroep werkt. Houd het bereik zo klein mogelijk en geef de voorkeur aan een VPN-subnet of een container-netwerk boven alles wat routeerbaar is. De andere juiste oplossing is om de agent volledig buiten het publieke pad te houden: verwijs deze naar het containeradres op het interne netwerk, waar de proxy en de bijbehorende limiter het verkeer nooit zien. Het configureren hiervan wordt behandeld in een AI-agent een SearXNG-zoekfunctie geven.
De optie die u moet vermijden, is het verwijzen van een agent naar een publieke instantie die door iemand anders wordt beheerd. Dat is de snelste manier om het IP-adres van een vrijwilliger te laten blokkeren door upstream-engines, en dat is precies de reden waarom het JSON-formaat standaard is uitgeschakeld.
Wanneer de engines u blokkeren
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"
}
]Wanneer een engine antwoordt met een eigen 429-foutmelding of een CAPTCHA-pagina, genereert SearXNG een benoemde exceptie en stopt het tijdelijk met het bevragen van die engine. Een 'too-many-requests'-antwoord schorst de engine voor 3600 seconden. Een standaard CAPTCHA of een 'access-denied'-antwoord schorst deze voor 1 day. Een CAPTCHA die via Cloudflare wordt geserveerd, schorst de engine voor 15 days; dit is de langste standaardduur in de lijst, omdat dit antwoord betekent dat de blokkade op de edge plaatsvindt en opnieuw proberen geen zin heeft.
Gewone fouten gebruiken andere instellingen. Een timeout of een parse-fout schorst de engine voor een korte tijd die is afgeleid van search.ban_time_on_fail, wat standaard 5 seconden is en door search.max_ban_time_on_fail wordt begrensd op 120 seconden. Een trage engine herstelt zichzelf dus binnen enkele minuten, terwijl een geblokkeerde engine voor uren verdwijnt. Dat verschil verklaart een symptoom dat gebruikers vaak als willekeurig rapporteren: de resultaten zijn in orde, totdat de resultaten van één engine de rest van de middag verdwijnen.
Het is raadzaam om timeouts op te lossen voordat u de oorzaak elders zoekt. De standaardwaarde voor request_timeout is 2.0 seconden, wat krap is voor een kleine VPS die zich ver van de dichtstbijzijnde edge-server van een engine bevindt.
outgoing:
request_timeout: 3.0
max_request_timeout: 10.0
engines:
- name: bing
timeout: 5.0request_timeout is de standaardwaarde voor elke engine, max_request_timeout is het maximum, en een individuele engine kan een eigen timeout hebben. Het verhogen van deze waarden ruilt paginalatentie in voor minder fouten; verhoog ze daarom in stappen van een halve seconde en houd /stats/errors in de gaten in plaats van direct naar 10 te springen.
Voor een engine die uw adres daadwerkelijk blokkeert, kunt u deze het beste verwijderen. Elke zoekopdracht wacht op de traagste engine, dus het behouden van een permanent geschorste engine kost latentie zonder resultaat op te leveren.
use_default_settings:
engines:
remove:
- googlePas wijzigingen toe met docker compose restart searxng-core, voer daarna enkele zoekopdrachten uit en ververs /stats/errors. Een lege pagina na vijf minuten daadwerkelijk gebruik betekent dat de wijziging heeft gewerkt.
Een IP-adres uit een datacenter wordt als bot aangemerkt
Uw VPS-adres behoort tot een reeks van een hostingprovider en grote zoekmachines beoordelen deze reeksen als automatisering. Sommige van deze engines tonen een CAPTCHA bij elk verzoek vanaf een dergelijk adres, ongeacht hoe correct de headers zijn of hoe laag het tempo ligt. Geen enkele instelling in settings.yml verandert dit oordeel.
Wat u wel kunt aanpassen, is welke engines u bevraagt en of uw instantie publiekelijk vermeld staat. Een privé-instantie die door één huishouden wordt gebruikt, activeert zelden beveiligingsmechanismen. Een publieke instantie op een hosting-IP zal echter schorsingen verzamelen bij de strengste engines; dit is het normale gedrag van de software en geen fout in uw configuratie. SearXNG kan engine-verzoeken routeren via een proxy met outgoing.proxies of outgoing.using_tor_proxy, waardoor het verkeer naar een ander adres wordt verplaatst. Exit-nodes en goedkope proxy-pools worden echter slechter beoordeeld dan hosting-reeksen, dus verwacht dat deze stap de resultaten eerder zal verslechteren.
Monitor de instantie om als eerste op de hoogte te zijn
SearXNG antwoordt op zijn poort, zelfs wanneer alle engines zijn gepauzeerd. Een uptime-check die alleen naar de statuscode kijkt, blijft dus groen terwijl de instantie niets teruggeeft. Controleer in plaats daarvan de inhoud: voer een echte zoekopdracht uit en match een woord dat u in de response body verwacht. Uptime Kuma keyword monitoring doet precies dat zonder extra tooling. Monitor /stats/errors ook na elke versie-update, omdat engines hun HTML wijzigen en een parser kan breken zonder dat er sprake is van een rate limit.
FAQ
Waarom geeft SearXNG aan elke bezoeker een 429-foutmelding nadat ik het achter een reverse proxy heb geplaatst?
Omdat de limiter de proxy als de client telt. SearXNG leest alleen X-Forwarded-For wanneer het verbindende adres in trusted_proxies in /etc/searxng/limiter.toml staat vermeld. Als dit niet het geval is, delen alle bezoekers één teller en overschrijden zij gezamenlijk de limiet van 150 verzoeken per 10 minuten. Voeg het adres toe van waaruit uw proxy verbinding maakt, wat in Docker meestal het bridge-bereik 172.16.0.0/12 is, en zorg ervoor dat de proxy X-Real-IP en X-Forwarded-For meestuurt. Vermeld nooit een bereik dat u niet beheert, omdat een vertrouwd netwerk elke bezoeker in staat stelt die header in te stellen en voor elk verzoek een nieuwe identiteit te kiezen.
Hoeveel API-verzoeken per uur staat de SearXNG-limiter toe?
Vier per IP-adres per uur. Elk verzoek dat om een ander formaat dan HTML vraagt, telt mee in een apart venster van een uur, en die limiet is ingesteld in searx/botdetection/ip_limit.py in plaats van in limiter.toml, waardoor deze niet via de configuratie kan worden verhoogd. Een agent of script verwerkt dit in één taak. Voeg het adres van de client toe aan pass_ip in limiter.toml, of benader de instantie via een intern netwerk waar de limiter het verzoek niet ziet.
Waarom zijn mijn zoekresultaten leeg zonder dat er een 429-fout optreedt?
De zoekmachines weigeren uw server, niet uw gebruikers. Open /stats/errors op uw eigen instantie: hierin staan de zoekmachines die zijn mislukt en de reden daarvoor. Een CAPTCHA of een melding van geweigerde toegang betekent dat de zoekmachine het IP-adres van uw server heeft geblokkeerd. SearXNG schorst de zoekmachine vervolgens voor een uur na een 'te veel verzoeken'-antwoord en voor een dag na een CAPTCHA. Geen enkele lokale instelling heft een blokkade van een externe partij op, dus verwijder de zoekmachines die uw adres blokkeren en behoud de zoekmachines die wel antwoorden.
Moet ik de limiter op een privé-instantie inschakelen?
Als er niets anders dan uzelf de instantie bereikt, laat limiter: false dan uitgeschakeld. Het voegt een Valkey-afhankelijkheid toe, blokkeert uw eigen scripts en biedt bescherming tegen verkeer dat u niet heeft. Schakel het in zodra de instantie een publiek adres krijgt, samen met public_instance: true. Dat paar is bewust gekozen: met public_instance: true en zonder werkende Valkey stopt het proces met status 1 in plaats van onbeschermd te draaien.