Files
tsunagi/dist/linux/README.md
T
UltradesuandClaude Opus 4.8 d1ab993dd2
Release / tsunagi-linux-aarch64 (push) Failing after 3m12s
Release / tsunagi-linux-x86_64 (push) Failing after 2m21s
Release / tsunagi-macos-aarch64 (push) Canceled after 0s
Release / tsunagi-windows-x86_64 (push) Canceled after 0s
Release / Publish release (push) Canceled after 0s
Add a tagged-release CI workflow and Linux/Windows packaging
Pushing a `v*` tag now builds the agent for every supported target and attaches
the archives to a GitHub release. Modelled on the furumi release workflow (a
build matrix, then a publish job that runs `gh release create`), adapted to this
project's two differences: it needs system integration (capabilities/polkit on
Linux, elevation+wintun on Windows, a root daemon on macOS), and its users run
varied distros, not just Ubuntu.

Linux is built as a fully **static musl** binary with cargo-zigbuild, so one
artifact runs on Arch, Alpine, NixOS and old-glibc systems alike, and can be
repackaged into whatever a distro prefers later. musl has no prebuilt
aws-lc-sys bindings, so the Linux jobs install cmake + libclang (bindgen) and
zig (the cross C compiler zigbuild drives). macOS (aarch64) and Windows (x86_64)
build natively; Linux covers x86_64 and aarch64.

Targets: x86_64/aarch64 linux-musl, aarch64 macOS, x86_64 Windows. Each archive
carries the binary, the top-level README, and the platform's install notes plus
integration files:
- dist/linux/: a static-friendly README, a systemd unit (runs as root, so no
  capability grant or polkit rule is needed; a commented non-root variant is
  included), and an install.sh that drops the binary and the unit or prints the
  setcap/polkit alternative.
- dist/windows/: install notes covering wintun.dll and Run-as-administrator.
- dist/macos/: the existing LaunchDaemon plist and notes, now also shipped in
  the archive.

Not exercised yet: the workflow only runs on a real tag push, and the
aws-lc-sys-under-musl build has not been run locally in this session (no zig
toolchain here). YAML and install.sh syntax are validated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-02 11:48:19 +01:00

2.1 KiB

Running tsunagi on Linux

This archive holds a static tsunagi binary (musl), so it runs on any distribution — Arch, Alpine, NixOS, old glibc systems — with no shared-library dependencies. Alongside it are a systemd unit and an installer.

Creating the TUN interface needs CAP_NET_ADMIN, and configuring systemd-resolved is decided by polkit (by user id, not capability). There are three ways to satisfy that; pick one.

Quick install — systemd service as root

sudo ./install.sh
sudo systemctl enable --now tsunagi

The service runs the agent as root, so the interface, low ports and the resolver all just work (root is not subject to polkit). Control it as root, so the client resolves the same state directory the daemon uses:

sudo tsunagi status
sudo tsunagi join <network-name> <tsn1…secret>

As your own user — one capability, no root at runtime

sudo install -m 0755 tsunagi /usr/local/bin/tsunagi
sudo setcap cap_net_admin,cap_net_bind_service+p /usr/local/bin/tsunagi
tsunagi up

Nothing is left behind and nothing runs as root. The capability is lost on every rebuild or copy of the binary, so re-run setcap after replacing it. For the local DNS resolver, run tsunagi dns once: it prints the exact polkit rule that lets your user configure systemd-resolved, ready to paste.

Without touching the OS

tsunagi up --no-tun

Tunnels form and handshake between agents, but no interface, address or route is created, so traffic never reaches the operating system. Needs no privileges.

What the agent installs

Everything is tagged to its own interface, computed from local state, and reversible — removed when a network leaves, broadcast is turned off, or the agent stops:

  • a TUN interface configured over netlink (addresses, MTU, up);
  • while broadcast is on, a 255.255.255.255 route through the interface and an inbound-UDP firewall allowance from the overlay range (iptables, tagged);
  • the systemd-resolved setting that sends the overlay zones' questions to the local resolver.

Nothing taken from a remote peer ever becomes a path, a command argument or an OS setting.