If you're building anything that needs live web results — a RAG pipeline, an agent that needs to check current prices, a chatbot that shouldn't hallucinate today's news — you've probably priced out Bing Search API, Serper, or Tavily and winced at the per-query cost once you're doing this at any real volume. SearXNG solves that from a completely different angle, and it also happens to double as a genuinely good private search engine for humans.
SearXNG is an open-source metasearch engine — it doesn't crawl the web itself, it fans a query out to 70+ upstream engines (Google, Bing, DuckDuckGo, Brave, Wikipedia, and a long tail of specialized ones) and merges the results, with no tracking or profiling of you as the requester. Point it at a browser and it's a private search page. Enable its JSON output format and it's a self-hosted search API you can hit from code — no API key, no per-query bill, no rate limit besides whatever the upstream engines tolerate.
The RAG/agent angle specifically
Most "give my LLM live web search" tutorials reach straight for a paid search API. SearXNG gets you the same shape of thing — query in, list of URLs + snippets out — for the cost of running a small container:
curl 'https://your-instance.example.com/search?q=railway+pricing&format=json'
That's it. Wire that into whatever tool-calling setup you're using and your agent has web search without a metered API sitting in the critical path.
The honest caveat here: SearXNG isn't its own index, so its answers are only as reliable as the upstream engines you enable, and if you hammer it hard some of those upstream engines (Google especially) will start CAPTCHA-ing or rate-limiting your instance's IP, not you personally, but SearXNG's request to them. For a personal or small-team RAG backend this basically never comes up. For anything doing serious volume, curate settings.yml down to a handful of stable engines (DuckDuckGo, Brave, Wikipedia, Bing) instead of leaving all 70+ on — fewer engines means fewer things that can flake, and it's genuinely more reliable that way, not just faster.
Running it yourself
The plain Docker path:
docker run -d -p 8080:8080 \
-v searxng-config:/etc/searxng \
-e SEARXNG_SECRET=$(openssl rand -hex 32) \
searxng/searxng:latest
Two things that aren't obvious the first time: it refuses to boot without SEARXNG_SECRET set, and the JSON format is off by default — you have to add json to search.formats in the generated settings.yml before format=json stops 403-ing.
The template
I maintain a one-click Railway template for this. Full disclosure: I get a kickback if you deploy through it. It handles the fiddly parts above automatically — auto-generates the secret, wires SEARXNG_BASE_URL to your live Railway domain so links resolve correctly behind the proxy, mounts a volume at /etc/searxng so your config survives redeploys, and sets the healthcheck: https://railway.com/deploy/searxng-metasearch-engine?referralCode=Z1xivh&utm_medium=integration&utm_source=template&utm_campaign=inventory
It's the stock searxng/searxng image underneath, nothing patched — the Dockerfile is just FROM searxng/searxng:latest plus a port pin, so it behaves identically to the raw docker run above if you'd rather self-host it on your own box. JSON format is still off by default even through the template; flip it on in /etc/searxng/settings.yml once it's up.
Tradeoffs, honestly
- It's a search aggregator, not a search index — quality and uptime both depend on which upstream engines you keep enabled.
- Heavy automated querying can get individual engines temporarily blocked for your instance; curate the engine list if you're doing production RAG volume rather than personal use.
- It's a single container with no built-in caching layer — if you're doing very high query volume, put a cache in front of it rather than hitting every query live.
None of that changes the core value: it's the difference between "$0.005/query forever" and "one small container, once."
Top comments (0)