Guide
Hermes Agent + SearXNG: Free Self-Hosted Web Search
SearXNG is a free, open-source metasearch engine you run yourself. Hermes Agent ships a first-party SearXNG provider, so pointing your agent at your own instance gives it web search with no API key, no per-query billing, and no search company building a profile from your agent's queries.
Why SearXNG for an Agent?
Most web-search backends charge per query and tie every search your agent runs to your account. An agent doing research can fire dozens of searches in a single turn, so both the cost and the exposure add up faster than they do for a human typing into a search box.
SearXNG sits in front of upstream engines — Google, Bing, Brave, DuckDuckGo, Wikipedia and dozens more — aggregates their results, and returns them over a simple JSON API. You host it, so there is no key to rotate and no usage meter. Worth being precise about what this does and does not buy you: queries are still forwarded to those upstream engines, so SearXNG strips the identifying details rather than stopping the search reaching Google or Bing at all.
What Ships in Hermes
SearXNG is not a community add-on here. Hermes bundles it as a backend plugin (web-searxng, authored by Nous Research) that registers a searxng web-search provider. It is one of eight providers in the box, alongside brave-free, ddgs, exa, firecrawl, keenable, parallel and xai.
One limitation worth knowing up front: the SearXNG provider is search-only. SearXNG aggregates results from upstream engines but does not fetch or extract arbitrary URLs, so the provider reports no extract support. If your agent needs to read full page bodies, pair it with a fetch-capable provider such as Firecrawl.
Step 1: Run SearXNG
The quickest path is the official container. The JSON API is not enabled in the default settings, so you must add it — this is the single most common reason a working SearXNG instance returns nothing to an agent.
SearXNG publishes dated tags of the form YYYY.M.D-<commit> and rebuilds most days. Pin one rather than tracking latest, and check the tag list for the current build.
docker run -d --name searxng \
-p 8080:8080 \
-v "$PWD/searxng:/etc/searxng" \
docker.io/searxng/searxng:2026.9.16-461f174b0
# Then edit searxng/settings.yml and make sure json is in the
# formats list, otherwise /search?format=json returns a 403:
#
# search:
# formats:
# - html
# - json
#
# Restart to apply:
docker restart searxngConfirm the API answers before you touch Hermes at all:
curl -s 'http://localhost:8080/search?q=hermes+agent&format=json' | head -c 300Step 2: Point Hermes at It
Hermes finds your instance through a single environment variable, SEARXNG_URL. The provider reports itself as available exactly when that variable is set, so an unset or empty value silently disables it rather than raising an error.
# The URL of your SearXNG instance — no trailing /search
export SEARXNG_URL=http://localhost:8080Hermes reads this through its own config-aware environment layer first and falls back to the process environment, so a value written into your Hermes .env is picked up the same way an exported shell variable is.
Step 3: Select the Backend
Setting the URL makes the provider available; it does not make it the default. Choose it explicitly in ~/.hermes/config.yaml:
web:
search_backend: "searxng" # explicit, per-capability
# or, to set every web capability at once:
web:
backend: "searxng" # shared fallbacksearch_backend wins for search specifically; backend is the shared fallback the provider also responds to. Restart the gateway to pick up the change:
hermes gateway restartStep 4: Verify
Ask the agent something it cannot answer from training data alone — a result that must be fresh. A question about today's date or a this-week news item is a better test than a general knowledge question, which the model may answer without searching at all.
Common Failure Modes
- 403 on
format=json. JSON is not in theformatslist insettings.yml. This is the default, so it will bite you unless you changed it. - Search silently does nothing.
SEARXNG_URLis unset or empty. The provider deliberately reports itself unavailable rather than erroring. - Works from your shell, not from the container.
localhostinside a container is the container, not the host. Use the host gateway address or put both on the same Docker network. - Upstream engines rate-limit. A public engine can start returning CAPTCHAs under agent-rate traffic. Disabling that one engine in
settings.ymlis usually better than fighting it. - No page bodies. Expected — the provider is search-only by design.
On OpenClaw
OpenClaw supports SearXNG too, but the wiring is different: it is configured through the searxng plugin's webSearch.baseUrl rather than an environment variable, and the plugin requires a private-range address for plain http endpoints. See OpenClaw + SearXNG for that path. The SearXNG instance itself is identical — one instance can serve both frameworks.
What's Next?
- Hermes Agent + Firecrawl — add page fetching and extraction
- Hermes Agent + X Search — search posts on X
- Hermes Agent Skills — teach your agent repeatable workflows
- OpenClaw + SearXNG — the same engine on the other framework