Quickstart

Documents the atlasd v0.2 release lineView as Markdown

In about fifteen minutes you will have two Linux machines joined by one encrypted tunnel that rides two network paths at once — and you will unplug one of those paths mid-ping and watch nothing happen. That behavior is the product; everything else in this documentation is refinement.

What you need

  • Two Linux hosts that can reach each other over at least one IP network. Two networks (say, Ethernet and Wi-Fi, or two Ethernet segments) make the demonstration real — with one network you still get the tunnel, just nothing to fail over to.
  • The atlasd binary — from Downloads with an approved evaluation (verify it against the release signatures first), or built from source if your organisation has repository access: cargo build --release produces target/release/atlasd.
  • Root or CAP_NET_ADMIN on both hosts — the daemon creates a TUN device and programs routes. In production the systemd unit grants exactly that one capability to an unprivileged service user; see Deploying with systemd.
No access yet? The whole run below is reproducible the moment a request is approved — reviews typically complete within one business day. Reading on costs nothing: every step is shown with its real output. And if you'd rather see the failover on one laptop with zero extra hardware, the Docker quickstart runs the same demonstration in two containers.

1 — Generate the node identities

Each node's identity is a Curve25519 keypair. Generate one per host and keep the private key private — it never leaves the machine.

node-a and node-b
$ atlasd keygen
private key: 4Ai…kEY=        # goes into this node's config, mode 0600
public key:  9Xp…bQc=        # goes into the OTHER node's [[peer]] block

2 — Write the two configs

One file per daemon: /etc/atlas/config.toml in production, any path during a bench run. The two files mirror each other — each lists its own private key and the other node's public key. Adjust the underlay addresses (192.168.…) and device names (eth0, wlan0) to your bench.

node-a.toml
[interface]
name = "nexus0"                     # the TUN device this daemon owns
address = "10.0.100.1/24"           # this node's address inside the tunnel
private_key = "NODE_A_PRIVATE_KEY"  # from: atlasd keygen
listen_port = 51820

[[link]]
name = "wired"
bind_device = "eth0"
bind_address = "0.0.0.0"            # survives the device being re-addressed

[[link]]
name = "wireless"
bind_device = "wlan0"
bind_address = "0.0.0.0"

[[peer]]
public_key = "NODE_B_PUBLIC_KEY"
endpoint = ["192.168.1.2:51820", "192.168.2.2:51820"]  # one per link, in order
allowed_ips = ["10.0.100.2/32"]
persistent_keepalive = 25
node-b.toml
[interface]
name = "nexus0"
address = "10.0.100.2/24"
private_key = "NODE_B_PRIVATE_KEY"
listen_port = 51820

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

[[link]]
name = "wireless"
bind_device = "wlan0"
bind_address = "0.0.0.0"

[[peer]]
public_key = "NODE_A_PUBLIC_KEY"
endpoint = ["192.168.1.1:51820", "192.168.2.1:51820"]
allowed_ips = ["10.0.100.1/32"]
persistent_keepalive = 25

Everything not written here takes its default: probes every 250 ms per link, a link declared dead after 5 consecutive misses, a re-handshake every 120 seconds, and the lowest_delivery_time scheduler picking the best path per packet. The configuration reference documents every one of those knobs.

3 — Validate before you run

config check runs the daemon's exact load pipeline without starting anything. Exit 0 means loadable; exit 1 means the daemon would refuse to start, with each finding pointing at the offending key.

node-a
$ atlasd config check -c node-a.toml
node-a.toml is valid

4 — Start both daemons

node-a (mirror on node-b)
$ sudo atlasd run -c node-a.toml
…  handshake init from peer 1 processed, sending response
…  handshake complete with peer 1
…  all peer handshakes established

The Noise IK handshake (X25519, ChaCha20-Poly1305, BLAKE2s) completes per peer; from that moment every packet entering nexus0 leaves encrypted on whichever link the scheduler judges best, and probes are already measuring both paths.

5 — Verify the tunnel

node-a
$ ping -c 3 10.0.100.2
64 bytes from 10.0.100.2: icmp_seq=1 time=2.1 ms
$ atlasd status
nexus0  10.0.100.1/24  strategy lowest_delivery_time  2/2 links alive  1 peer established
$ atlasd stats -i nexus0 -f json-pretty | head
{ "interface": "nexus0", "links": [ { "name": "wired", "alive": true, "rtt_ms": 0.4, … } ] }

Three more windows into the same state, pick your favourite: atlasd monitor -i nexus0 is a live terminal dashboard; atlasd web -i nexus0 serves the browser dashboard and REST API on :9800; and the snapshot file /tmp/atlas/nexus0.json is rewritten every second for anything that wants to scrape it.

Start a continuous ping, then take the wired path down — unplug the cable, or:

node-a, two terminals
$ ping -i 0.2 10.0.100.2
64 bytes from 10.0.100.2: icmp_seq=38 time=1.9 ms
$ sudo ip link set eth0 down
64 bytes from 10.0.100.2: icmp_seq=39 time=4.6 ms   # now riding "wireless"
64 bytes from 10.0.100.2: icmp_seq=40 time=4.4 ms

The scheduler was shifting traffic toward the healthier link before the failure finished happening — reweighting is continuous, not a binary failover — and after five missed probes the dead link is formally removed. Bring eth0 back up and watch it rejoin the bond the same way: gradually, as its measurements recover. Your SSH session, your video stream, your ping never dropped.

Where to go next

  • Multi-link scheduling — the eight strategies, probes, and per-link tuning for asymmetric bearers (a 250 ms probe on 4G next to a 1000 ms probe on VSAT).
  • Mesh & multi-hop routing — three or more nodes, link-state routing, and relaying through your own fleet.
  • NAT traversal & relays — when the two machines are behind carrier NAT and can't address each other at all.
  • Deploying with systemd — turn the bench run into a hardened, watchdog-supervised service.
Esc
↑ ↓ navigateEnter — openEsc — close