Expand variables.nix: NFS shares, ports, image size, GC/rotation, Pi host
Check NixOS configurations / eval-hosts (push) Failing after 10m51s

Adds nested vars.nfsShares (subpath + mountpoint per dataset, previously
duplicated independently across server.nix's NFS exports, mount-data.nix's
client mounts, docker.nix's tmpfiles rules, traefik's log rotation path,
and hosts/server/host.nix's beszel config), vars.ports (every literal port
in modules/ and hosts/, kept as separate entries per service even where
numbers coincide so changing one can't silently change another), plus
vars.proxmoxImageSize, vars.nixCacheGcMaxAge, vars.traefikLogRotate, and
raspberryPiHost/raspiNfsPath/raspiMountpoint for the Pi's own NFS export.

Also fixes docker.nix/minimal.nix/gui.nix hardcoding the literal "nixos"
username instead of the existing vars.primaryUser, found during the sweep.

system.stateVersion is deliberately left untouched everywhere -- per
NixOS's own docs that value must stay fixed from first install, not
follow any shared variable.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01La55Nsss8jZ7ZuzUV9mfot
This commit is contained in:
2026-07-20 08:27:37 +10:00
co-authored by Claude Sonnet 5
parent 89308730ab
commit 87eb8f7c39
15 changed files with 159 additions and 49 deletions
+1 -1
View File
@@ -46,7 +46,7 @@ nix eval --json .#nixosConfigurations --apply builtins.attrNames | jq -r '.[]'
| Path | Purpose |
| --- | --- |
| `flake.nix` | Flake inputs, the `mkTarget` platform × build-type generator, and `nixosConfigurations` outputs |
| `variables.nix` | Single source of truth for shared values (LAN domain/CIDR, hostnames, timezone, primary username, storage root, ...) — passed to every module and Home Manager config as the `vars` argument via `specialArgs`/`extraSpecialArgs` |
| `variables.nix` | Single source of truth for shared values (LAN domain/CIDR, hostnames, timezone, primary username, storage root, NFS share subpaths/mountpoints, service ports, ...) — passed to every module and Home Manager config as the `vars` argument via `specialArgs`/`extraSpecialArgs` |
| `hosts/<name>/host.nix` | Per-machine identity: hostname, hostId, per-machine secrets, `system.stateVersion` |
| `hosts/nixos/home.nix` | Workstation-specific Home Manager config (used by the `gui` build type) |
| `modules/platforms/` | Platform-specific config: virtualisation guest tools, boot method, hardware config (`linode.nix`, `proxmox.nix`, `lxc.nix`) |
+4 -4
View File
@@ -31,7 +31,7 @@
[Desktop Entry]
Type=Application
Name=Proxmox (Chromium)
Exec=chromium --app=https://pve.${vars.homeDomain}:${toString vars.pveWebPort} --window-size=1920,1080 --window-position=0,0
Exec=chromium --app=https://pve.${vars.homeDomain}:${toString vars.ports.pveWeb} --window-size=1920,1080 --window-position=0,0
Icon=${config.home.homeDirectory}/.local/share/icons/proxmox.png
Terminal=false
Categories=Hypervisor;
@@ -41,7 +41,7 @@
[Desktop Entry]
Type=Application
Name=Proxmox Backup Server (Chromium)
Exec=chromium --app=https://${vars.pbsIp}:${toString vars.pbsWebPort} --window-size=1920,1080 --window-position=0,0
Exec=chromium --app=https://${vars.pbsIp}:${toString vars.ports.pbsWeb} --window-size=1920,1080 --window-position=0,0
Icon=${config.home.homeDirectory}/.local/share/icons/proxmox.png
Terminal=false
Categories=backup;
@@ -51,7 +51,7 @@
[Desktop Entry]
Type=Application
Name=Proxmox (Firefox)
Exec=firefox --new-instance https://pve.${vars.homeDomain}:${toString vars.pveWebPort} --profile ProxmoxWebApp --window-size=1920,1080 --class ProxmoxWebApp
Exec=firefox --new-instance https://pve.${vars.homeDomain}:${toString vars.ports.pveWeb} --profile ProxmoxWebApp --window-size=1920,1080 --class ProxmoxWebApp
Icon=${config.home.homeDirectory}/.local/share/icons/proxmox.png
Terminal=false
Categories=Hypervisor;
@@ -61,7 +61,7 @@
[Desktop Entry]
Type=Application
Name=Proxmox Backup Server (Firefox)
Exec=firefox --new-window https://${vars.pbsIp}:${toString vars.pbsWebPort} --profile PbsWebApp --window-size=1920,1080 --class PbsWebApp
Exec=firefox --new-window https://${vars.pbsIp}:${toString vars.ports.pbsWeb} --profile PbsWebApp --window-size=1920,1080 --class PbsWebApp
Icon=${config.home.homeDirectory}/.local/share/icons/proxmox.png
Terminal=false
Categories=backup;
+1 -1
View File
@@ -14,7 +14,7 @@
services.beszel.agent.environment = {
#DOCKER_HOST = "tcp://docker-socket-proxy:2375";
KEY = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFPR9kwtC4TAeTRu46A7+opZsYpxqkRJ+x/ZyB2GWCeG";
EXTRA_FILESYSTEMS = "${vars.storageRoot}/docker/volumes";
EXTRA_FILESYSTEMS = "${vars.storageRoot}/${vars.nfsShares.dockerVolumes.subpath}";
LOG_LEVEL = "debug";
};
+1 -1
View File
@@ -4,6 +4,6 @@
services.beszel.agent.enable = true;
services.beszel.agent.environment = {
#DOCKER_HOST = "tcp://docker-socket-proxy:2375";
HUB_URL = "http://${vars.dockerHost}.${vars.homeDomain}:${toString vars.beszelHubPort}";
HUB_URL = "http://${vars.dockerHost}.${vars.homeDomain}:${toString vars.ports.beszelHub}";
};
}
+10 -5
View File
@@ -28,13 +28,18 @@
boot.supportedFilesystems = [ "nfs" ];
systemd.tmpfiles.rules = [
"L+ /home/nixos/docker - - - - /mnt/docker/config"
"d /mnt/docker 0755 nixos users -"
"d /mnt/raspi-backup 0755 nixos users -"
"L+ /home/${vars.primaryUser}/docker - - - - ${vars.nfsShares.dockerConfig.mountpoint}"
"d /mnt/docker 0755 ${vars.primaryUser} users -"
"d ${vars.nfsShares.raspiVolumes.mountpoint} 0755 ${vars.primaryUser} users -"
];
users.users.nixos.extraGroups = [ "docker" ];
users.users.${vars.primaryUser}.extraGroups = [ "docker" ];
services.openssh.settings.PermitRootLogin = "yes";
networking.firewall.allowedTCPPorts = [ 80 8080 443 vars.beszelHubPort ];
networking.firewall.allowedTCPPorts = [
vars.ports.dockerHttp
vars.ports.dockerExtra
vars.ports.dockerHttps
vars.ports.beszelHub
];
}
+2 -2
View File
@@ -1,4 +1,4 @@
{ config, pkgs, lib, inputs, ... }:
{ config, pkgs, lib, inputs, vars, ... }:
{
environment.systemPackages = with pkgs; [
@@ -65,7 +65,7 @@
# The networkmanager group only exists when NM is actually enabled — the
# lxc platform module force-disables it, so don't add the user to a group
# that won't exist there.
users.users.nixos.extraGroups = lib.mkIf config.networking.networkmanager.enable [ "networkmanager" ];
users.users.${vars.primaryUser}.extraGroups = lib.mkIf config.networking.networkmanager.enable [ "networkmanager" ];
programs.firefox.enable = true;
+2 -2
View File
@@ -1,4 +1,4 @@
{ lib, pkgs, config, ... }:
{ lib, pkgs, config, vars, ... }:
{
networking.networkmanager.enable = true;
@@ -6,7 +6,7 @@
# The networkmanager group only exists when NM is actually enabled — the
# lxc platform module force-disables it, so don't add the user to a group
# that won't exist there.
users.users.nixos.extraGroups = lib.mkIf config.networking.networkmanager.enable [ "networkmanager" ];
users.users.${vars.primaryUser}.extraGroups = lib.mkIf config.networking.networkmanager.enable [ "networkmanager" ];
environment.systemPackages = with pkgs; [
inetutils
+2 -2
View File
@@ -155,6 +155,6 @@ in
};
};
networking.firewall.allowedTCPPorts = [ 80 ];
networking.firewall.allowedUDPPorts = [ 69 ];
networking.firewall.allowedTCPPorts = [ vars.ports.pxeBootHttp ];
networking.firewall.allowedUDPPorts = [ vars.ports.pxeBootTftp ];
}
+6 -6
View File
@@ -16,13 +16,13 @@
services.nfs.server = {
enable = true;
exports = ''
${vars.storageRoot}/docker/config ${vars.lanCidr}(rw,sync,no_subtree_check,no_root_squash)
${vars.storageRoot}/docker/volumes ${vars.lanCidr}(rw,sync,no_subtree_check,no_root_squash)
${vars.storageRoot}/docker/databases ${vars.lanCidr}(rw,sync,no_subtree_check,no_root_squash)
${vars.storageRoot}/docker/nextcloud-data ${vars.lanCidr}(rw,sync,no_subtree_check,no_root_squash)
${vars.storageRoot}/raspi/volumes ${vars.lanCidr}(rw,sync,no_subtree_check,no_root_squash)
${vars.storageRoot}/${vars.nfsShares.dockerConfig.subpath} ${vars.lanCidr}(rw,sync,no_subtree_check,no_root_squash)
${vars.storageRoot}/${vars.nfsShares.dockerVolumes.subpath} ${vars.lanCidr}(rw,sync,no_subtree_check,no_root_squash)
${vars.storageRoot}/${vars.nfsShares.dockerDatabases.subpath} ${vars.lanCidr}(rw,sync,no_subtree_check,no_root_squash)
${vars.storageRoot}/${vars.nfsShares.nextcloudData.subpath} ${vars.lanCidr}(rw,sync,no_subtree_check,no_root_squash)
${vars.storageRoot}/${vars.nfsShares.raspiVolumes.subpath} ${vars.lanCidr}(rw,sync,no_subtree_check,no_root_squash)
'';
};
networking.firewall.allowedTCPPorts = [ 111 2049 ];
networking.firewall.allowedTCPPorts = [ vars.ports.nfsRpcbind vars.ports.nfsd ];
}
+2 -2
View File
@@ -1,4 +1,4 @@
{ config, ... }:
{ config, vars, ... }:
{
disko.devices = {
@@ -13,7 +13,7 @@
# whatever's left after ESP + swap within it); imageName keeps each
# host's image distinctly named instead of every proxmox-* host
# producing an identical "main.raw".
imageSize = "20G";
imageSize = vars.proxmoxImageSize;
imageName = config.networking.hostName;
content = {
+10 -10
View File
@@ -2,8 +2,8 @@
{
fileSystems = {
"/mnt/docker/config" = {
device = "${vars.nfsServerHost}:${vars.storageRoot}/docker/config";
${vars.nfsShares.dockerConfig.mountpoint} = {
device = "${vars.nfsServerHost}:${vars.storageRoot}/${vars.nfsShares.dockerConfig.subpath}";
fsType = "nfs";
options = [
@@ -14,8 +14,8 @@
];
};
"/mnt/docker/databases" = {
device = "${vars.nfsServerHost}:${vars.storageRoot}/docker/databases";
${vars.nfsShares.dockerDatabases.mountpoint} = {
device = "${vars.nfsServerHost}:${vars.storageRoot}/${vars.nfsShares.dockerDatabases.subpath}";
fsType = "nfs";
options = [
@@ -26,8 +26,8 @@
];
};
"/mnt/docker/volumes" = {
device = "${vars.nfsServerHost}:${vars.storageRoot}/docker/volumes";
${vars.nfsShares.dockerVolumes.mountpoint} = {
device = "${vars.nfsServerHost}:${vars.storageRoot}/${vars.nfsShares.dockerVolumes.subpath}";
fsType = "nfs";
options = [
@@ -38,8 +38,8 @@
];
};
"/mnt/nextcloud-data" = {
device = "${vars.nfsServerHost}:${vars.storageRoot}/docker/nextcloud-data";
${vars.nfsShares.nextcloudData.mountpoint} = {
device = "${vars.nfsServerHost}:${vars.storageRoot}/${vars.nfsShares.nextcloudData.subpath}";
fsType = "nfs";
options = [
@@ -50,8 +50,8 @@
];
};
"/mnt/raspi-backup" = {
device = "${vars.nfsServerHost}:${vars.storageRoot}/raspi/volumes";
${vars.nfsShares.raspiVolumes.mountpoint} = {
device = "${vars.nfsServerHost}:${vars.storageRoot}/${vars.nfsShares.raspiVolumes.subpath}";
fsType = "nfs";
options = [
+2 -2
View File
@@ -28,7 +28,7 @@
openssh.enable = true;
};
networking.firewall.allowedTCPPorts = [ 80 ];
networking.firewall.allowedTCPPorts = [ vars.ports.nixCacheHttp ];
users.groups.${vars.remoteBuilderUser} = { };
@@ -54,6 +54,6 @@
nix.gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 30d";
options = "--delete-older-than ${vars.nixCacheGcMaxAge}";
};
}
+2 -2
View File
@@ -1,8 +1,8 @@
{ vars, ... }:
{
fileSystems."/mnt/raspi" = {
device = "raspberrypi.${vars.tailnetDomain}:/home/raspi/raspi";
fileSystems.${vars.raspiMountpoint} = {
device = "${vars.raspberryPiHost}.${vars.tailnetDomain}:${vars.raspiNfsPath}";
fsType = "nfs4";
options = [
"nofail"
+4 -4
View File
@@ -1,14 +1,14 @@
_:
{ vars, ... }:
{
services.logrotate = {
enable = true;
settings = {
"/mnt/docker/volumes/traefik-data/logs/*.log" = {
"${vars.nfsShares.dockerVolumes.mountpoint}/traefik-data/logs/*.log" = {
daily = true;
size = "100M";
rotate = 20;
size = vars.traefikLogRotate.maxSize;
rotate = vars.traefikLogRotate.keep;
compress = true;
missingok = true;
notifempty = true;
+110 -5
View File
@@ -12,6 +12,11 @@
nfsServerHost = "server"; # NFS export source hostname
dockerHost = "docker"; # docker-compose stack host
# Raspberry Pi's own Tailscale hostname (not fronted by `server` — it
# exports its own NFS share directly). Resolved as
# "${raspberryPiHost}.${tailnetDomain}" in modules/raspi/mount-data.nix.
raspberryPiHost = "raspberrypi";
remoteBuilderUser = "nixremote"; # remote builder SSH user
# Public keys authorized to SSH in as remoteBuilderUser on the nix-cache
@@ -32,13 +37,113 @@
# System
timeZone = "Australia/Brisbane";
primaryUser = "nixos"; # main interactive user on every host
# Main interactive user on every host. Every module that grants this user
# a group, a home directory, or tmpfiles ownership should reference
# vars.primaryUser rather than the literal "nixos", so renaming it is a
# one-line change.
primaryUser = "nixos";
# Storage
storageRoot = "/tank"; # ZFS pool root on `server`
# Well-known ports for LAN services referenced from multiple hosts
beszelHubPort = 8090;
pveWebPort = 8006;
pbsWebPort = 8007;
# NFS datasets exported from `storageRoot` on `nfsServerHost` and mounted
# by client hosts. `subpath` is relative to `storageRoot` — combined with
# it to build both the export line in modules/build-types/server.nix and
# the "<nfsServerHost>:<storageRoot>/<subpath>" device string each client
# mount uses in modules/docker/mount-data.nix. `mountpoint` is the
# absolute local path clients mount it at, referenced by that same file's
# fileSystems attribute name plus every other place that needs to know
# where the share lives locally (modules/build-types/docker.nix's
# tmpfiles rules, modules/traefik/rotate-logs.nix's log path). Renaming a
# dataset or moving where it's mounted only needs changing it here — the
# export and every client reference follow automatically.
nfsShares = {
dockerConfig = {
subpath = "docker/config";
mountpoint = "/mnt/docker/config";
};
dockerDatabases = {
subpath = "docker/databases";
mountpoint = "/mnt/docker/databases";
};
dockerVolumes = {
subpath = "docker/volumes";
mountpoint = "/mnt/docker/volumes";
};
nextcloudData = {
subpath = "docker/nextcloud-data";
mountpoint = "/mnt/nextcloud-data";
};
raspiVolumes = {
subpath = "raspi/volumes";
mountpoint = "/mnt/raspi-backup";
};
};
# The Raspberry Pi's own NFS export — not under storageRoot/nfsServerHost,
# served directly by the Pi itself over Tailscale (see raspberryPiHost
# above) and mounted at raspiMountpoint by modules/raspi/mount-data.nix.
raspiNfsPath = "/home/raspi/raspi";
raspiMountpoint = "/mnt/raspi";
# Every literal port referenced from modules/ or hosts/, grouped by the
# service/host that opens or connects to it — kept as separate entries
# even where two happen to share a number today (e.g. nixCacheHttp and
# pxeBootHttp are both 80) so changing one service's port can never
# silently change an unrelated one.
ports = {
# nix-cache's nginx reverse proxy in front of nix-serve
# (modules/nix-cache/server.nix).
nixCacheHttp = 80;
# pxe-boot's nginx asset server, also used to build pxeBaseUrl
# (modules/build-types/pxe-boot.nix).
pxeBootHttp = 80;
# pxe-boot's atftpd TFTP server — UDP, not TCP
# (modules/build-types/pxe-boot.nix).
pxeBootTftp = 69;
# `server`'s NFS exports need both the portmapper (rpcbind) and the
# NFS data port itself opened (modules/build-types/server.nix).
nfsRpcbind = 111;
nfsd = 2049;
# Opened on the docker host's firewall for the Traefik-fronted
# container stack (docker-compose config lives in the separate
# /home/debian/docker repo, not here): 80/443 are Traefik's own
# HTTP/HTTPS listeners; 8080 is an additional exposed service whose
# exact backend isn't declared in this repo (modules/build-types/docker.nix).
dockerHttp = 80;
dockerHttps = 443;
dockerExtra = 8080;
# Beszel monitoring hub, reachable at
# http://<dockerHost>.<homeDomain>:<beszelHub> from every agent
# (modules/beszel/enable-agent.nix, hosts/nixos/home.nix).
beszelHub = 8090;
# Proxmox VE and Proxmox Backup Server web UIs, opened as desktop
# shortcuts on the gui build type (hosts/nixos/home.nix).
pveWeb = 8006;
pbsWeb = 8007;
};
# .raw disk image size for every proxmox-* host's standalone Disko image
# build (modules/disko/proxmox.nix, config.system.build.diskoImagesScript
# — see docs/proxmox-images.md). Root fills whatever's left after the ESP
# and swap partitions within this total.
proxmoxImageSize = "20G";
# nix-cache's Nix store garbage collection retention
# (modules/nix-cache/server.nix).
nixCacheGcMaxAge = "30d";
# Traefik access log rotation, watched on the docker host at
# nfsShares.dockerVolumes.mountpoint (modules/traefik/rotate-logs.nix).
traefikLogRotate = {
maxSize = "100M"; # rotate once a log file exceeds this size
keep = 20; # number of rotated logs to retain before deleting the oldest
};
}