colibri/packaging/linux/README.md
Sam & Claude 2be8d4f72f
Some checks are pending
CI / rust (pull_request) Waiting to run
CI / markdown (pull_request) Waiting to run
CI / port (pull_request) Waiting to run
CI / agent-jail-pkgs (pull_request) Waiting to run
docs(packaging): scrub real Tailscale IPs from bridge files
Per the no-real-100.x-IPs-in-git policy: env.example now ships
COLIBRI_BRIDGE_LISTEN_ADDR=TAILSCALE_IP_REQUIRED (operator fills in via
tailscale ip -4 at deploy time), and the README uses placeholders/commands
instead of literal addresses for both domedog and hermes.
2026-06-26 01:22:10 +02:00

4.6 KiB
Raw Blame History

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)

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:

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), 84338443/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; 84338442 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, kill-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.