Sign inSign up

calabinet/calabi

By calabinet

•Updated 2 days ago

Calabi client — public reverse tunnels + a private WireGuard mesh, via Calabi Cloud.

Image
Networking
Developer tools
0

2.7K

calabinet/calabi repository overview

⁠Docker Hub page — calabinet/calabi

⁠Short description

Calabi client — public reverse tunnels + a private WireGuard mesh, via Calabi Cloud.

⁠Overview

⁠Calabi (Client)

calabi is the client for Calabi Cloud — a reverse-tunneling service that gives a local service (on your laptop, a container, a Raspberry Pi, or a private LAN) a public HTTPS/TCP/UDP address, over a single outbound connection with no inbound ports to open.

This image is configured for Calabi Cloud: it authenticates with your API key and serves tunnels through the managed edge nodes.

The same client also joins your mesh: your devices, containers and LANs connected to each other over WireGuard — directly when they can, through a relay when they cannot — each at a private IP, with nothing exposed to the internet. Tunnels and the mesh run side by side in one client.

Without an account: run your own server — edge, coordinator and client are open source (Apache-2.0): https://github.com/calabinet/calabi⁠

⁠Quick start

  1. Create an API key in the console → https://console.calabi.net⁠
  2. Expose a local service (e.g. an app on port 8080):
docker run --rm -it \
  -e CALABI_API_KEY=tk_xxxxxxxx \
  --network host \
  calabinet/calabi:latest http 8080

--network host lets the client reach services on 127.0.0.1 (Linux). Swap http 8080 for tcp 5432, udp 51820, and so on.

⁠Run as a long-lived agent

The image's default command is daemon, which stays online as an agent: give it your API key and manage its tunnels from the console. Mount a volume so the agent keeps its device identity across restarts (otherwise it re-registers every time).

docker run -d --restart unless-stopped \
  -e CALABI_API_KEY=tk_xxxxxxxx \
  --network host \
  -v calabi-data:/home/calabi \
  calabinet/calabi:latest

⁠Mesh (private network)

Enable Mesh for your organization in the console, and this agent joins it with the same API key; there is no extra command. The container needs a few grants from the host to create the mesh interface:

docker run -d --restart unless-stopped \
  --user 0:0 \
  --cap-add=NET_ADMIN \
  --device=/dev/net/tun \
  --sysctl net.ipv4.ip_forward=1 \
  -e CALABI_API_KEY=tk_xxxxxxxx \
  -v calabi-data:/home/calabi \
  calabinet/calabi:latest
  • --cap-add=NET_ADMIN + --device=/dev/net/tun — to create and configure the mesh interface.
  • --user 0:0 — the mesh interface can only be configured as root (why⁠). The data stays in the same /home/calabi/.config/calabi as the plain agent above.
  • --sysctl net.ipv4.ip_forward=1 — only if this device shares subnet routes or is an exit device. It has to be set when the container starts.
  • -v calabi-data:/home/calabi — the same volume and path as the plain agent above, so it stays the same device when you turn the mesh on.

If your container panel has no fields for these options (they do not go in the "command" field), use this Compose file — on the command line (docker compose up -d) or in any panel that imports Compose:

services:
  calabi:
    image: calabinet/calabi:latest
    restart: unless-stopped
    user: "0:0"                              # --user 0:0
    cap_add: [NET_ADMIN]                     # --cap-add=NET_ADMIN
    devices: ["/dev/net/tun:/dev/net/tun"]   # --device=/dev/net/tun
    sysctls: ["net.ipv4.ip_forward=1"]       # --sysctl net.ipv4.ip_forward=1
    environment:
      CALABI_API_KEY: "tk_xxxxxxxx"
    volumes:
      - calabi-data:/home/calabi
    # optional — to reach the client's own local console, add to environment:
    #   CALABI_STATUS_ADDR: "0.0.0.0:7400"
    # then publish it to loopback:  ports: ["127.0.0.1:7400:7400"]
    # it will ask for an unlock secret; `docker compose logs calabi` prints it
volumes:
  calabi-data:

Other devices then reach this one at its private mesh IP. In the console's Mesh page you add and remove devices, edit access rules (ACLs), and set up subnet routes and exit devices.

Bridge networking works. With --network host, more connections go direct; set net.ipv4.ip_forward on the host then, instead of with --sysctl.

⁠Environment

VariablePurpose
CALABI_API_KEYYour platform API key (tk_…), from the console. Required.
CALABI_STATUS_ADDRBind address of the local web console (default 127.0.0.1:7400). Read the note below before changing it.
CALABI_STATUS_SECRETUnlock secret the console asks of anyone reaching it from another machine. Unset = one is generated on first start and printed in the container log. See the note below.
CALABI_DEBUG1 = verbose logging for troubleshooting.

The daemon stores its device identity, credentials, and state under $HOME (/home/calabi). Mount a volume there (as in the agent example above) so a restarted container stays the same device instead of re-registering.

⁠The :7400 console from outside the container

Set CALABI_STATUS_ADDR=0.0.0.0:7400 and publish the port to loopback (-p 127.0.0.1:7400:7400). Opening it from the host asks for an unlock secret (why⁠):

docker logs <container> 2>&1 | grep "unlock secret"
  • The secret is kept as console-secret in /home/calabi/.config/calabi; mount the volume, or it changes whenever the container is recreated. CALABI_STATUS_SECRET sets your own.
  • One unlock lasts 12 hours. Wrong answers are limited to 5 per address per 5 minutes.
  • The console is plain HTTP, and it can create and delete tunnels and export your config. Across a network you don't fully trust, reach it over an SSH tunnel or put an HTTPS proxy in front. Publishing on 0.0.0.0 exposes it on public interfaces too, and Docker's -p can bypass a host firewall.

Day to day, manage the agent from the cloud console.

⁠Questions

⁠Why does the mesh need --user 0:0?

The image runs as a non-root user, and Docker gives added capabilities no ambient rights to a non-root process, so bringing the interface up fails with EPERM. The image sets HOME=/home/calabi for every user, so root uses the same data directory.

⁠Why does the console ask the host for a secret?

The console answers freely only to a caller on the same machine. A request published with -p arrives from the Docker bridge, not from loopback, so the host counts as another machine.

⁠Tags

  • latest — most recent release
  • x.y.z — pinned version

Tag summary

Content type

Image

Digest

sha256:6626d4020…

Size

13.9 MB

Last updated

2 days ago

docker pull calabinet/calabi