# skyworks-Nix-infra

NixOS configurations for the two NixOS hosts. Flake-based (`flake.nix`)
with `disko` for disk layout, `agenix` for secrets, and `deploy-rs` for
push-based deploys from a workstation (the canonical workflow, magic-rollback
on). Hosts can also self-update with `git pull && nixos-rebuild switch` on the
box — handy when the workstation can't cross-build the target closure.

## Hosts

| Host | IP (mgmt) | Role |
|---|---|---|
| `xlab-gateway` | 10.253.254.1 | Lab gateway / WAN router. Bond + VLANs (lan254, wan99, mgmt) + WireGuard tunnels with policy routing, NAT/masquerade. Kea DHCP4/DDNS, IPv6 SLAAC, radvd, fail2ban. |
| `skydick` | 10.0.1.1 | Storage server. ZFS data pool with hot spares; Samba (LDAP-backed passdb) + NFS + iSCSI. Jumbo frames (MTU 9200) over bonded 2×40G ConnectX-3 (LACP 802.3ad, `bond40g`). |

## Layout

```
flake.nix              # entrypoint, defines both hosts + deploy-rs nodes
hosts/
  xlab-gateway/
    default.nix          # host config (boot, users, packages, smartd)
    networking.nix       # bond/VLAN/WG/nftables/services.resolved
    dhcp.nix             # Kea DHCP4/DDNS + IPv6 SLAAC advertisements
    disko.nix            # ZFS root layout
    hardware-configuration.nix
  skydick/
    default.nix          # host config + most networking inline
    datapool.nix         # ZFS pool layout, Samba + LDAP integration
    disko.nix            # boot disk layout
    samba-ldap-bootstrap.ldif
modules/
  common.nix             # locale, packages, sshd hardening defaults
  users.nix              # ldx user + ssh keys
  ssh.nix                # sshd hardening
  monitoring.nix         # node-exporter, smart, etc.
secrets/                 # agenix-encrypted (.age files)
```

## Deploy (the simple way, from the box)

```sh
ssh ldx@<host>
cd /etc/nixos && sudo git pull && sudo nixos-rebuild switch --flake /etc/nixos#<host>
```

## Deploy via deploy-rs (from a workstation)

```sh
# From an aarch64-darwin Mac (can't cross-build the x86_64-linux closure):
nix run github:serokell/deploy-rs -- --remote-build --skip-checks .#<host>
```

`--remote-build` builds on the target (its store is reachable as
`ssh-ng://ldx@<host>`); `--skip-checks` skips `nix flake check`, whose
x86_64-linux `deployChecks` can't be built on darwin. Magic-rollback is on, so a
bad activation auto-reverts. Note: deploy-rs activates a closure but does **not**
update `/etc/nixos` git on the host — use the on-the-box `git pull` flow if you
want the host's checkout to track `main`.

## Common gotchas

- **DNS**: MosDNS at `10.0.0.1` remains the first normal upstream. Do not use
  `FallbackDNS` as an availability mechanism: systemd-resolved ignores it
  while any global or per-link DNS server is configured, even if that server
  is unreachable. Xlab clients query the gateway-local stubs at
  `10.253.254.1` / `fd99:23eb:1682:1::1`. The only upstreams are the main
  MosDNS addresses `10.0.0.1` and `fd99:23eb:1682::1`; do not add a mainland
  resolver as a same-priority secondary because resolved load-balances global
  servers and can leak polluted foreign-domain answers to clients.

- **Skyworks WLAN authentication**: the C9800 live configuration is WPA3-SAE
  with PMF required. Keep OKC and band-select disabled on this FlexConnect
  WLAN: live traces showed SAE clients being rejected with an invalid PMKID
  after a 2.4/5 GHz reassociation. The WLC configuration is not currently
  declared in this repository, so preserve the controller backup and audit
  live state after upgrades.

- **Xlab WireGuard control**: networkd owns `wg-to-wgnet` and
  `wg-to-skyworks`, so do not use `wg-quick` to remove them. Use
  `sudo xlab-wg status all`, `sudo xlab-wg disable <wgnet|skyworks>`,
  `sudo xlab-wg enable <wgnet|skyworks>`, or
  `sudo xlab-wg restart <wgnet|skyworks>`. Disable state persists across the
  health timer and reboot until explicitly enabled.

- **Xlab campus admission**: WireGuard recovery starts only after the campus
  WAN is admitted. For unattended cold boots, register the server address as
  `open` with the unit network administrator or provision a dedicated Tunet
  credential through agenix. Never embed the account password in a Nix value
  or a systemd command line.

- **IPv6 RA**: `skydick` runs IPv6 *enabled* (SLAAC, stable token `::d1c0` on
  `bond40g`). RA-provided DNS is kept out of systemd-resolved with `UseDNS =
  false` in `ipv6AcceptRAConfig` — **not** by disabling IPv6. Pin the stable
  token address with `IPv6PrivacyExtensions = lib.mkForce false` (NixOS forces
  `"kernel"` otherwise) and `tempAddress = "disabled"`. Do not reintroduce
  `enableIPv6 = false` / `accept_ra = 0` on skydick.

- **deploy-rs ssh user**: defined as `ldx` with sudo escalation to root.
  Make sure the host key in `secrets.nix` matches reality after a reinstall
  (rekey all secrets if the host key changes).

## Remote

`gitbucket.skyw.top/Skyworks/skyworks-Nix-infra` is canonical. No GitHub
remote configured.
