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 viaapt/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.envwith a fresh admin token and internal token. - Registers + starts the
utm-coordinatorsystemd 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
- Click Add peer (top right).
- Enter a name (e.g.
alice-laptop), pick a role (defaultuser), click Create. - 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.json→ Save URL. - Or set
UTM_UPDATE_MANIFEST_URL=in/etc/utm/coordinator.envand restart.
From then on:
- Coord checks the manifest every 6 hours (and on-demand via Check now).
- When a newer version is detected, the Settings page shows an Update available: v0.16.0 banner.
- 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. - The UI freezes for ~5 seconds while the service restarts, then reconnects automatically.
- Agents notice the coord’s new version on their next
/configpoll 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
localhostif 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
utmctlin scripts / CI if you’re automating enrollment at scale. - Front the admin UI with a reverse proxy for HTTPS in production deployments.
Happy meshing.