Interconnect two networks opt-in · default off
You are a member of two Atlas networks that other people run — network A on 10.0.101.0/24 and network B on 10.0.9.0/24 — and you want host 10.0.101.2 in A to reach host 10.0.9.2 in B, with nothing changed on either of them. This guide builds that seam on one host. Read the concept page first if address maps are new; if both networks are yours, fold them into one instead.
atlasd instance per network, each admitted by that network's owner — running a build with interconnect support on both instances. The other members need nothing: any build that routes its own subnet works.1 — Plan the addresses
Pick, on each side, a free address inside that network's own subnet for every host you want visible from the other side. Each owner keeps its own address plan; you are only reserving addresses in it.
| Host | Real address | Seen in the other network as |
|---|---|---|
| A's host | 10.0.101.2 | 10.0.9.102 in B |
| B's host | 10.0.9.2 | 10.0.101.202 in A |
| Your daemon in A | 10.0.101.1 | not exported |
| Your daemon in B | 10.0.9.1 | not exported |
10.0.9.0/24, say — can still be joined, one host at a time: map each host to a free address on the other side. What config check refuses is mapping the overlapping subnet itself.2 — The A-side daemon
Add a loopback seam link and the B-side daemon as a peer on it. Its allowed_ips is B's real address space; the map says where B's host appears in A; export says which of A's hosts take part.
[[link]]
name = "seam"
type = "local" # loopback only
bind_device = "lo"
bind_address = "127.0.0.1"
listen_port = 51841
[[peer]] # the B-side daemon on this same host
public_key = "<net-b daemon public key>"
endpoint_per_link = { "seam" = "127.0.0.1:51831" }
allowed_ips = ["10.0.9.0/24"] # B's real address space
[peer.interconnect]
export = ["10.0.101.2/32"] # only this A host takes part
[[peer.interconnect.map]] # B's host, as A's members will see it
remote = "10.0.9.2/32"
local = "10.0.101.202/32"
3 — The B-side daemon
The mirror image, written from B's point of view:
/etc/atlas/net-b.toml (additions)[[link]]
name = "seam"
type = "local"
bind_device = "lo"
bind_address = "127.0.0.1"
listen_port = 51831
[[peer]] # the A-side daemon on this same host
public_key = "<net-a daemon public key>"
endpoint_per_link = { "seam" = "127.0.0.1:51841" }
allowed_ips = ["10.0.101.0/24"]
[peer.interconnect]
export = ["10.0.9.2/32"]
[[peer.interconnect.map]]
remote = "10.0.101.2/32"
local = "10.0.9.102/32"
Use endpoint_per_link for the seam peer, so it is reached only over the seam link. Members of each network keep whatever endpoints they had; a loopback-bound link simply never carries traffic to them.
4 — Check, then start
atlasd config check -c /etc/atlas/net-a.toml
atlasd config check -c /etc/atlas/net-b.toml
Config check refuses every unsound map with the entry named — an overlapping subnet, a local address outside the subnet or on a member, mismatched prefix lengths, a remote outside allowed_ips, a seam link off loopback. Restart both instances once both pass.
5 — Verify
From A's host, B's host is just another address in A's subnet:
ping 10.0.101.202 # on 10.0.101.2 — answered by 10.0.9.2 in network B
$ atlasd status
interconnect 3f1a..9c2e up out 916 pkt / 1.1M in 3092 pkt / 4.3M
10.0.101.202/32 here = 10.0.9.2/32 there
exports 10.0.101.2/32B's host sees every packet from A's host as coming from 10.0.9.102, and replies there. On the dashboard, the Mesh & Routes tab of each instance shows an Interconnect card, and Full Topology badges your host as a seam between the two instances. Neither instance's topology contains a single node of the other network.
6 — Who controls what
- Each side's export list is that side's decision. A host that A maps but B does not export is unreachable, and it cannot send into A either; the refusal is counted on the seam.
- Each owner can end it. Your daemons are ordinary members; when B's owner revokes your B-side daemon, traffic from A to B stops at once, with nothing to change in A.
- A second operator host configured the same way adds a parallel seam, not a loop. Traffic uses one seam; if that host goes down, the other carries it once the first host's adverts expire, within about 100 seconds.
Limits today
End-to-end payload encryption is opened and sealed again at the seam, IPv4 only, and ICMP error messages carry the untranslated header of the packet that caused them. The full list lives on Known limitations.