Public Access
The daemon binds to 127.0.0.1:7890 by default. To accept GitHub webhooks or reach the daemon from another machine, expose it through a tunnel.
| Cloudflare Quick Tunnel | Tailscale Funnel | |
|---|---|---|
| Account required | No | Yes (free) |
| URL stability | Rotates on restart | Persistent (*.ts.net) |
| Best for | One-off testing, demos | Production webhooks, daily use |
| Prerequisite | cloudflared on PATH | Tailscale enrolled on host |
Cloudflare Tunnel
Bento can spin up a Cloudflare Quick Tunnel alongside the daemon, exposing the local 127.0.0.1:7890 port via an ephemeral *.trycloudflare.com URL with no Cloudflare account required. Useful for one-off webhook receivers, demos, and "show this to a teammate for an hour."
Prerequisites
cloudflaredon the daemon host'sPATH. On macOS:brew install cloudflared. On Linux see Cloudflare's install docs.bento doctorvalidates this when thetunnel:block is present inbento.yaml.
Quick tunnel (no account)
Add a tunnel: block to bento.yaml:
tunnel:
provider: cloudflare
mode: quickThen restart the daemon:
bento restartThe daemon spawns cloudflared, parses the public URL out of its startup log, and emits one info line:
[INFO] [tunnel] public URL ready: https://essentially-carrying-recorder-merely.trycloudflare.combento status surfaces the same URL:
local : reachable (8ms) — @bento/daemon uptime=14s
tunnel : reachable (83ms) — https://essentially-carrying-recorder-merely.trycloudflare.com
funnel : not configured (tailscale funnel not active)Use the public URL
GitHub webhooks — point the webhook delivery URL at:
https://<random>.trycloudflare.com/eventsMake sure webhooks.secret in bento.yaml matches the GitHub webhook secret so signature verification passes. The daemon also accepts /webhooks/github and /webhooks/linear.
MCP clients — configure Claude Code / Codex / pi against the tunnel URL — see Authentication for the exact commands. Issue a bearer token first:
bento token issue --email you@example.comLifecycle
- The tunnel is supervised as a child of the daemon.
bento stopsendsSIGTERMtocloudflaredbefore stopping the HTTP server. - If
cloudflaredcrashes while the daemon is up, the daemon logs the exit code atwarnand keeps running. Restart to re-establish the tunnel. - The daemon does not block on tunnel readiness during startup.
Named tunnels (stable URL)
For a stable URL, pre-create a named tunnel in your Cloudflare account. The auto-generated <uuid>.cfargotunnel.com URL is only valid as a CNAME target — you need a real hostname.
Prerequisites
- A free Cloudflare account.
cloudflaredon the host.- A hostname you control with a CNAME pointing at the tunnel:
- Cloudflare DNS —
cloudflared tunnel route dnscreates the CNAME automatically. - External DNS — create
bento.example.com CNAME <tunnel-uuid>.cfargotunnel.comyourself.
- Cloudflare DNS —
One-time setup
-
Authenticate
cloudflared:cloudflared tunnel login -
Create the tunnel:
cloudflared tunnel create bento-prod -
Route a hostname:
# Cloudflare-managed DNS: cloudflared tunnel route dns bento-prod bento.example.com # External DNS: add a CNAME manually: # bento.example.com CNAME <uuid>.cfargotunnel.com
Point bento at the tunnel
tunnel:
provider: cloudflare
mode: named
name: bento-prodThen bento restart. The daemon runs cloudflared tunnel run, detects the registered hostname, and surfaces it in bento status.
Tear down
cloudflared tunnel delete bento-prodRemove the DNS CNAME separately via your DNS provider.
Files
| Path | Created by | Purpose | Needed at runtime? |
|---|---|---|---|
~/.cloudflared/cert.pem | tunnel login | Manage tunnels (create/delete/route DNS) | No |
~/.cloudflared/<uuid>.json | tunnel create <name> | Authenticate the running tunnel | Yes |
~/.cloudflared/config.yml | hand-written (optional) | Ingress rules | Only if not passing --url |
Notes
- Quick tunnels are public and unauthenticated at the tunnel layer. The daemon's bearer-token middleware and webhook signature verification are the only auth — never disable them.
- Cloudflare may rate-limit Quick Tunnels under heavy traffic. For production webhook ingestion use a named tunnel.
Tailscale Funnel
Tailscale Funnel gives a persistent TLS-terminated *.ts.net URL routed back to your machine over the tailnet.
Two ways to wire it up:
- Let bento manage it —
tunnel:block inbento.yaml; bento callstailscale funnel --bg <port>at start and teardown. - Manage it yourself — run
tailscale funnel --bg 7890once;bento statusstill detects it.
Prerequisites
- A Tailscale account with the daemon's host enrolled.
- HTTPS certificates and Funnel enabled for your tailnet (admin console: DNS → HTTPS Certificates and Access Controls → Funnel).
Bento-managed mode
tunnel:
provider: tailscale
mode: funnelbento restart execs tailscale funnel --bg 7890, polls tailscale funnel status for the public URL, and surfaces it via bento status.
On shutdown bento runs tailscale funnel --bg off — but only if it was the one that enabled the funnel. If a funnel was already active at startup, bento adopts the existing URL and skips both setup and teardown.
Manual mode
tailscale funnel --bg 7890--bg persists across shell exits. You only need to run this once per machine.
Verify:
tailscale funnel status
# https://8640p.tail673878.ts.net (Funnel on)
# |-- / proxy http://127.0.0.1:7890bento status picks it up automatically:
local : reachable (4ms) — bento uptime=120s
funnel : reachable (38ms) — https://8640p.tail673878.ts.netUse the public URL
MCP clients — configure Claude Code, Codex, or pi — see Authentication. Issue a token first:
bento token issue --email you@example.comGitHub webhooks — point the delivery URL at:
https://<node>.tail<id>.ts.net/eventsSet the same secret as webhooks.secret in bento.yaml.
Stopping the funnel
tailscale funnel --bg offUnbinds the public URL but leaves the daemon running locally.
Notes
- Funnel only serves ports
443,8443, and10000on the public side. Tailscale maps:443→:7890automatically. - Funnel traffic counts against tailnet bandwidth limits. For high-volume webhook traffic consider a server with a real DNS record.
- The funnel URL is publicly reachable. Authentication is enforced by the daemon's bearer-token middleware — never disable it.

