feat(searxng): move to nh3-docker, update, and expose as an MCP tool

The ana-docker instance was returning zero results for every query while
reporting healthy — 4.5 months stale (2026.4.17 against a current 2026.9.3),
its engine scrapers rotted against sites that had changed. /healthz proves
the web app answers and says nothing about whether search works, so seven
days of green sat on top of a search box that found nothing.

Moved to nh3-docker rather than updated in place, because the colo egress is
the other half of the problem: 38.120.12.42 is a datacenter address that
DuckDuckGo and Startpage CAPTCHA, while nh3-docker egresses residentially at
70.230.226.88. Same reasoning as the fleet's residential proxy for yt-dlp,
applied at the source instead of around it.

Config corrected along the way: base_url said searxng.pfi.local, a name
retired on 2026-08-19, while the environment said something else — the env
won so nothing broke and the file quietly lied. The karmasearch.videos
removal key never matched, because the engine's real name has a space.

scripts/searxng-health.sh asserts results > 0 across three unrelated
queries. That is the check that would have caught this, and the only kind
that can: the mechanism was healthy throughout.

services/searxng-mcp exposes it as `web_search` at user scope, so every
Claude Code session has it. Zero results raise rather than returning an
empty list — an empty list is indistinguishable from a broken aggregator,
which is precisely how this hid.

Old instance stopped and removed; DNS alias repointed to searxng.nh3.internal.
This commit is contained in:
vh
2026-09-03 14:07:06 -07:00
parent d4aa59a199
commit 0f748ea54e
9 changed files with 335 additions and 88 deletions
+38 -32
View File
@@ -1,73 +1,79 @@
# =============================================================================
# SearXNG Custom Settings — overrides defaults from the container image
# Full reference: https://docs.searxng.org/admin/settings/index.html
# =============================================================================
# SearXNG — PFI fleet meta-search. Deployed on nh3-docker (10.100.50.40:9996).
#
# ⚠ WHY NH3 AND NOT THE COLO. Measured 2026-09-03:
# ana-docker egress 38.120.12.42 (datacenter) -> DuckDuckGo + Startpage CAPTCHA
# nh3-docker egress 70.230.226.88 (residential) -> no CAPTCHA
# Search engines gate datacenter ranges. Same reason the fleet keeps a
# residential SOCKS5 egress proxy on nh3-dev for yt-dlp. Running the search
# aggregator from a residential-egress site removes the problem at the source
# rather than proxying around it.
use_default_settings:
engines:
remove:
- wikidata
# Onion engines: no Tor proxy is configured here, so they only ever
# contribute timeouts.
- ahmia
- torch
# ⚠ Removal keys must match the engine's REAL name, spaces and all.
# `karmasearch.videos` (dotted) did NOT match on the old instance and the
# engine kept appearing in unresponsive_engines despite being "removed".
# The name is "karmasearch videos".
- karmasearch
- karmasearch.videos
- brave
- brave.images
- brave.news
- brave.videos
- karmasearch videos
general:
instance_name: "SearXNG"
instance_about_url: false
contact_url: false
debug: false
# Disable public metrics page (/stats/errors) to reduce attack surface
# Public metrics page off — smaller attack surface on an unauthenticated
# internal service.
enable_metrics: false
search:
safe_search: 0
# "" disables; "duckduckgo" is the most private working option
autocomplete: ""
default_lang: "auto"
# `json` is what makes this usable as a tool rather than only a web page.
# Removing it breaks every non-browser consumer, including Claude sessions.
formats:
- html
- json
# 3s is too tight; 8s covers slower engines without hanging the UI
# 3s is too tight for slower engines; 8s covers them without hanging the UI.
request_timeout: 8.0
# Ban time after an engine raises a suspended-time exception (default 86400)
# Ban an engine only briefly when it raises suspended-time. The default 86400
# means one bad afternoon silences an engine for a day.
ban_time_on_fail: 60
max_ban_time_on_fail: 600
server:
# REQUIRED. Generate with: openssl rand -hex 32
# Prefer setting SEARXNG_SECRET in docker-compose and letting the entrypoint
# substitute it; hardcoding a real secret here is a leak risk.
#secret_key: "changeme_please_generate_a_secret"
# secret_key comes from SEARXNG_SECRET in the environment — never hardcode it
# here. Generated + vaulted at nh3-docker/searxng-secret.
bind_address: "0.0.0.0"
port: 8080
# Enable ONLY if you ship a limiter.toml AND your proxy forwards X-Real-IP.
# Otherwise you'll get "X-Forwarded-For nor X-Real-IP header is set!" noise.
# Enable ONLY with a limiter.toml AND a proxy that forwards X-Real-IP;
# otherwise it logs "X-Forwarded-For nor X-Real-IP header is set!" forever.
limiter: false
# Mark as true if instance is internet-facing; tightens some defaults.
public_instance: false
base_url: "https://searxng.pfi.local/"
# Allow only GET to the search endpoint (simpler, works with most clients)
# ⚠ Kept in sync with BASE_URL in compose.yaml. The old instance still said
# `https://searxng.pfi.local/` here — a name retired on 2026-08-19 — while the
# environment said something else. The env wins, so nothing broke, and the
# file quietly lied to everyone who read it.
base_url: "http://10.100.50.40:9996/"
method: "GET"
compression: true
# Set to true if you need image_proxy rewriting for privacy
image_proxy: false
# Outgoing HTTP pool — tuned for a low-traffic private instance.
# Defaults are fine for most, but these reduce memory use and tighten timeouts.
# Outgoing pool — low-traffic private instance.
outgoing:
request_timeout: 6.0
max_request_timeout: 12.0
pool_connections: 100
pool_maxsize: 20
enable_http2: true
# Uncomment if you want to route outbound traffic via Tor for .onion engines
# proxies:
# all://:
# - socks5h://tor:9050
# No proxy needed: this host already egresses residentially (see header).
# If that ever changes, the fleet's NH3 SOCKS5 proxy is the fallback:
# proxies:
# all://:
# - socks5h://10.100.10.50:1080