Self-hosted API for search, crawl, vector search and agentic AI across 20+ engines.
2.2K
Source, issues and full documentation: https://github.com/hackerdogs-ai/hdsearch
Images:
hackerdogs/hdsearch:api(REST API + MCP server) andhackerdogs/hdsearch:web(Next.js UI). Run them together with the compose files in the repo.
One self-hosted API for search, crawl, vector search, and agentic AI answers — across 20+ engines.
hdsearch is an aggregated search results cache with built-in modalities and an AI Search mode. It saves you cash. You work hard for money, save it, don't give it away in credits and subscriptions.
A free, open-source alternative to SerpAPI + Perplexity that you run on your own box. Prioritized multi-engine search with fallback & dedup, a Redis cache with configurable TTLs, per-user encrypted provider keys, vector search + RAG over your own files, agentic AI Search with persistent threads, and an MCP server — TypeScript throughout.
WHY? Because I was tired of paying subscriptions and credits to all these search providers. You don't need to index everything to search. What is Serp doing for you? It's just a wrapper on search APIs. I wanted a choice between multiple engines: free and paid. And I don't want long term index. AI agents can query, results are cached, you query the cache again and SAVE!!!
Quickstart · Features · API · AI Search · MCP · Config · Security · Self-host at scale · Credits
search, maps, crawl, archive, chart, weather, render UI) and streams the answer. Threads, folders, and file attachments persist (Redis + S3); temporary chat skips server history. Works with local Ollama (no API key, $0) or any commercial model you add. Also exposes an OpenAI-compatible /v1/openai/chat/completions endpoint./trends headlines panel (platform defaults; optional hd-feeds integration).hd_search, hd_crawl, hd_vector_search, hd_vector_index, hd_list_engines to Claude / any MCP client (Streamable HTTP on :8792, or stdio).docker compose up bundles Postgres/TimescaleDB, Redis, SeaweedFS, embeddings, and every provider. No accounts, no SaaS, no per-request bills for the aggregator.You need Docker (with Compose). Nothing else.
Pick a deployment topology — all on the hdsearchnet network. The helper
scripts (./start_docker.sh, ./stop_docker.sh) are thin wrappers; you can
always run docker compose directly.
| Compose file | What it runs |
|---|---|
docker-compose-full.yml | Everything — infra + api + web (includes the two below) |
docker-compose-infra.yml | Datastores + providers only |
docker-compose-core.yml | hds-api + hds-web only (point at your own services) |
Full — everything in one command (recommended to start):
git clone https://github.com/hackerdogs-ai/hdsearch.git && cd hdsearch
docker compose -f docker-compose-full.yml up -d
open http://localhost:3000 # first run → setup wizard, then admin account
# stop: docker compose -f docker-compose-full.yml down
# optional wrappers: ./start_docker.sh · ./stop_docker.sh
Local development (API / web on the host, against Docker infra or your own services):
./start_api.sh # API on :8791 (tsx watch)
./start_web.sh 3005 # Web UI (pick a free port)
# stop: ./stop_local.sh
Split — run infra and core separately (scale them independently):
docker compose -f docker-compose-infra.yml up -d # datastores + providers
docker compose -f docker-compose-core.yml up -d # api + web
Core only — point HD-Search at services you already run (Postgres, Redis, S3, …):
docker compose -f docker-compose-core.yml up -d # then open the wizard and enter your endpoints
No env vars required — the setup wizard (below) collects and verifies your
endpoints in the browser. You can still pre-seed them with
HDSEARCH_DATABASE_URL / HDSEARCH_REDIS_URL / HDSEARCH_S3_ENDPOINT if you
prefer a headless bootstrap.
On first visit every page redirects to /setup — an OS-installer-style wizard
that connects HD-Search to its infrastructure:
hdsearchnet
(hds-db, hds-redis, …), so the Full/Split stacks are all green out of the box —
just click through.HDSEARCH_ADMIN_EMAIL / HDSEARCH_ADMIN_PASSWORD for a headless bootstrap).docker restart hds-api.That's the whole setup. There are no secrets to configure — the app auto-generates its crypto secrets on first boot.
First run → create the admin. With no accounts yet, the sign-in page shows "Create your admin account"; the account you create becomes the administrator.
Self-service sign-up is open by default — the sign-in page has a Create an account link (email, password, confirm) that creates a normal user.
Lock it down anytime at System Admin → User registration: flip to
invite-only and the sign-up form disappears (admins create accounts). Or set
HDSEARCH_OPEN_SIGNUP=false at deploy time.
Optional SMTP (System Admin → Email) unlocks email verification, forgot / reset password, and magic-link sign-in. Without SMTP, local password auth still works.
After sign-in, a one-time disclaimer gate records consent before the app unlocks.
Add search/LLM provider keys later, in the UI — Account → Provider Keys (per-user) or System Admin (system-wide). Rank engines under Dashboard → Services. The free/self-hosted engines and local Ollama work with no keys.
The API also serves the MCP server (Streamable HTTP) on :8792, in the same container — no separate process to run.
Build from source instead of pulling images: ./publish_to_docker.sh --build-only --native <ns> then run any compose above (they use <ns>/hdsearch:*).
Firecrawl (AGPL-3.0) is available as an extra
crawl provider. It is opt-in, not part of the default stack — it brings its own
Postgres, Redis, RabbitMQ and Playwright service and wants ~8 GB RAM, while the bundled
crawl4ai + browserless pair already covers most crawling.
docker compose -f docker-compose-firecrawl.yml up -d # start it on hdsearchnet
HDSEARCH_FIRECRAWL_URL=http://hds-firecrawl:3002 \
docker compose -f docker-compose-full.yml up -d hds-api # point HD-Search at it
A self-hosted instance runs with auth disabled, so no API key is needed — HD-Search
detects the local endpoint and stops asking for the firecrawl credential. You can also
set the endpoint in the setup wizard or System Admin → Infrastructure.
Worth knowing: Firecrawl's anti-bot engine is closed-source and cloud-only, so a self-hosted instance has no anti-bot capability and uses your own proxies.
# issue an API key: Account → API Keys in the UI, or:
docker compose -f docker-compose-full.yml exec hds-api node dist/scripts/hds-keys.js issue --user me --name laptop
KEY=sk-hds-...
curl http://localhost:8791/v1/search -H "authorization: Bearer $KEY" \
-H 'content-type: application/json' \
-d '{"q":"open source search","mode":"aggregate","facets":true}'
┌─────────────────────────── hdsearchnet (private) ───────────────────────────┐
Browser ─▶ hds-web ─▶ hds-api ─▶ engine ─▶ providers (searxng, openserp, crawl4ai, browserless, tor) │
(Next.js) (Hono) │ ├─ Redis Stack ── cache · history · threads · RediSearch vectors │
│ ├─ Postgres/TimescaleDB ── users · encrypted keys · usage │
│ ├─ SeaweedFS (S3) ── crawl archive · AI files · thread archive │
│ ├─ embeddings (MiniLM-384) ── vectors for search + RAG │
│ └─ Ollama (host) ── local LLMs for AI Search (no key, $0) │
MCP client ─▶ :8792 /mcp ──────┘ │
└────────────────────────────────────────────────────────────────────────────┘
Every backend is bundled and internal-only. The API degrades gracefully if an optional dependency is down (search still works without Postgres; vector falls back to brute-force without RediSearch, etc.).
Base URL http://localhost:8791. Auth: Authorization: Bearer sk-hds-….
OpenAPI at GET /openapi.json; interactive Swagger UI at /api (public) and
/dashboard/api-reference (signed-in). In-app docs: /docs.
| Endpoint | Purpose |
|---|---|
POST /v1/search · GET /v1/search | Aggregated/fallback search. Body: q, modality, engine?, mode(fallback|aggregate), limit, page, facets, freshness?, country?, lang?, ttl?, noCache? |
POST /v1/crawl | Crawl a URL → { result: { markdown, links, ... } }. render:true for JS pages. |
POST /v1/search/vector/index · POST /v1/search/vector | Index documents (per-namespace, TTL) and semantic KNN (groundWithWeb optional). |
GET /v1/archive | Extract a Wayback / Common Crawl capture. |
GET /v1/engines | List engines, modalities, access type, and availability. |
GET/DELETE /v1/history | Signed-in search history (respects history TTL / temporary mode). |
POST /v1/ai/chat | Agentic AI Search (SSE stream). |
GET/PATCH/DELETE /v1/ai/threads · /v1/ai/threads/:id | AI thread list and persistence. |
POST/GET/DELETE /v1/files · /v1/folders | File upload RAG + chat folders. |
POST /v1/openai/chat/completions | OpenAI-compatible chat endpoint (+ /v1/openai/models). |
GET /v1/trends | Trends headlines payload (powers /trends). |
PUT /v1/keys/providers · POST /v1/keys/api | Manage provider keys (encrypted) and API keys. |
GET /health · GET /healthz | Liveness / deep health (redis/postgres/seaweedfs/rediSearch). |
{ "query":"open source search","total":16,"cached":false,"tookMs":1254,
"engines":[{"engine":"searxng","ok":true,"count":16}],
"results":[{"title":"…","url":"https://…","snippet":"…","engine":"searxng"}],
"facets":{"engine":[…],"site":[…]} }
A chat that plans, calls tools, and streams a cited answer. Tools:
hd_search, hd_maps, hd_plot_map, hd_crawl, hd_archive, hd_chart,
hd_weather, and hd_render (rich UI components).
host.docker.internal:11434.Ten providers ship in the registry. Only Ollama is required for AI Search to work — everything else is optional and needs your own key, entered in the UI and stored AES-256-GCM encrypted.
| Provider | Type | Key field | Docs |
|---|---|---|---|
| Ollama | self-hosted, free | none | API docs |
| Anthropic | commercial | anthropic | docs |
| OpenAI | commercial | openai | docs |
| Google (Gemini) | commercial | google | docs |
| xAI (Grok) | commercial | xai | docs |
| Groq | commercial | groq | docs |
| Mistral AI | commercial | mistral | docs |
| OpenRouter | commercial (gateway) | openrouter | docs |
| AWS Bedrock | commercial | aws_bedrock (Bedrock API key) | docs |
| Azure OpenAI | commercial | azure_openai | docs |
Add your own. System Admin → LLM providers takes any OpenAI-compatible endpoint — vLLM, LM Studio, llama.cpp server, Together, Fireworks, DeepSeek, Perplexity — by base URL alone, no code change. Register its models under AI Search models on the same page. Both are stored in Postgres and take effect without a restart.
Model metadata (context window, max output, tool/vision/thinking support) is admin-editable, so you can add a model the day it ships rather than waiting on a release.
The stack runs a Streamable HTTP MCP server at http://localhost:8792/mcp.
Connect any MCP client (Claude, Cursor, …) — each caller authenticates with their
own key via the Authorization header (so their scopes and rate limits apply):
{ "mcpServers": { "hd-search": {
"type": "streamable-http",
"url": "http://localhost:8792/mcp",
"headers": { "Authorization": "Bearer sk-hds-…" }
}}}
Prefer a local process (stdio)? That works too:
{ "mcpServers": { "hd-search": {
"command": "node", "args": ["dist/mcp/server.js"],
"env": { "HDSEARCH_API_URL": "http://127.0.0.1:8791", "HDSEARCH_API_KEY": "sk-hds-…" }
}}}
Tools: hd_search, hd_crawl, hd_vector_search, hd_vector_index, hd_list_engines.
.env.selfhost / .env is optional and contains no secrets — only ports,
URLs, and flags. Copy .env.selfhost.example to change a default.
| Var | Default | Purpose |
|---|---|---|
WEB_PORT / API_PORT | 3000 / 8791 | Published host ports |
PUBLIC_API_URL / APP_BASE_URL | localhost | Public URLs (set to your domain in prod) |
HDSEARCH_ADMIN_EMAIL / _PASSWORD | – | Headless admin bootstrap (else use the UI) |
HDSEARCH_OPEN_SIGNUP | true | Allow self-service signup (admin can override at System Admin → User registration) |
HDSEARCH_OLLAMA_URL | host.docker.internal:11434 | Local LLMs for AI Search |
HDSEARCH_OPENSERP_ENGINES | google,yandex,bing,baidu | OpenSERP engine order |
HDSEARCH_EMBEDDINGS_PROVIDER | minilm | minilm | openai | none |
HDSEARCH_GEOCODER_URL | public Photon | Self-hosted maps geocoder (--profile maps) |
SMTP (SMTP_HOST / SMTP_USER / SMTP_PASSWORD / SMTP_FROM, or System Admin → Email) is optional — it enables verification, password reset, and magic-link sign-in.
Provider keys and all secrets are handled in the UI or auto-generated — never in env. See docs/CONFIGURATION_DEPLOYMENT.md.
admin/user). Sessions are an encrypted, httpOnly cookie. With SMTP: email verification, password reset, magic-link sign-in.X-RateLimit-* headers; CORS is configurable.up is heavy — it pulls a few GB (embeddings, browsers, providers). The embeddings image is amd64 (emulated on Apple Silicon).Full README, development guide and roadmap: https://github.com/hackerdogs-ai/hdsearch
Content type
Image
Digest
sha256:de3ba8f7b…
Size
80 MB
Last updated
about 2 months ago
docker pull hackerdogs/hdsearch:web