Self-hosted dashboard for managing IndexNow submissions across multiple sites. Handles keys, sitemaps, and submission scheduling from one place. Pushes to Bing, Yandex, and every other participating engine via api.indexnow.org.
- Multi-site: add sites, generate/rotate IndexNow keys, bulk Submit / Sync / Verify / Delete
- Sitemap diffing: fetches sitemaps, submits only new or changed URLs, batches up to 10,000 per request
- Three submission modes per site:
manual(dashboard button),scheduled(hourly / 6 h / daily cron), orwebhook(POST /hook/:siteIdfrom your CMS or build pipeline) - Key file helper: copy or download the exact
<key>.txtcontent directly from the dashboard - Discord notifications: optional webhook with per-event toggles and a test button
- Simple auth: optional login gate via
ADMIN_EMAIL/ADMIN_PASSWORD. SetAUTH_ENABLED=falseto skip entirely - One process: Fastify serves the API and React dashboard on a single port. SQLite, no external services
pnpm install
pnpm dev # http://localhost:3020Add a site, host the generated key file at https://<your-domain>/<key>.txt, then submit.
Set ADMIN_EMAIL, ADMIN_PASSWORD, and AUTH_SECRET in .env to enable the login gate. Leave them empty or set AUTH_ENABLED=false to run without auth. Changing credentials never affects your stored sites or URLs.
pnpm build
AUTH_SECRET=$(openssl rand -base64 32) pnpm startSee .env.example for all options. The SQLite database lives at ./data/indexnow.db. Back that file up and you've backed up everything.
No clone needed, pulls the published image directly.
docker run
docker run -d \
--name indexnow-server \
--restart unless-stopped \
-p 3020:3020 \
-v indexnow-data:/app/data \
-e AUTH_SECRET=$(openssl rand -base64 32) \
-e ADMIN_EMAIL=admin@example.com \
-e ADMIN_PASSWORD=your-strong-password \
ghcr.io/thetechbasket/index-now-server:latestdocker compose
curl -O https://raw.githubusercontent.com/TheTechBasket/index-now-server/main/docker-compose.yml
AUTH_SECRET=$(openssl rand -base64 32) \
ADMIN_EMAIL=admin@example.com \
ADMIN_PASSWORD=your-strong-password \
docker compose up -dOpen http://your-server:3020 and sign in. To skip the login gate entirely, drop the AUTH_SECRET/ADMIN_* vars and add -e AUTH_ENABLED=false (or AUTH_ENABLED=false before docker compose up -d).
To build from source instead of pulling, clone the repo and edit docker-compose.yml per the comment at the top of the indexnow-server service.
Set API_TOKEN in .env to enable programmatic access to all /api/* endpoints via Authorization: Bearer <token>:
API_TOKEN=$(openssl rand -hex 32)
curl -H "Authorization: Bearer $API_TOKEN" http://localhost:3020/api/sitesExisting cookie-based auth continues to work unchanged.
IndexNow Server ships an MCP server for AI agent integration. It connects via stdio and accesses the database directly (no HTTP round-trip).
{
"mcpServers": {
"indexnow": {
"command": "pnpm",
"args": ["mcp"],
"cwd": "/path/to/index-now-server",
"env": { "DATABASE_PATH": "./data/indexnow.db" }
}
}
}Tools (project-level, not per-site):
| Tool | Description |
|---|---|
get_overview |
Full project state: all sites, cron, settings, version, API reference. Call first. |
get_site_detail |
One site: config, URL counts, recent submissions, errors, key status |
add_site |
Add a site (auto-discovers sitemap from robots.txt) |
update_site |
Change submission level, cron interval, sitemap URL, name |
verify_key |
Check key deployment + return setup instructions |
submit_urls |
Submit pending URLs to search engines |
sync_sitemap |
Refresh URLs from sitemap without submitting |
get_site_urls |
Browse/search URLs with status filter and pagination |
Fastify · Drizzle + better-sqlite3 · React + shadcn/ui + Tailwind v4 · node-cron
src/server/ Fastify, auth, Drizzle schema, submission engine, cron
src/client/ React SPA (Vite)
drizzle/ SQL migrations (applied automatically at boot)
PRs welcome, see CONTRIBUTING.md. Run pnpm exec tsc --noEmit && pnpm build before pushing.
See SECURITY.md. Do not open a public issue for security problems.




