Other
Donor configuration reference
Every field in node.yaml, what it does, and what happens if you change it.
Most of these are generated by novactl node invite and should not be edited —
they point at files inside the bundle. The table marks which are yours.
If you just want a node running, use the donor quickstart.
The three you choose
| Field | Required | Meaning |
|---|---|---|
storage_max_bytes |
no (default 0) | Maximum bytes of encrypted data this node will hold. 0 means no limit. A transfer that would exceed it is refused with out_of_space rather than silently overfilling your disk. |
bandwidth_budget_bytes_per_day |
yes | The authoritative daily traffic budget. Must be greater than zero — the node refuses to start otherwise. This is the umbrella budget every other traffic limit derives from. |
storage_dir |
yes | Where the node keeps its own state: registration, sync cursor, assignment set, transfer progress. Not where the stored data lives — that is in the Kubo sidecar's volume. Created if absent, and must be writable by the container user. |
How the traffic budgets relate
There are three, and they are not interchangeable:
bandwidth_budget_bytes_per_day ← required, the umbrella
│
└── egress_budget_bytes_per_day ← optional; INHERITS the umbrella when unset
│
└── audit_budget_fraction ← optional; a fraction of egress, default 0.01
bandwidth_budget_bytes_per_daygoverns the node's work overall.egress_budget_bytes_per_daygoverns serving reads specifically. Leave it unset and it takes the umbrella's value, so raising the umbrella raises this too. Set it only if you want read-serving capped separately.audit_budget_fractionreserves a slice of the egress budget for possession-audit replies — small, frequent proofs that you still hold what you said. Defaults to0.01. Setting it to0means you fail audits and lose reputation.
The generated node.yaml leaves the second and third commented out on
purpose. Pinning a literal equal to your umbrella would break the inheritance,
and a later change to the umbrella would silently not apply.
Generated: identity and trust
Do not edit these. They name files in your bundle.
| Field | Meaning |
|---|---|
coordinator_url |
Your operator's federation endpoint, on the overlay, port 9443. |
federation_ca_path |
The operator's federation CA certificate. Establishes that the coordinator you are talking to is really theirs. |
federation_cert_path |
Your node's federation certificate — your identity to the Nova API. |
federation_key_path |
The matching private key. Under /run/secrets. |
nebula_cert_path |
Your node's overlay-network certificate. |
nebula_key_path |
The matching private key. Under /run/secrets. |
swarm_key_path |
The shared private-swarm key. Everyone in the federation holds the same one; it is what keeps your storage off the public network. |
Two separate trust roots. The Nebula certificate authorizes membership of the network. The federation certificate authorizes talking to the API. They come from different CAs and cannot substitute for one another. Neither CA private key is ever in your bundle.
Generated: storage and serving
| Field | Meaning |
|---|---|
kubo_api_addr |
The storage sidecar's API, on loopback. This only resolves because your kubo and nova-node containers share a network namespace — see below. |
source_nebula_addr |
The address your operator uses to reach you for reads. Empty means you store but never serve. |
source_read_listen_addr |
The local address your read server binds. Deliberately distinct from source_nebula_addr: one is advertised, the other is bound. Required whenever source_nebula_addr is set. |
health_listen_addr |
Local health endpoint. Loopback only; defaults to 127.0.0.1:9100. |
Why loopback works across containers
kubo_api_addr is http://127.0.0.1:5001, which looks wrong for two separate
containers. It works because both kubo and nova-node run with
network_mode: "service:nebula" — they share one network namespace, so
loopback is genuinely shared.
If you split them into ordinary separate containers, that address becomes unreachable and nothing can be stored, with no obvious error. The generated compose is checked in CI to keep them together.
Generated: placement hints
| Field | Meaning |
|---|---|
failure_domain.provider |
Your hosting provider, e.g. hetzner. |
failure_domain.asn |
Your network's ASN. |
failure_domain.region |
Rough location, e.g. eu-central. |
These help your operator avoid putting every copy of something in one place. On your side they are informational — they only count once your operator verifies them, so filling them in optimistically achieves nothing.
Leaving them blank is fine. Filling them in honestly is better: it is how the federation avoids losing data when one provider has a bad day.
Ports
| Port | Purpose |
|---|---|
4242/udp |
Overlay network, outbound to your operator's lighthouse. |
9555/tcp |
Your read-source server. Reachable only over the overlay. |
Your node publishes nothing to the host. All traffic is mutually authenticated over the overlay.
Changing settings
Edit node.yaml, then:
docker compose up -d
Lowering storage_max_bytes below what you already hold is safe — your
operator's coordinator notices and moves the excess elsewhere. It does not
delete data that is still needed until a replacement copy exists.