colibri/packaging/linux/README.md
Sam & Claude 968534d528
Some checks failed
CI / agent-jail-pkgs (pull_request) Has been cancelled
CI / rust (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
CI / port (pull_request) Has been cancelled
refactor: kill→stop across API surface, CLI, TUI, and docs
Clean sweep — no kill on the Colibri wire protocol, CLI surface,
TUI keybinding, or documentation. Backward-compat aliases removed;
daemon and client deploy together so no transitional period needed.

  Wire: KillAgent→StopAgent, "kill-agent"→"stop-agent" (no alias)
  CLI:  colibri kill→stop, Command::KillAgent→StopAgent
  Lib:  client.kill_agent()→stop_agent()
  TUI:  kill_selected()→stop_selected(), "kill"→"stop" label
  Docs: spawn/kill→spawn/stop, kill-agent→stop-agent (40+ instances)

  Retained kill only where it belongs:
  - child.kill() / handle.kill() (OS SIGKILL)
  - Unix kill(1) in sigterm tests
  - OOM kill, process-group kill comments (kernel mechanism)
2026-06-26 14:40:10 +02:00

96 lines
4.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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),
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`, `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.