Evaluate

Two machines, two links, twenty minutes.

There is no download button on this site, and an install one-liner would be fiction: Nexus Atlas is proprietary, licensed by subscription, and builds are issued to people we have spoken to. So this page answers the question that actually stops people short of the contact form — what am I signing up for, and can I even run it? Everything below is what happens once a build lands: what you supply, what the daemon needs from a host, the smallest configuration that does something real, and what we would like to see when you are done.

No public download · builds are issuedLinux x86-64 & ARM64
What you bring

Nothing you would have to order.

The entry bar is deliberately low, because an evaluation that needs a lab, a second site and a shipment of radios is an evaluation that never starts. The first run is meant to happen on hardware already on your desk.

Two Linux machines

Or one machine and a VM on it. They do not have to match — dissimilar is the entire point. A laptop and a single-board computer is a perfectly good pair, and so is a server and a virtual machine on the same server.

Two links, any kind

Anything that carries a UDP datagram. Ethernet beside Wi-Fi is enough. Two VLANs on one switch is enough. A tethered phone beside the office network is enough. Nothing in the first run needs a radio, a satellite terminal or a second site.

Root on both

The daemon creates a TUN device and pins each link’s socket to a named interface. Both are privileged operations. Run it as root for the evaluation; the reference systemd unit shows the hardened form for later.

About twenty minutes

Generate a keypair on each node, write seventeen lines of TOML on each side, prove the file loads, start the daemon, ping across the tunnel — then pull one of the two cables and watch nothing happen to the ping.

What the first run is for. It is not a benchmark and it will not tell you anything about your radios. It exists so that the second run — the one with the bearer you actually distrust — starts from a tunnel you have already seen work, on a config file you wrote yourself. That is rung two: the shipping binary on your own hardware, with a link broken on purpose.
Host requirements

What it needs to run.

Collected here for the first time, from the shipping source and the reference packaging rather than from a datasheet. Where a figure has not been measured, this table says so instead of guessing.

RequirementWhat it actually is
ArchitectureLinux on x86-64 or ARM64 — the two release targets are x86_64-unknown-linux-gnu and aarch64-unknown-linux-gnu, each built on its own native runner. There is no musl target today, which rules out Alpine and musl-only OpenWrt images.
DistributionA glibc userland with OpenSSL 3 present — stock on Debian 12, Ubuntu 22.04, RHEL 9, Rocky 9 and anything newer, and absent on Debian 11 and Ubuntu 20.04. Those four are what the reference packaging is written and tested against; the Ansible role refuses to run outside the Debian and Red Hat families rather than guessing.
KernelNo minimum version is documented, and there is nothing in the daemon that would create an interesting floor: no kernel module, no DKMS, no eBPF, no io_uring. It needs the TUN driver and ordinary socket options. The practical test is one line — if ls /dev/net/tun succeeds, the kernel side is finished.
PrivilegesTwo privileged operations: creating the TUN device (root, or CAP_NET_ADMIN) and pinning each link’s socket to its device with SO_BINDTODEVICE (root, or CAP_NET_RAW). Run it as root for an evaluation. The reference systemd unit is the hardened form for afterwards: a dedicated unprivileged user whose only capability is CAP_NET_ADMIN, everything else dropped from the bounding set, a default-deny syscall filter, and exactly three devices it may open.
PortsOne UDP port, which you choose — [interface] listen_port has no default, so the file has to name it. Every link binds that port unless the link overrides it with its own; two links that share a device and an address must differ, or the kernel load-balances the two sockets against each other. Validation catches that case by name.
InboundOne reachable UDP port between the pair is enough. The daemon only ever initiates towards a peer it has an endpoint for, so the reachable end can be either one and the other may sit behind NAT — it learns its peer’s address from the first packet that authenticates, and a persistent_keepalive keeps the mapping open. On a desk both ends have addresses and none of this arises. When neither end is reachable — carrier-grade NAT on both sides — that is the job of the opt-in traversal stack, not of this first run.
Anything else runningNothing. No controller, no orchestrator, no licence server, no phone-home, no database, no message bus. The dashboard and REST API are a separate process on TCP 9800, and the tunnel does not care whether you ever start it. systemd is optional too — the readiness, stopping and watchdog notifications become no-ops when there is no init socket to send them to, so the binary runs correctly in the foreground. That is how a first evaluation should start.
DiskThe binary, one config file, and logs with hard ceilings: the structured event journal is capped at 4 × 2 MiB per interface by default, and the crash spool at twenty reports or 8 MiB, oldest evicted. Nothing grows unbounded on a node you cannot reach.
CPU and memoryNo figure has been measured and published, so this table will not invent one. What is known is below.
On the resource question, plainly. There is no benchmarked CPU or RSS number for the daemon, and quoting one would be the sort of claim this site exists to avoid. Three things are true instead. The queues are bounded by construction — 32 packets per link — so the memory floor does not move with offered load, and the logs have hard ceilings rather than rotation policies. It has run on single-board ARM computers under real load: five of them relayed continuously for four days at HEMUS while the fleet carried MAVLink command-and-control and H.265 video, with an airborne node on the same fabric — which is a demonstration of the class of hardware it fits on, not a benchmark, and it is described that way on the evidence page. If you need a resource number for a procurement document, measure it during the evaluation on the hardware you will actually field. That number is worth more than ours, and we will publish it with your method beside it.
The minimum

Seventeen lines, and nothing left to remove.

The site has shown plenty of configuration and never the floor. Here it is: the smallest file that produces a real bonded tunnel between two peers over two links. Three tables, seventeen lines, and every key in it is one the config types carry no default for — delete a line and the daemon refuses to load. Everything else that makes this site interesting, strategies and classes and mesh and prediction, has a default, and the defaults are what run here. The full parameter surface is on operations.

