Deployment

Deploy Tubo with Docker Compose for local testing or run it directly on VMs with systemd for production. The relay only needs one machine with a public IP and an open TCP port.

Docker Compose (local testing)

The repository ships with a docker-compose.yml that starts a relay, a gateway, and a demo service:

$ git clone https://github.com/origama/tubo.git
$ cd tubo
$ docker compose up -d --build

# Verify everything is healthy
$ curl http://127.0.0.1:8092/healthz  # relay
$ curl http://127.0.0.1:8443/healthz  # gateway
$ curl http://127.0.0.1:8444/services # admin API

# Run the end-to-end smoke test
$ ./tests/smoke-compose.sh

Multi-host production setup

A typical 3-machine production setup:

Relay host setup

# Install tubo
$ curl -fsSL https://www.tubo.click/install.sh | sh

# Generate swarm key (do this only once, store securely)
$ tubo keygen swarm --out /etc/tubo/swarm.key
$ chmod 600 /etc/tubo/swarm.key

# Start relay
$ tubo relay \
    --swarm-key   /etc/tubo/swarm.key \
    --public-addr /ip4/1.2.3.4/tcp/4001 \
    -d

# Note the printed multiaddr, e.g.:
  /ip4/1.2.3.4/tcp/4001/p2p/12D3KooWExample...

systemd unit (relay)

[Unit]
Description=Tubo relay
After=network-online.target
Wants=network-online.target

[Service]
ExecStart=/usr/local/bin/tubo relay \
  --swarm-key /etc/tubo/swarm.key \
  --public-addr /ip4/1.2.3.4/tcp/4001
Restart=on-failure
RestartSec=5s
User=tubo
ProtectSystem=strict
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Service host setup

# Copy swarm.key from relay host (use scp or your secrets manager)
$ scp relay-host:/etc/tubo/swarm.key ~/.config/tubo/swarm.key
$ chmod 600 ~/.config/tubo/swarm.key

# Join the private swarm
$ tubo join overlay/manual \
    --relay     /ip4/1.2.3.4/tcp/4001/p2p/12D3KooWExample... \
    --swarm-key ~/.config/tubo/swarm.key

# Publish a service
$ tubo attach http://127.0.0.1:8080 --name myapi -d

systemd unit (service)

[Unit]
Description=Tubo attach - myapi
After=network-online.target myapi.service
Wants=network-online.target

[Service]
ExecStart=/usr/local/bin/tubo attach http://127.0.0.1:8080 --name myapi
Restart=on-failure
RestartSec=10s
User=myapp
EnvironmentFile=/etc/tubo/env

[Install]
WantedBy=multi-user.target

/etc/tubo/env can contain LIBP2P_PRIVATE_NETWORK_KEY=/etc/tubo/swarm.key.

Firewall rules

Host Port Direction Purpose
Relaytcp/4001Inboundlibp2p bootstrap + circuit relay
Relaytcp/8092Inbound (optional)Health check endpoint
Service hostnoneOutbound onlyConnects outbound to relay
Client hostnoneOutbound onlyConnects outbound to relay

Health checks

$ curl http://RELAY_HOST:8092/healthz
{"status":"ok","peer_id":"12D3KooW..."}

$ tubo doctor          # local connectivity checks

Process supervisors

When -d is not enough — for example, when you need restart-on-failure across reboots — use the OS process supervisor directly. Tubo processes are plain executables with no daemon. See the Process Supervisors guide for systemd, launchd, and runit examples.

Next steps