No description
Replace template-based handlers (h.Index, h.Preferences) with the new spa handler. API routes (healthz, search, autocompleter, opensearch.xml) are registered first as exact matches, followed by the SPA catchall handler for all other routes. Remove unused views and io/fs imports. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|---|---|---|
| .forgejo/workflows | ||
| .github/workflows | ||
| cmd/kafka | ||
| docs/superpowers | ||
| internal | ||
| .gitignore | ||
| CLAUDE.md | ||
| config.example.toml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| flake.lock | ||
| flake.nix | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| README.md | ||
kafka
A privacy-respecting, open metasearch engine written in Go. SearXNG-compatible API with an HTML frontend, designed to be fast, lightweight, and deployable anywhere.
9 engines. No JavaScript. No tracking. One binary.
Features
- SearXNG-compatible API — drop-in replacement for existing integrations
- 9 search engines — Wikipedia, arXiv, Crossref, Brave, Qwant, DuckDuckGo, GitHub, Reddit, Bing
- HTML frontend — HTMX + Go templates with instant search, dark mode, responsive design
- Valkey cache — optional Redis-compatible caching with configurable TTL
- Rate limiting — three layers: per-IP, burst, and global (all disabled by default)
- CORS — configurable origins for browser-based clients
- OpenSearch — browsers can add kafka as a search engine from the address bar
- Graceful degradation — individual engine failures don't kill the whole search
- Docker — multi-stage build, ~20MB runtime image
- NixOS — native NixOS module with systemd service
Quick Start
Binary
git clone https://git.ashisgreat.xyz/penal-colony/gosearch.git
cd kafka
go build ./cmd/kafka
./kafka -config config.toml
Docker Compose
cp config.example.toml config.toml
# Edit config.toml — set your Brave API key, etc.
docker compose up -d
NixOS
Add to your flake inputs:
inputs.kafka.url = "git+https://git.ashisgreat.xyz/penal-colony/gosearch.git";
Enable in your configuration:
imports = [ inputs.kafka.nixosModules.default ];
services.kafka = {
enable = true;
openFirewall = true;
baseUrl = "https://search.example.com";
# config = "/etc/kafka/config.toml"; # default
};
Write your config:
sudo mkdir -p /etc/kafka
sudo cp config.example.toml /etc/kafka/config.toml
sudo $EDITOR /etc/kafka/config.toml
Deploy:
sudo nixos-rebuild switch --flake .#
Nix Development Shell
nix develop
go test ./...
go run ./cmd/kafka -config config.toml
Endpoints
| Endpoint | Description |
|---|---|
GET / |
HTML search page |
GET /search?q=…&format=html |
HTML results (full page or HTMX fragment) |
GET/POST /search |
JSON/CSV/RSS results |
GET /opensearch.xml |
OpenSearch description XML |
GET /healthz |
Health check |
GET /static/* |
Embedded CSS, images, favicon |
Search API
Parameters
| Parameter | Default | Description |
|---|---|---|
q |
— | Search query (required) |
format |
json |
json, csv, rss, html |
pageno |
1 |
Page number |
safesearch |
0 |
Safe search level (0–2) |
time_range |
— | day, week, month, year |
language |
auto |
BCP-47 language code |
engines |
all | Comma-separated engine names |
Example
curl "http://localhost:8080/search?q=golang&format=json&engines=github,duckduckgo"
Response (JSON)
{
"query": "golang",
"number_of_results": 14768,
"results": [
{
"title": "The Go Programming Language",
"url": "https://go.dev/",
"content": "Go is an open source programming language...",
"engine": "duckduckgo",
"score": 1.0,
"type": "result"
}
],
"suggestions": ["golang tutorial", "golang vs rust"],
"unresponsive_engines": []
}
Configuration
Copy config.example.toml to config.toml and edit. All settings can also be overridden via environment variables (listed in the example file).
Key Sections
[server]— port, timeout, public base URL for OpenSearch[upstream]— optional upstream metasearch proxy for unported engines[engines]— which engines run locally, engine-specific settings[cache]— Valkey/Redis address, password, TTL[cors]— allowed origins and methods[rate_limit]— per-IP sliding window (30 req/min default)[global_rate_limit]— server-wide limit (disabled by default)[burst_rate_limit]— per-IP burst + sustained windows (disabled by default)
Environment Variables
| Variable | Description |
|---|---|
PORT |
Listen port (default: 8080) |
BASE_URL |
Public URL for OpenSearch XML |
UPSTREAM_SEARXNG_URL |
Upstream instance URL |
LOCAL_PORTED_ENGINES |
Comma-separated local engine list |
HTTP_TIMEOUT |
Upstream request timeout |
BRAVE_API_KEY |
Brave Search API key |
BRAVE_ACCESS_TOKEN |
Gate requests with token |
VALKEY_ADDRESS |
Valkey/Redis address |
VALKEY_PASSWORD |
Valkey/Redis password |
VALKEY_CACHE_TTL |
Cache TTL |
See config.example.toml for the full list including rate limiting and CORS variables.
Engines
| Engine | Source | Notes |
|---|---|---|
| Wikipedia | MediaWiki API | General knowledge |
| arXiv | arXiv API | Academic papers |
| Crossref | Crossref API | Academic metadata |
| Brave | Brave Search API | General web (requires API key) |
| Qwant | Qwant Lite HTML | General web |
| DuckDuckGo | DDG Lite HTML | General web |
| GitHub | GitHub Search API v3 | Code and repositories |
| Reddit JSON API | Discussions | |
| Bing | Bing RSS | General web |
Engines not listed in engines.local_ported are proxied to an upstream metasearch instance if upstream.url is configured.
Architecture
┌─────────────────────────────────────┐
│ HTTP Handler │
│ /search / /opensearch.xml │
├─────────────────────────────────────┤
│ Middleware Chain │
│ Global → Burst → Per-IP → CORS │
├─────────────────────────────────────┤
│ Search Service │
│ Parallel engine execution │
│ WaitGroup + graceful degradation │
├─────────────────────────────────────┤
│ Cache Layer │
│ Valkey/Redis (optional, no-op if │
│ unconfigured) │
├─────────────────────────────────────┤
│ Engines (×9) │
│ Each runs in its own goroutine │
│ Failures → unresponsive_engines │
└─────────────────────────────────────┘
Docker
The Dockerfile uses a multi-stage build:
# Build stage: golang:1.24-alpine
# Runtime stage: alpine:3.21 (~20MB)
# CGO_ENABLED=0 — static binary
docker compose up -d
Includes Valkey 8 with health checks out of the box.