Nodes

Needs attention

Offliners this week

Busiest CPU & GPU now · 24 h peak

Network traffic now · 24 h average

Slow responders round trip to the server

Uptime checks

Signed in

Tunnels

Pick a node with the switcher at the top.
Pick a node with the switcher at the top to reach it.

Names under this server's domain, each with its own Let's Encrypt certificate, renewed for as long as the name is here. Every name resolves already — a wildcard record points the whole domain at this server — so a certificate normally arrives within seconds of adding one.

…
HostnameCertificate IssuedCreated
A name is only a name here. Point one at something from the page that uses it — the VPN today. Pointing one at a port on a node, so a camera or a web page answers at its own address, is the next thing this grows into.
Primary…
Backup…
In use…

Profiles

ProfileNetwork Clients hereMay use Clients

Clients

NameProfile AddressEnabled Last seen — primary Last seen — backup

Xray — VLESS with REALITY

…
Every code you have handed out stops working the moment you do.

AmneziaWG

Obfuscation numbers

Profiles

ProfileNetwork Clients hereMay use Clients

Clients

NameProfile AddressEnabled On the VPN Added

Exit proxies

A proxy port on a node — SOCKS5 and HTTPS on the same port — whose traffic leaves the internet from its exit: unicomplex, or another node. unicomplex runs on AWS, which charges for traffic; a home or work node as the exit costs nothing. An exit node is reached directly where possible; when that cannot be set up the traffic goes through unicomplex to the same exit (the Last route column says which). If the exit is offline, connections fail — they never fall back to unicomplex.

NodePortOpen toExitLoginStatusLast route Today14 days
Pick a node with the switcher at the top to browse its files.

A mount makes a folder on a node appear as an ordinary folder on your own computer, so you can open its files in your editor and file browser. The node serves its files itself, and the node on your computer mounts them with rclone, which it fetches from this server into its own folder the first time; nothing is installed on either machine. Your computer must be a node too: that is where the connection comes out. Where folders land is set on the Settings page. Access is full (root). For one-off transfers, use Files.

New mount

Mounts

Files fromMounted onStatePassword

Each node has its own password, kept by this server. New password changes it for every mount of that node: folders already mounted stay mounted, but the next connection needs the new command.

A mount looks after itself: if rclone stops, the folder disappears, or it stops answering (checked every 30 seconds), the node mounts it again. remount does the same on demand.

… Group:

Uptime checks run from a node against something on its network. Add one from the Map — pick a node, open its Ping tab. The reserved Excluded group keeps a host in the config but stops testing it.

NameHostMethodVia nodeEvery StatusLatencyLast onlineMissed sinceGroup

Claude Code running on your nodes. Click a session for everything known about it, and its last prompts.

NodeAccountNameStateRemote control

Sessions that have ended, from what the nodes reported. Only these records are kept here — never what was said in them. Open opens a terminal on your computer with Claude going on where the session left off.

AccountNameTitleLast active

Claude's login belongs to an account on a node, and every session that account runs shares it. Claude renews its short-lived token by itself; the login itself must be done again (/login in Claude) before the date shown.

NodeAccountPlanLog in again by

Every tunnel, by the machine it comes out at. Click a tunnel for its details.

TunnelStatusCreated

A start point is where a tunnel begins: a node, and the host and port it reaches from its own network. One start point can come out at many endpoints. While any tunnel uses a start point it cannot be changed or deleted. These are also the inputs parked on the Map's server box.

NameNodeReachesTunnels
… · connections, policy changes, and remote actions across all nodes
TimestampNodeActionResult
UsernameRoleModulesLast seenFrom CountrySigned inTwo-factor
Click a row to manage that account. Sessions are cookies the server does not keep a list of, so Signed in means the account has used the panel in the last few minutes.

Require two-factor for everyone

With this on, an account that has not set one up is made to during its next sign-in — the password alone gets it no further than the QR code, and no session is opened until a code from the new phone is accepted. Sessions already open are asked the same thing before they can do anything else. Turning it on applies to you too.

Account

Now

Modules

Log

Lines in the server log that name this account — what it did, and what was done to it. The log keeps the most recent events only.
WhenAboutWhat

