What you are looking at
One box for the server and one for every node. A line between two boxes is a real connection: blue is the link a node already holds to the server, and green is a tunnel riding over that link. A line turns red when it cannot work right now — usually because a machine it passes through is offline.
Ports
Every circle is a port. Hollow means nothing is plugged into it; filled means it is carrying something. Each one is labelled in or out, except the uplink jacks, which are the node's link to the server. A node keeps its ports on the side facing the server, and they swap sides if you drag it past it.
Rolled up, a box shows a single dark port instead — everything it carries meets there. The server keeps one at each end, since it has nodes on both sides of it.
Finding something to tunnel
Press NET on a node to slide out the network that node can see. Click a host to reveal its open ports. If nothing has been scanned yet, use the Discover tab on the right to scan that node's network first.
Building a tunnel
Drag a discovered port onto the server. That parks it as an input: the traffic can now reach the collective over the node's existing link, so no port is opened and none is asked for. The input shows an out port marked not connected underneath it.
Drag that out port onto whichever machine you want the port to appear on, and choose the port number there. That machine can be the server itself or any node. The machine now shows an in port for it, named by the port it opened.
Changing and removing
Drag a port that already has a cable on it onto a different machine to move that tunnel there. Drop it on empty space instead and it is removed — you are asked first. Clicking a cable removes it too. Removing an input removes everything it feeds; removing one delivery leaves the input parked, ready to be sent somewhere else.
Bending a line out of the way
Drag any cable and it drops a pin where you took hold of it. Move the pin and the line runs straight through it — a pinned cable is routed by hand, so it is drawn as straight runs rather than a curve, while its two ends still curve away from their ports. A pin dropped near a port lines itself up with it, so the run into that port comes in level; otherwise it takes the grid. Drag the same cable again for a second pin, and so on. Double-click a pin to take it out. Pins snap to the grid when grid is on, and are kept and restored with the rest of the layout.
Getting around
Drag the background to pan, scroll to zoom, drag a title bar to move a box, and click a title bar to roll it up or open it again. Shift-drag on the background draws a box round several nodes and any pins among them; everything caught lights up, and dragging any one of them moves the whole group.
The buttons, top right
−, the percentage, and + zoom out, reset to 100%, and zoom in. ⤢ frames everything on screen. save keeps this layout — where each box sits, which are rolled up, and the zoom — and restore puts it back; the map restores it by itself whenever you open this view. reset lays everything out fresh without touching what you saved. grid makes boxes snap to a grid as you move them.
Scored so the worst comes first: one machine offline is 5 points; a whole site offline (every machine behind one internet address — a power cut or a dead line) is 10 per machine; a watched laptop on battery is 15 (30 when low). 30+ is critical, 15+ high, 5+ warning. Site and power problems also raise an alert — see Settings.
| Node | Status | Communication | Interval | Version | Desktop | GUI | Network | VPN | Local IP | Agent up | Last seen |
|---|
| Network lock on for every node until somebody turns it off · while it is on, nothing here can change this machine's route |
|
| Heartbeat interval (seconds) | |
| Random 2–30s | |
| Reconnect interval (s) 0 = stay continuously connected | |
| Auto-update | |
| Temperature interval (s) how often CPU/GPU temperature is read · 0 = off | |
| GUI / system tray run the desktop tray on this node · off when the server is unreachable |
Coming soon. A gateway turns a node into a doorway onto its network: point your browser or apps at the gateway and reach hosts behind it as if you were on-site, without setting up a tunnel per service.
When this feature ships, you will pick a node, choose what it may reach (whole subnet, or selected hosts), and get a single address to connect through — with access controlled per user.
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.
| Hostname | Certificate | Issued | Created |
|---|
Add one to give a service its own name and certificate — vpn, say, for the VPN to answer on.
Profiles
| Profile | Network | Clients here | May use | Clients |
|---|
Clients
| Name | Profile | Address | Enabled | Last seen — primary | Last seen — backup |
|---|
Xray — VLESS with REALITY
AmneziaWG
Obfuscation numbers
Profiles
| Profile | Network | Clients here | May use | Clients |
|---|
Clients
On the VPN applies to a node only, and it is the switch that re-routes everything that machine does. Test it first: the node brings the tunnel up, writes down the way back before it changes anything, and undoes all of it by itself unless this server confirms the link survived. If the way in it is using stops working it moves to the other one on its own; Retry starts again from the top.
| Name | Profile | Address | Enabled | On the VPN | Added |
|---|
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
Stop the mount with Ctrl+C (or fusermount -u on the folder).
Mounts
| Files from | Mounted on | State | Password |
|---|
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.
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.
| Name | Host | Method | Via node | Every | Status | Latency | Last online | Missed since | Group |
|---|
| Timestamp | Node | Action | Result |
|---|
| Username | Last login | From | Country | Signed in | Two-factor |
|---|
Change your password
Two-factor sign-in
1. Open the authenticator app and scan this code.
Can't scan? Enter the key by hand:
2. Type the six-digit code the app now shows, to prove it worked.
Require it for everyone
Add user
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.
| Platform | Arch | File | Version | glibc | Min distro | Size | Built | Checksum |
|---|
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.
…
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.
…
If the machine cannot reach this server at all — the installers handle a wrong DNS answer themselves, but only once they are running, and fetching one is itself a name lookup. This form carries the address () instead of asking the local resolver. TLS is unaffected: only the route is pinned, the certificate is still checked against the real name.
…
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.
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.
- 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.
- 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.
- Apps → Discover Apps → the three dots → Install via YAML. Give it a name.
- 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.
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.
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.
Accounts
| Account | In user groups | Sees |
|---|
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.
| Group | Nodes | Reached by |
|---|