Unified Tactical Mesh

Quickstart

Zero-to-mesh in about ten minutes. Assumes you have a Linux machine with a reachable IP (the coordinator) and at least one device (Linux, Windows, macOS, iOS, or Android) that will join as a peer.


1. Install the coordinator

On your chosen Linux host, extract and run the installer:

tar -xzf UTM-v0.15.1-coord-linux.tar.gz
cd UTM-coordinator-linux-amd64/
sudo ./install.sh

The installer:

  • Detects any missing prerequisites (wireguard-tools, nftables, iproute2, libwebkit2gtk-4.1-0) and offers to install them via apt / dnf / pacman / zypper.
  • Installs binaries to /usr/local/bin/ (utm-coordinator, utmctl, utm-admin).
  • Installs the UTM Admin launcher into your application menu.
  • Creates /etc/utm/coordinator.env with a fresh admin token and internal token.
  • Registers + starts the utm-coordinator systemd service.
  • Opens the admin UI in its own native window, already signed in.

You shouldn’t need to touch the terminal for anything beyond this step.


2. Day-one admin flow (in the UI)

The app window pops up on the Peers page. A first-run wizard walks you through what you’re looking at and suggests your next step.

Add your first peer

  1. Click Add peer (top right).
  2. Enter a name (e.g. alice-laptop), pick a role (default user), click Create.
  3. The enrollment modal offers two paths:

Option A — Linux device, full feature set (observability, auto-failover, direct peer-to-peer):

Copy the printed one-liner and run it on the peer machine. For persistent install:

tar -xzf UTM-v0.15.1-agent-linux.tar.gz
cd UTM-agent-linux-amd64/
sudo ./install.sh    # prompts for URL + token, then installs as a systemd service

Option B — any OS with stock WireGuard (Windows, macOS, iOS, Android):

Click Generate WireGuard config in the modal, then either:

  • Download .conf → import into WireGuard on a desktop, or
  • Show QR → scan with WireGuard mobile.

Windows with UTM’s native agent (full features):

Unzip UTM-v0.15.1-agent-windows.zip on the Windows machine, right-click install.bat → Run as administrator. Prompts for URL + token, installs to C:\Program Files\UTM\, registers the UTMAgent Windows service.


3. Verify the tunnel

On the peer machine:

# Linux
ip -4 addr show wg0         # your overlay IP, e.g. 10.77.0.2
ping 10.77.0.1              # should reach the coordinator

# Windows (PowerShell)
Get-NetIPAddress -InterfaceAlias wg0
Test-Connection 10.77.0.1

Back in the admin UI, the Peers page shows the peer as Online with a recent handshake. Click the row for endpoint, bytes, and the peer’s self-reported view of its own WireGuard state.


4. Control who can reach what (ACL rules)

By default, the mesh is open — every peer can reach every other peer. Add at least one ACL rule and the mesh switches to default-deny: only the role-to-role pairs you explicitly allow can talk. Peer↔coordinator traffic always works either way.

Click ACL Rules in the sidebar. The matrix has rows = sources, columns = destinations. Click a cell to toggle. Rules are role-level, so toggling user → operator affects every current and future peer in those roles.

Quick starting points (preset buttons in the UI):

  • Mesh-wide — everyone talks to everyone.
  • Isolate by role — peers only reach others of the same role.
  • Admin-privileged — admins reach everyone; others don’t reach each other.

Reply traffic for established flows is automatically allowed (conntrack), so a single one-way rule gives you a working bidirectional conversation.


5. Everything else lives in the UI

  • Settings — change public endpoint, rotate admin token, restart the coord, view the update status.
  • Logs — live journalctl stream for the coordinator, with pause / download.
  • Cluster — each coordinator’s status (primary, replicas, heartbeats).
  • Peers → click a row — per-peer drilldown (traffic, endpoint, agent report).

6. Keeping up to date (v0.13+)

UTM can self-update from a manifest URL that you control.

On your build machine, for each release:

./build-dist.sh                                           # produces tarballs
./tools/publish-manifest.sh v0.16.0 https://dl.example.com/utm

Upload these four files to whatever HTTPS endpoint you control (S3, your own nginx, wherever):

manifest.json
UTM-v0.16.0-coord-linux.tar.gz
UTM-v0.16.0-agent-linux.tar.gz
UTM-v0.16.0-agent-windows.zip

On each coordinator, set the manifest URL once:

  • Settings page → Update manifest URL → paste https://dl.example.com/utm/manifest.jsonSave URL.
  • Or set UTM_UPDATE_MANIFEST_URL= in /etc/utm/coordinator.env and restart.

From then on:

  1. Coord checks the manifest every 6 hours (and on-demand via Check now).
  2. When a newer version is detected, the Settings page shows an Update available: v0.16.0 banner.
  3. Click Install update → coord downloads, verifies SHA-256, runs the new version’s install.sh --upgrade (which installs any new system packages listed in the manifest), swaps binaries atomically, restarts via systemd.
  4. The UI freezes for ~5 seconds while the service restarts, then reconnects automatically.
  5. Agents notice the coord’s new version on their next /config poll and self-update by fetching the binary from the coord, atomic-renaming, and re-exec-ing in place — TUN device + enrollment state survive the swap, no re-enrollment.

Rollback is one click: Settings → Rollback to v0.15.1. The previous binary is retained as /usr/local/bin/utm-coordinator.prev for 24h after an update.


7. Optional: admin from the CLI

The web UI is the primary surface, but utmctl works equally well for scripts and CI:

export UTM_URL=http://localhost:8080
export UTM_ADMIN_TOKEN=$(sudo awk -F= '/UTM_ADMIN_TOKEN/ {print $2}' /etc/utm/coordinator.env)

utmctl list                              # show all peers
utmctl add-peer bob --role operator      # flags before the name!
utmctl rule-add --from user --to operator
utmctl remove alice-laptop
utmctl --version

Troubleshooting

Permission denied reading admin-token / coordinator.env Those files are root-owned (0600). Use sudo cat / sudo grep.

Agent says “no reachable coordinator”

  • Check the coord is running: Settings page → Service, or sudo systemctl status utm-coordinator.
  • Firewall allows inbound on the coord’s UDP port (default 51820) and API port (default 8080).
  • The enrollment URL must be the coord’s address as reachable from the peer, not localhost if the peer is remote.

“tunnel up” logs but ping fails

  • Same-machine testing with multiple WG interfaces hits routing weirdness. Run in a netns or on a different host.
  • ACL rules: the mesh is open by default, but if you’ve added even one rule the matrix flips to default-deny. Check ACL Rules — pinging the coord (10.77.0.1) always works regardless; pinging another peer needs a matching role-to-role rule when the matrix is in default-deny mode.

Windows “wintun.dll failed to load” wintun.dll must live next to agent.exe. The installer handles this — don’t move files out of C:\Program Files\UTM\.

Update check shows “Check failed” Open Settings → Updates — the error message shows what went wrong (manifest URL unreachable, invalid JSON, TLS error, etc.). Common cause: HTTP instead of HTTPS, or a URL that’s only reachable from outside your network.

The update installed but the coordinator didn’t come back Reconnect via terminal and swap the binary back manually:

sudo mv /usr/local/bin/utm-coordinator.prev /usr/local/bin/utm-coordinator
sudo systemctl restart utm-coordinator

Then check journalctl -u utm-coordinator -n 100 for the underlying error.


What’s next

  • Scale to multiple coordinators for HA — see the main README’s Cluster section.
  • Use utmctl in scripts / CI if you’re automating enrollment at scale.
  • Front the admin UI with a reverse proxy for HTTPS in production deployments.

Happy meshing.