nova

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_day governs the node's work overall.
  • egress_budget_bytes_per_day governs 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_fraction reserves a slice of the egress budget for possession-audit replies — small, frequent proofs that you still hold what you said. Defaults to 0.01. Setting it to 0 means 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.

Source: docs/reference/donor-configuration.md