SSD Nodes Learn Hosting plans →
Guias Matt ConnorPor Matt Connor · Atualizado 2026-09-05

Como corrigir erros 429 e limites no SearXNG

Descubra se o erro 429 vem do limitador do SearXNG ou do bloqueio do IP pelos motores. Leia o log e aplique a correção certa sem alterar configurações às cegas.

Por que o SearXNG devolve erros 429

Uma instância SearXNG autoalojada devolve erros 429 por duas razões não relacionadas, e o limite de taxa que precisa de corrigir normalmente não é o que supõe. A primeira razão é local: o próprio limitador do SearXNG decidiu que um pedido veio de um bot e respondeu Too Many Requests com o estado 429. A segunda é upstream: um motor de pesquisa recusou o endereço IP do seu servidor, o que chega aos seus utilizadores como uma página de resultados com elementos em falta, não como um erro 429.

Os dois casos não têm a mesma correção. O limitador é seu, por isso pode alterá-lo. O bloqueio upstream ocorre do lado da Google, por isso nada na sua settings.yml o vai remover. O log indica qual dos casos está a ocorrer em cerca de um minuto, portanto comece por aí.

Este guia pressupõe a instalação em contentor descrita em uma instância SearXNG autoalojada no seu próprio VPS. Todos os nomes de definições abaixo vêm da documentação e do código-fonte upstream atuais, verificados em agosto de 2026.

Leia o log antes de alterar uma configuração

Reproduza o problema com uma janela de log aberta.

cd ./searxng/
docker compose logs -f searxng-core

As mensagens do limitador vêm do logger chamado searx.limiter e identificam um endereço IP. Uma ocorrência na blocklist aparece como BLOCK 203.0.113.10: matched BLOCKLIST, e uma ocorrência na allowlist aparece como PASS 203.0.113.10: matched PASSLIST. Se o limitador não conseguir alcançar o armazenamento dos contadores, o log regista The limiter requires Valkey, please consult the documentation. Isso significa que nada está a ser contabilizado.

Cada verificação individual de bot é registada no nível debug, por isso não a verá por predefinição. Ative o debug para um teste em settings.yml:

general:
  debug: true

O log passa então a incluir linhas no formato NOT OK (http_accept_language) junto à rede do cliente, identificando a verificação que falhou. Desative-o novamente depois, porque a documentação upstream recomenda não executar uma instância em produção com o debug ativado.

As falhas do motor têm um formato completamente diferente. Identificam um motor em vez de um IP, e a mais comum é um timeout:

HTTP requests timeout (search duration : 3.1 s, timeout: 3.0 s)

Também existe uma página para isto. Com enable_metrics no valor predefinido de true, a sua instância regista os erros dos motores em /stats/errors, e /preferences lista os motores que estão atualmente a responder. Se /stats/errors estiver cheio e o log não contiver linhas searx.limiter, o limitador não é a causa do problema.

Fixe a versão antes de investigar qualquer problema

A configuração do contentor a montante é composta por dois ficheiros.

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 .env

O ficheiro Compose obtém docker.io/searxng/searxng:${SEARXNG_VERSION:-latest}. Uma variável não definida significa latest, e latest significa que a instância muda no próximo docker compose pull. Assim, uma definição que funcionou na semana passada pode deixar de corresponder ao código que a lê. As tags do SearXNG incluem uma data e um commit. A tag de exemplo no .env.example a montante, em agosto de 2026, é 2026.3.25-541c6c3cb. Defina uma versão concreta em .env:

SEARXNG_VERSION=2026.3.25-541c6c3cb

Consulte as tags publicadas e fixe a versão que testou efetivamente. Depois, investigue os problemas usando um destino fixo. O mesmo ficheiro .env contém a sua chave secreta. Leia como funcionam os ficheiros de ambiente e os segredos no Docker Compose antes de confirmar esse diretório em qualquer repositório.

O limitador precisa do Valkey; caso contrário, não é executado

O limitador contabiliza os pedidos por cliente, e essas contagens têm de ser partilhadas entre os processos de trabalho. Esse armazenamento é o Valkey, o fork mantido do Redis. Os guias antigos do SearXNG chamam a esta definição redis:. As versões atuais leem valkey:. Por isso, copie o nome da chave da documentação atual, não de uma publicação antiga. Algumas dessas páginas são ainda mais antigas e descrevem o Searx em vez do SearXNG. Trata-se de uma base de código diferente, com um limitador diferente. Por isso, confirme para qual dos dois projetos a página foi escrita antes de copiar um bloco de configuração.

use_default_settings: true
server:
  secret_key: "change-this-value"
  limiter: true
  public_instance: false
