# Colibri bridge — Linux (systemd) Linux/systemd peer of `packaging/freebsd/colibri_bridge.in`. Exposes the colibri-daemon control-plane Unix socket as a TCP port **on the Tailscale interface only**, so other mesh hosts can drive the control plane. The FreeBSD bridge already runs on hermes (binds hermes's own tailnet address); this is the matching domedog side. The network gate (ufw) is **already applied on domedog** (see "domedog host facts"); the systemd unit here is the proposed service — review the open questions with hermes before `enable --now`. > Real `100.x` Tailscale addresses are never committed to git. Each host's > address is supplied at deploy time (`tailscale ip -4`) via > `/etc/colibri/bridge.env` — see `COLIBRI_BRIDGE_LISTEN_ADDR=TAILSCALE_IP_REQUIRED`. ## Files | File | Purpose | | ---------------------------- | ------------------------------------------------------------ | | `colibri-bridge.service` | systemd unit running socat (peer of the rc.d script) | | `colibri-bridge.env.example` | tunables — install to `/etc/colibri/bridge.env` | | `colibri-bridge.nft` | nftables ruleset **for hosts without ufw** (see facts below) | ## Install (one-time, as root) ```sh install -D -m 0644 packaging/linux/colibri-bridge.service \ /etc/systemd/system/colibri-bridge.service install -D -m 0644 packaging/linux/colibri-bridge.env.example \ /etc/colibri/bridge.env # then edit for this host # Firewall: scope port 9190 to tailscale0 (peer of the hermes pf rule). # domedog runs ufw (active, default-deny input) — the allow goes in ufw, and # ufw's default-deny already blocks 9190 on every other interface: ufw allow in on tailscale0 to any port 9190 proto tcp comment 'colibri-bridge' # On a host WITHOUT ufw / with a default-accept input, use the nft table instead: # install -D -m 0644 packaging/linux/colibri-bridge.nft /etc/colibri/colibri-bridge.nft # nft -f /etc/colibri/colibri-bridge.nft systemctl daemon-reload systemctl enable --now colibri-bridge.service systemctl status colibri-bridge.service ``` Quick check from another tailnet host: ```sh printf '{"cmd":"status"}\n' | nc -w2 "$(tailscale ip -4)" 9190 # run on/against this host ``` ## domedog host facts (verified 26.jun.2026) The networking reality this packaging assumes, recorded so the next person doesn't have to re-derive it: - **Tailnet IPv4:** each host has a distinct `100.x` address — get it with `tailscale ip -4` (not committed to git per policy). - **Init / service mgr:** systemd (Ubuntu 24.04). FreeBSD/hermes uses rc.d. - **Daemon user:** `clawdija` (hermes: `clawdie`). No dedicated `colibri` group exists on domedog; the bridge runs as the daemon's own user so it can reach the 0770 socket. - **Firewall:** **ufw active + enabled**, default **deny (incoming)** / allow (outgoing), backed by nftables, with fail2ban on top. Live packet counters confirm it's enforcing, not just configured. - **Currently-allowed inbound ports:** 22/tcp (ssh), 80/tcp, 443 (tcp+udp), 8433–8443/tcp, and now **9190/tcp scoped to `tailscale0`** (the bridge, added for this work). - **Port 8443 = CloudPanel** server control panel (nginx vhost `cloudpanel.conf`, run by the `clp` user from `/home/clp/services/nginx/`). Only 8443 actually listens; 8433–8442 are allowed but unused (range wider than needed). ⚠️ CloudPanel's admin login is exposed to **Anywhere** (public), not tailnet-scoped — the opposite posture from this bridge; flagged for the host-exposure review. ## Open questions for the hermes discussion 1. **The socket has no auth — the tailnet boundary is the auth.** With both hosts bridging the control plane, any tailnet peer that can reach either host can issue full control-plane commands (`spawn-agent`, `stop-agent`, `terminal-*`). Consider a Tailscale ACL scoping `:9190` to specific peers. 2. **Socket path parity.** Both sides assume `/run/colibri/colibri.sock` (FreeBSD: `/var/run/colibri/colibri.sock`). domedog's daemon must be started with a matching `COLIBRI_DAEMON_SOCKET`; the daemon's default is under `$XDG_DATA_HOME`, which the bridge can't see under `ProtectHome=yes`. 3. **CloudPanel public exposure** (8443) — decide whether to keep it public or move it behind the tailnet like the bridge. ## Notes - The FreeBSD `colibri_bridge.in` `health`/`status` block bug (scrambled function definitions) was **fixed and pushed** on the hermes side during this work. - `colibri-bridge.nft` is retained for hosts with a default-accept input chain; on a ufw host its `accept` is not reliable (ufw's `drop` is terminal across base chains) and its `drop` is redundant (ufw already default-denies). Kept as documentation of intent and for the no-ufw case.