search-engine/README.md
King Omar b3aea18d9c Initial commit: RADICAL_SEARCH self-hosted web search engine
Crawler (Majestic Million → undici → cheerio → Meilisearch), Hono search
API with P2P peer federation, Cloudflare Worker frontend, VM provisioning
scripts. Adds README, .gitignore, and moves VM credentials out of deploy.sh
into a git-ignored deploy.env.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 01:52:31 +10:00

94 lines
4.5 KiB
Markdown

# 🔍 RADICAL_SEARCH
> **The open web — unfiltered.** A self-hosted, from-scratch web search engine.
RADICAL_SEARCH crawls the most-linked domains on the web, indexes them in
[Meilisearch](https://www.meilisearch.com/), and serves results through a
Cloudflare Worker frontend at **[search.theradicalparty.com](https://search.theradicalparty.com)**.
The search API also supports optional **P2P federation** — nodes can register as
peers and fan queries out across a cluster.
## Architecture
```
┌─────────────────────────────┐
browser ───▶ │ frontend/ (Cloudflare Worker) │ search.theradicalparty.com
│ SSR UI, dark/light, proxies /search │
└───────────────┬─────────────┘
│ fetch(API_URL) (HTTPS :443)
┌─────────────────────────────┐
│ api/ (Hono, Node, on VM) │ search-api.theradicalparty.com
│ /search /peers /stats /health │
└───────────────┬─────────────┘
│ localhost:7700
┌─────────────────────────────┐
│ Meilisearch (index: pages) │
└───────────────▲─────────────┘
│ batched docs
┌───────────────┴─────────────┐
│ crawler/ (Node, on VM) │ Majestic Million → fetch → parse → index
└─────────────────────────────┘
```
## Components
| Dir | What it is | Runtime |
|-----|-----------|---------|
| `crawler/` | Downloads the [Majestic Million](https://majestic.com/reports/majestic-million) domain list, crawls each domain (undici, 8s timeout, HTML-only, 500 KB cap), parses with cheerio (title/description/body/outlinks), and batches docs into Meilisearch. | Node on the VM |
| `api/` | Hono search API. `/search` proxies to Meilisearch with highlighting and optional P2P peer fan-out. Also `/peers`, `/peers/register`, `/stats`, `/health`. | Node on the VM (`:PORT`) |
| `frontend/` | Cloudflare Worker. Server-rendered UI (Roboto Mono, dark/light theme), proxies `/search` to `API_URL`. | Cloudflare Workers |
| `scripts/` | `install-vm.sh` provisions Meilisearch + api + crawler as systemd services; `deploy.sh` syncs & runs it over SSH. | local → VM |
## Local development
```bash
# 1. Meilisearch (Docker)
docker run -it --rm -p 7700:7700 getmeili/meilisearch:latest --master-key masterKey
# 2. API
cd api && npm install && MEILI_KEY=masterKey npm run dev # :3000
# 3. A small crawl
cd crawler && npm install && LIMIT=500 CONCURRENCY=8 npm start
# 4. Frontend
cd frontend && npm install && npm run dev # wrangler dev
```
## Deploy
**Frontend (Cloudflare Worker):**
```bash
cd frontend && npm run deploy
```
**API + crawler (VM):** copy `scripts/deploy.env.example``scripts/deploy.env`,
fill in the VM host/user/password (this file is git-ignored), then:
```bash
cd scripts && ./deploy.sh
```
### API exposure
The frontend Worker reaches the API over **HTTPS on port 443** — a deployed
Cloudflare Worker's `fetch()` cannot reliably use non-standard ports like 3000.
The API is fronted at `search-api.theradicalparty.com` (see
[`docs/DEPLOY.md`](docs/DEPLOY.md) for the port/DNS setup).
## Configuration
| Var | Component | Default | Notes |
|-----|-----------|---------|-------|
| `MEILI_URL` | api, crawler | `http://localhost:7700` | Meilisearch endpoint |
| `MEILI_KEY` | api, crawler | `masterKey` | Meilisearch master key (VM-local only) |
| `PORT` | api | `3000` | API listen port |
| `NODE_ID` | api | `main` | P2P node identity |
| `CONCURRENCY` | crawler | `8` | Parallel fetches |
| `LIMIT` | crawler | `100000` | Max domains to crawl |
| `API_URL` | frontend | — | Set in `frontend/wrangler.jsonc` `vars` |
## License
Private / unlicensed — © the maintainer.