/etc/atlas/config.toml — node A, two links, one peer
[interface]
name = "nexus0"
address = "10.0.100.1/24"       # this node, inside the tunnel
private_key = "…"              # from `atlasd keygen`
listen_port = 51820

[[link]]
name = "wired"
bind_device = "eth0"
bind_address = "192.168.1.10"

[[link]]
name = "wifi"
bind_device = "wlan0"
bind_address = "192.168.2.10"

[[peer]]
public_key = "…"               # node B's public key
endpoint = ["192.168.1.20:51820", "192.168.2.20:51820"]
allowed_ips = ["10.0.100.2/32"]

Node B runs the mirror image: its own private key, address = "10.0.100.2/24", allowed_ips = ["10.0.100.1/32"], and node A’s two addresses as its endpoints. Both peers must know each other — there is no discovery in a point-to-point config. And give each link its own bind_address rather than 0.0.0.0: device pinning is best-effort by design, so if the process cannot set it the daemon warns and carries on, and a distinct source address is what keeps the two sockets separate anyway.

Then four commands

The whole walkthrough
# 1 — identity, on each node. It prints the two lines ready to paste.
atlasd keygen

# 2 — prove the file loads, using the daemon's own pipeline minus the engine.
#     Exit 0 = provably loadable, warnings listed. Exit 1 = fatal.
atlasd config check -c /etc/atlas/config.toml

# 3 — start it. Root, because it creates the TUN device and pins the sockets.
sudo atlasd run -c /etc/atlas/config.toml

# 4 — watch, from a second terminal, then prove it end to end.
atlasd monitor -i nexus0 -r 500
ping 10.0.100.2
What to expect

Both daemons log handshake complete once the second one starts, and the ping runs. monitor is the terminal dashboard — per-link RTT, jitter, loss and each link’s live share, refreshed twice a second. It reads the same once-per-second JSON snapshot the browser dashboard and the REST API read, so nothing you see in one view can disagree with another. the whole CLI ↗

The moment

Now pull one of the two cables while the ping runs. That is the demonstration, and it takes ten seconds — the ping does not stop, because the other link was already carrying part of the stream and simply carries the rest. Everything else on this site is an elaboration of that one behaviour.

Afterwards

What we would want back.

Four things, and none of them are a testimonial. An evaluation is worth more to us as measurement than as endorsement — your numbers, from your links, on your hardware, are data we cannot generate ourselves.

Your tax

The bonding tax, measured on your CPU

The daemon continuously measures the latency its own pipeline adds and publishes the digest. The figure quoted across this site — p50 0.18 ms / p95 0.42 ms — is from our reference run, and it is a property of that machine and that traffic. Yours will differ. Send us the panel. Measured the ledger ↗

Your worst link

The decision log around the failure

Not the summary — the minutes either side of the moment your distrusted bearer degraded, with the costs the scheduler computed. If it made a decision you would not have made, that is the most useful message you can send us, and it is the one that changes code.

The validator

Everything config check told you

Which warnings should have been hard errors on your topology, which errors were unhelpfully worded, and — most valuable — anything the file got past the validator that then misbehaved at runtime. Every field-aware check in there exists because someone lost an evening to it once.

The gap

The thing that didn’t work at all

The bearer that would not present an IP interface, the radio we have no telemetry adapter for, the field you went looking for and did not find. The roadmap is mostly a list of these, and the ones that arrive from evaluations move first.

Before you start

What would waste the evaluation.

Stated up front, because a boundary discovered in week three costs more than one read in ten seconds. Being explicit here deflects some evaluations; the ones it saves are worth more.

Where it runs, exactly

  • Linux is the supported platform: x86-64 and ARM64. Android runs the same engine in evaluation builds; there is no Windows or macOS daemon.
  • The inner tunnel is IPv4. The underlay — link binds and peer endpoints — speaks IPv6, but IPv6 addressing inside the tunnel is still an open gap.
  • It carries IP: a Layer-3 tunnel, not an Ethernet bridge and not a Layer-2 fabric. If the requirement is transparent bridging, stop here.
  • One build across the fleet, by policy. There is no version negotiation on the wire, so mixed builds fail loudly rather than corrupting quietly — plan on updating both ends together.
  • Debian 11 and Ubuntu 20.04 are below the floor. Anything from Debian 12, Ubuntu 22.04 or RHEL 9 onwards is fine.

Off until you ask for it

  • Transport classes are opt-in: the qos block defaults to disabled, and with it off the data path is byte-identical to a build without them.
  • Mesh and its gossip control plane are opt-in and default to disabled. A point-to-point bond needs no control plane at all.
  • NAT traversal is opt-in and defaults to disabled — with it off, no netcheck task is spawned at all.
  • Prediction stays off until the link monitor is given a prediction source. Range knobs configured without one are inert, and the validator warns about that rather than leaving you to wonder.
  • Erasure coding is doubly gated: a global switch and a per-class policy. Neither one on its own does anything.
  • Redundancy is off in the sense that matters — one copy per packet by default. Mirroring costs bandwidth, so you turn it on deliberately.
If one of those is the thing you came to evaluate, say so before the build is issued — the config ships with it turned on and a note on what to watch, instead of a default file that produces a plain bonded tunnel and a puzzled afternoon. Tell us what you run
Request an evaluation

Bring the link you don’t trust.

There is no download button — evaluation builds are issued to people we have talked to. Tell us what you actually run, and the first conversation is about your bearers rather than our slides.