mantis.<your-domain> via Cloudflare Tunnel. Optionally, you can put parts of mantis behind Cloudflare Access for SSO (Google/GitHub/email-OTP/etc.).
When this is the right choice:
- You already own a domain that’s on Cloudflare DNS (or are willing to move one).
- You want a
mantis.<your-domain>URL rather than*.ts.net. - You like the idea of SSO-gating the dashboard for free (up to 50 users).
- You’re OK with all mantis traffic flowing through Cloudflare’s edge.
Prerequisites
- Docker + Docker Compose.
- A domain you own. Any registrar.
- Cloudflare account, free tier. Two things must be in place:
- The domain’s nameservers must point at Cloudflare. Add the domain in the main Cloudflare dashboard → it gives you two NS values → change them at your registrar → wait for propagation (5 min to a few hours).
- A Cloudflare Zero Trust team must be created (free, 50 seats). See Step 1 below.
Step 1 — Create a Zero Trust team
Cloudflare Zero Trust is a separate dashboard athttps://one.dash.cloudflare.com (different URL from the main CF dashboard).
- Go to one.dash.cloudflare.com. First visit prompts for team name — becomes
<team>.cloudflareaccess.com. Pick whatever. - Choose the Free plan (50 seats).
- (Skip for now) Identity providers. We’ll come back to this only if you decide to enable Access in Step 7.
Step 2 — Create the tunnel
- Networks → Tunnels → Create a tunnel.
- Connector type:
Cloudflared. - Name:
mantis→ Save. - The next screen shows install commands for various OSes. Ignore them — we run cloudflared inside Docker via our compose file. What you need is the key (long JWT) shown under “Install and run a connector”. Copy it.
- Click Next.
- Public Hostnames tab → Add a public hostname:
- Subdomain:
mantis(or your preference) - Domain: select your zone
- Path: leave blank (matches everything)
- Type:
HTTP - URL:
mantis:3000← this is the Docker service name; cloudflared resolves it via the compose network - Additional application settings → HTTP Settings → HTTP Host Header:
mantis.<your-domain>(helps with cookie domain matching for the dashboard)
- Subdomain:
- Save → Cloudflare auto-creates the DNS record. No manual DNS needed.
Step 3 — Configure and start
./scripts/setup.sh generates POSTGRES_PASSWORD and MANTIS_API_KEY_PEPPER,
which Compose refuses to start without — a plain cp .env.example .env leaves
POSTGRES_PASSWORD empty and the stack won’t boot.
Step 4 — Verify
https://mantis.<your-domain> → mantis /login.
Step 5 — Add public edge limits
Before sharing trigger URLs broadly, add Cloudflare rules for the public Mantis surfaces:- block oversized
/c/*,/status/*, and/api/wallet/*URLs - rate-limit
/c/*and/status/*by client IP - keep
/inbox*and/api/inboxblocked unless this is a deliberate dev box
edge-limits.md.
Step 6 — Bootstrap an API key
Step 7 (optional) — Cloudflare Access
This is the part where you need to make a decision. Before adding Access, decide what paths to gate. There are three reasonable levels:
The CLI now supports auth-passthrough for Cloudflare Access. The auth flow happens entirely on your machine: the CLI gets a short-lived JWT from cloudflared (via SSO) or sends a Service Auth header pair — and forwards it on every management API call. Mantis itself doesn’t validate Cloudflare JWTs; it just receives requests that have already passed CF’s gate, then validates the API key as usual. The server stays unaware of Cloudflare.
Recommended setup: full gating with CLI passthrough
The CLI handles Cloudflare auth client-side. Server is none the wiser. Two flavors, pick one:Option 1 — SSO (real user identity, recommended for personal use)
Requires thecloudflared binary on every machine where you run the CLI.
mantis cloudflare login whenever the JWT expires (Cloudflare default: 24h).
Option 2 — Service Auth (headless / CI use, pre-shared key)
For machines where opening a browser isn’t an option (servers, CI runners, etc.):CF-Access-Client-Id and CF-Access-Client-Secret headers on every /api/* request. Cloudflare Access validates them at the edge and passes through.
Cloudflare app configuration (either option)
- Settings → Authentication → Login methods. Add at least one (email OTP is simplest; SSO providers for teams).
- Access → Applications → Add an application → Self-hosted.
- Configuration:
- Application name: “Mantis”
- Session duration: 24h
- Application Domain:
mantis.<your-domain>
- Paths: gate dashboard and management API routes:
//login*/logout*/keys*/settings*/api/keys*/api/hits*/api/api-keys*/api/device-profiles*/api/audit*/api/cron*
- Identity providers (for Option 1 / browser SSO): tick the methods you configured.
- Policies → add as needed:
- Operator — Allow, Selector: Emails matching your address (for SSO / browser login).
- Mantis CLI — Service Auth, Selector: your service key (only if using Option 2).
- Save.
/c/*— mantis triggers. Must be public; this is the whole point./status/*— Uptime Kuma monitor URLs. Must be public so Uptime Kuma can poll./api/wallet/*— Apple Wallet callbacks. Required only if you enable.pkpasssupport./api/health— optional public health check. Gate it unless an external public monitor needs it./inbox*and/api/inbox— dev webhook inbox. Disable for production withENABLE_DEV_INBOX=0if you don’t need it.
After Access is on
Dashboard (browser):- Visit
https://mantis.<your-domain>/keys→ Cloudflare redirects to<team>.cloudflareaccess.com→ email-OTP / SSO login. - After auth, redirects back to mantis.
- Mantis shows
/login(paste API key). - After paste, dashboard appears.
- With SSO mode: the CLI calls
cloudflared access token --app=…for each request, getting a cached short-lived JWT. Transparent after the initialmantis cloudflare login. - With Service Auth: the CLI sends the stored Client-ID/Secret headers. No browser interaction ever.
- All credential state lives on your machine. The mantis server never sees Cloudflare config and doesn’t need to verify anything Cloudflare-related — Access has already validated the request before mantis ever sees it.
Gotchas
- Cloudflare terminates TLS. All mantis traffic — including potentially sensitive hit metadata — passes through Cloudflare’s edge in plaintext. If your mantis catches genuinely confidential content (email contents, document bodies), CF logs see it. Privacy tradeoff worth knowing.
- Free Access seats: 50. Plenty for personal / small team. Past that, paid plan.
- Origin protection. Cloudflare recommends locking your origin to only accept traffic from CF IPs. Mantis already binds to
127.0.0.1(only reachable inside the Docker network, where cloudflared also lives), so this is taken care of without extra config. - Cloudflare Access cookie + Set-Cookie domain. If you see the dashboard login cookie not sticking, check the HTTP Host Header setting from Step 2.6 — it should be
mantis.<your-domain>, notlocalhost:3000.
Uninstalling cleanly
- In Cloudflare Zero Trust: Networks → Tunnels → mantis → Delete. Also removes the DNS record.
- Access → Applications → Mantis dashboard → Delete if you set that up.
- The DNS record auto-cleans on tunnel deletion (Cloudflare-managed).