Every platform this server can enroll, and what is built for each right now. A name listed but not built would 404 if an installer asked for it — which is why the missing ones are still shown rather than quietly left out.

PlatformArchFileVersionglibcMin distroSizeBuiltChecksum

Download pinned certificate (unicomplex-cert.der)

Run this on any Linux machine to enroll it as a node (detects arch, installs a root systemd service):

…

The x86_64 build carries the system tray, so it links GTK at load time, and on a headless x86_64 box with no GTK it will not start. The installer handles that itself — before installing anything it runs the client once, and if it will not start it falls back to node-docker-x86_64, the same node built static with the tray compiled out, and says so while it does it. Nothing to pick: the command above is the right one on a desktop and on a headless server alike.

Debug install — writes a log file (for when an install succeeds but the node then won't run)

Same install, with the node's log turned on → /var/log/interlink-node.log. Read it with journalctl -u interlink-node.

…

For a Linux machine where you have an ordinary account but no root. Run it as that account — no sudo anywhere. It installs into ~/.local/um and the node runs as that account.

…

Short form, for typing by hand — and for a network whose firewall re-signs HTTPS (curl says self signed certificate in certificate chain). It saves that firewall's certificate for this account's curl, then runs the same install:

…

Starting at boot. Nobody needs to be logged in: the installer adds two lines to the account's own crontab — at boot, and every 5 minutes — that run ~/.local/um/run.sh. Only one copy ever runs, and it restarts the node whenever it stops. Logs go to ~/.local/um/node.log. A machine with no cron gets a systemd user service instead, which only starts at boot if someone with root has run loginctl enable-linger <account> once; the installer says when that is missing.

Works: tunnels and forwards on ports 1024 and up, hole-punched direct links, the shell and native terminal, file manager and SFTP (all as that account), uptime checks, network scans, updates and uninstall from this panel, folder mounts if the machine has fuse3.
Not available: acting as a VPN exit or putting the machine on the VPN, ports below 1024, other accounts' files, and remote desktop.

From PowerShell — run it as Administrator to install for the whole machine and start at boot; run it as yourself to install for your account and start at logon:

…

From cmd.exe — cmd cannot run a script straight off a pipe, so this fetches one with the curl Windows ships with, runs it and deletes it. This one is cmd syntax: in PowerShell && is not a separator and curl means Invoke-WebRequest, so it will not run there.

…
Debug install — writes a log file (for when an install succeeds but the node then won't run)

Same install, with the node's log turned on → node.log in the install dir. Read it with Get-Content …\node.log -Tail 40.

…

Coming soon. macOS enrollment will work the same way as Linux: one command that fetches the client, installs it as a launchd service, and brings the machine into the collective at next login.

No macOS client built yet.

Apple silicon cannot be cross-compiled from this project's build host — the SDK is Apple's to hand out, not ours to ship — so the binary has to be built on a Mac and dropped in. The download name is reserved either way, and the Overview tab shows it as not built rather than pretending the platform is unsupported.
curl -fsSL "https://…/install.sh?token=…" | bash

The node, in a container — for a machine where installing a service is not wanted or not possible: a NAS with a read-only system partition, an immutable host, or a box that is only ever managed through its container manager.

This build is static: x86_64 musl, with the system tray compiled out. It links nothing at all, so it starts on any image — including one with no libraries. The ordinary x86_64 Linux build cannot, because the tray links GTK at load time.

On a headless machine you do not have to come here for it — the Linux installer falls back to this same binary by itself when the ordinary one will not start. This tab is for when you want it in a container.

How do you run containers on that machine?

TrueNAS SCALE

Nothing to build and nothing to download first. TrueNAS cannot build an image from its own web interface, so this YAML does not ask it to: it starts a stock Alpine container which fetches the node on first run and keeps it in the data directory, reusing it on every start after that.

Make the dataset first — before you deploy anything. It has to exist, and it has to be on one of your data pools. If the path in the YAML does not exist, Docker quietly creates it on the system filesystem instead, and TrueNAS mounts that noexec. Everything then looks like it worked — the app deploys, the node downloads — and it silently never starts, because a binary on a noexec filesystem cannot be run. The app flaps and ends up stopped, with nothing in any log to say why.

  1. Find your pool's real name. Storage — the name at the top of each pool. tank is only the usual example; yours is very likely called something else.
  2. Make the dataset. Datasets → Add Dataset, for example yourpool/apps/unimatrix. This is what keeps the node's identity — without it, it joins as a brand-new machine every redeploy.
  3. Apps → Discover Apps → the three dots → Install via YAML. Give it a name.
  4. Paste the YAML and deploy. Change the two lines marked CHANGE ME: the dataset path you just made, and the hostname you want in the roster.

Portainer, Synology, Unraid, or any YAML box

The same single paste as TrueNAS — only the menu differs. Portainer: Stacks → Add stack → Web editor. Synology: Container Manager → Project → Create. Unraid: Docker → Compose.

Make the data directory first, on real storage, and point the volume line at it. If the path does not exist Docker invents it somewhere of its own choosing — on a NAS that is often a system filesystem mounted noexec, where the node downloads perfectly and then cannot be started.

A shell on the machine

With a shell you can build a proper image, which is tidier than bootstrapping at start-up: the node is baked in, so a start needs nothing from the network and nothing is fetched twice.

Save this as Dockerfile — that is the whole recipe. It fetches the binary itself while building, so there is nothing to download first. Alpine rather than an empty image because two of the node's features want a userland: a remote shell spawns bash, and network discovery uses nmap when it is there. Nothing is needed for TLS — the certificate roots are compiled into the binary.

…

Then, in the same folder:

…

And run it with the compose file below.

copied ✓

Change your password

Changing a password does not sign anything out: a session already open stays open until it expires.

Two-factor sign-in

Works with Authy, Google Authenticator, Microsoft Authenticator, Aegis, 1Password — any app that scans a QR code and shows six-digit codes.

What you can use

File mounts

{node} becomes the name of the node the files come from, so seg-lab1's files land in /net/seg-lab1. Used for new mounts and for the commands on the File mounts page; a mount already running keeps its folder until you mount it again.

Alerts

A whole site going offline, or a watched laptop switching to battery, is written to the Log and shown as a desktop notification on the computers ticked here (Linux for now), when it starts and again when it is over.

API tokens

A token lets a script read the panel without signing in. Send it as a header: Authorization: Bearer umx_…. It sees only the machines its owner can see, and only the parts ticked here. The token is shown once, when it is made — copy it then.

NameTokenAccessOwnerCreatedExpiresLast used
What a token can reach

Ping — read: GET /api/pings — every check with its status.
Ping — read + write: also POST /api/pings, DELETE /api/pings/<name>, POST /api/pings/<name>/group.

Any token: GET /api/token — the token's own name, owner, access and expiry.

Nodes — read: GET /api/nodes — the roster with live stats (load, CPU %, memory, GPU % and VRAM, CPU/GPU temperatures, latency); GET /api/nodes/<id>/history?since=<unix>&until=<unix>&limit=<n> — heartbeat samples (the same figures; kept 30 days, up to 20000 per call); GET /api/nodes/<id>/presence — the hours each node was online.

Example: curl -H "Authorization: Bearer umx_…" https://unimatrix.sg/api/pings

Feature requests

An idea, or something you would like changed. Everyone signed in sees the list.

RequestByWhen

A user group is a set of people that reaches one or more node groups. Somebody in a user group sees and manages only the nodes inside the node groups it reaches — everything else is not merely hidden from the roster, it is refused if asked for directly.

Granting All grants every node, now and in future — that is the plain way to say "this person sees everything". Every node is in All whatever else it is filed under, so no machine is ever invisible for want of being filed.

An account in no user group is unrestricted and sees every node, which is what every account was before this page existed. Restricting somebody is a deliberate act, so nobody is shut out by surprise.

Anyone signed in can edit this page, including their own group. This decides what people see by default; it is not a wall.

Accounts

AccountIn user groupsSees

The groups nodes are arranged into — the same ones the node roster and the map use. Click a name to rename it. All is built in: every node is in it, nothing can be taken out of it, and it cannot be removed.

To put nodes in a group, tick them in the node roster and choose Move to group from Actions. Any number at once, and the ticks respect whatever you have filtered or searched for.

GroupNodes Reached by

Dark mode
Overrides your system theme for this browser.