Skip to main content

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.

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: 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 developmentDevelopment with tunneling
Agent is reachable only on localhostAgent gets a public https:// URL
Webhook testing is awkward or impossibleExternal services call back into your local agent
Sharing requires a deployment stepAnyone with the URL can hit the agent directly
Iteration stays trapped in one machineDevelopment stays local while access becomes public
Production setup is overkill for quick feedbackPublic 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 to 127.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.
Trust model in one line: anyone with the public URL can call your agent. Treat the URL as a development secret, and use Bindu’s auth (Hydra, DID, x402) the same way you would in production if you’re testing auth-protected flows.

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 with launch=True in bindufy():
from bindu import bindufy

config = {
    "author": "your.email@example.com",
    "name": "my_agent",
    "description": "My development agent",
    "deployment": {"url": "http://localhost:3773", "expose": True},
    "skills": ["skills/question-answering"],
}

async def handler(message):
    return {"role": "assistant", "content": "Hello!"}

# Enable tunneling for local development
bindufy(config, handler, launch=True)
When the agent starts, the logs look like this:
INFO  bindu.penguin.bindufy   Tunnel enabled, creating public URL...
INFO  bindu.tunneling.manager Creating tunnel for localhost:3773 with subdomain 'abc12def3456'
INFO  bindu.tunneling.binary  Downloading FRP client binary for darwin_arm64...
INFO  bindu.tunneling.binary  ✅ FRP client binary downloaded to /Users/you/.bindu/frpc/frpc_darwin_arm64_v0.61.0
INFO  bindu.tunneling.tunnel  Starting FRP tunnel...
INFO  bindu.tunneling.tunnel  ✅ Tunnel established: https://abc12def3456.tunnel.getbindu.com
INFO  bindu.penguin.bindufy   ✅ Tunnel created: https://abc12def3456.tunnel.getbindu.com
🌐 Public URL: https://abc12def3456.tunnel.getbindu.com
The URL maps back to the local agent for as long as the process is alive.

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.
1

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.
2

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_SUBDOMAIN env var, the tunnel.subdomain config key, or by calling TunnelManager.create_tunnel(subdomain="my-agent").
On success, the server replies start proxy success and Bindu logs the public URL.
3

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 in bindu.tunneling.config controls every knob.
FieldTypeDefaultNotes
enabledboolFalseMaster switch. launch=True sets this to True.
server_addressstr142.132.241.44:7000FRP server host:port. Override for self-hosted FRP.
subdomainOptional[str]NoneCustom subdomain. Auto-generated if None.
tunnel_domainstrtunnel.getbindu.comBase domain the subdomain attaches to.
protocolstr"http"One of http, https, tcp. Passed straight to frpc.
use_tlsboolFalseTLS between frpc and the FRP server. The public URL is always https regardless — the server terminates TLS.
local_hoststr127.0.0.1Local interface to forward to.
local_portOptional[int]NoneSet automatically from your deployment.url.

Custom Subdomain

The default subdomain is random and changes every restart. To pin it, set TUNNEL_SUBDOMAIN:
export TUNNEL_SUBDOMAIN=my-agent-dev
uv run python my_agent.py
# → https://my-agent-dev.tunnel.getbindu.com
Or pass a tunnel block in your config:
config = {
    "author": "your.email@example.com",
    "name": "my_agent",
    "deployment": {"url": "http://localhost:3773", "expose": True},
    "skills": ["skills/question-answering"],
    "tunnel": {
        "enabled": True,
        "subdomain": "my-agent-dev",
        "protocol": "http",
    },
}

bindufy(config, handler, launch=True)
Custom subdomains are first-come, first-served on the shared tunnel.getbindu.com domain. If someone else already holds it, frpc will fail with a registration error and Bindu falls back to running local-only.

Environment Variables

Every TunnelConfig field has an env-var equivalent that create_tunnel_config_from_env() reads:
VariableMaps to
TUNNEL_ENABLEDenabled
TUNNEL_SERVER_ADDRESSserver_address
TUNNEL_SUBDOMAINsubdomain
TUNNEL_DOMAINtunnel_domain
TUNNEL_PROTOCOLprotocol
TUNNEL_USE_TLSuse_tls
TUNNEL_LOCAL_HOSTlocal_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:
from bindu.tunneling import TunnelManager

manager = TunnelManager()
did_subdomain = TunnelManager._generate_subdomain_from_did(
    "did:bindu:alice:my_agent:0001"
)
# → "bindu-alice-my-agent-0001"
public_url = manager.create_tunnel(local_port=3773, subdomain=did_subdomain)

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.
from bindu.tunneling import TunnelManager, TunnelConfig

# Expose any local HTTP service, not just a Bindu agent
with TunnelManager() as manager:
    public_url = manager.create_tunnel(
        local_port=3773,
        subdomain="my-test-run",
    )
    print(f"Hit me at: {public_url}")

    # ... run your test, send some traffic ...

# Tunnel is torn down here; frpc subprocess is terminated.
A more explicit config:
config = TunnelConfig(
    enabled=True,
    subdomain="webhook-staging",
    protocol="http",
    local_host="127.0.0.1",
)

with TunnelManager() as manager:
    url = manager.create_tunnel(local_port=8000, config=config)
    ...
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

# Terminal 1: Start agent with tunnel
uv run python my_agent.py

# Terminal 2: Test from anywhere
curl https://abc12def3456.tunnel.getbindu.com/.well-known/agent.json
curl https://abc12def3456.tunnel.getbindu.com/health

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.
# 1. Pin a subdomain so the upstream URL doesn't change every restart
export TUNNEL_SUBDOMAIN=alice-webhook-dev
uv run python my_agent.py
# → https://alice-webhook-dev.tunnel.getbindu.com

# 2. Register the URL with the upstream service
#    e.g. set the webhook URL in Stripe / GitHub / your provider to:
#    https://alice-webhook-dev.tunnel.getbindu.com/webhooks/incoming

# 3. Trigger an event upstream and watch your local logs.
#    Requests land on your handler exactly as if the agent were deployed.
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

Test your agent without deploying it. The agent runs on your machine, but the public URL makes it reachable for quick external checks.
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.
Share the public URL so someone else can hit the agent without you having to deploy it first. Combine with auth if the agent handles anything sensitive.
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.
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 relaytunnel.getbindu.com is 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 second bindufy(launch=True) in the same process and you’ll get a RuntimeError.
  • No persistence — when the agent stops, frpc is terminated and the URL stops resolving.

Troubleshooting

frpc couldn’t reach the FRP server within the default 30-second timeout. Check network egress first:
# DNS + reachability
ping tunnel.getbindu.com

# The FRP control channel uses TCP 7000 on 142.132.241.44
nc -vz 142.132.241.44 7000
Corporate firewalls often block arbitrary outbound TCP ports. Port 7000 is the one to allowlist.
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).
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.
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:
pkill -f "bindu-tunnel"

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 keep launch=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.
Sunflower LogoBindu tunneling makes a local agentreachable for development without pretending to be production, so testing can move faster without changing where you build.