valkey:
  url: valkey://searxng-valkey:6379/0

O ficheiro compose de origem já executa um serviço searxng-valkey com a imagem docker.io/valkey/valkey:9-alpine, por isso esse nome de host é resolvido dentro da rede do compose. O mesmo valor pode ser definido com a variável de ambiente SEARXNG_VALKEY_URL, e um URL de socket Unix (unix:///path/to/socket.sock?db=0) funciona quando o SearXNG e o Valkey partilham o mesmo host.

O comportamento quando o armazenamento está indisponível depende de outra chave. Com public_instance: false, o limitador regista o erro do Valkey e desiste, por isso a instância continua a servir pedidos sem qualquer limitação de taxa. Com public_instance: true, o processo chama sys.exit(1), porque uma instância pública com a proteção contra bots avariada recolhe CAPTCHAs (teste público de Turing completamente automatizado para distinguir computadores de pessoas) de todos os motores no espaço de um dia. Se um contentor reiniciar continuamente logo depois de definir public_instance: true, esta é a causa, e a última linha antes de cada saída identifica o Valkey.

O que o limitador realmente contabiliza

ChartSearXNG limiter: requests allowed per client IP, defaults in ip_limit.py
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"
  }
]

Um cliente normal pode fazer 15 pedidos dentro de uma janela de rajada de 20 segundos e 150 dentro de uma janela de 10 minutos. Quando um pedido é marcado como suspeito, o mesmo cliente fica limitado a 2 por janela de rajada. A última linha é a mais severa: depois de 3 pedidos marcados dentro de uma janela de 30 dias, esse endereço é redirecionado para a página inicial em vez de poder pesquisar, e o log indica BLOCK: too many request from ... in SUSPICIOUS_IP_WINDOW (redirect to /).

Estes números são constantes em searx/botdetection/ip_limit.py. Não são definições de configuração, e limiter.toml não os expõe. Para os alterar, é necessário editar o código-fonte. O que /etc/searxng/limiter.toml controla são os prefixos de endereço usados para agrupar clientes, a lista de proxies fidedignos, a verificação opcional do token da ligação e as listas de permissão e bloqueio.

Um pedido é marcado como suspeito por verificações de cabeçalhos, e cada verificação tem um nome que aparece no log de depuração:

  • http_accept: o cabeçalho Accept não contém text/html.
  • http_accept_encoding: o cabeçalho Accept-Encoding não identifica gzip nem deflate.
  • http_accept_language: não existe um cabeçalho Accept-Language.
  • http_connection: o cabeçalho Connection está definido como close.
  • http_user_agent: User-Agent está em falta ou corresponde a um padrão de bot conhecido.
  • http_sec_fetch: o cabeçalho Sec-Fetch-Mode ou Sec-Fetch-Dest não corresponde ao que um navegador envia.

Um navegador envia todos estes elementos. Uma chamada simples de curl envia quase nenhum deles. Por isso, um pedido de teste escrito manualmente é marcado logo na primeira tentativa, enquanto a mesma pesquisa funciona num separador do navegador. É por isso que "funciona no meu navegador, mas o meu script recebe 429" é o resultado normal, e não um mistério.

Atrás de um reverse proxy, o limitador bloqueia todos ao mesmo tempo

Esta é a forma mais comum de deixar uma instância funcional indisponível. O SearXNG obtém o endereço do cliente a partir do primeiro IP não confiável em X-Forwarded-For, recorre a X-Real-IP se necessário e, por fim, usa o endereço que abriu a ligação. A decisão de aceitar ou não esses cabeçalhos é controlada por trusted_proxies em limiter.toml.

Se o endereço do proxy não estiver nessa lista, os cabeçalhos são ignorados e todos os visitantes chegam com o endereço do proxy. Assim, partilham o mesmo contador e todo o site fica bloqueado quando o total ultrapassa 150 pedidos em 10 minutos. Um utilizador que recarregue uma página de resultados algumas vezes pode bloquear o acesso de todos os outros.

Confiar demasiado é pior. Se for indicado um intervalo público, qualquer visitante pode enviar o seu próprio cabeçalho X-Forwarded-For e escolher uma identidade nova em cada pedido. Isto desativa o limitador para quem souber explorar essa configuração. Liste apenas o endereço a partir do qual o seu próprio proxy estabelece ligações. No Docker, esse endereço costuma estar numa rede bridge dentro de 172.16.0.0/12, e essa linha vem comentada por predefinição.

[botdetection]
ipv4_prefix = 32
ipv6_prefix = 48

trusted_proxies = [
  '127.0.0.0/8',
  '::1',
  '172.16.0.0/12',
]

