Files
tsunagi/dist/linux
UltradesuandClaude Opus 4.8 63178574ce
Release / tsunagi-linux-aarch64 (push) Successful in 2m39s
Release / tsunagi-linux-x86_64 (push) Successful in 2m32s
Release / tsunagi-macos-aarch64 (push) Canceled after 0s
Release / tsunagi-windows-x86_64 (push) Canceled after 0s
Release / Publish release (push) Canceled after 0s
Package as a dedicated tsunagi user; add Arch packages
Reworks the Linux packaging so the service runs as an unprivileged, dedicated
"tsunagi" user instead of root — the point of a native package is to set things
up properly for that OS's users — and adds Arch Linux packages beside the deb.
Both package families are built from the already-compiled static binary; nothing
is recompiled.

Service model (shared systemd unit, dist/linux/tsunagi.service):
- User=tsunagi with AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE, so
  it creates the TUN and binds low ports without root.
- StateDirectory/CacheDirectory/RuntimeDirectory give it /var/lib/tsunagi,
  /var/cache/tsunagi and /run/tsunagi, and the agent is pointed at them (and the
  socket at /run/tsunagi/agent.sock) through TSUNAGI_* env in the unit.
- The polkit rule now grants the resolve1 actions to the "tsunagi" group; the
  service user is in it, and admins can add themselves.

CLI: when no state dir is chosen, the control commands prefer the system
service's socket at /run/tsunagi/agent.sock when it exists, so `sudo tsunagi
status`/`join` reach the packaged daemon with no flags. A per-user agent (its
socket absent from /run) still uses its own.

Packaging:
- deb (build-deb.sh): postinst now creates the tsunagi system user+group; unit
  installed to /lib/systemd/system, binary to /usr/bin.
- Arch (new dist/arch/build-pkg.sh): a dependency-free .pkg.tar.zst assembled
  with bsdtar + zstd (no makepkg, no Arch host) — .PKGINFO, a .INSTALL scriptlet
  that creates the user and reloads systemd, and a gzipped .MTREE; unit to
  /usr/lib/systemd/system.
- The polkit rule moved to dist/linux (shared by deb, Arch and the tarball), and
  the tarball install.sh now creates the user and installs the unit + rule.
- Both release workflows build the deb and the Arch package on the two Linux
  matrix entries (deb_arch/pkg_arch), install libarchive-tools+zstd for it, and
  attach both to the release (Gitea API loop / gh).

Not exercised in this session: the .deb and .pkg.tar.zst build and install only
on Linux (no dpkg-deb/bsdtar+pacman locally); CLI build, clippy, fmt and tests
pass, and all shell/YAML is syntax-checked.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-02 13:46:27 +01:00
..

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, a polkit rule, and an installer.

Creating the TUN interface needs CAP_NET_ADMIN, and configuring systemd-resolved is decided by polkit. There are three ways to run it; pick one.

On Debian/Ubuntu and Arch, prefer the native package (.deb / .pkg.tar.zst) from the release — it does all of the below for you.

Quick install — systemd service as a dedicated user

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

The service runs as an unprivileged tsunagi user with just CAP_NET_ADMIN and CAP_NET_BIND_SERVICE (granted by systemd), not root. systemd creates its state (/var/lib/tsunagi), cache (/var/cache/tsunagi) and runtime (/run/tsunagi) directories, and the polkit rule lets it configure the resolver. Control it with sudo — the CLI finds the running service's socket at /run/tsunagi/agent.sock with no flags:

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

As your own user — one capability, no service

sudo install -m 0755 tsunagi /usr/local/bin/tsunagi
sudo setcap cap_net_admin,cap_net_bind_service+p /usr/local/bin/tsunagi
sudo usermod -aG tsunagi "$USER"   # so the resolver works; log in again after
tsunagi up

Nothing runs as root. The capability is lost on every rebuild or copy of the binary, so re-run setcap after replacing it. The agent uses your per-user state directory and socket, so plain tsunagi status (no sudo) reaches it.

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.