✦ Private libp2p tunnels · HTTP + raw TCP/TLS · No cloud proxy required

Expose local HTTP APIs
and raw TCP/TLS services

Tubo publishes local services into a private libp2p swarm and lets authorized clients reach them from anywhere — even behind NAT — with end-to-end encryption, invite-based access, and secret-backed namespace discovery for collaborative scopes.

Latest release: v0.12.1. Changelog now includes the latest connect health and manual grant approval fixes.

Get started See quickstart View on GitHub
$ curl -fsSL https://www.tubo.click/install.sh | sh
Architecture

How Tubo works

A minimal set of roles connect over an encrypted libp2p swarm. No central server sees your traffic — streams are end-to-end encrypted and routed peer-to-peer.

flowchart LR Client(["🖥️ Client\nHTTP or TCP"]) Connect["tubo connect"] Relay(["tubo relay\nbootstrap · circuit v2"]) Attach["tubo attach"] Origin(["⚙️ Origin Service\nHTTP or TCP/TLS"]) Client -- "HTTP or TCP" --> Connect Connect -- "libp2p stream\n🔒 encrypted" --> Attach Attach -- "HTTP or raw TCP" --> Origin Connect -. "NAT traversal\nfallback" .-> Relay Relay -. "NAT traversal\nfallback" .-> Attach style Connect fill:#2563eb,color:#fff,stroke:#1d4ed8 style Attach fill:#2563eb,color:#fff,stroke:#1d4ed8 style Relay fill:#7c3aed,color:#fff,stroke:#6d28d9 style Client fill:#0f172a,color:#e2e8f0,stroke:#334155 style Origin fill:#059669,color:#fff,stroke:#047857
1

Start a relay

A public relay node bootstraps the swarm and assists with NAT traversal via libp2p circuit v2. One relay handles many service/client pairs.

2

Attach your service

Run tubo attach next to any HTTP API or raw TCP/TLS service. It joins the swarm, publishes signed service metadata, and starts serving libp2p streams.

3

Connect from anywhere

Run tubo connect on any machine. It redeems an invite or uses namespace discovery, opens a tunnel, and exposes a local HTTP or TCP endpoint immediately.

4

Traffic flows P2P

libp2p dials directly when possible; falls back to relay-assisted circuit automatically. No port forwarding. No cloud proxy in the data path.

Features

Everything you need, nothing you don't

Tubo is small, self-hosted, and built on open standards.

🔒

End-to-end encrypted

All traffic travels over libp2p Noise-encrypted streams. No relay or gateway sees plaintext data — only the origin service and the authorized client do.

🌐

Works behind NAT

Uses libp2p circuit relay v2 and hole punching to traverse NAT and firewalls. No inbound ports required on service hosts.

🔑

Secret-backed namespace discovery

Collaborative namespaces use Discovery V3 topics derived from namespace secret material. Overlay reachability alone does not grant service visibility.

🏗️

Private swarm (PSK)

Generate a swarm key with tubo keygen swarm and share it among your nodes for a fully isolated private network.

🎟️

Invite-based and team-based access

Use one-time share invites for direct access or cluster invites for collaborative namespaces with member/viewer roles and scoped connect permissions.

🗂️

Clusters & namespaces

Organise services into clusters and namespaces. Discovery, access control, and grants are all scoped — no cross-namespace leakage.

HTTP and raw TCP/TLS

Publish classic HTTP APIs or raw tcp://... targets. TLS passthrough works end-to-end because Tubo can expose a local raw TCP listener instead of forcing HTTP bridging.

🔄

Managed namespace secret rotation

Rotate namespace discovery entries with a current/previous grace model using tubo rotate secret/namespace-discovery/... and inspect metadata with tubo get secrets.

🤖

AI & LLM ready

Expose LM Studio, Ollama, or any OpenAI-compatible API to collaborators. Streams and WebSocket upgrades work transparently.

Quickstart

Up and running in minutes

Three commands on two machines and you have a working encrypted tunnel.

# — Machine A: publish your local service —
$ tubo join                     # join the public Tubo network
$ tubo attach http://127.0.0.1:8080 --name myapi -d

 Service published   name=myapi  visibility=unlisted
 Share token         tubo connect --token eyJ...

# — Machine B: connect with the token —
$ tubo connect --token eyJ... --local 127.0.0.1:9000

 Tunnel ready        http://127.0.0.1:9000  →  myapi

$ curl http://127.0.0.1:9000/healthz
OK
# — Relay host (public IP): start the relay —
$ tubo keygen swarm --out swarm.key   # generate once, share to all nodes
$ tubo relay --swarm-key ./swarm.key --public-addr /ip4/1.2.3.4/tcp/4001 -d

# — Service host: join and publish —
$ tubo join overlay/manual \
    --relay /ip4/1.2.3.4/tcp/4001/p2p/12D3... \
    --swarm-key ./swarm.key
$ tubo create cluster/myteam
$ tubo create namespace/team
$ tubo attach http://127.0.0.1:8080 --name myapi -d
$ tubo share cluster/myteam --namespace team --role member

# — Client host: join, discover, and connect —
$ tubo join cluster/myteam --token <invite>
$ tubo get services
  NAME    SERVICE ID   CONNECT POLICY
  myapi   service-...  namespace_members
$ tubo connect myapi --local 127.0.0.1:9000
# — On the machine running LM Studio (port 1234) —
$ tubo attach http://127.0.0.1:1234 --name lmstudio -d

 Service published   name=lmstudio
 Share token         tubo connect --token eyJ...

# — On the client machine —
$ tubo connect --token eyJ... --local 127.0.0.1:51234 -d

# Use the OpenAI-compatible endpoint as if it were local
$ curl http://127.0.0.1:51234/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{"model":"local-model","messages":[{"role":"user","content":"Hello"}]}'

# Works with Ollama too
$ tubo attach http://127.0.0.1:11434 --name ollama -d

# And raw TLS/TCP passthrough is first-class too
$ tubo attach tcp://127.0.0.1:8443 --name tlsdemo -d

Want the full picture? Read the Getting Started guide →

Use cases

What people build with Tubo

🤖

Share local AI models

Run LM Studio or Ollama on your workstation and give teammates a working API endpoint — no cloud GPU required, and no central proxy in the data path.

LM StudioOllamaOpenAI API
🔧

Webhook development

Receive webhooks from Stripe, GitHub, or any SaaS directly to your local dev server without ngrok or open firewall rules.

WebhooksDevLocal
🏠

Self-hosted API access

Expose a Home Assistant, Nextcloud, or Gitea instance to trusted users without touching your router.

Self-hostedHome network
🧪

Remote staging environments

Share a local staging build with a remote reviewer via a one-time signed token. No deployment needed.

StagingPreviewTokens
🏢

Private team APIs

Run a cluster with secret-backed namespace discovery. Services are only visible to members carrying the right namespace discovery entry and connect permissions.

ClustersNamespacesTeam
🔬

Edge & IoT services

Publish sensor APIs or edge compute endpoints from devices behind carrier-grade NAT — no static IPs needed.

IoTEdgeNAT
Comparison

Tubo vs alternatives

See how Tubo compares to similar tunneling and overlay tools.

Capability Tubo ngrok Tailscale Cloudflare Tunnel
Self-hostable Fully ~ Partial ~ Headscale
No cloud proxy in data path
P2P NAT traversal libp2p WireGuard
Signed discovery Ed25519
Invite-only / token access ~ ~
HTTP API tunneling ~
Private swarm (PSK)
Open source

See full comparison →

Documentation

Explore the docs

Everything from a 5-minute quickstart to the full security model.