O proxy também tem de enviar os cabeçalhos. O Nginx não adiciona nenhum deles por si só:

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;
}

O Caddy e o Traefik configuram os cabeçalhos encaminhados automaticamente. Com essas ferramentas, só precisa da parte trusted_proxies da configuração. As vantagens e limitações são explicadas em escolher um reverse proxy para um serviço self-hosted. Para verificar qualquer uma das configurações, ative debug, faça uma pesquisa no telemóvel através de dados móveis e confirme que o endereço no log é o endereço do telemóvel, e não o do proxy.

O seu agente recebe quatro pedidos de API por hora

A saída JSON está desativada por predefinição, por isso é necessário adicioná-la ao agente:

search:
  formats:
    - html
    - json

Agora leia novamente a linha do gráfico. Qualquer pedido que solicite um formato diferente de HTML é contabilizado na sua própria janela: 4 pedidos por 1 hour, por endereço. Um agente de pesquisa esgota esse limite numa única tarefa, e todas as chamadas seguintes devolvem 429. Aumentar o limite não é uma opção, porque o número está definido no código-fonte.

A correção adequada é informar o limitador de que este cliente não é desconhecido. Adicione o respetivo endereço à lista de permissões em limiter.toml:

[botdetection.ip_lists]
block_ip = []

pass_ip = [
  '10.8.0.0/24',
]

pass_searxng_org = true

pass_ip tem prioridade sobre todos os outros métodos. Por isso, um cliente incluído na lista de permissões também ignora as verificações dos cabeçalhos, e uma chamada curl simples funciona. Mantenha o intervalo tão pequeno quanto possível. Prefira uma sub-rede VPN ou uma rede de contentores a qualquer rede encaminhável. A outra correção adequada é manter o agente completamente fora do caminho público. Aponte-o para o endereço do contentor na rede interna, onde o proxy e o respetivo limitador nunca veem o tráfego. A configuração dessa opção é explicada em dar ao agente de IA uma capacidade de pesquisa no SearXNG.

Evite apontar o agente para uma instância pública gerida por outra pessoa. Essa é a forma mais rápida de fazer com que o endereço IP de um voluntário seja bloqueado pelos motores upstream. É também por isso que o formato JSON está desativado por predefinição.

Quando os motores bloqueiam o acesso

ChartHow long SearXNG suspends an engine, search.suspended_times defaults
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"
  }
]

Quando um mecanismo responde com o seu próprio erro 429 ou com uma página CAPTCHA, o SearXNG gera uma exceção identificada e deixa de consultar esse mecanismo durante algum tempo. Uma resposta de excesso de pedidos suspende-o durante 3600 segundos. Uma resposta CAPTCHA simples ou de acesso negado suspende-o durante 1 day. Um CAPTCHA servido através do Cloudflare suspende-o durante 15 days, o período predefinido mais longo da lista, porque essa resposta indica que o bloqueio está na camada de edge e que repetir o pedido não ajudará. A linha de CAPTCHA em que o seu caso aparece altera o que vale a pena tentar a seguir, e os erros de CAPTCHA têm o seu próprio conjunto de correções depois de saber qual foi a exceção registada pela sua instância.

As falhas normais usam definições diferentes. Um timeout ou um erro de análise suspende o motor durante um período curto derivado de search.ban_time_on_fail, que por predefinição é de 5 segundos e é limitado a 120 segundos por search.max_ban_time_on_fail. Assim, um motor lento recupera automaticamente em poucos minutos, enquanto um motor bloqueado fica indisponível durante horas. Essa diferença explica um sintoma que muitas pessoas descrevem como aleatório: os resultados estão normais e, depois, os resultados de um motor desaparecem durante o resto da tarde.

Vale a pena corrigir os timeouts antes de atribuir a culpa a alguém. O valor predefinido de request_timeout é 2.0 segundos, o que é apertado para um VPS pequeno situado longe do servidor edge mais próximo de um motor.

outgoing:
  request_timeout: 3.0
  max_request_timeout: 10.0
engines:
  - name: bing
    timeout: 5.0

request_timeout é o valor predefinido para todos os motores, max_request_timeout é o limite máximo e um motor individual pode ter o seu próprio timeout. Aumentar estes valores troca latência das páginas por menos falhas. Por isso, avance em incrementos de meio segundo e monitorize /stats/errors, em vez de saltar diretamente para 10.

Se um motor estiver realmente a bloquear o seu endereço, remova-o. Cada pesquisa espera pelo motor mais lento. Manter um motor permanentemente suspenso aumenta a latência e não devolve resultados.

use_default_settings:
  engines:
    remove:
      - google

