Warning
Beta. APIs, DB schema, and CLI flags may still change before v1.0. Components are versioned independently — CLI v0.1.6, full server v0.1.1, edge v0.1.3 at time of writing. Pin a release tag for stability.
Self-hostable mantis key service. API-first.
You mint a unique URL; when something fetches it, you get notified through the destinations you configure. Useful for honeypot files on shared drives, fake credentials in .envs, SSH-login alarms on jump boxes, detecting site clones, or any "did someone touch the thing they shouldn't" tripwire.
Highlights:
- File keys in 10 formats (
.docx/.xlsx/.pptx/.pdf/.svg/.html/.md/.eml/.ics/.vcf) plus a 9-file honey-directory.zipand Apple Wallet.pkpasspasses (install / uninstall / fetch callbacks each fire the key) - Host-event installers — shell, sudo, login, boot, wake, network — for macOS, Linux, and Windows, with parsed
X-Mantis-*context including SSH client IP - Web canaries — CSS-background + JS clone-detector — plus NFC NDEF tag URLs and printable QR/NFC sticker labels
- Smart-home triggers via Home Assistant, Scrypted, and an optional LAN watcher
- Smart-home actions —
home_assistantdestination posts to a HA webhook automation, so a hit can flip a switch (e.g. cut a VLAN via the OPNsense integration), fire a scene, or push a phone notification (mantis install <key> --type homeassistant-receiverprints a ready-to-paste automation skeleton) - Direct notification destinations — webhook, email, Slack, Discord, Teams — with a Postgres-backed retry queue and per-key dedup
- Optional stateless variant (
mantis-edge/) — a Cloudflare Worker that decrypts URLs at the edge, no DB to host - Uptime Kuma integration — per-key status URL flips on hit, watched by Kuma for 80+ notification channel fan-out
- Getting started — stateful server or stateless edge?
- Run from source — for contributors
- Components — in-repo docs for each part
- Docs — full prose documentation
Stateful server or stateless edge? Run the full server (docker compose, Postgres-backed) when you want the web dashboard, notification queue, file/host-event keys, and history. Run the edge (mantis-edge/) — a Cloudflare Worker that decrypts URLs at the edge with no DB to host — when you only need fire-and-forget hit alerts and want zero infrastructure.
The fastest path either way is the guided CLI: mantis init asks server-or-edge and walks you through login and your first key.
brew install privacykey/tap/mantis
mantis initgit clone https://github.com/privacykey/mantis && cd mantis
./scripts/setup.sh # creates .env with a random DB password + API-key pepper
docker compose up -d
# Wait for the boot banner, then read the one-time bootstrap admin key
docker compose logs -f mantis | grep -m1 -A1 "bootstrap API key"setup.sh is idempotent — re-running it leaves existing secrets untouched. Postgres is never published to the host (it sits on an internal-only docker network), and the DB password is the single value you set in .env; the app's DATABASE_URL is derived from it.
The mantis_live_... value printed above is the bootstrap admin key — it is both your CLI token and your dashboard login. To know it up front instead, pre-set BOOTSTRAP_API_KEY=mantis_live_... in .env before the first boot.
Open http://localhost:3000 and paste that same key to sign in to the web dashboard. Then log in the CLI and mint a key:
mantis --key mantis_live_... login --url http://localhost:3000
mantis new "first mantis" -w http://localhost:3000/inbox/demoThis is fine for evaluation but don't rely on a laptop deploy for canaries that need to fire when you're away from your machine. For a real public-reachable deploy — Tailscale Funnel, Cloudflare Tunnel, Railway, Fly.io, or Render — see deployment options.
Serve it over HTTPS, never plain HTTP. Mantis authenticates with an API key sent as a bearer token and a session cookie — over plain HTTP on a routable address both travel in cleartext and can be sniffed. Put it behind a tunnel (the
tailscale/cloudflaredcompose profiles terminate TLS for you) or a TLS reverse proxy. The compose setup keeps Postgres on an internal-only network with no published port, so the database is never reachable from the host or LAN.
No DB to host: deploy the Cloudflare Worker, then mint URLs that decrypt at the edge.
mantis edge keygen # generate the AES key
mantis edge set-key <worker-url> # link the deployed Worker
mantis edge mint # interactive wizard for a stateless URLSee mantis-edge/README.md for Worker deploy and full mantis edge usage.
For contributors hacking on the web dashboard / server:
pnpm install
cp .env.example .env # set DATABASE_URL and generate MANTIS_API_KEY_PEPPER
pnpm run db:migrate
pnpm devGenerate the pepper with openssl rand -base64 32 and add it as MANTIS_API_KEY_PEPPER in .env.
Each part of the repo has its own reference:
- CLI —
cli/README.md(full reference) andcli/COMMAND_MAP.md(command map) - Edge worker —
mantis-edge/README.md - IoT / LAN helper —
iot-helper/README.md - Benchmarks —
bench/README.md - Deploy assets —
deploy/(Fly.io and Render examples)
Full documentation: github.com/privacykey/mantis-docs.
Common starting points:
- Getting started — five steps from
brew installto first key - Use cases — defensive / detective / operational / adversarial patterns
- HTTP API — endpoints, response kinds, webhook payload shape
- File keys and host-event keys
- Updating — update commands per component
MIT License. See LICENSE.
