SSD Nodes Learn 8GB de RAM — $66/año
Guías Matt ConnorPor Matt Connor · Actualizado 2026-08-02

Cómo alojar SearXNG privado con Docker y HTTPS

Monta SearXNG en tu VPS con Docker Compose: configura settings.yml, el limiter, nginx con TLS y una API JSON para consultar desde tus scripts.

Qué vas a crear

Alojar SearXNG en tu propio servidor te proporciona un motor de búsqueda privado. SearXNG es un metabuscador: recibe tu consulta, pregunta a otros motores como Google, Bing, DuckDuckGo y Wikipedia, y combina las respuestas en una sola página de resultados. No crea ningún perfil ni establece ninguna cookie de seguimiento, porque la única máquina que conserva tu consulta es la tuya.

La pila es pequeña. Consta de dos contenedores, un archivo de configuración y un proxy inverso. La decisión importante es si la instancia será privada, es decir, si solo tú y tus propios scripts podrán acceder a ella, o pública, es decir, si cualquier persona en Internet podrá consultarla. Esta elección cambia la configuración de seguridad, así que debes tomarla antes de escribir nada. La opción predeterminada es privada.

Hay una segunda razón para ejecutar una instancia. SearXNG ofrece una interfaz JSON, por lo que cualquier script o agente de IA que escribas tendrá una API de búsqueda propia, sin clave, sin facturación por consulta y sin correos sobre cuotas.

Instalar SearXNG con Docker Compose

El proyecto publica una imagen de contenedor y un archivo de Compose. Descargue ambos en un servidor Ubuntu 24.04 nuevo que ya tenga Docker Engine y el plugin de Compose. Si Docker es nuevo para usted, empiece por Conceptos básicos de Docker Compose en un VPS y vuelva después.

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

El archivo de Compose define dos servicios. core es SearXNG y valkey es un almacén de datos en memoria que se usa para limitar la frecuencia y almacenar estado temporal. Monta ./core-config/ en /etc/searxng/ dentro del contenedor, por lo que toda la configuración se encuentra en ese único directorio del host.

Ahora edite .env. Todas las líneas del ejemplo incluido están comentadas, por eso el contenedor se inicia en el puerto 8080 en todas las direcciones. Quite los comentarios y establezca estos tres valores.

SEARXNG_VERSION=latest
SEARXNG_HOST=127.0.0.1
SEARXNG_PORT=8080

SEARXNG_HOST=127.0.0.1 es el ajuste importante. Hace que el puerto publicado sea 127.0.0.1:8080:8080 en lugar de [::]:8080:8080, por lo que el contenedor responde únicamente en la dirección de loopback y no se puede acceder a él directamente desde Internet. Si omite este ajuste, el contenedor queda expuesto en cuanto se inicia, porque un puerto de Docker publicado se inserta antes que las reglas del firewall. Consulte la explicación completa de este problema: los puertos publicados de Docker omiten ufw.

SEARXNG_VERSION=latest es adecuado mientras está aprendiendo. En un servidor importante, fije la etiqueta. En julio de 2026, las etiquetas de lanzamiento se basan en fechas y tienen un formato como 2026.3.25-541c6c3cb, por lo que una implementación con una etiqueta fija se actualiza cuando usted lo decide y no cuando cambia el registro.

settings.yml: las partes importantes

Crea core-config/settings.yml antes del primer inicio. use_default_settings: true indica a SearXNG que cargue sus valores predeterminados incluidos y, después, aplique solo las claves que has escrito. Así, el archivo es corto y sigue funcionando después de las actualizaciones que añaden opciones nuevas.

Genera primero el secreto, porque el valor se escribe directamente en el archivo.

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 firma los datos de sesión y de los tokens. El valor predeterminado incluido es la cadena literal ultrasecretkey. Si la dejas, cualquiera que conozca ese valor predeterminado puede falsificar esos tokens. Sustitúyela una vez y no la cambies después: cambiarla elimina todas las preferencias guardadas.

base_url debe ser la dirección HTTPS pública, con la barra final. SearXNG la escribe en los enlaces que genera. Si la dejas apuntando a localhost, el enlace "página siguiente" de un navegador remoto apunta al propio equipo del lector y falla.

