SSD Nodes Learn Hosting plans →
Guias Matt ConnorPor Matt Connor

Como hospedar seu próprio SearXNG com Docker Compose

Instale o SearXNG em um VPS com Docker Compose, configure settings.yml e o limiter, use nginx com TLS e consulte a API JSON nos seus scripts.

O que você vai criar

A hospedagem própria do SearXNG fornece um mecanismo de pesquisa privado executado no seu próprio servidor. O SearXNG é um mecanismo de metapesquisa: recebe a sua consulta, consulta outros mecanismos como Google, Bing, DuckDuckGo e Wikipedia e combina os resultados numa única página. Não é criado nenhum perfil nem é definido nenhum cookie de rastreamento, porque a única máquina que mantém a sua consulta é a sua. Se encontrou guias antigos sobre algo chamado simplesmente Searx, esse é o projeto a partir do qual este fork foi criado. O projeto não recebe manutenção desde setembro de 2023, quando o próprio repositório anunciou que o Searx deixou de ser mantido. O único commit posterior, uma nota de documentação em maio de 2026, não alterou essa situação. Por isso, verifique o estado de ambos antes de seguir um deles.

A stack é pequena. São dois containers, um ficheiro de definições e um reverse proxy. Ela funciona bem num VPS pequeno, o que não acontece com todos os serviços self-hosted: as bibliotecas de fotografias comparadas em PhotoPrism e Immich definem o consumo mínimo de RAM pelo indexador, e não pela aplicação web. A decisão principal é saber se a instância será privada, ou seja, apenas você e os seus próprios scripts terão acesso, ou pública, permitindo que qualquer pessoa na internet faça consultas. Essa escolha altera as definições de segurança, por isso faça-a antes de escrever qualquer comando. A resposta predefinida é privada.

Há uma segunda razão para executar uma instância. Uma instância do SearXNG disponibiliza uma API JSON. Assim, qualquer script ou agente de IA que você escrever terá uma API de pesquisa sob o seu controlo, sem chave, cobrança por consulta ou mensagens sobre quotas.

Instalar o SearXNG com o Docker Compose

O projeto publica uma imagem de contentor e um ficheiro Compose. Transfira ambos para um servidor Ubuntu 24.04 novo que já tenha o Docker Engine e o plugin Compose. Se o Docker é novidade para si, comece por Noções básicas do Docker Compose num VPS e depois volte aqui.

sudo install -d -o "$USER" -g "$USER" -m 750 /opt/searxng
cd /opt/searxng
mkdir -p core-config
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 define dois serviços. core é o próprio SearXNG e valkey é um armazenamento de dados em memória usado para limitar a taxa de pedidos e manter estado temporário. O ficheiro monta ./core-config/ em /etc/searxng/ dentro do contentor, por isso tudo o que configurar fica nesse único diretório no host.

Agora edite .env. Todas as linhas do exemplo fornecido estão comentadas. Por isso, o contentor arranca na porta 8080 em todos os endereços. Retire os comentários e defina estes três valores.

SEARXNG_VERSION=latest
SEARXNG_HOST=127.0.0.1
SEARXNG_PORT=8080

SEARXNG_HOST=127.0.0.1 é o parâmetro importante. Faz com que a porta publicada seja 127.0.0.1:8080:8080 em vez de um 8080:8080 simples. Este último é publicado pelo Docker em todos os endereços. Assim, o contentor responde apenas no endereço de loopback e a Internet não consegue aceder-lhe diretamente. Se ignorar este passo, o contentor fica exposto assim que arranca, porque uma porta publicada pelo Docker é inserida antes das regras da firewall. Vale a pena ler esta armadilha na íntegra: as portas publicadas pelo Docker ignoram o ufw.

SEARXNG_VERSION=latest é adequado enquanto está a aprender. Num servidor importante, fixe a tag. Em outubro de 2026, as tags de lançamento são baseadas na data e têm um formato como 2026.10.4-d48c4b555. Assim, uma implantação com tag fixa só é atualizada quando decidir fazê-lo, e não quando o registo for alterado. A mesma disciplina é útil para qualquer outro serviço de longa duração no servidor. Por isso, um relay RustDesk autoalojado também fixa as tags das imagens: uma atualização não supervisionada de um serviço de acesso remoto manifesta-se no pior momento possível.

