Local development is comfortable right up until something outside your machine needs to hit your agent. A webhook provider, a teammate, or a quick external test all run into the same wall:Documentation Index
Fetch the complete documentation index at: https://docs.getbindu.com/llms.txt
Use this file to discover all available pages before exploring further.
localhost does not exist anywhere except your own machine.
Why Tunneling Matters
Bindu ships a built-in FRP-based tunnel so a local agent can be reached from the public internet without a deploy step. The agent process stays on your machine; only the network path changes.| Local-only development | Development with tunneling |
|---|---|
Agent is reachable only on localhost | Agent gets a public https:// URL |
| Webhook testing is awkward or impossible | External services call back into your local agent |
| Sharing requires a deployment step | Anyone with the URL can hit the agent directly |
| Iteration stays trapped in one machine | Development stays local while access becomes public |
| Production setup is overkill for quick feedback | Public access is available for testing and demos |
Tunneling is for local development and testing only. Do not use it in production.
Production deployments should sit behind proper hosting, certificates, and auth — not
a shared FRP relay.
What A Reverse Tunnel Actually Does
If you’ve never used FRP or ngrok before, the trust model is the important part. A normal server listens for incoming connections. That doesn’t work from a laptop behind NAT or a corporate firewall: nothing on the public internet can route a packet to127.0.0.1.
A reverse tunnel flips the direction. Your agent opens an outbound connection to a public FRP server. That connection stays open. When a request hits the public URL, the FRP server pushes it down the already-open socket to your agent, which responds back through the same pipe.
Your laptop never accepts a new inbound connection. It only keeps one outbound TCP
connection open to the FRP server. That is why this works through NAT and most
corporate firewalls, and it is the reason the agent — not the user — is the side that
initiates the tunnel.
How Bindu Tunneling Works
Bindu uses FRP (Fast Reverse Proxy) to relay traffic between a public URL and your local agent.The first time you enable tunneling, Bindu downloads the official
frpc client binary
(currently v0.61.0) from the FRP GitHub releases and caches it under
~/.bindu/frpc/. Subsequent runs reuse the cached binary. If your OS or firewall
prompts about a new executable making outbound network connections, that is expected.The Public Address Model
Tunneling is enabled withlaunch=True in bindufy():
Local First
Your agent still runs locally on
localhost:3773. Nothing about the handler
changes.Public URL
A random 12-character subdomain is generated under
tunnel.getbindu.com — one
lowercase letter followed by 11 alphanumerics.Development Only
This is meant for testing, webhooks, and demos — not production traffic.
The Lifecycle: Start, Tunnel, Forward
Under the hood, tunneling moves through three practical stages.Start
bindufy() constructs a TunnelConfig(enabled=True), the binary is downloaded if
missing, and a TunnelManager spawns frpc as a subprocess that connects to the
Bindu FRP server.Tunnel
frpc registers a subdomain on the server. The subdomain is either:- Random (default) — 12 characters: 1 lowercase letter + 11 lowercase letters or
digits, e.g.
abc12def3456. - Custom — whatever you set via
TUNNEL_SUBDOMAINenv var, thetunnel.subdomainconfig key, or by callingTunnelManager.create_tunnel(subdomain="my-agent").
start proxy success and Bindu logs the public URL.Forward
For every public request,
frpc reads it off the already-open socket and forwards
it to 127.0.0.1:<your_port>. Responses go back the same way. The agent has no
idea it’s being tunneled — to the handler it looks like a normal local request.When the agent process exits, atexit terminates the frpc subprocess and the
public URL stops resolving.Configuration
TunnelConfig
The dataclass inbindu.tunneling.config controls every knob.
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | bool | False | Master switch. launch=True sets this to True. |
server_address | str | 142.132.241.44:7000 | FRP server host:port. Override for self-hosted FRP. |
subdomain | Optional[str] | None | Custom subdomain. Auto-generated if None. |
tunnel_domain | str | tunnel.getbindu.com | Base domain the subdomain attaches to. |
protocol | str | "http" | One of http, https, tcp. Passed straight to frpc. |
use_tls | bool | False | TLS between frpc and the FRP server. The public URL is always https regardless — the server terminates TLS. |
local_host | str | 127.0.0.1 | Local interface to forward to. |
local_port | Optional[int] | None | Set automatically from your deployment.url. |
Custom Subdomain
The default subdomain is random and changes every restart. To pin it, setTUNNEL_SUBDOMAIN:
Environment Variables
EveryTunnelConfig field has an env-var equivalent that
create_tunnel_config_from_env() reads:
| Variable | Maps to |
|---|---|
TUNNEL_ENABLED | enabled |
TUNNEL_SERVER_ADDRESS | server_address |
TUNNEL_SUBDOMAIN | subdomain |
TUNNEL_DOMAIN | tunnel_domain |
TUNNEL_PROTOCOL | protocol |
TUNNEL_USE_TLS | use_tls |
TUNNEL_LOCAL_HOST | local_host |
DID-Derived Subdomains
TunnelManager._generate_subdomain_from_did() converts an agent DID into a DNS-safe
label (strips did:, replaces colons with hyphens, lowercases, truncates to 63 chars).
It exists for future stable per-agent URLs, but the default create_tunnel() path uses
the random generator — wire it in yourself if you want DID-stable URLs today:
Programmatic Use
bindufy(..., launch=True) is the common path. For tests, scripts, or anything that
isn’t a full agent, TunnelManager can be used directly as a context manager — it
handles frpc cleanup on exit.
TunnelManager allows exactly one active tunnel per instance — calling
create_tunnel() twice raises RuntimeError. The process also registers an atexit
hook globally, so even hard exits clean up the frpc subprocess.
Local Testing Through The Tunnel
Basic Development Test
End-To-End Webhook Test
A common reason to tunnel: an external service (Stripe, GitHub, a partner agent) needs to POST into your local agent during development.The tunneled agent is still your local process. If
python my_agent.py stops, the
public URL keeps resolving for a moment but returns 404 — there’s nothing behind it.Use Cases
Local development
Local development
Test your agent without deploying it. The agent runs on your machine, but the public
URL makes it reachable for quick external checks.
Webhook testing
Webhook testing
Let an external service call back into your local agent during development. Pin a
custom subdomain so the upstream URL doesn’t change every restart.
Sharing work in progress
Sharing work in progress
Quick demos
Quick demos
Use the tunnel for demos where local iteration matters more than production
deployment. Combine with
expose: True in your deployment block so the agent card
advertises the public URL.Cross-machine A2A
Cross-machine A2A
Point another agent at your tunnel URL to test A2A flows (negotiation, task send)
end-to-end without standing up shared infrastructure.
Limits And Troubleshooting
Tunneling is intentionally narrow in scope. It solves development reachability, not production hosting.Current Limits
- Development only — not suitable for production traffic.
- Shared relay —
tunnel.getbindu.comis operated as a convenience, not as guaranteed infrastructure. No SLA. - Temporary URLs by default — the random 12-character subdomain changes every restart unless you pin one.
- One tunnel per
TunnelManager— start a secondbindufy(launch=True)in the same process and you’ll get aRuntimeError. - No persistence — when the agent stops,
frpcis terminated and the URL stops resolving.
Troubleshooting
Tunnel fails to start (timeout)
Tunnel fails to start (timeout)
frpc couldn’t reach the FRP server within the default 30-second timeout. Check
network egress first:Subdomain registration fails
Subdomain registration fails
If you pinned a subdomain via
TUNNEL_SUBDOMAIN and someone else already holds it,
frpc exits non-zero. Bindu logs the failure and continues local-only. Pick
something less generic (alice-agent-dev beats agent).Binary download fails
Binary download fails
On first run Bindu fetches
frpc_<os>_<arch> from the official FRP GitHub release.
If your platform isn’t in the release matrix, you’ll see a 404 from
bindu.tunneling.binary. Download frpc manually from
https://github.com/fatedier/frp/releases and drop it at
~/.bindu/frpc/frpc_<os>_<arch>_v0.61.0 with executable permissions.frpc subprocess survives after Ctrl+C
frpc subprocess survives after Ctrl+C
Bindu registers an
atexit hook to terminate frpc. If the parent dies in a way
that skips atexit (kill -9, OOM kill), the subprocess can linger. Kill it
manually:For Production
Do not use tunneling in production. Use proper hosting with your own certificates and ingress — Cloudflare, a managed load balancer, or whatever your platform offers — and keeplaunch=False in deployed environments.
Practical Boundaries
Good Fit
Tunneling is a good fit when you need quick public access to a local agent for
testing, demos, or webhook development.
Wrong Fit
It’s the wrong fit for production traffic, persistent public infrastructure, or
anything that depends on strong uptime guarantees.