SearxNG — Privacy-Focused Metasearch Engine

Privacy-respecting metasearch engine that aggregates results from 70+ search engines without tracking. Primary consumer is the haiven-mcp search/web tool used by LLM agents.

Access

Containers

Container Role Networks Port
searxng Main metasearch engine web, backend 8080 (internal)
searxng-redis Session/cache store (Redis 7-alpine) backend 6379 (internal)
searxng-tor Tor SOCKS5 proxy for arxiv engine backend 9050 (internal)
searxng-metrics Prometheus exporter (polls /stats/errors every 30s) backend, monitoring 9109

Quick Start

# Start all containers
docker compose -f /mnt/apps/docker/searxng/docker-compose.yml up -d

# Check status
docker compose -f /mnt/apps/docker/searxng/docker-compose.yml ps

# View logs
docker logs --tail 100 searxng

Configuration Files

File Purpose
docker-compose.yml Service definitions for all 4 containers
.env SEARXNG_SECRET, SEARXNG_VALKEY_URL
config/settings.yml SearxNG engine config, timeouts, Tor network routing
config/limiter.toml Rate limiter — 10.10.1.0/24 in pass_ip for internal callers
tor/Dockerfile Alpine 3.20 + tor, runs as tor user
tor/torrc Tor configuration (SocksPort 9050, ExitRelay 0)
exporter/Dockerfile Python 3.11-slim + prometheus-client + httpx
exporter/exporter.py Metrics exporter source (120 lines)

Architecture Notes

Tor sidecar

searxng-tor is an Alpine-based Tor container providing a SOCKS5 proxy at tor:9050. Only the arxiv engine routes through it (selective routing via outgoing.networks.tor_network in settings.yml). This recovered arxiv from 100% TooManyRequests errors to 0%. Other engines (brave, duckduckgo) are not routed via Tor because Cloudflare blocks Tor exits — routing them through Tor made their error rates worse.

Authentik gating

Traefik label authentik-secure-chain@file,searxng-headers gates the public domain. Internal MCP callers use http://searxng:8080 directly on the backend network and are unaffected. As of 2026-05-02, no Authentik application provider is configured for this service — a follow-up task.

Rate limiter

server.limiter: true is enabled. The backend subnet 10.10.1.0/24 is in config/limiter.toml pass_ip so internal callers bypass rate limiting. Without this entry, all internal tool calls return 429.

Valkey rename

SearxNG's redis: config block is named valkey: and the env var is SEARXNG_VALKEY_URL (renamed from SEARXNG_REDIS_URL). The underlying container still runs redis:7-alpine.

Prometheus Metrics

The searxng-metrics sidecar exposes metrics at port 9109, auto-discovered by Prometheus via Docker labels. Grafana dashboard UID: searxng-engine-health (auto-provisioned from docker/infrastructure/grafana/dashboards/09-ai/).

Alert rule SearxNGEnginesDegraded fires when searxng_engines_with_errors_count >= 4 for 10m.

Directory Layout

searxng/
├── docker-compose.yml      # All 4 containers
├── .env                    # Secrets (gitignored)
├── config/
   ├── settings.yml        # SearxNG engine and network config
   └── limiter.toml        # Rate limiter pass_ip list
├── tor/
   ├── Dockerfile          # Alpine 3.20 + tor
   └── torrc               # Tor configuration
├── exporter/
   ├── Dockerfile          # Python 3.11-slim
   └── exporter.py         # Prometheus metrics exporter
├── data/                   # SearxNG runtime cache (bind-mounted)
├── CLAUDE.md               # Agent context and operations
├── USER_GUIDE.md           # Operator guide
├── MEMORY.md               # Operational history
└── README.md               # This file