Give your Breadbox instance a public HTTPS URL so MCP clients and bank webhooks can reach it.
Remote hosting is the intended default for Breadbox. Almost every integration that makes Breadbox useful assumes a public HTTPS URL:
Cloud AI clients. Claude (Desktop / web / mobile), ChatGPT, Manus, Openclaw, and most other MCP-speaking AI apps can only reach an MCP server over https:// — a bare localhost is unreachable from a cloud-hosted model.
Bank webhooks. Plaid and Teller push real-time updates (new transactions, reauth events) to a webhook URL you register with them. Without a public URL those events are dropped and you fall back to polling.
Reading from anywhere. Phone, laptop, a browser at work — any of those assumes Breadbox is more than localhost on the one machine you installed it on.
The one case where pure-localhost is legitimate: you’re running a local autonomous agent (e.g., an Openclaw runner on the same box) that is the only client that will ever touch Breadbox. If that’s not you, pick one of the four options below — they’re ordered easiest to most hands-on.
None of these replace the admin login. They put Breadbox on the public internet; Breadbox still authenticates every request against your admin account, API keys, and MCP mode.
exe.dev is our recommended easy path. It spins up a persistent Linux VM in a couple of seconds, gives it an HTTPS endpoint at https://<vmname>.exe.xyz/, and handles TLS, DNS, and reverse-proxying for you. No ports to open, no Caddy to configure.
1
Register your SSH key
exe.dev is driven entirely over SSH. Register your public key once:
ssh exe.dev ssh-key add < ~/.ssh/id_ed25519.pub
2
Create a VM
ssh exe.dev new
The command prints a VM name (e.g. breadbox-a1b2). Every VM gets https://<vmname>.exe.xyz/ automatically, with TLS and auth handled by the platform.
Or use any other method from the installation guide — Docker Compose, binary download, or go install.
4
Point the proxy at port 8080
exe.dev’s proxy defaults to port 80 or the smallest exposed port; tell it to forward to Breadbox:
ssh exe.dev share port <vmname> 8080
Open https://<vmname>.exe.xyz/ in a browser and the setup wizard loads over HTTPS.
5
(Optional) Bring your own domain
Point a CNAME at your VM and exe.dev will issue a cert for it automatically:
breadbox.example.com CNAME <vmname>.exe.xyz
exe.dev keeps the HTTPS endpoint behind its own identity layer by default. If you want Breadbox’s own login to be the only gate, run ssh exe.dev share set-public <vmname>.
Cloudflare Tunnel exposes a local service at a public HTTPS URL without opening any inbound ports. cloudflared dials out to Cloudflare, and traffic flows back through that outbound connection. It works behind NAT, CGNAT, or a home router you don’t control, and it’s free on any Cloudflare plan.
For a one-off disposable HTTPS URL — useful for spot-checking that a remote client can reach Breadbox at all:
cloudflared tunnel --url http://localhost:8080
The command prints a random https://<random>.trycloudflare.com URL and proxies it to your local Breadbox until you kill the process. Treat this as testing-only: the URL changes every run, and there’s a 200-in-flight-requests ceiling. Quick tunnels also require that no ~/.cloudflared/config.yml file exists — if you’ve already set up a named tunnel, you’ll need to rename the config file before the quick tunnel will start.
Cloudflare quick tunnels don’t support Server-Sent Events (SSE) — and Breadbox’s MCP endpoint (/mcp) uses streamable HTTP with SSE. A quick tunnel is fine for sanity-checking plain HTTP against the admin dashboard or REST API, but you’ll need a named tunnel (below) before any MCP client can actually connect.
Point credentials-file at the actual JSON file cloudflared tunnel create wrote — it lives under whatever $HOME/.cloudflared/ is for the user running cloudflared. If you’re running as root, the path is /root/.cloudflared/....
5
Route DNS to the tunnel
cloudflared tunnel route dns breadbox breadbox.example.com
Cloudflare creates the CNAME automatically. Replace the hostname with whatever subdomain you want Breadbox to live at.
6
Run the tunnel
cloudflared tunnel run breadbox
On a long-running host, install it as a service so it survives reboots — Cloudflare’s docs have cloudflared service install snippets per-OS.
If you already have a VPS (DigitalOcean, Hetzner, Fly machine, a home server with ports 80 and 443 reachable from the public internet), Breadbox ships a Caddy reverse proxy you can turn on with a single flag at install time. Caddy requests a Let’s Encrypt cert automatically the first time a request lands on your domain. Both ports must be open: port 80 is used for the Let’s Encrypt HTTP-01 challenge, port 443 for the actual HTTPS traffic.
Point an A record (or AAAA) for your chosen domain at the VPS’s public IP.
Run the one-liner installer with --domain to enable the Caddy profile up front:
This starts Breadbox, PostgreSQL, and Caddy in one shot. Caddy is gated behind a caddy compose profile — localhost-only installs skip it and leave ports 80/443 unbound.
If you already installed without a domain, edit breadbox/.env to set DOMAIN=breadbox.example.com and bring the Caddy profile up:
cd breadbox && docker compose --profile caddy up -d
The bundled Caddyfile is a single reverse_proxy breadbox:8080 block keyed on {$DOMAIN}. See Install Breadbox for the full installer reference.
Tailscale Funnel is a nice middle ground if you already live inside Tailscale. Machines on your tailnet reach Breadbox privately at its MagicDNS name; Funnel then optionally exposes specific ports to the public internet over HTTPS, using certificates Tailscale issues automatically.On the machine running Breadbox:
tailscale funnel 8080
Funnel prints a public URL like https://<hostname>.<tailnet>.ts.net/. MagicDNS and HTTPS certs must be enabled for your tailnet, and Funnel only accepts ports 443, 8443, and 10000 — Tailscale relays the incoming HTTPS traffic to localhost:8080 on the target machine for you.
Share-only-with-my-devices is the default: tailscale serve 8080 keeps Breadbox private to your tailnet. Reach for Funnel only when you actually need the public HTTPS URL (webhooks, cloud MCP clients).
The absolute shortest path; happy running a small managed VM
exe.dev
To host Breadbox at home behind NAT/CGNAT without port forwarding
Cloudflare Tunnel (named)
To try an MCP client once before committing to a real URL
Cloudflare Tunnel (quick tunnel)
A VPS you already own and full control over TLS/logs
Caddy on a VPS
To start private inside your own network and only selectively go public
Tailscale Funnel
Once you have a public HTTPS URL, register it with Plaid/Teller as your webhook endpoint and plug it into your MCP client of choice — everything in the rest of the docs applies unchanged.
Last modified on June 2, 2026
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Breadbox","description":"Self-hosted financial data aggregation for households. Sync bank transactions from Plaid, Teller, and CSV into a PostgreSQL database you control, then expose it to AI agents via MCP and REST. Includes a CLI, an admin dashboard, scheduled Claude Agent SDK runs, and a transaction-rule engine for autonomous categorization.","colors":{"primary":"#16A34A","light":"#22C55E","dark":"#15803D"},"logo":{"light":"https://mintcdn.com/breadbox/d0QBHUmdZVqbsv3S/images/fried-egg.svg?fit=max\u0026auto=format\u0026n=d0QBHUmdZVqbsv3S\u0026q=85\u0026s=f653995ffcf649db40c69ed2ecce3a8a","dark":"https://mintcdn.com/breadbox/d0QBHUmdZVqbsv3S/images/fried-egg.svg?fit=max\u0026auto=format\u0026n=d0QBHUmdZVqbsv3S\u0026q=85\u0026s=f653995ffcf649db40c69ed2ecce3a8a","href":"https://breadbox.sh"},"favicon":{"light":"https://mintcdn.com/breadbox/d0QBHUmdZVqbsv3S/images/fried-egg.svg?fit=max\u0026auto=format\u0026n=d0QBHUmdZVqbsv3S\u0026q=85\u0026s=f653995ffcf649db40c69ed2ecce3a8a","dark":"https://mintcdn.com/breadbox/d0QBHUmdZVqbsv3S/images/fried-egg.svg?fit=max\u0026auto=format\u0026n=d0QBHUmdZVqbsv3S\u0026q=85\u0026s=f653995ffcf649db40c69ed2ecce3a8a"},"api":{"playground":{"display":"none"}},"appearance":{"default":"system"},"background":{"color":{"light":"#FCF9F3","dark":"#1A1612"}},"navbar":{"links":[],"primary":{"type":"github","href":"https://github.com/canalesb93/breadbox"}},"search":{"prompt":"Search..."},"icons":{"library":"lucide"},"styling":{"eyebrows":"breadcrumbs","latex":true},"banner":{"content":"Breadbox is in early access pending the v1.0 release. [See the changelog →](/changelog)","dismissible":true,"type":"warning"},"errors":{"404":{"redirect":true}},"metadata":{"timestamp":true},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"breadbox","hasAudioNarration":false,"actualSubdomain":"breadbox","customDomains":["docs.breadbox.sh"],"gitSource":{"type":"github","owner":"canalesb93","repo":"breadbox-docs","deployBranch":"main","isPrivate":false,"contentDirectory":"","mountPath":"","label":""},"chroma":{"liveDeploymentHistoryId":"6a829e30021dd593d8d5b25f","collectionId":"1fa3972f-64d1-42c9-999c-6dde8a385243","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6a829e30021dd593d8d5b25f"},"entitlements":{"AI_CHAT":{"status":"ENABLED"}},"buildId":"6a829e30021dd593d8d5b25f:success","clientVersion":"0.0.4006","searchFilterCounts":[{"language":"default","tag":"Reference","count":185},{"language":"default","tag":"API","count":168},{"language":"default","tag":"Endpoints","count":165},{"language":"default","tag":"Transactions","count":24},{"language":"default","tag":"Docs","count":23},{"language":"default","tag":"Connections","count":22},{"language":"default","tag":"Workflows","count":21},{"language":"default","tag":"Model Context Protocol","count":17},{"language":"default","tag":"Users","count":14},{"language":"default","tag":"Guides","count":11}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-v7-file-tree","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"pause-universal-search-reconcile","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"per-site-search-delta","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-private-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-nav-generations","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"byok-sep-25","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-agent-model-picker","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[],"page":{"pagePath":"installation/remote-hosting","slug":"/installation/remote-hosting","pageMetadata":{"title":"Make Breadbox reachable from the internet","description":"Give your Breadbox instance a public HTTPS URL so MCP clients and bank webhooks can reach it.","sidebarTitle":"Remote hosting","href":"/installation/remote-hosting"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Give your Breadbox instance a public HTTPS URL so MCP clients and bank webhooks can reach it.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,em:`em`,li:`li`,ol:`ol`,p:`p`,pre:`pre`,span:`span`,strong:`strong`,tbody:`tbody`,td:`td`,th:`th`,thead:`thead`,tr:`tr`,ul:`ul`,..._provideComponents(),...props.components},{CodeBlock,Heading,Note,Step,Steps,Tab,Table,Tabs,Tip}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Note)_missingMdxReference(`Note`,true);if(!Step)_missingMdxReference(`Step`,true);if(!Steps)_missingMdxReference(`Steps`,true);if(!Tab)_missingMdxReference(`Tab`,true);if(!Table)_missingMdxReference(`Table`,true);if(!Tabs)_missingMdxReference(`Tabs`,true);if(!Tip)_missingMdxReference(`Tip`,true);return _jsxs(_Fragment,{children:[_jsx(_components.p,{children:`Remote hosting is the intended default for Breadbox. Almost every integration that makes Breadbox useful assumes a public HTTPS URL:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Cloud AI clients.`}),` Claude (Desktop / web / mobile), ChatGPT, Manus, Openclaw, and most other MCP-speaking AI apps can only reach an MCP server over `,_jsx(_components.code,{children:`https://`}),` — a bare `,_jsx(_components.code,{children:`localhost`}),` is unreachable from a cloud-hosted model.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Bank webhooks.`}),` Plaid and Teller push real-time updates (new transactions, reauth events) to a webhook URL you register with them. Without a public URL those events are dropped and you fall back to polling.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Reading from anywhere.`}),` Phone, laptop, a browser at work — any of those assumes Breadbox is more than `,_jsx(_components.code,{children:`localhost`}),` on the one machine you installed it on.`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`The one case where pure-localhost is legitimate: you’re running a local autonomous agent (e.g., an Openclaw runner on the same box) that is the `,_jsx(_components.em,{children:`only`}),` client that will ever touch Breadbox. If that’s not you, pick one of the four options below — they’re ordered easiest to most hands-on.`]}),`\n`,_jsx(Note,{children:_jsx(_components.p,{children:`None of these replace the admin login. They put Breadbox on the public internet; Breadbox still authenticates every request against your admin account, API keys, and MCP mode.`})}),`\n`,_jsx(Heading,{level:`2`,id:`pick-an-option`,children:`Pick an option`}),`\n`,_jsxs(Tabs,{children:[_jsxs(Tab,{title:`exe.dev (easiest)`,id:`exe-dev-easiest`,children:[_jsxs(_components.p,{children:[_jsx(_components.a,{href:`https://exe.dev`,children:`exe.dev`}),` is our recommended easy path. It spins up a persistent Linux VM in a couple of seconds, gives it an HTTPS endpoint at `,_jsx(_components.code,{children:`https://\u003cvmname>.exe.xyz/`}),`, and handles TLS, DNS, and reverse-proxying for you. No ports to open, no Caddy to configure.`]}),_jsxs(Steps,{children:[_jsxs(Step,{title:`Register your SSH key`,children:[_jsx(_components.p,{children:`exe.dev is driven entirely over SSH. Register your public key once:`}),_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`ssh`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` exe.dev`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` ssh-key`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` add`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` ~/.ssh/id_ed25519.pub`})]}),`\n`]})})})]}),_jsxs(Step,{title:`Create a VM`,children:[_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`ssh`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` exe.dev`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` new`})]}),`\n`]})})}),_jsxs(_components.p,{children:[`The command prints a VM name (e.g. `,_jsx(_components.code,{children:`breadbox-a1b2`}),`). Every VM gets `,_jsx(_components.code,{children:`https://\u003cvmname>.exe.xyz/`}),` automatically, with TLS and auth handled by the platform.`]})]}),_jsxs(Step,{title:`Install Breadbox on the VM`,children:[_jsx(_components.p,{children:`SSH in and run the one-liner installer:`}),_jsx(CodeBlock,{filename:``,numberOfLines:`2`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`2`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`ssh`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`vmnam`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`e`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`.exe.xyz`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`curl`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -fsSL`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` https://breadbox.sh/install.sh`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` |`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:` bash`})]}),`\n`]})})}),_jsxs(_components.p,{children:[`Or use any other method from the `,_jsx(_components.a,{href:`/installation`,children:`installation guide`}),` — Docker Compose, binary download, or `,_jsx(_components.code,{children:`go install`}),`.`]})]}),_jsxs(Step,{title:`Point the proxy at port 8080`,children:[_jsx(_components.p,{children:`exe.dev’s proxy defaults to port 80 or the smallest exposed port; tell it to forward to Breadbox:`}),_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`ssh`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` exe.dev`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` share`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` port`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`vmnam`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`e`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:` 8080`})]}),`\n`]})})}),_jsxs(_components.p,{children:[`Open `,_jsx(_components.code,{children:`https://\u003cvmname>.exe.xyz/`}),` in a browser and the setup wizard loads over HTTPS.`]})]}),_jsxs(Step,{title:`(Optional) Bring your own domain`,children:[_jsx(_components.p,{children:`Point a CNAME at your VM and exe.dev will issue a cert for it automatically:`}),_jsx(CodeBlock,{filename:``,numberOfLines:`2`,language:`text`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`text`,children:_jsxs(_components.code,{language:`text`,numberOfLines:`2`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`breadbox.example.com CNAME \u003cvmname>.exe.xyz`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{})})]})})})]})]}),_jsx(Tip,{children:_jsxs(_components.p,{children:[`exe.dev keeps the HTTPS endpoint behind its own identity layer by default. If you want Breadbox’s own login to be the only gate, run `,_jsx(_components.code,{children:`ssh exe.dev share set-public \u003cvmname>`}),`.`]})})]}),_jsxs(Tab,{title:`Cloudflare Tunnel`,id:`cloudflare-tunnel`,\"data-child-heading-ids\":`[\"quick-tunnel-testing%2C-no-account-needed\",\"named-tunnel-permanent-url-on-your-own-domain\"]`,children:[_jsxs(_components.p,{children:[_jsx(_components.a,{href:`https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/`,children:`Cloudflare Tunnel`}),` exposes a local service at a public HTTPS URL without opening any inbound ports. `,_jsx(_components.code,{children:`cloudflared`}),` dials out to Cloudflare, and traffic flows back through that outbound connection. It works behind NAT, CGNAT, or a home router you don’t control, and it’s free on any Cloudflare plan.`]}),_jsx(Heading,{level:`3`,id:`quick-tunnel-testing-no-account-needed`,children:`Quick tunnel (testing, no account needed)`}),_jsx(_components.p,{children:`For a one-off disposable HTTPS URL — useful for spot-checking that a remote client can reach Breadbox at all:`}),_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`cloudflared`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` tunnel`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --url`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` http://localhost:8080`})]}),`\n`]})})}),_jsxs(_components.p,{children:[`The command prints a random `,_jsx(_components.code,{children:`https://\u003crandom>.trycloudflare.com`}),` URL and proxies it to your local Breadbox until you kill the process. Treat this as testing-only: the URL changes every run, and there’s a 200-in-flight-requests ceiling. Quick tunnels also require that `,_jsxs(_components.strong,{children:[`no `,_jsx(_components.code,{children:`~/.cloudflared/config.yml`}),` file exists`]}),` — if you’ve already set up a named tunnel, you’ll need to rename the config file before the quick tunnel will start.`]}),_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Cloudflare quick tunnels don’t support Server-Sent Events (SSE)`}),` — and Breadbox’s MCP endpoint (`,_jsx(_components.code,{children:`/mcp`}),`) uses streamable HTTP with SSE. A quick tunnel is fine for sanity-checking plain HTTP against the admin dashboard or REST API, but you’ll need a `,_jsx(_components.strong,{children:`named tunnel`}),` (below) before any MCP client can actually connect.`]})}),_jsx(Heading,{level:`3`,id:`named-tunnel-permanent-url-on-your-own-domain`,children:`Named tunnel (permanent URL on your own domain)`}),_jsx(_components.p,{children:`For a stable URL you can register with Plaid/Teller webhooks and Claude Desktop, use a named tunnel bound to a domain you’ve added to Cloudflare:`}),_jsxs(Steps,{children:[_jsx(Step,{title:`Install cloudflared`,children:_jsx(CodeBlock,{filename:``,numberOfLines:`5`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`5`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# macOS`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`brew`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` install`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` cloudflared`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# Ubuntu / Debian`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`sudo`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` apt-get`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` update`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` \u0026\u0026 `}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`sudo`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` apt-get`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` install`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` cloudflared`})]}),`\n`]})})})}),_jsxs(Step,{title:`Authenticate`,children:[_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`cloudflared`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` tunnel`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` login`})]}),`\n`]})})}),_jsxs(_components.p,{children:[`This opens a browser to authorize `,_jsx(_components.code,{children:`cloudflared`}),` against one of your Cloudflare zones and writes a cert to `,_jsx(_components.code,{children:`~/.cloudflared/`}),`.`]})]}),_jsxs(Step,{title:`Create the tunnel`,children:[_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`cloudflared`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` tunnel`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` create`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` breadbox`})]}),`\n`]})})}),_jsx(_components.p,{children:`Note the tunnel UUID from the output — you’ll need it for the config file.`})]}),_jsxs(Step,{title:`Write ~/.cloudflared/config.yml`,children:[_jsx(CodeBlock,{filename:``,numberOfLines:`3`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`3`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`tunnel`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\u003cYOUR-TUNNEL-UUID>`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`credentials-file`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`/home/\u003cuser>/.cloudflared/\u003cYOUR-TUNNEL-UUID>.json`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`url`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`http://localhost:8080`})]}),`\n`]})})}),_jsxs(_components.p,{children:[`Point `,_jsx(_components.code,{children:`credentials-file`}),` at the actual JSON file `,_jsx(_components.code,{children:`cloudflared tunnel create`}),` wrote — it lives under whatever `,_jsx(_components.code,{children:`$HOME/.cloudflared/`}),` is for the user running `,_jsx(_components.code,{children:`cloudflared`}),`. If you’re running as root, the path is `,_jsx(_components.code,{children:`/root/.cloudflared/...`}),`.`]})]}),_jsxs(Step,{title:`Route DNS to the tunnel`,children:[_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`cloudflared`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` tunnel`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` route`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` dns`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` breadbox`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` breadbox.example.com`})]}),`\n`]})})}),_jsx(_components.p,{children:`Cloudflare creates the CNAME automatically. Replace the hostname with whatever subdomain you want Breadbox to live at.`})]}),_jsxs(Step,{title:`Run the tunnel`,children:[_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`cloudflared`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` tunnel`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` run`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` breadbox`})]}),`\n`]})})}),_jsxs(_components.p,{children:[`On a long-running host, install it as a service so it survives reboots — Cloudflare’s docs have `,_jsx(_components.code,{children:`cloudflared service install`}),` snippets per-OS.`]})]})]})]}),_jsxs(Tab,{title:`Caddy on a VPS`,id:`caddy-on-a-vps`,children:[_jsx(_components.p,{children:`If you already have a VPS (DigitalOcean, Hetzner, Fly machine, a home server with ports 80 and 443 reachable from the public internet), Breadbox ships a Caddy reverse proxy you can turn on with a single flag at install time. Caddy requests a Let’s Encrypt cert automatically the first time a request lands on your domain. Both ports must be open: port 80 is used for the Let’s Encrypt HTTP-01 challenge, port 443 for the actual HTTPS traffic.`}),_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`Point an `,_jsx(_components.code,{children:`A`}),` record (or `,_jsx(_components.code,{children:`AAAA`}),`) for your chosen domain at the VPS’s public IP.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`Run the one-liner installer with `,_jsx(_components.code,{children:`--domain`}),` to enable the Caddy profile up front:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`curl`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -fsSL`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` https://breadbox.sh/install.sh`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` |`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:` bash`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -s`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --yes`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --domain=breadbox.example.com`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`This starts Breadbox, PostgreSQL, `,_jsx(_components.strong,{children:`and`}),` Caddy in one shot. Caddy is gated behind a `,_jsx(_components.code,{children:`caddy`}),` compose profile — localhost-only installs skip it and leave ports 80/443 unbound.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`If you already installed without a domain, edit `,_jsx(_components.code,{children:`breadbox/.env`}),` to set `,_jsx(_components.code,{children:`DOMAIN=breadbox.example.com`}),` and bring the Caddy profile up:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#DCDCAA`},children:`cd`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` breadbox`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` \u0026\u0026 `}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`docker`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` compose`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --profile`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` caddy`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` up`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -d`})]}),`\n`]})})}),`\n`]}),`\n`]}),_jsxs(_components.p,{children:[`The bundled `,_jsx(_components.code,{children:`Caddyfile`}),` is a single `,_jsx(_components.code,{children:`reverse_proxy breadbox:8080`}),` block keyed on `,_jsx(_components.code,{children:`{$DOMAIN}`}),`. See `,_jsx(_components.a,{href:`/installation`,children:`Install Breadbox`}),` for the full installer reference.`]})]}),_jsxs(Tab,{title:`Tailscale Funnel`,id:`tailscale-funnel`,children:[_jsxs(_components.p,{children:[_jsx(_components.a,{href:`https://tailscale.com/kb/1223/funnel`,children:`Tailscale Funnel`}),` is a nice middle ground if you already live inside Tailscale. Machines on your tailnet reach Breadbox privately at its MagicDNS name; Funnel then optionally exposes specific ports to the public internet over HTTPS, using certificates Tailscale issues automatically.`]}),_jsx(_components.p,{children:`On the machine running Breadbox:`}),_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`tailscale`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` funnel`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:` 8080`})]}),`\n`]})})}),_jsxs(_components.p,{children:[`Funnel prints a public URL like `,_jsx(_components.code,{children:`https://\u003chostname>.\u003ctailnet>.ts.net/`}),`. MagicDNS and HTTPS certs must be enabled for your tailnet, and Funnel only accepts ports `,_jsx(_components.code,{children:`443`}),`, `,_jsx(_components.code,{children:`8443`}),`, and `,_jsx(_components.code,{children:`10000`}),` — Tailscale relays the incoming HTTPS traffic to `,_jsx(_components.code,{children:`localhost:8080`}),` on the target machine for you.`]}),_jsx(Note,{children:_jsxs(_components.p,{children:[`Share-only-with-my-devices is the default: `,_jsx(_components.code,{children:`tailscale serve 8080`}),` keeps Breadbox private to your tailnet. Reach for Funnel only when you actually need the public HTTPS URL (webhooks, cloud MCP clients).`]})})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`which-should-i-pick`,children:`Which should I pick?`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`You want…`}),_jsx(_components.th,{children:`Recommended option`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`The absolute shortest path; happy running a small managed VM`}),_jsx(_components.td,{children:_jsx(_components.strong,{children:`exe.dev`})})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`To host Breadbox at home behind NAT/CGNAT without port forwarding`}),_jsxs(_components.td,{children:[_jsx(_components.strong,{children:`Cloudflare Tunnel`}),` (named)`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`To try an MCP client once before committing to a real URL`}),_jsxs(_components.td,{children:[_jsx(_components.strong,{children:`Cloudflare Tunnel`}),` (quick tunnel)`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`A VPS you already own and full control over TLS/logs`}),_jsx(_components.td,{children:_jsx(_components.strong,{children:`Caddy on a VPS`})})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`To start private inside your own network and only selectively go public`}),_jsx(_components.td,{children:_jsx(_components.strong,{children:`Tailscale Funnel`})})]})]})]}),`\n`,_jsx(_components.p,{children:`Once you have a public HTTPS URL, register it with Plaid/Teller as your webhook endpoint and plug it into your MCP client of choice — everything in the rest of the docs applies unchanged.`})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Make Breadbox reachable from the internet","description":"Give your Breadbox instance a public HTTPS URL so MCP clients and bank webhooks can reach it.","sidebarTitle":"Remote hosting","href":"/installation/remote-hosting"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Pick an option","slug":"pick-an-option","depth":2,"children":[{"title":"Quick tunnel (testing, no account needed)","slug":"quick-tunnel-testing-no-account-needed","depth":3,"children":[],"tabId":"cloudflare-tunnel"},{"title":"Named tunnel (permanent URL on your own domain)","slug":"named-tunnel-permanent-url-on-your-own-domain","depth":3,"children":[],"tabId":"cloudflare-tunnel"}]},{"title":"Which should I pick?","slug":"which-should-i-pick","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"breadbox","siteName":"Breadbox","title":"Make Breadbox reachable from the internet - Breadbox","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-06-02T17:44:57.434Z","gitLastModified":"2026-06-02T17:44:38.000Z","originalFileLocation":"installation/remote-hosting.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Give your Breadbox instance a public HTTPS URL so MCP clients and bank webhooks can reach it.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Breadbox\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/breadbox/wfRExqoTacYaBhYJ/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/breadbox/wfRExqoTacYaBhYJ/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/breadbox/wfRExqoTacYaBhYJ/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/breadbox/wfRExqoTacYaBhYJ/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/breadbox/wfRExqoTacYaBhYJ/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/breadbox/wfRExqoTacYaBhYJ/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/breadbox/wfRExqoTacYaBhYJ/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/breadbox/wfRExqoTacYaBhYJ/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/breadbox/wfRExqoTacYaBhYJ/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Make Breadbox reachable from the internet - Breadbox\">\u003cmeta data-mint-head property=\"og:description\" content=\"Give your Breadbox instance a public HTTPS URL so MCP clients and bank webhooks can reach it.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Breadbox\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.breadbox.sh/installation/remote-hosting\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://breadbox.mintlify.app/_mintlify/api/og/v2?division=Overview\u0026amp;title=Make+Breadbox+reachable+from+the+internet\u0026amp;description=Give+your+Breadbox+instance+a+public+HTTPS+URL+so+MCP+clients+and+bank+webhooks+can+reach+it.\u0026amp;theme=3fb025393b2bbd4c898d29c3\u0026amp;signature=5c1e7ea085d65c3750775828e84fcb195c0443c599913919ad0c6c358617c554\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Make Breadbox reachable from the internet - Breadbox\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Give your Breadbox instance a public HTTPS URL so MCP clients and bank webhooks can reach it.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://breadbox.mintlify.app/_mintlify/api/og/v2?division=Overview\u0026amp;title=Make+Breadbox+reachable+from+the+internet\u0026amp;description=Give+your+Breadbox+instance+a+public+HTTPS+URL+so+MCP+clients+and+bank+webhooks+can+reach+it.\u0026amp;theme=3fb025393b2bbd4c898d29c3\u0026amp;signature=5c1e7ea085d65c3750775828e84fcb195c0443c599913919ad0c6c358617c554\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/breadbox/wfRExqoTacYaBhYJ/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Breadbox\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#16A34A\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.breadbox.sh/installation/remote-hosting\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/installation/remote-hosting.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.breadbox.sh/#organization\",\"name\":\"Breadbox\",\"url\":\"https://docs.breadbox.sh\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/breadbox/d0QBHUmdZVqbsv3S/images/fried-egg.svg?fit=max\u0026auto=format\u0026n=d0QBHUmdZVqbsv3S\u0026q=85\u0026s=f653995ffcf649db40c69ed2ecce3a8a\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.breadbox.sh#website\",\"name\":\"Breadbox\",\"url\":\"https://docs.breadbox.sh\",\"publisher\":{\"@id\":\"https://docs.breadbox.sh/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.breadbox.sh/installation/remote-hosting#webpage\",\"url\":\"https://docs.breadbox.sh/installation/remote-hosting\",\"name\":\"Make Breadbox reachable from the internet\",\"description\":\"Give your Breadbox instance a public HTTPS URL so MCP clients and bank webhooks can reach it.\",\"dateModified\":\"2026-06-02T17:44:38.000Z\",\"isPartOf\":{\"@id\":\"https://docs.breadbox.sh#website\"},\"breadcrumb\":{\"@id\":\"https://docs.breadbox.sh/installation/remote-hosting#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.breadbox.sh/installation/remote-hosting#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Overview\",\"item\":\"https://docs.breadbox.sh/introduction\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Make Breadbox reachable from the internet\",\"item\":\"https://docs.breadbox.sh/installation/remote-hosting\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.breadbox.sh/installation/remote-hosting#article\",\"headline\":\"Make Breadbox reachable from the internet\",\"name\":\"Make Breadbox reachable from the internet\",\"description\":\"Give your Breadbox instance a public HTTPS URL so MCP clients and bank webhooks can reach it.\",\"url\":\"https://docs.breadbox.sh/installation/remote-hosting\",\"mainEntityOfPage\":{\"@id\":\"https://docs.breadbox.sh/installation/remote-hosting#webpage\"},\"dateModified\":\"2026-06-02T17:44:38.000Z\",\"publisher\":{\"@id\":\"https://docs.breadbox.sh/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.breadbox.sh#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Breadbox\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Breadbox","nav":{"global":null,"tabs":[{"tab":"Docs","icon":"book-open","pages":[{"group":"Overview","icon":"sparkles","pages":[{"title":"What is Breadbox?","href":"/introduction"},{"title":"Install Breadbox","description":"The recommended one-liner installs Breadbox on macOS or Linux; alternate paths (Docker Compose, binary, go install, from source) are available for specialist needs.","sidebarTitle":"Install","href":"/installation"},{"title":"Make Breadbox reachable from the internet","sidebarTitle":"Remote hosting","href":"/installation/remote-hosting"},{"title":"Updating Breadbox","description":"Breadbox tells you when a new release ships and lets you update on your schedule. Updating is two commands, your data and secrets are untouched, and database migrations run automatically on the next start.","sidebarTitle":"Updating","href":"/installation/updating"},{"title":"Onboard your Breadbox instance","sidebarTitle":"Onboarding","href":"/quickstart"}]},{"group":"Bank Connections","icon":"landmark","pages":[{"title":"Connect your bank accounts","href":"/connections/overview"},{"group":"Providers","icon":"plug","expanded":true,"pages":[{"title":"Connect banks with Teller","sidebarTitle":"Teller","href":"/connections/teller"},{"title":"Connect banks with Plaid","sidebarTitle":"Plaid","href":"/connections/plaid"},{"title":"Import transactions from CSV","sidebarTitle":"CSV import","href":"/connections/csv-import"}]}]},{"group":"Transactions","icon":"receipt","pages":[{"title":"How Breadbox syncs, stores, and exposes transactions","sidebarTitle":"Overview","href":"/transactions/overview"},{"title":"Categories: the two-level classification hierarchy","sidebarTitle":"Categories","href":"/transactions/categories"},{"title":"Tags","href":"/transactions/tags"},{"title":"Rules: the substrate that turns provider data into intelligence","sidebarTitle":"Rules","href":"/transactions/rules"},{"title":"Counterparties: the canonical 'other side' of a charge","sidebarTitle":"Counterparties","href":"/transactions/counterparties"},{"title":"Review workflow","href":"/transactions/review-workflow"}]},{"group":"AI Integration","icon":"bot","pages":[{"title":"Give AI agents access to your finances with Breadbox MCP","sidebarTitle":"Overview","href":"/mcp/overview"},{"title":"Set up MCP for Claude and AI agents","href":"/mcp/setup"},{"title":"MCP tools for querying financial data","sidebarTitle":"Tools","href":"/mcp/tools"},{"title":"Scheduled agents","href":"/guides/scheduled-agents"}]},{"group":"Configuration","icon":"settings","pages":[{"title":"Configure Breadbox with environment variables","sidebarTitle":"Environment","href":"/configuration/environment"},{"title":"App config and precedence","sidebarTitle":"App config","href":"/configuration/app-config"},{"title":"Create and manage API keys","href":"/configuration/api-keys"},{"title":"Back up and restore your Breadbox data","sidebarTitle":"Backup \u0026 restore","href":"/configuration/backup"}]}]},{"tab":"Reference","icon":"code","pages":[{"title":"Reference","href":"/api/overview"}]},{"tab":"CLI","icon":"terminal","pages":[{"title":"CLI","href":"/cli/overview"}]},{"tab":"Guides","icon":"map","pages":[{"title":"Guides","href":"/guides/overview"}]},{"tab":"Changelog","icon":"history","pages":[{"title":"Changelog","href":"/changelog"}]}]},"title":"Make Breadbox reachable from the internet - Breadbox","buildId":"dpl_2xiSHD9XEvLsPGPcfoMtkLTB3dy9","deploymentId":"dpl_2xiSHD9XEvLsPGPcfoMtkLTB3dy9","dynamics":["10e4515597"],"chunks":["BannerMarkdown-B-Glu166.js","dist-zbf22OZA.js","lib-DuNMoZ05.js","lib-B8HbPgcC.js","clsx-Cs6nMGht.js","html-void-elements-mCSPHezU.js","katex-YMM-FMeD.js","marked.esm-CZWythHk.js"]}