Files
nixos/secrets/nebula/README.md
root 792217f640
buildbot/nix-eval Build done.
buildbot/nix-build gitea:greg/nixos#checks.x86_64-linux.nixos-exodus Build done.
buildbot/nix-build gitea:greg/nixos#checks.x86_64-linux.nixos-isaiah Build done.
buildbot/nix-build gitea:greg/nixos#checks.x86_64-linux.nixos-genesis Build done.
buildbot/nix-build gitea:greg/nixos#checks.x86_64-linux.nixos-linode Build done.
buildbot/nix-build gitea:greg/nixos#checks.x86_64-linux.nixos-jeremiah Build done.
buildbot/nix-build gitea:greg/nixos#checks.x86_64-linux.nixos-zeke Build done.
buildbot/nix-build gitea:greg/nixos#checks.x86_64-linux.nixos-hosea Build done.
buildbot/nix-build Build done.
feat: add Nebula mesh network overlay
Introduces a greg.nebula NixOS module and enables it across all managed
hosts for the nebula.thehellings.com overlay (CIDR: 10.157.0.0/16).

Architecture:
- linode: lighthouse + relay (public internet, UDP 4242)
- genesis: regular node + unsafe_routes router for 10.42.0.0/16 (home LAN)
- hosea, isaiah, jeremiah, zeke, exodus: regular nodes with unsafe_routes
  pointing to genesis to reach the home LAN

Changes:
- modules/nixos/nebula.nix: new greg.nebula module
  - isLighthouse / isRelay options
  - unsafeRoutes option (tun.unsafe_routes)
  - routesSubnet option: enables IP forwarding + nftables masquerade NAT
    on the gateway host (genesis) so Nebula peers reach 10.42.0.0/16
  - agenix secret reference per-host (secrets/nebula/<name>.key.age)
  - opens UDP/4242 in the firewall
- modules/nixos/default.nix: import nebula.nix
- hosts/unstable/linode/default.nix: greg.nebula.isLighthouse = true
- hosts/unstable/genesis/default.nix: greg.nebula.routesSubnet = "10.42.0.0/16"
- hosts/unstable/{hosea,isaiah,jeremiah,zeke,exodus}/default.nix:
  greg.nebula.enable = true with unsafeRoutes via genesis
- network.json: add nebulaIp field for each managed host
- secrets/secrets.nix: declare nebula/<host>.key.age entries
- secrets/nebula/README.md: full PKI bootstrap guide (CA, certs, agenix)
2026-03-28 23:24:52 -05:00

3.1 KiB

Nebula PKI Bootstrap Guide

This directory holds the Nebula CA certificate, host certificates, and agenix-encrypted private keys for the nebula.thehellings.com overlay network.

CIDR

10.157.0.0/16

Host IP Assignments

Host Nebula IP Role
linode 10.157.0.1 Lighthouse + relay
genesis 10.157.0.2 LAN router (unsafe)
hosea 10.157.0.3 Regular node
isaiah 10.157.0.4 Regular node
jeremiah 10.157.0.5 Regular node
zeke 10.157.0.6 Regular node
exodus 10.157.0.7 Regular node (laptop)

Step 1 — Install nebula-cert

nix shell nixpkgs#nebula

Step 2 — Create the CA

Run once; keep ca.key offline/safe (do NOT commit it):

nebula-cert ca -name "thehellings.com" -out-crt ca.crt -out-key ca.key

Commit ca.crt (public) to the repo at secrets/nebula/ca.crt. Store ca.key securely (password manager / offline).

Step 3 — Sign host certificates

For most hosts (no subnet routing):

nebula-cert sign -ca-crt ca.crt -ca-key ca.key \
  -name <hostname> \
  -ip <nebulaIp>/16 \
  -out-crt secrets/nebula/<hostname>.crt \
  -out-key secrets/nebula/<hostname>.key

For genesis (routes the home LAN 10.42.0.0/16), add -subnets:

nebula-cert sign -ca-crt ca.crt -ca-key ca.key \
  -name genesis \
  -ip 10.157.0.2/16 \
  -subnets '10.42.0.0/16' \
  -out-crt secrets/nebula/genesis.crt \
  -out-key secrets/nebula/genesis.key

Commit *.crt files (public) to the repo. Do NOT commit raw *.key files — encrypt them first (Step 4).

Step 4 — Encrypt private keys with agenix

From the repo root:

cd nixos
for host in linode genesis hosea isaiah jeremiah zeke exodus; do
  agenix -e secrets/nebula/${host}.key.age < secrets/nebula/${host}.key
  rm secrets/nebula/${host}.key   # remove plaintext key
done

The secrets/secrets.nix file already declares the .key.age recipients.

Step 5 — Configure linode's public DNS / firewall

  • Add a DNS A record: linode.nebula.thehellings.com → linode's public IP
  • Open UDP port 4242 in linode's firewall / Linode Cloud Firewall rules

Step 6 — Deploy

colmena apply --on linode   # lighthouse first
colmena apply               # rest of the fleet

Verifying

# From any host, ping another by Nebula IP
ping 10.157.0.2   # genesis

# From any host, reach home LAN via unsafe_routes
ping 10.42.1.1    # UDM Pro (via genesis)

Notes

  • ca.crt is public and lives in the repo unencrypted.
  • *.crt (host certs) are public and live in the repo unencrypted.
  • *.key.age are agenix-encrypted private keys (in secrets/nebula/).
  • The NixOS module (modules/nixos/nebula.nix) references these paths directly.
  • The lighthouse (linode) has isLighthouse = true and isRelay = true.
  • genesis has routesSubnet = "10.42.0.0/16" which enables IP forwarding and nftables masquerade so Nebula peers can reach the home LAN.
  • All other hosts have unsafeRoutes pointing to genesis (10.157.0.2) for the 10.42.0.0/16 subnet.