Start here
Turning on federation
This is the whole path from a running Nova operator to a donor storing your data. Eight steps, about fifteen minutes.
Every knob you could set is in
docs/reference/operator-configuration.md.
This page has only what you need.
Before you start
- Nova is already running (you followed the quickstart).
- Your host has
/dev/net/tun. Most Linux servers do. Check:sh ls -l /dev/net/tunExpected:crw-rw-rw- 1 root root 10, 200 ... /dev/net/tunIf it fails: runsudo modprobe tun, then check again. - You know your server's public IP, and UDP port 4242 can reach it.
- You picked a private network range for the overlay. Use
10.42.0.0/24unless it clashes with something you already run.
Throughout, replace nova.example.org with your hostname and 203.0.113.7
with your server's public IP.
1. Create the federation identity
docker compose --env-file docker/.env \
-f docker/docker-compose.yml \
-f deploy/operator/compose.federation.yaml \
--profile federation run --rm nova-admin \
federation init \
--overlay-cidr 10.42.0.0/24 \
--operator-overlay-ip 10.42.0.1 \
--lighthouse-public 203.0.113.7:4242 \
--hostname nova.example.org
Expected:
federation ready at /var/lib/nova/fedpki/active
created: 12
adopted: 0
existing: 0
listen_addr: 10.42.0.1:9443
ca: sha256:118fe2a4...
lighthouse: 203.0.113.7:4242
If it fails on /dev/net/tun: see the prerequisite above.
If it fails on a route conflict: something already uses that range. Pick a
different --overlay-cidr.
This is safe to run twice. A second run changes nothing and says
created: 0.
Upgrading rather than starting fresh? If you built a federation CA by hand before Nova had
federation init, do not run the command above as written — it would mint a new CA and orphan your existing donors. Followdocs/UPGRADING.mdinstead, which adopts your existing authority.
2. Restart with federation enabled
docker compose --env-file docker/.env \
-f docker/docker-compose.yml \
-f deploy/operator/compose.federation.yaml \
--profile prod --profile federation up -d
Nova reads its configuration once at startup, so this restart is what picks up the federation settings step 1 wrote.
3. Wait for the overlay
docker compose logs -f coordinator
You are looking for, in order:
federation.listener.waiting iface=nebula1 listen=10.42.0.1:9443
federation listener bound listen=10.42.0.1:9443
The first line is normal — the overlay takes a few seconds to come up, and Nova waits for it rather than giving up. Your site keeps serving the whole time.
If you only ever see the first line: the overlay did not start. Check
docker compose logs nebula.
4. Check everything before inviting anyone
docker compose --env-file docker/.env \
-f docker/docker-compose.yml \
-f deploy/operator/compose.federation.yaml \
--profile federation run --rm nova-doctor \
federation doctor --live
Expected: every line starts ok.
ok [A] pki.parse all certificate/key pairs parse and match
ok [A] pki.sans coordinator certificate names the configured hostname and overlay IP
ok [A] pki.seed repair signing key parses
ok [A] pki.perms no key material is group- or world-readable
ok [A] cfg.manifest operator.yaml federation block agrees with the manifest
ok [A] swarm.key swarm key present and matches the manifest
ok [B] net.iface coordinator sees overlay interface nebula1
ok [B] net.bind federation listener bound overlay-only on 10.42.0.1:9443
ok [B] net.ready coordinator reports federation ready
ok [B] net.mtls mTLS handshake with 10.42.0.1:9443 succeeded
Each failure names what is wrong and where. Fix them before step 5 — an invite issued against a broken federation produces a bundle your donor cannot run, and they are the one who finds out.
5. Create an invite
One command produces everything your donor needs.
docker compose --env-file docker/.env \
-f docker/docker-compose.yml \
-f deploy/operator/compose.federation.yaml \
--profile federation run --rm nova-admin \
node invite \
--name alice-desktop \
--nebula-ip 10.42.0.10/24 \
--image ghcr.io/nova-archive/nova-node@sha256:<digest> \
--out /invites/alice-desktop
Give each donor their own --nebula-ip: .10, .11, .12, and so on.
Get <digest> from the release you want them to run — see
docs/UPGRADING.md. A version tag will be rejected: your
donor must run exactly the bytes you verified.
Expected:
invite for alice-desktop written to /invites/alice-desktop
node_id: 19e8f7b9-2ddc-4d12-8260-14dea6d39edf
fingerprint: sha256:70bcae01...
files: 11
6. Send it
The bundle is at deploy/operator/invites/alice-desktop/ on your server. Send
the whole directory — a zip over any channel you trust.
It contains your donor's own keys, so treat it as private. It contains none of your CA or coordinator keys; Nova refuses to write the bundle at all if any of them would end up inside.
Point your donor at the donor quickstart. They run
docker compose up -d in the folder, unchanged.
7. Confirm they arrived
docker compose exec coordinator novactl node list
Expected:
NODE_ID DISPLAY STATUS TRUST LAST_SEEN
19e8f7b9-2ddc-4d12-8260-14dea6d39edf alice-desktop active probationary 2026-08-09 12:04:11
probationary is normal for a new donor. Trust rises automatically as they
prove they are holding what they claim.
If nothing appears: the donor's node has not registered. Ask them for
docker compose logs nova-node.
8. Done
Nova starts placing data with them on its own. Nothing further is required.
Day-to-day
Add another donor: repeat steps 5 and 6 with a new --name and
--nebula-ip.
Someone wants to stop: drain first, so their data is copied elsewhere before they go.
docker compose exec coordinator novactl node drain --id <node-id>
Watch until their outstanding work reaches zero, then:
docker compose exec coordinator novactl node revoke --id <node-id>
Changed your mind: novactl node undrain --id <node-id>.
A donor's machine is compromised: revoke immediately, without draining. Their certificate stops working at their next request.
Rotate a donor's certificate:
docker compose exec coordinator novactl node rotate-cert --id <node-id> \
--dir /var/lib/nova/fedpki/active
The old certificate stops working straight away, so send the replacement before you run this.
The full decision guide is in
docs/runbooks/donor-lifecycle.md.
Back up your CA
If you lose the federation CA, every donor has to re-enroll from scratch.
docker run --rm -v nova_nova-fedpki:/pki:ro -v "$PWD":/out debian:bookworm-slim \
tar czf /out/nova-fedpki-backup.tar.gz -C /pki .
Store it somewhere encrypted and off this machine. Everything else Nova can rebuild; this it cannot.
Two kinds of identity
Nova uses two separate certificate authorities, and they are not interchangeable:
- Nebula decides who may join your private network.
- Nova federation decides who may talk to Nova's API.
A donor gets one of each. Neither CA key ever leaves your server — not in an invite, not in a backup you send anyone, not in a support bundle.