Compare commits

...

5 Commits

Author SHA1 Message Date
beatzaplenty 770cbaf098 updated authorized keys 2026-05-12 11:24:54 +10:00
beatz174-bit dec3e25472 Merge pull request #1 from beatz174-bit/codex/refactor-nix-cache-for-binary-cache-and-remote-builder
Add Nix cache / remote-builder modules, wire hosts, and harden maintenance scripts
2026-05-12 11:09:50 +10:00
beatz174-bit 8b919d2d5a Fix pure eval and harden nix script bootstrap 2026-05-12 11:09:23 +10:00
beatzaplenty d52e892559 update setup script 2026-05-12 07:15:12 +10:00
beatzaplenty df4161265b Add codex environment scripts, README and AGENTS 2026-05-12 07:02:43 +10:00
16 changed files with 378 additions and 31 deletions
+33
View File
@@ -0,0 +1,33 @@
# AGENTS.md
## Repo purpose
This repository contains flake-based NixOS configurations for Waynes LAN servers and workstation.
The flake currently exposes these NixOS configurations:
- `nixos`
- `docker`
- `kuma`
- `server`
- `nix-cache`
- `nix-minimal`
Do not deploy, switch, reboot, repartition, format disks, or run destructive install commands from this repository unless explicitly asked.
## Safety rules
- Never run `nixos-rebuild switch`, `boot`, `test`, `nixos-install`, `parted`, `mkfs`, `mkswap`, `swapon`, `mount`, or destructive disk commands in Codex.
- Validation work should be limited to evaluation, linting, formatting checks, and `nix build --dry-run --no-link`.
- Do not add secrets, tokens, private keys, password hashes, or live credentials to the repo.
- Treat `flake.nix`, Home Manager config, and Nix config files as public.
- If you find committed tokens or hashes, flag them immediately and recommend rotation/removal.
## Expected commands
Use these commands when validating changes:
```bash
bash scripts/codex-setup.sh
bash scripts/codex-maintenance.sh
bash scripts/codex-maintenance.sh dry-run
+24 -1
View File
@@ -1,2 +1,25 @@
# nixos
## `README.md`
```markdown
# NixOS LAN Configurations
Flake-based NixOS configuration repository for Waynes LAN machines.
## Hosts
This flake currently defines:
| Host | Purpose |
|---|---|
| `nixos` | Main NixOS workstation / desktop |
| `docker` | Docker host for the main container stack |
| `kuma` | Docker-enabled Uptime Kuma style host |
| `server` | Storage / NFS / backup style server |
| `nix-cache` | Local Nix binary cache host |
| `nix-minimal` | Minimal NixOS host profile |
List hosts with:
```bash
nix eval --json .#nixosConfigurations --apply builtins.attrNames | jq -r '.[]'
+4 -12
View File
@@ -49,18 +49,10 @@ users.users.root = {
#Enable flakes #Enable flakes
nix.settings.experimental-features = "nix-command flakes"; nix.settings = {
experimental-features = [ "nix-command" "flakes" ];
nix.settings = { auto-optimise-store = true;
substituters = [ };
"http://nix-cache"
# "https://cache.nixos.org/"
];
trusted-public-keys = [
"cache.local-1:usoWYanY3Kpq2+kDIS2nhWoLZiRxanmdysdzqCFBHW4="
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
];
};
programs.git = { programs.git = {
+48
View File
@@ -0,0 +1,48 @@
# nix-cache architecture
This repository configures `nix-cache` as a **binary cache server** and a **remote builder** for other hosts.
## Important design notes
- This is **not** a shared `/nix/store` setup.
- Every machine still keeps and uses its own local `/nix/store`.
- Clients prefer `http://nix-cache` for substitutes and keep `https://cache.nixos.org/` as fallback.
- Clients can offload builds to `nix-cache` through SSH (`nix.distributedBuilds`).
## Binary cache signing keys (on nix-cache)
```bash
sudo install -d -m 0700 /etc/nix
sudo nix-store --generate-binary-cache-key nix-cache-1 /etc/nix/cache-priv.pem /etc/nix/cache-pub.pem
sudo chmod 0600 /etc/nix/cache-priv.pem
sudo chmod 0644 /etc/nix/cache-pub.pem
cat /etc/nix/cache-pub.pem
```
Do not commit private keys.
## Remote builder SSH keys
On each client, install the private key used to authenticate as `nixremote`:
```bash
sudo install -d -m 0700 /root/.ssh
sudo install -m 0600 ./nixremote /root/.ssh/nixremote
sudo ssh -i /root/.ssh/nixremote nixremote@nix-cache nix-store --version
```
On `nix-cache`, install the matching public key used by `nixremote` authorized keys.
## Manual verification
After deployment:
```bash
curl http://nix-cache/nix-cache-info
nix store ping --store http://nix-cache
nix show-config | grep -E 'substituters|trusted-public-keys|builders-use-substitutes'
sudo ssh -i /root/.ssh/nixremote nixremote@nix-cache nix-store --version
nix build nixpkgs#hello --builders 'ssh://nixremote@nix-cache x86_64-linux /root/.ssh/nixremote 4 2 big-parallel,kvm,nixos-test,benchmark' -L
nix path-info -r nixpkgs#hello
curl -I "http://nix-cache/$(basename "$(nix path-info nixpkgs#hello)").narinfo"
```
+1 -5
View File
@@ -1,11 +1,7 @@
{ {
description = "LAN NixOS configs"; description = "LAN NixOS configs";
nixConfig = { # GitHub tokens must be provided outside this repository (local nix.conf, env, or deployment secrets).
access-tokens = [
"github.com=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"
];
};
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
nixos-conf-editor.url = "github:snowfallorg/nixos-conf-editor"; nixos-conf-editor.url = "github:snowfallorg/nixos-conf-editor";
+2
View File
@@ -15,6 +15,8 @@ in
imports = imports =
[ # Include the results of the hardware scan. [ # Include the results of the hardware scan.
../../common/configuration.nix ../../common/configuration.nix
../../modules/nix/cache-client.nix
../../modules/nix/remote-builder-client.nix
]; ];
networking.hostName = "docker"; # Define your hostname. networking.hostName = "docker"; # Define your hostname.
+2
View File
@@ -15,6 +15,8 @@ in
imports = imports =
[ # Include the results of the hardware scan. [ # Include the results of the hardware scan.
../../common/configuration.nix ../../common/configuration.nix
../../modules/nix/cache-client.nix
../../modules/nix/remote-builder-client.nix
]; ];
networking.hostName = "kuma"; # Define your hostname. networking.hostName = "kuma"; # Define your hostname.
+1 -11
View File
@@ -8,26 +8,16 @@
imports = imports =
[ # Include the results of the hardware scan. [ # Include the results of the hardware scan.
../../common/configuration.nix ../../common/configuration.nix
../../modules/nix/cache-server.nix
]; ];
networking.hostName = "nix-cache"; # Define your hostname. networking.hostName = "nix-cache"; # Define your hostname.
services.nix-serve.enable = true;
services.nix-serve.secretKeyFile = "/etc/nix/cache-priv.pem";
services.nginx = {
enable = true;
recommendedProxySettings = true;
virtualHosts."cache.local" = {
locations."/".proxyPass = "http://${config.services.nix-serve.bindAddress}:${toString config.services.nix-serve.port}";
};
};
services.prometheus.exporters.node = { services.prometheus.exporters.node = {
enable = true; enable = true;
openFirewall = true; openFirewall = true;
}; };
networking.firewall.allowedTCPPorts = [ config.services.nginx.defaultHTTPListenPort ];
# Open ports in the firewall. # Open ports in the firewall.
# networking.firewall.allowedTCPPorts = [ 80 8080 443 ]; # networking.firewall.allowedTCPPorts = [ 80 8080 443 ];
# networking.firewall.allowedUDPPorts = [ ... ]; # networking.firewall.allowedUDPPorts = [ ... ];
+2
View File
@@ -8,6 +8,8 @@
imports = imports =
[ # Include the results of the hardware scan. [ # Include the results of the hardware scan.
../../common/configuration.nix ../../common/configuration.nix
../../modules/nix/cache-client.nix
../../modules/nix/remote-builder-client.nix
]; ];
networking.hostName = "nix-minimal"; # Define your hostname. networking.hostName = "nix-minimal"; # Define your hostname.
+2 -2
View File
@@ -28,6 +28,8 @@ in {
imports = imports =
[ # Include the results of the hardware scan. [ # Include the results of the hardware scan.
../../common/configuration.nix ../../common/configuration.nix
../../modules/nix/cache-client.nix
../../modules/nix/remote-builder-client.nix
]; ];
# Bootloader. # Bootloader.
@@ -94,8 +96,6 @@ in {
system.stateVersion = "25.05"; # Did you read the comment? system.stateVersion = "25.05"; # Did you read the comment?
nix.settings.experimental-features = "nix-command flakes";
services.xrdp.enable = true; services.xrdp.enable = true;
services.xrdp.defaultWindowManager = "cinnamon-session"; services.xrdp.defaultWindowManager = "cinnamon-session";
services.xrdp.openFirewall = true; services.xrdp.openFirewall = true;
+2
View File
@@ -8,6 +8,8 @@
imports = imports =
[ # Include the results of the hardware scan. [ # Include the results of the hardware scan.
../../common/configuration.nix ../../common/configuration.nix
../../modules/nix/cache-client.nix
../../modules/nix/remote-builder-client.nix
]; ];
networking.hostName = "server"; # Define your hostname. networking.hostName = "server"; # Define your hostname.
+15
View File
@@ -0,0 +1,15 @@
{ ... }:
{
nix.settings = {
substituters = [
"http://nix-cache"
"https://cache.nixos.org/"
];
trusted-public-keys = [
"cache.local-1:usoWYanY3Kpq2+kDIS2nhWoLZiRxanmdysdzqCFBHW4="
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
];
auto-optimise-store = true;
};
}
+58
View File
@@ -0,0 +1,58 @@
{ config, pkgs, ... }:
{
# Generate the binary cache key pair on the nix-cache host:
# sudo install -d -m 0700 /etc/nix
# sudo nix-store --generate-binary-cache-key nix-cache-1 \
# /etc/nix/cache-priv.pem \
# /etc/nix/cache-pub.pem
# sudo chmod 0600 /etc/nix/cache-priv.pem
# sudo chmod 0644 /etc/nix/cache-pub.pem
# cat /etc/nix/cache-pub.pem
services.nix-serve = {
enable = true;
secretKeyFile = "/etc/nix/cache-priv.pem";
};
services.nginx = {
enable = true;
recommendedProxySettings = true;
virtualHosts."nix-cache" = {
locations."/" = {
proxyPass = "http://${config.services.nix-serve.bindAddress}:${toString config.services.nix-serve.port}";
};
};
};
networking.firewall.allowedTCPPorts = [ 80 ];
users.groups.nixremote = {};
users.users.nixremote = {
isSystemUser = true;
group = "nixremote";
createHome = true;
home = "/var/lib/nixremote";
shell = pkgs.bashInteractive;
# Provide remote builder public keys here (safe to commit public keys only):
# openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAA... client@host" ];
#
# Avoid absolute keyFiles paths here because they break pure flake evaluation.
openssh.authorizedKeys.keys = ["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFDEA1S2ikpObREgbP5uVBWMxIOGbY8B+Wx7VTZK1m6t root@server" ];
};
services.openssh.enable = true;
nix.settings = {
trusted-users = [ "root" "nixremote" ];
experimental-features = [ "nix-command" "flakes" ];
auto-optimise-store = true;
builders-use-substitutes = true;
};
nix.gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 30d";
};
}
+26
View File
@@ -0,0 +1,26 @@
{ pkgs, ... }:
{
# Install the remote builder key on each client host (do not commit private keys):
# sudo install -d -m 0700 /root/.ssh
# sudo install -m 0600 ./nixremote /root/.ssh/nixremote
# sudo ssh -i /root/.ssh/nixremote nixremote@nix-cache nix-store --version
nix.distributedBuilds = true;
nix.buildMachines = [
{
hostName = "nix-cache";
sshUser = "nixremote";
sshKey = "/root/.ssh/nixremote";
system = pkgs.stdenv.hostPlatform.system;
maxJobs = 4;
speedFactor = 2;
supportedFeatures = [ "nixos-test" "benchmark" "big-parallel" "kvm" ];
}
];
nix.settings = {
builders-use-substitutes = true;
max-jobs = "auto";
};
}
+70
View File
@@ -0,0 +1,70 @@
#!/usr/bin/env bash
set -euo pipefail
export NIX_CONFIG="${NIX_CONFIG:-}
experimental-features = nix-command flakes
accept-flake-config = false
warn-dirty = false
"
MODE="${1:-validate}"
ensure_nix_profile() {
if [ -f /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh ]; then
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
elif [ -f "$HOME/.nix-profile/etc/profile.d/nix.sh" ]; then
. "$HOME/.nix-profile/etc/profile.d/nix.sh"
fi
}
ensure_nix_profile
if ! command -v nix >/dev/null 2>&1; then
echo "ERROR: nix is not available in PATH. Run bash scripts/codex-setup.sh first." >&2
exit 127
fi
hosts_json="$(nix eval --json --no-use-registries --no-accept-flake-config .#nixosConfigurations --apply builtins.attrNames)"
hosts="$(echo "$hosts_json" | jq -r '.[]')"
echo "Hosts:"
echo "$hosts"
echo
echo "Checking for obvious committed secrets..."
if grep -RInE 'github_pat_|ghp_|access-tokens|hashedPassword[[:space:]]*=' \
--exclude-dir=.git \
--exclude=flake.lock \
.; then
echo
echo "WARNING: Potential secrets or password hashes found. Review before committing."
else
echo "No obvious token patterns found."
fi
echo
echo "Checking Nix formatting with nixpkgs-fmt..."
nix run --no-use-registries --no-accept-flake-config github:NixOS/nixpkgs/nixos-25.11#nixpkgs-fmt -- --check .
echo
echo "Running statix lint..."
nix run --no-use-registries --no-accept-flake-config github:NixOS/nixpkgs/nixos-25.11#statix -- check .
echo
echo "Evaluating host toplevel derivations..."
for host in $hosts; do
echo "==> $host"
nix eval --raw --no-use-registries --no-accept-flake-config ".#nixosConfigurations.${host}.config.system.build.toplevel.drvPath"
done
if [[ "$MODE" == "dry-run" ]]; then
echo
echo "Running dry-run builds for all hosts. This will not create result symlinks."
for host in $hosts; do
echo "==> Dry-run build: $host"
nix build --dry-run --no-link --no-use-registries --no-accept-flake-config ".#nixosConfigurations.${host}.config.system.build.toplevel"
done
fi
echo
echo "Maintenance checks complete."
+88
View File
@@ -0,0 +1,88 @@
#!/usr/bin/env bash
set -euo pipefail
export NIX_CONFIG="${NIX_CONFIG:-}
experimental-features = nix-command flakes
accept-flake-config = false
warn-dirty = false
"
ensure_nix_profile() {
if [ -f /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh ]; then
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
elif [ -f "$HOME/.nix-profile/etc/profile.d/nix.sh" ]; then
. "$HOME/.nix-profile/etc/profile.d/nix.sh"
fi
}
install_nix_if_missing() {
if command -v nix >/dev/null 2>&1; then
return
fi
echo "Nix not found. Installing Nix..."
if [ "$(id -u)" -eq 0 ]; then
echo "Running as root; preparing nixbld users for container/Codex environment..."
if ! getent group nixbld >/dev/null; then
groupadd -r nixbld
fi
for i in $(seq 1 10); do
if ! id "nixbld$i" >/dev/null 2>&1; then
useradd \
-r \
-g nixbld \
-G nixbld \
-d /var/empty \
-s /usr/sbin/nologin \
"nixbld$i" || true
fi
done
mkdir -p /etc/nix
cat > /etc/nix/nix.conf <<'EOF'
experimental-features = nix-command flakes
accept-flake-config = false
warn-dirty = false
build-users-group = nixbld
EOF
sh <(curl -L https://nixos.org/nix/install) --no-daemon
else
sh <(curl -L https://nixos.org/nix/install) --no-daemon
fi
ensure_nix_profile
}
install_nix_if_missing
ensure_nix_profile
mkdir -p "$HOME/.config/nix"
cat > "$HOME/.config/nix/nix.conf" <<'EOF'
experimental-features = nix-command flakes
accept-flake-config = false
warn-dirty = false
EOF
echo "Nix version:"
nix --version
echo "Installing jq if unavailable..."
if ! command -v jq >/dev/null 2>&1; then
nix profile install nixpkgs#jq
fi
echo "Available NixOS hosts:"
hosts="$(nix eval --json --no-use-registries --no-accept-flake-config .#nixosConfigurations --apply builtins.attrNames | jq -r '.[]')"
echo "$hosts"
echo "Evaluating all host toplevel derivations..."
for host in $hosts; do
echo "==> Evaluating $host"
nix eval --raw --no-use-registries --no-accept-flake-config ".#nixosConfigurations.${host}.config.system.build.toplevel.drvPath"
done
echo "Codex setup complete."