← Home

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 searxng

Confirm the API answers before you touch Hermes at all:

curl -s 'http://localhost:8080/search?q=hermes+agent&format=json' | head -c 300

Step 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:8080

Hermes 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 fallback

search_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 restart

Step 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 the formats list in settings.yml. This is the default, so it will bite you unless you changed it.
  • Search silently does nothing. SEARXNG_URL is unset or empty. The provider deliberately reports itself unavailable rather than erroring.
  • Works from your shell, not from the container. localhost inside 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.yml is 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?

Want Web Search Without Hosting Anything?

OpenClaw Launch runs Hermes Agent with web search already wired up — no SearXNG instance to maintain.

Deploy Managed Hermes