formats decide qué tipos de salida producirá el endpoint web. json no está en la lista predeterminada, por lo que una solicitud JSON devuelve 403 hasta que lo añades. image_proxy: true hace que las miniaturas de los resultados pasen por tu servidor. Así, los sitios que alojan esas imágenes nunca ven las direcciones de tus visitantes.

El valkey.url usa el nombre de host valkey porque ese es el nombre del servicio en el archivo Compose. Compose coloca ambos contenedores en una misma red, donde los nombres de servicio se resuelven. Si lo diriges a localhost, el limitador falla, porque dentro del contenedor core localhost es ese contenedor.

El secreto está en un archivo sin cifrar. Por eso, protege el directorio que lo contiene en lugar del propio archivo. chmod 750 /opt/searxng impide el acceso de otros usuarios del host. No restrinjas core-config/settings.yml al modo 600: el contenedor se ejecuta con su propio usuario sin privilegios, y un archivo que no pueda leer impide que SearXNG se inicie.

Inicia el stack y compruébalo.

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

docker compose ps debería mostrar ambos contenedores en el estado running. curl debería responder con HTTP/1.1 200 OK. Si no responde, consulta docker compose logs core, porque un error de YAML en settings.yml aparece allí como un error de análisis que indica la línea.

Configúralo detrás de nginx con TLS

El contenedor solo escucha en loopback, por lo que nginx permite acceder a él. nginx también añade seguridad de la capa de transporte (TLS). Escribe /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 muestra syntax is ok y test is successful antes de volver a cargar la configuración. Certbot reescribe el mismo archivo para escuchar en 443 con un certificado y añade una redirección desde el puerto 80. El registro DNS de search.example.com ya debe apuntar a este servidor, porque la autoridad certificadora demuestra la propiedad mediante la descarga de un archivo por HTTP. La guía completa, incluida la renovación, está en la guía de Certbot y nginx para Ubuntu 24.04.

Las dos cabeceras de reenvío no son decorativas. Sin X-Forwarded-For y X-Real-IP, cada solicitud que llega a SearXNG contiene la dirección del proxy. Por tanto, el limitador de velocidad ve a un solo cliente generando todo el tráfico y no puede distinguir a los visitantes.

Por qué los scripts y los agentes necesitan una API de búsqueda JSON

Con json en formats, el mismo endpoint que muestra la página devuelve datos estructurados.

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

Recibe un objeto con una matriz results. Cada entrada contiene url, title, content y el motor que proporcionó el resultado, junto con answers, infoboxes y suggestions. Esto basta para alimentar un resumidor, un comprobador de enlaces o un ciclo de investigación.

Esto es importante para cualquier sistema con agentes. Un modelo de lenguaje tiene una fecha de corte de entrenamiento. Por eso necesita búsquedas en tiempo real para responder preguntas sobre el presente. Las API de búsqueda comerciales cobran por consulta y aplican límites de velocidad estrictos. Una instancia local solo requiere un contenedor en un servidor que ya paga. Además, las consultas no salen de ese servidor. Si integra herramientas en un modelo, el mismo razonamiento se aplica a ejecutar servidores MCP en un VPS, donde una herramienta de búsqueda suele ser la primera que se añade.

Hay 2 reglas para usar la API. Mantenga privada la instancia. Enlace el lado de la API a la dirección de loopback o a una red privada, y permita el acceso únicamente a sus propios hosts. Después, consulte con moderación. SearXNG reenvía su solicitud a motores de búsqueda reales. Por tanto, un script que ejecute cien consultas por segundo está pidiendo a Google que bloquee su servidor.

El limitador y los cambios para una instancia pública

El limitador es la defensa contra bots de SearXNG. Supervisa las cabeceras de las solicitudes, las direcciones y las tasas de solicitudes, y descarta el tráfico que parece automatizado. Necesita Valkey para almacenar ese estado, por eso el archivo Compose lo incluye.

En una instancia privada, mantén limiter: false. Tus propios scripts son tráfico automatizado por definición, por lo que el limitador bloquearía precisamente las llamadas JSON para las que configuraste la instancia. El control de acceso corresponde al proxy inverso: un par allow y deny en location de nginx, autenticación básica HTTP o un firewall que solo admita tus otros servidores.