settings.yml: as partes relevantes

Crie core-config/settings.yml antes do primeiro arranque. use_default_settings: true instrui o SearXNG a carregar os valores predefinidos fornecidos pelo próprio programa e, em seguida, aplicar apenas as chaves que escreveu. Assim, o ficheiro mantém-se curto e continua compatível com atualizações que adicionem novas opções.

Gere primeiro o segredo, porque o valor será escrito diretamente no ficheiro.

openssl rand -hex 32
use_default_settings: true

general:
  instance_name: "search.example.com"

server:
  base_url: "https://search.example.com/"
  secret_key: "paste-the-openssl-output-here"
  limiter: false
  public_instance: false
  image_proxy: true

valkey:
  url: valkey://valkey:6379/0

search:
  safe_search: 0
  autocomplete: "duckduckgo"
  formats:
    - html
    - json

secret_key assina os dados de sessão e dos tokens. O valor predefinido fornecido pelo programa é a cadeia literal ultrasecretkey. Se o deixar, qualquer pessoa que conheça esse valor pode falsificar esses tokens. Substitua-o uma vez e não o altere depois: alterá-lo elimina todas as preferências guardadas.

base_url tem de ser o endereço HTTPS público, com a barra final. É esse o endereço que o SearXNG escreve nas ligações que gera. Se o deixar apontar para localhost, a ligação para a "página seguinte" num navegador remoto apontará para a própria máquina do leitor e falhará.

formats determina os tipos de saída que o endpoint web pode produzir. json não faz parte da lista predefinida, por isso um pedido JSON devolve 403 até o adicionar. image_proxy: true encaminha as miniaturas dos resultados através do seu servidor, para que os sites que alojam essas imagens nunca vejam os endereços dos seus visitantes.

O valkey.url usa o hostname valkey porque esse é o nome do serviço no ficheiro Compose, e o Compose coloca ambos os contentores na mesma rede, onde os nomes dos serviços são resolvidos. Aponte-o para localhost e o limitador falhará, porque, dentro do contentor core, localhost refere-se a esse próprio contentor.

O segredo está num ficheiro de texto simples, por isso proteja também o diretório que o contém. chmod 750 /opt/searxng impede o acesso de outros utilizadores do host. Também pode restringir core-config/settings.yml para o modo 600 sem causar problemas: o entrypoint do contentor oficial começa como root e, com FORCE_OWNERSHIP no valor predefinido de true, atribui o diretório de configuração montado ao utilizador searxng do próprio contentor antes de o SearXNG arrancar. Assim, o ficheiro continua legível para esse utilizador. O efeito secundário aparece no host: esse mesmo passo altera o proprietário de core-config/ para o ID de utilizador do contentor, por isso conte com a necessidade de editar o ficheiro usando sudo depois.

Inicie a stack e verifique-a.

cd /opt/searxng
docker compose up -d
docker compose ps
curl -I http://127.0.0.1:8080/

docker compose ps deve mostrar ambos os contentores no estado running. O curl deve responder com HTTP/1.1 200 OK. Se não responder, consulte docker compose logs core, porque um erro YAML em settings.yml aparece aí como um erro de análise que indica a linha.

Coloque-o atrás do nginx com TLS

O contentor escuta apenas na interface de loopback. Por isso, o nginx torna-o acessível e também adiciona a segurança da camada de transporte (TLS). Escreva /etc/nginx/sites-available/searxng.