Aplique as alterações com docker compose restart searxng-core, execute algumas pesquisas e volte a carregar /stats/errors. Uma página vazia após cinco minutos de utilização real significa que a alteração funcionou.

Um endereço IP de um datacenter será tratado como um bot

O endereço do seu VPS pertence a uma faixa de hospedagem, e os grandes mecanismos de pesquisa classificam essas faixas como automação. Alguns apresentam um CAPTCHA a todos os pedidos provenientes de um endereço desse tipo, independentemente de os cabeçalhos serem corretos ou do ritmo ser lento. Nenhuma configuração em settings.yml altera essa avaliação. O facto de os mecanismos de pesquisa verem o seu servidor em vez da pessoa que escreve a consulta também faz parte do compromisso de privacidade assumido ao alojar o serviço por conta própria, e vale a pena ler o que o SearXNG realmente oculta antes de presumir que ele oculta mais.

Pode alterar os mecanismos de pesquisa consultados e decidir se a sua instância será listada publicamente. Uma instância privada usada por uma família raramente aciona bloqueios. Uma instância pública num IP de hospedagem acumulará suspensões nos mecanismos mais rigorosos. Esse é o estado normal do software, e não uma falha na sua configuração. O SearXNG pode encaminhar os pedidos aos mecanismos através de um proxy com outgoing.proxies ou outgoing.using_tor_proxy, transferindo o tráfego para outro endereço. Os nós de saída e os pools de proxies baratos têm uma classificação pior do que as faixas de hospedagem. Portanto, espere resultados piores depois dessa alteração.

Monitore a instância para detetar problemas primeiro

O SearXNG responde na sua porta mesmo quando todos os motores estão suspensos. Por isso, uma verificação de disponibilidade que monitoriza apenas o código de estado permanece verde enquanto a instância não devolve resultados. Verifique o conteúdo. Faça uma pesquisa real e procure no corpo da resposta uma palavra que espera encontrar. monitorização por palavra-chave do Uptime Kuma faz exatamente isso sem ferramentas adicionais. Monitorize também /stats/errors depois de cada atualização de versão, porque os motores alteram o respetivo HTML e um analisador pode deixar de funcionar sem qualquer relação com limites de taxa.

FAQ

Porque é que o SearXNG devolve 429 a todos os visitantes depois de o colocar atrás de um reverse proxy?

Porque o limiter está a contar o proxy como cliente. O SearXNG só lê X-Forwarded-For quando o endereço de ligação está listado em trusted_proxies em /etc/searxng/limiter.toml. Se não estiver listado, todos os visitantes partilham o mesmo contador e ultrapassam juntos o limite de 150 requests por 10 minutos. Adicione o endereço a partir do qual o proxy estabelece a ligação. No Docker, normalmente é o intervalo da bridge 172.16.0.0/12. Confirme também se o proxy envia X-Real-IP e X-Forwarded-For. Nunca liste um intervalo que não controle, porque uma rede confiável permite que qualquer visitante defina esse cabeçalho e escolha uma nova identidade em cada request.

Quantos requests de API por hora o limiter do SearXNG permite?

Quatro por endereço IP por hora. Qualquer request que peça um formato diferente de HTML é contado numa janela separada de uma hora. Esse limite é definido em searx/botdetection/ip_limit.py, e não em limiter.toml, por isso não pode ser aumentado a partir da configuração. Um agent ou script atinge esse limite durante uma tarefa. Adicione o endereço do cliente a pass_ip em limiter.toml, ou aceda à instância através de uma rede interna onde o limiter nunca veja o request.

Porque é que os meus resultados de pesquisa aparecem vazios sem um erro 429?

Os engines estão a recusar o seu servidor, não os seus utilizadores. Abra /stats/errors na sua própria instância. O ficheiro identifica cada engine que falhou e explica o motivo. Uma entrada de CAPTCHA ou de acesso negado significa que esse engine bloqueou o endereço IP do seu servidor. O SearXNG suspende então o engine durante uma hora depois de uma resposta de demasiados requests e durante um dia depois de um CAPTCHA. Nenhuma definição local remove um bloqueio a montante. Remova os engines que bloqueiam o seu endereço e mantenha os que respondem.

Devo ativar o limiter numa instância privada?

Se apenas você acede à instância, mantenha limiter: false desativado. Ele adiciona uma dependência do Valkey, bloqueia os seus próprios scripts e protege contra tráfego que não existe. Ative-o assim que a instância tiver um endereço público, juntamente com public_instance: true. Essa combinação é intencional: com public_instance: true e sem um Valkey funcional, o processo termina com o status 1 em vez de funcionar sem proteção.