Si publicas la instancia para otras personas, activa ambos interruptores.

server:
  limiter: true
  public_instance: true

El control más detallado se configura en core-config/limiter.toml, que el contenedor lee desde /etc/searxng/limiter.toml. Escribe únicamente las claves que quieras cambiar. Detrás de un proxy debes declarar el proxy; de lo contrario, el limitador tratará la dirección de nginx como la del único cliente abusivo.

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

[botdetection.ip_limit]
link_token = true

link_token = true hace que SearXNG emita un token que solo obtiene una sesión real de navegador, lo que detiene a la mayoría de los scrapers simples. Una instancia pública empezará a atraerlos en pocos días. También habrá errores de los motores, porque cuanto más tráfico reenvíes, antes los motores ascendentes empezarán a devolver CAPTCHAs a la dirección de tu servidor. Una instancia pública de SearXNG requiere trabajo continuo. Una privada no, por eso aparece en la mayoría de las listas breves de cosas que merece la pena alojar por cuenta propia en 2026.

Por qué las búsquedas no devuelven resultados

Abra /stats en su instancia. Muestra todos los motores con su tasa de errores y tiempo de respuesta. Es el primer lugar que debe revisar cuando los resultados son escasos.

Un motor que muestra errores como "Access denied" o "CAPTCHA" ha bloqueado la dirección de su servidor. Esto es habitual en direcciones de rangos de centros de datos, porque los motores de búsqueda asumen que pertenecen a scrapers. SearXNG suspende el motor que falla durante un periodo en lugar de volver a intentarlo. Por eso, un motor bloqueado deja de contribuir a los resultados sin mostrarlo claramente. Desactívelo en settings.yml o acepte la pérdida. Los demás motores seguirán respondiendo.

Si todos los motores fallan al mismo tiempo, el contenedor no tiene una resolución de nombres saliente funcional o no tiene una ruta a Internet. Compruébelo desde dentro del contenedor.

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

FAQ

¿SearXNG hace anónimas mis búsquedas?

Oculta tu identidad ante los motores que consulta, porque estos ven que tu servidor realiza la solicitud en lugar de tu navegador. No oculta la consulta a tu servidor ni oculta tu servidor ante esos motores. En una instancia de un solo usuario, todo el tráfico de esa dirección es tuyo, por lo que la propia dirección se convierte en el identificador. El tráfico entre tu navegador y tu instancia está protegido por el certificado TLS.

¿Por qué una solicitud JSON devuelve 403 Forbidden?

Hay dos causas y ambas están relacionadas con la configuración. Falta json en la lista formats de search: en settings.yml, que es el estado predeterminado, o el limitador está activado y ha clasificado tu script como un bot. Añade primero el formato, reinicia con docker compose restart core y vuelve a intentarlo. Si sigue fallando, establece limiter: false y controla el acceso en el proxy inverso.

¿Necesito el contenedor de Valkey si mantengo desactivado el limitador?

Déjalo en ejecución. SearXNG funciona sin él, pero el limitador no se puede activar más adelante sin este contenedor y, además, almacena otros datos de estado de corta duración. El contenedor es pequeño y solo almacena datos en caché, por lo que eliminarlo ahorra muy poco y te hace perder esa opción.

¿Cómo actualizo SearXNG?

Ejecuta docker compose pull y después docker compose up -d en /opt/searxng. Compose vuelve a crear cualquier contenedor cuya imagen haya cambiado y deja intacto el directorio core-config/, por lo que settings.yml se conserva. Como use_default_settings: true combina tus claves con los valores predeterminados incluidos en la versión, las opciones añadidas por el proyecto llegan con valores adecuados en lugar de romper el archivo.

¿Pueden varias personas compartir una instancia?

Sí. Este es el caso en el que debes activar el limitador y establecer public_instance: true. Las preferencias se almacenan en el navegador de cada visitante, por lo que no hay cuentas que administrar. Supervisa /stats durante una semana después de abrir el acceso, porque los motores externos empiezan a rechazar tu servidor mucho antes de que detectes que faltan resultados.

#searxng#search#privacy#self-hosting#docker