server {
    listen 80;
    server_name search.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
sudo ln -s /etc/nginx/sites-available/searxng /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d search.example.com

nginx -t apresenta syntax is ok e test is successful antes de recarregar. O Certbot reescreve o mesmo ficheiro para escutar na porta 443 com um certificado e adiciona um redirecionamento da porta 80. O registo DNS de search.example.com já tem de apontar para este servidor, porque a autoridade de certificação prova a propriedade ao obter um ficheiro através de HTTP. O guia completo, incluindo a renovação, está em no guia do Certbot e do nginx para Ubuntu 24.04.

Os dois cabeçalhos de encaminhamento não são decorativos. Sem X-Forwarded-For e X-Real-IP, todos os pedidos que chegam ao SearXNG transportam o endereço do proxy. Assim, o limitador de taxa vê um único cliente a gerar todo o tráfego e não consegue distinguir os visitantes.

Porque os scripts e os agentes precisam de uma API de pesquisa JSON

Com json em formats, o mesmo endpoint que apresenta a página devolve dados estruturados.

curl -s 'http://127.0.0.1:8080/search?q=wireguard+mtu&format=json' \
  | jq -r '.results[0:5][] | .url'

É devolvido um objeto com um array results, em que cada entrada contém url, title, content e o mecanismo que forneceu o resultado, além de answers, infoboxes e suggestions. Isto é suficiente para alimentar um sumarizador, um verificador de ligações ou um ciclo de investigação. Passar esses resultados a um modelo de linguagem é um passo maior do que parece, porque os resultados da pesquisa são texto não confiável que pode conter instruções próprias. É isto que apontar um agente de IA para a sua instância SearXNG explica em detalhe.

Isto é importante para qualquer aplicação com agentes. Um modelo de linguagem tem uma data-limite dos dados de treino. Por isso, precisa de pesquisa em tempo real para responder a perguntas sobre o presente. As APIs de pesquisa comerciais cobram por consulta e impõem limites de velocidade rigorosos. Uma instância local custa apenas um container num servidor que já paga, e as consultas nunca saem desse servidor. Se estiver a integrar ferramentas num modelo, o mesmo raciocínio aplica-se a executar servidores MCP num VPS, onde uma ferramenta de pesquisa costuma ser a primeira a ser adicionada.

Existem duas regras para utilizar a API. Mantenha a instância privada. Associe o lado da API ao endereço de loopback ou a uma rede privada. Permita o acesso apenas aos seus próprios hosts. O mesmo tratamento é necessário para um rastreador de localização autoalojado, que fornece a posição do telefone a um endpoint. Depois, faça as consultas com moderação. O SearXNG encaminha o seu pedido para mecanismos de pesquisa reais. Por isso, um script que execute cem consultas por segundo está a pedir ao Google para bloquear o seu servidor.

O limitador e o que muda numa instância pública

O limitador é a defesa do SearXNG contra bots. Monitoriza os cabeçalhos dos pedidos, os endereços e as taxas de pedidos, e descarta o tráfego que parece automatizado. Precisa do Valkey para guardar esse estado, razão pela qual o ficheiro Compose o inclui.

Numa instância privada, mantenha limiter: false. Os seus próprios scripts são tráfego automatizado por definição, pelo que o limitador bloquearia exatamente as chamadas JSON para as quais criou a instância. O controlo de acesso deve ficar a cargo do reverse proxy: um par allow e deny no location do nginx, autenticação HTTP básica ou uma firewall que apenas aceite ligações dos seus outros servidores. Se precisar de aceder à instância privada a partir de um portátil que muda de rede, colocar um endereço onion v3 à frente dela é uma quarta opção, porque o tor liga-se à mesma porta de loopback sem expor nada de novo à Internet.

Se publicar a instância para outras pessoas, ative ambas as opções.

server:
  limiter: true
  public_instance: true

O controlo mais detalhado está em core-config/limiter.toml, que o contentor lê a partir de /etc/searxng/limiter.toml. Escreva apenas as chaves que pretende alterar. Atrás de um proxy, tem de declarar o proxy; caso contrário, o limitador considera o endereço do nginx como o único cliente abusivo.

[botdetection]
trusted_proxies = [
  '127.0.0.0/8',
  '::1',
]

[botdetection.ip_limit]
link_token = true

link_token = true faz o SearXNG emitir um token que apenas uma sessão de navegador real obtém, o que impede a maioria dos scrapers simples. Espere que uma instância pública os atraia em poucos dias. Espere também erros dos motores, porque quanto mais tráfego encaminhar, mais cedo os motores upstream começarão a devolver CAPTCHAs ao endereço do seu servidor. Uma instância pública do SearXNG exige manutenção contínua. Uma instância privada não exige, razão pela qual aparece em muitas listas curtas de serviços que vale a pena alojar por conta própria em 2026. Nem todas as entradas dessas listas são infraestrutura: reconstruir uma biblioteca do Jellyfin como uma loja de aluguer dos anos 90 onde se pode passear usa o mesmo contentor atrás do mesmo bloco do nginx, apontado para uma noite, e não para um fluxo de trabalho.

Por que as pesquisas não retornam resultados

Abra /stats na sua instância. Esta página lista todos os motores, com a respetiva taxa de erros e tempo de resposta. É o primeiro local a consultar quando os resultados parecem escassos.

Um motor apresentado com erros "Access denied" ou "CAPTCHA" bloqueou o endereço do seu servidor. Isto é comum em endereços de intervalos de centros de dados, porque os motores de pesquisa assumem que pertencem a scrapers. O SearXNG suspende então o motor com falhas durante algum tempo, em vez de repetir o pedido. Assim, um motor bloqueado deixa de contribuir para os resultados sem chamar a atenção. Desative-o em settings.yml ou aceite a perda. Essas não são as únicas opções, porque alguns bloqueios por CAPTCHA têm uma correção que permanece após um reinício. Os restantes motores continuam a responder. Um erro 429 é o caso ambíguo, porque pode ser causado pelo seu próprio limitador ou por um motor upstream que está a recusar o seu servidor. A linha do log indica qual das duas situações está a ocorrer antes de começar a alterar definições.

Se todos os motores falharem ao mesmo tempo, o contentor não tem resolução de nomes de saída funcional ou não tem uma rota para a internet. Teste isso a partir do interior do contentor.

docker compose exec core wget -qO- https://duckduckgo.com > /dev/null && echo ok

Nada no servidor indicará quando esta verificação começar a falhar. Por isso, execute-a através do cron e faça uma falha enviar um alerta para o seu telemóvel através do seu próprio servidor ntfy, em vez de esperar até notar que os resultados ficaram escassos.

FAQ

O SearXNG torna as minhas pesquisas anónimas?

O SearXNG oculta a sua identidade dos motores que consulta, porque estes veem o seu servidor a fazer o pedido em vez do seu navegador. Não oculta a consulta do seu servidor nem oculta o seu servidor dos motores. Numa instância com um único utilizador, todo o tráfego desse endereço é seu, por isso o próprio endereço torna-se o identificador. O tráfego entre o seu navegador e a instância é protegido pelo certificado TLS. O que isto significa perante o seu ISP, o operador de uma instância pública e os próprios motores é explicado em o que o SearXNG realmente oculta.

Porque é que um pedido JSON devolve 403 Forbidden?

Há duas causas, e ambas estão relacionadas com a configuração. Ou json está ausente da lista formats em search: dentro de settings.yml, que é o estado predefinido, ou o limitador está ativo e classificou o seu script como um bot. Adicione primeiro o formato, reinicie com docker compose restart core e tente novamente. Se continuar a falhar, defina limiter: false e controle o acesso no reverse proxy.

Preciso do contentor Valkey se mantiver o limitador desativado?

Deixe-o em execução. O SearXNG funciona sem ele, mas o limitador não pode ser ativado posteriormente sem esse contentor, que também armazena outros dados de estado temporários. O contentor é pequeno e armazena apenas dados em cache, por isso removê-lo poupa muito pouco e elimina essa opção.

Como atualizo o SearXNG?

Execute docker compose pull e depois docker compose up -d em /opt/searxng. O Compose recria qualquer contentor cuja imagem tenha sido alterada e deixa o diretório core-config/ intacto, por isso settings.yml é preservado. Como use_default_settings: true combina as suas chaves com os valores predefinidos fornecidos, as opções adicionadas a montante recebem valores adequados em vez de invalidarem o ficheiro.

Várias pessoas podem partilhar uma instância?

Sim. Nesse caso, ative o limitador e defina public_instance: true. As preferências são armazenadas no navegador de cada visitante, por isso não há contas para gerir. Monitorize /stats durante uma semana depois de disponibilizar a instância, porque os motores a montante começam a rejeitar o seu servidor muito antes de notar resultados em falta.

Este artigo foi útil?