My nix-darwin and NixOS config
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore: switch to sops-nix, clean flake, overhaul secrets + tunnel setup

+519 -1448
+10 -184
flake.lock
··· 1 1 { 2 2 "nodes": { 3 - "agenix": { 4 - "inputs": { 5 - "darwin": "darwin", 6 - "home-manager": "home-manager_2", 7 - "nixpkgs": [ 8 - "ragenix", 9 - "nixpkgs" 10 - ], 11 - "systems": "systems_3" 12 - }, 13 - "locked": { 14 - "lastModified": 1761656077, 15 - "narHash": "sha256-lsNWuj4Z+pE7s0bd2OKicOFq9bK86JE0ZGeKJbNqb94=", 16 - "owner": "ryantm", 17 - "repo": "agenix", 18 - "rev": "9ba0d85de3eaa7afeab493fed622008b6e4924f5", 19 - "type": "github" 20 - }, 21 - "original": { 22 - "owner": "ryantm", 23 - "repo": "agenix", 24 - "type": "github" 25 - } 26 - }, 27 3 "catppuccin": { 28 4 "inputs": { 29 5 "nixpkgs": "nixpkgs" ··· 63 39 "type": "github" 64 40 } 65 41 }, 66 - "crane": { 67 - "locked": { 68 - "lastModified": 1760924934, 69 - "narHash": "sha256-tuuqY5aU7cUkR71sO2TraVKK2boYrdW3gCSXUkF4i44=", 70 - "owner": "ipetkov", 71 - "repo": "crane", 72 - "rev": "c6b4d5308293d0d04fcfeee92705017537cad02f", 73 - "type": "github" 74 - }, 75 - "original": { 76 - "owner": "ipetkov", 77 - "repo": "crane", 78 - "type": "github" 79 - } 80 - }, 81 - "darwin": { 82 - "inputs": { 83 - "nixpkgs": [ 84 - "ragenix", 85 - "agenix", 86 - "nixpkgs" 87 - ] 88 - }, 89 - "locked": { 90 - "lastModified": 1744478979, 91 - "narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=", 92 - "owner": "lnl7", 93 - "repo": "nix-darwin", 94 - "rev": "43975d782b418ebf4969e9ccba82466728c2851b", 95 - "type": "github" 96 - }, 97 - "original": { 98 - "owner": "lnl7", 99 - "ref": "master", 100 - "repo": "nix-darwin", 101 - "type": "github" 102 - } 103 - }, 104 42 "flake-compat": { 105 43 "flake": false, 106 44 "locked": { ··· 156 94 "type": "indirect" 157 95 } 158 96 }, 159 - "flake-utils_2": { 160 - "inputs": { 161 - "systems": "systems_4" 162 - }, 163 - "locked": { 164 - "lastModified": 1731533236, 165 - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", 166 - "owner": "numtide", 167 - "repo": "flake-utils", 168 - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", 169 - "type": "github" 170 - }, 171 - "original": { 172 - "owner": "numtide", 173 - "repo": "flake-utils", 174 - "type": "github" 175 - } 176 - }, 177 97 "home-manager": { 178 98 "inputs": { 179 99 "nixpkgs": [ ··· 195 115 "type": "github" 196 116 } 197 117 }, 198 - "home-manager_2": { 199 - "inputs": { 200 - "nixpkgs": [ 201 - "ragenix", 202 - "agenix", 203 - "nixpkgs" 204 - ] 205 - }, 206 - "locked": { 207 - "lastModified": 1745494811, 208 - "narHash": "sha256-YZCh2o9Ua1n9uCvrvi5pRxtuVNml8X2a03qIFfRKpFs=", 209 - "owner": "nix-community", 210 - "repo": "home-manager", 211 - "rev": "abfad3d2958c9e6300a883bd443512c55dfeb1be", 212 - "type": "github" 213 - }, 214 - "original": { 215 - "owner": "nix-community", 216 - "repo": "home-manager", 217 - "type": "github" 218 - } 219 - }, 220 118 "mac-app-util": { 221 119 "inputs": { 222 120 "cl-nix-lite": "cl-nix-lite", ··· 243 141 "nix-darwin": { 244 142 "inputs": { 245 143 "nixpkgs": [ 246 - "nixpkgs-darwin" 144 + "nixpkgs" 247 145 ] 248 146 }, 249 147 "locked": { ··· 293 191 "original": { 294 192 "owner": "NixOS", 295 193 "ref": "nixos-unstable", 296 - "repo": "nixpkgs", 297 - "type": "github" 298 - } 299 - }, 300 - "nixpkgs-darwin": { 301 - "locked": { 302 - "lastModified": 1771216249, 303 - "narHash": "sha256-FNEmjUiwVcbaMx+DLNAPyEZMdw4ASGvEqJaswcJVRDc=", 304 - "owner": "nixos", 305 - "repo": "nixpkgs", 306 - "rev": "7cdb2c9a4f4ec945cdd8348800b9205e5069b48f", 307 - "type": "github" 308 - }, 309 - "original": { 310 - "owner": "nixos", 311 - "ref": "nixpkgs-25.11-darwin", 312 194 "repo": "nixpkgs", 313 195 "type": "github" 314 196 } ··· 431 313 "type": "github" 432 314 } 433 315 }, 434 - "ragenix": { 435 - "inputs": { 436 - "agenix": "agenix", 437 - "crane": "crane", 438 - "flake-utils": "flake-utils_2", 439 - "nixpkgs": [ 440 - "nixpkgs" 441 - ], 442 - "rust-overlay": "rust-overlay" 443 - }, 444 - "locked": { 445 - "lastModified": 1761832913, 446 - "narHash": "sha256-VCNVjjuRvrKPiYYwqhE3BAKIaReiKXGpxGp27lZ0MFM=", 447 - "owner": "yaxitech", 448 - "repo": "ragenix", 449 - "rev": "83bccfdea758241999f32869fb6b36f7ac72f1ac", 450 - "type": "github" 451 - }, 452 - "original": { 453 - "owner": "yaxitech", 454 - "repo": "ragenix", 455 - "type": "github" 456 - } 457 - }, 458 316 "root": { 459 317 "inputs": { 460 318 "catppuccin": "catppuccin", ··· 463 321 "nix-darwin": "nix-darwin", 464 322 "nix-vscode-extensions": "nix-vscode-extensions", 465 323 "nixpkgs": "nixpkgs_6", 466 - "nixpkgs-darwin": "nixpkgs-darwin", 467 324 "plasma-manager": "plasma-manager", 468 - "ragenix": "ragenix" 325 + "sops-nix": "sops-nix" 469 326 } 470 327 }, 471 - "rust-overlay": { 328 + "sops-nix": { 472 329 "inputs": { 473 330 "nixpkgs": [ 474 - "ragenix", 475 331 "nixpkgs" 476 332 ] 477 333 }, 478 334 "locked": { 479 - "lastModified": 1761791894, 480 - "narHash": "sha256-myRIDh+PxaREz+z9LzbqBJF+SnTFJwkthKDX9zMyddY=", 481 - "owner": "oxalica", 482 - "repo": "rust-overlay", 483 - "rev": "59c45eb69d9222a4362673141e00ff77842cd219", 335 + "lastModified": 1771166946, 336 + "narHash": "sha256-UFc4lfGBr+wJmwgDGJDn1cVD6DTr0/8TdronNUiyXlU=", 337 + "owner": "Mic92", 338 + "repo": "sops-nix", 339 + "rev": "2d0cf89b4404529778bc82de7e42b5754e0fe4fa", 484 340 "type": "github" 485 341 }, 486 342 "original": { 487 - "owner": "oxalica", 488 - "repo": "rust-overlay", 343 + "owner": "Mic92", 344 + "repo": "sops-nix", 489 345 "type": "github" 490 346 } 491 347 }, ··· 516 372 "original": { 517 373 "owner": "nix-systems", 518 374 "repo": "default-darwin", 519 - "type": "github" 520 - } 521 - }, 522 - "systems_3": { 523 - "locked": { 524 - "lastModified": 1681028828, 525 - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 526 - "owner": "nix-systems", 527 - "repo": "default", 528 - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 529 - "type": "github" 530 - }, 531 - "original": { 532 - "owner": "nix-systems", 533 - "repo": "default", 534 - "type": "github" 535 - } 536 - }, 537 - "systems_4": { 538 - "locked": { 539 - "lastModified": 1681028828, 540 - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 541 - "owner": "nix-systems", 542 - "repo": "default", 543 - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 544 - "type": "github" 545 - }, 546 - "original": { 547 - "owner": "nix-systems", 548 - "repo": "default", 549 375 "type": "github" 550 376 } 551 377 },
+2
flake.nix
··· 68 68 { 69 69 home-manager.useGlobalPkgs = true; 70 70 home-manager.useUserPackages = true; 71 + home-manager.extraSpecialArgs = { isDarwin = false; }; 71 72 home-manager.sharedModules = sharedHMModules ++ [ 72 73 plasma-manager.homeModules.plasma-manager 73 74 ]; ··· 89 90 { 90 91 home-manager.useGlobalPkgs = true; 91 92 home-manager.useUserPackages = true; 93 + home-manager.extraSpecialArgs = { isDarwin = true; }; 92 94 home-manager.sharedModules = sharedHMModules ++ [ 93 95 mac-app-util.homeManagerModules.default 94 96 ];
+5 -2
home/default.nix
··· 1 1 # Home-manager configuration — all hosts. 2 2 # 3 3 # Access system-level options via `osConfig.myConfig.*`. 4 - # Platform detection uses `pkgs.stdenv.isDarwin` — no flags passed as args. 4 + # Platform detection: `isDarwin` is passed via extraSpecialArgs in flake.nix. 5 5 { 6 6 config, 7 7 pkgs, 8 8 lib, 9 9 osConfig, 10 + isDarwin, 10 11 ... 11 12 }: 12 13 let 13 14 cfg = osConfig.myConfig; 14 - isDarwin = pkgs.stdenv.isDarwin; 15 15 16 16 # Custom scripts from home/scripts/ — available on PATH on both platforms. 17 17 myScripts = pkgs.stdenv.mkDerivation { ··· 129 129 }; 130 130 131 131 # ── Encrypted secrets (sops-nix) ───────────────────────────────────────── 132 + # Tell the home-manager sops module to decrypt using the host's SSH ed25519 133 + # key as an age key — same source as the system-level sops in common.nix. 134 + sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; 132 135 sops.secrets = lib.mkMerge [ 133 136 (lib.mkIf cfg.secrets.docker.enable { 134 137 "docker-config" = {
+2 -2
modules/options.nix
··· 388 388 secrets = { 389 389 docker.enable = mkOption { 390 390 type = bool; 391 - default = true; 391 + default = false; 392 392 }; 393 393 claude.enable = mkOption { 394 394 type = bool; 395 - default = true; 395 + default = false; 396 396 }; 397 397 duckdns.enable = mkOption { 398 398 type = bool;
+9 -3
scripts/diagnose-macos-apps.sh
··· 7 7 8 8 # Get list of Homebrew casks from nix config 9 9 CONFIG_DIR="$HOME/.config/nix-config" 10 - CASKS_FILE="$CONFIG_DIR/settings/config/darwin.nix" 10 + CASKS_FILE="$CONFIG_DIR/modules/options.nix" 11 11 12 - # Extract cask list from config 12 + # Extract cask list from modules/options.nix (darwin.homebrew.casks default list) 13 13 echo "Reading cask list from config..." 14 - CASKS=$(grep -A 50 'casks = \[' "$CASKS_FILE" | grep '"' | grep -v '^\s*#' | sed 's/.*"\(.*\)".*/\1/') 14 + CASKS=$(awk ' 15 + /homebrew = \{/ { in_hb=1 } 16 + in_hb && /casks = mkOption/ { in_casks=1 } 17 + in_casks && /default = \[/ { in_list=1; next } 18 + in_list && /\];/ { exit } 19 + in_list && /"/ { gsub(/[[:space:]]*"/, ""); gsub(/".*/, ""); if (length > 0) print } 20 + ' "$CASKS_FILE") 15 21 16 22 echo "" 17 23 echo "Found casks in config:"
+9 -3
scripts/fix-macos-apps.sh
··· 12 12 NC='\033[0m' # No Color 13 13 14 14 CONFIG_DIR="$HOME/.config/nix-config" 15 - CASKS_FILE="$CONFIG_DIR/settings/config/darwin.nix" 15 + CASKS_FILE="$CONFIG_DIR/modules/options.nix" 16 16 17 - # Extract cask list 18 - CASKS=$(grep -A 50 'casks = \[' "$CASKS_FILE" | grep '"' | grep -v '^\s*#' | sed 's/.*"\(.*\)".*/\1/') 17 + # Extract cask list from modules/options.nix (darwin.homebrew.casks default list) 18 + CASKS=$(awk ' 19 + /homebrew = \{/ { in_hb=1 } 20 + in_hb && /casks = mkOption/ { in_casks=1 } 21 + in_casks && /default = \[/ { in_list=1; next } 22 + in_list && /\];/ { exit } 23 + in_list && /"/ { gsub(/[[:space:]]*"/, ""); gsub(/".*/, ""); if (length > 0) print } 24 + ' "$CASKS_FILE") 19 25 20 26 echo "Checking all Homebrew cask apps from config..." 21 27 echo ""
+182 -120
scripts/pds-matrix-setup.sh
··· 1 1 #!/usr/bin/env bash 2 2 ################################################################################ 3 - # unified-setup.sh — Combined Matrix + PDS + Cloudflare Setup 3 + # pds-matrix-setup.sh — PDS + Matrix + Cloudflare tunnel initial setup 4 + # 5 + # Encrypts secrets with sops (age backend), creates the Cloudflare tunnel, 6 + # configures DNS, and pushes the Matrix .well-known delegation files. 7 + # 8 + # Prerequisites: 9 + # - age key at ~/.config/age/keys.txt (run: age-keygen -o ~/.config/age/keys.txt) 10 + # - .sops.yaml at repo root with your age pubkey already set 11 + # - cloudflared, pwgen, openssl, jq, curl in PATH (or installable via nix run) 12 + # 13 + # Usage: 14 + # ./scripts/pds-matrix-setup.sh # full run 15 + # ./scripts/pds-matrix-setup.sh --resume # skip steps whose output files exist 16 + # ./scripts/pds-matrix-setup.sh --force-tunnel # delete + recreate CF tunnel 4 17 ################################################################################ 5 18 set -euo pipefail 6 19 7 - # ── Colour helpers ──────────────────────────────────────────────────────────── 20 + # ── Colour helpers ───────────────────────────────────────────────────────────── 8 21 BOLD=$'\e[1m'; DIM=$'\e[2m'; GREEN=$'\e[32m' 9 22 YELLOW=$'\e[33m'; RED=$'\e[31m'; CYAN=$'\e[36m'; RESET=$'\e[0m' 23 + NC=$RESET 10 24 11 - log() { echo; echo "${BOLD}${CYAN}==> $*${RESET}"; } 12 - ok() { echo "${GREEN} ✓${RESET} $*"; } 13 - warn() { echo "${YELLOW} ⚠${RESET} $*"; } 14 - fail() { echo "${RED} ✗${RESET} $*" >&2; exit 1; } 15 - log_step() { echo -e "${CYAN}[STEP]${NC} $*"; } 25 + log() { echo; echo "${BOLD}${CYAN}==> $*${RESET}"; } 26 + ok() { echo "${GREEN} ✓${RESET} $*"; } 27 + warn() { echo "${YELLOW} ⚠${RESET} $*"; } 28 + fail() { echo "${RED} ✗${RESET} $*" >&2; exit 1; } 16 29 17 - # ── Configuration & Paths ───────────────────────────────────────────────────── 18 - ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" 19 - CONFIG_DIR="$HOME/.config/nix-config" 20 - SECRETS_FILE="$ROOT/secrets/secrets.nix" 21 - SECRETS_DIR="$ROOT/secrets/age" 30 + # ── Configuration ────────────────────────────────────────────────────────────── 31 + ROOT="$(git rev-parse --show-toplevel 2>/dev/null || echo "$HOME/.config/nix-config")" 32 + SECRETS_DIR="$ROOT/secrets" 22 33 AGE_KEY="$HOME/.config/age/keys.txt" 23 34 WEBSITE_DIR="$HOME/Developer/Git/GitHub/ewanc26/website" 24 35 DOMAIN="ewancroft.uk" 25 36 37 + # sops needs to find the age private key for decryption. 38 + # The public key is already in .sops.yaml for encryption. 39 + export SOPS_AGE_KEY_FILE="$AGE_KEY" 40 + 26 41 # Flags 27 42 RESUME=false 28 43 FORCE_TUNNEL=false 29 - 30 44 for arg in "$@"; do case "$arg" in 31 - --resume) RESUME=true ;; 45 + --resume) RESUME=true ;; 32 46 --force-tunnel) FORCE_TUNNEL=true ;; 33 47 esac; done 34 48 35 - # ── Helpers ─────────────────────────────────────────────────────────────────── 49 + # ── Helpers ──────────────────────────────────────────────────────────────────── 36 50 run_cmd() { 37 51 local cmd="$1"; shift 38 - if command -v "$cmd" &> /dev/null; then "$cmd" "$@" 52 + if command -v "$cmd" &>/dev/null; then 53 + "$cmd" "$@" 39 54 else 40 55 case "$cmd" in 41 56 cloudflared) nix run nixpkgs#cloudflared -- "$@" ;; 42 - pwgen) nix run nixpkgs#pwgen -- "$@" ;; 43 - age) nix run nixpkgs#age -- "$@" ;; 44 - ragenix) nix run github:yaxitech/ragenix -- "$@" ;; 45 - *) fail "Command $cmd not found." ;; 57 + pwgen) nix run nixpkgs#pwgen -- "$@" ;; 58 + sops) nix run nixpkgs#sops -- "$@" ;; 59 + *) fail "Command '$cmd' not found and no nix fallback configured." ;; 46 60 esac 47 61 fi 48 62 } 49 63 50 - sedi() { if [[ "$(uname -s)" == Darwin ]]; then sed -i '' "$@"; else sed -i "$@"; fi; } 51 - 52 - ensure_secrets_rules() { 53 - log "Verifying Ragenix rules..." 54 - # 1. Ensure matrixKeys block 55 - if ! grep -q "matrixKeys =" "$SECRETS_FILE"; then 56 - sedi "/in/i\\ 57 - matrixKeys = [ users.ewan ];" "$SECRETS_FILE" 58 - fi 59 - # 2. Add required rules 60 - local rules=( 61 - "\"age/matrix.env.age\".publicKeys = matrixKeys;" 62 - "\"age/pds.env.age\".publicKeys = pdsKeys;" 63 - "\"age/cf-tunnel.json.age\".publicKeys = matrixKeys;" 64 - "\"age/cloudflare.token.age\".publicKeys = matrixKeys;" 65 - ) 66 - for rule in "${rules[@]}"; do 67 - local key=$(echo "$rule" | cut -d'"' -f2) 68 - if ! grep -q "$key" "$SECRETS_FILE"; then 69 - sedi "/^}/i\\ 70 - $rule" "$SECRETS_FILE" 71 - fi 72 - done 64 + sops_encrypt_binary() { 65 + # Encrypt a plaintext file as a sops binary secret. 66 + # Usage: sops_encrypt_binary <plaintext-tmpfile> <output-secrets-path> 67 + local src="$1" dst="$2" 68 + # sops resolves key groups from .sops.yaml based on the output path. 69 + # We pass --output so sops writes directly and uses the path for rule matching. 70 + cd "$ROOT" 71 + run_cmd sops --encrypt --input-type binary --output-type binary \ 72 + --output "$dst" "$src" 73 + ok "Encrypted → $dst" 73 74 } 74 75 75 - # ── Step 0: Cloudflare Credentials (Auto-Vault) ─────────────────────────────── 76 + # ── Step 0: Cloudflare credentials ───────────────────────────────────────────── 77 + # The CF token is stored encrypted as secrets/cloudflare.token (binary sops secret). 76 78 load_cf_creds() { 77 - local token_age="$SECRETS_DIR/cloudflare.token.age" 78 - if [[ -f "$token_age" ]]; then 79 - log "Decrypting Cloudflare credentials..." 80 - local decrypted=$(run_cmd age -d -i "$AGE_KEY" "$token_age") 79 + log "Step 0: Cloudflare credentials" 80 + local token_file="$SECRETS_DIR/cloudflare.token" 81 + 82 + if [[ -f "$token_file" ]]; then 83 + ok "Found encrypted credentials at $token_file" 84 + local decrypted 85 + decrypted=$(run_cmd sops --decrypt --input-type binary --output-type binary "$token_file") 81 86 export CF_TOKEN=$(echo "$decrypted" | awk '{print $1}') 82 - export CF_ZONE=$(echo "$decrypted" | awk '{print $2}') 87 + export CF_ZONE=$(echo "$decrypted" | awk '{print $2}') 83 88 else 84 - warn "Cloudflare credentials not found in vault." 89 + warn "No cloudflare.token secret found — prompting for credentials." 85 90 read -rp " Enter CF API Token: " CF_TOKEN 86 91 read -rp " Enter CF Zone ID: " CF_ZONE 87 - ensure_secrets_rules 88 - local tmp=$(mktemp) 92 + export CF_TOKEN CF_ZONE 93 + 94 + # Encrypt and store 95 + local tmp 96 + tmp=$(mktemp) 89 97 echo "$CF_TOKEN $CF_ZONE" > "$tmp" 90 - cd "$ROOT" 91 - EDITOR="cp $tmp" run_cmd ragenix --rules "secrets/secrets.nix" --identity "$AGE_KEY" -e "secrets/age/cloudflare.token.age" 98 + sops_encrypt_binary "$tmp" "$SECRETS_DIR/cloudflare.token" 92 99 rm "$tmp" 93 100 fi 101 + ok "Cloudflare credentials loaded." 94 102 } 95 103 96 - # ── Step 1: PDS Secrets ─────────────────────────────────────────────────────── 104 + # ── Step 1: PDS secrets ──────────────────────────────────────────────────────── 97 105 step_pds_secrets() { 98 - log "Step 1: PDS Secrets (pds.env.age)" 99 - if [[ -f "$SECRETS_DIR/pds.env.age" ]] && [[ "$RESUME" == true ]]; then ok "Skipping PDS secrets"; return 0; fi 100 - 101 - local jwt=$(openssl rand --hex 16) 102 - local admin=$(openssl rand --hex 16) 103 - 104 - local tmp=$(mktemp) 105 - echo "PDS_JWT_SECRET=$jwt" > "$tmp" 106 - echo "PDS_ADMIN_PASSWORD=$admin" >> "$tmp" 107 - 108 - cd "$ROOT" 109 - EDITOR="cp $tmp" run_cmd ragenix --rules "secrets/secrets.nix" --identity "$AGE_KEY" -e "secrets/age/pds.env.age" 106 + log "Step 1: PDS secrets (secrets/pds.env)" 107 + local dst="$SECRETS_DIR/pds.env" 108 + if [[ -f "$dst" ]] && [[ "$RESUME" == true ]]; then ok "Skipping (exists)"; return 0; fi 109 + 110 + local jwt admin tmp 111 + jwt=$(openssl rand --hex 16) 112 + admin=$(openssl rand --hex 16) 113 + 114 + tmp=$(mktemp) 115 + printf "PDS_JWT_SECRET=%s\nPDS_ADMIN_PASSWORD=%s\n" "$jwt" "$admin" > "$tmp" 116 + sops_encrypt_binary "$tmp" "$dst" 110 117 rm "$tmp" 111 - ok "PDS secrets encrypted. Admin Password: $admin" 118 + 119 + ok "PDS secrets encrypted. Admin password: ${BOLD}${admin}${RESET} (save this!)" 112 120 } 113 121 114 - # ── Step 2: Matrix Secrets ──────────────────────────────────────────────────── 122 + # ── Step 2: Matrix secrets ───────────────────────────────────────────────────── 115 123 step_matrix_secrets() { 116 - log "Step 2: Matrix Secrets (matrix.env.age)" 117 - if [[ -f "$SECRETS_DIR/matrix.env.age" ]] && [[ "$RESUME" == true ]]; then ok "Skipping Matrix secrets"; return 0; fi 124 + log "Step 2: Matrix secrets (secrets/matrix.env)" 125 + local dst="$SECRETS_DIR/matrix.env" 126 + if [[ -f "$dst" ]] && [[ "$RESUME" == true ]]; then ok "Skipping (exists)"; return 0; fi 118 127 119 - local reg=$(run_cmd pwgen -s 64 1) 120 - local mac=$(run_cmd pwgen -s 64 1) 121 - 122 - local tmp=$(mktemp) 123 - echo "REGISTRATION_SHARED_SECRET=$reg" > "$tmp" 124 - echo "MACAROON_SECRET_KEY=$mac" >> "$tmp" 125 - 126 - cd "$ROOT" 127 - EDITOR="cp $tmp" run_cmd ragenix --rules "secrets/secrets.nix" --identity "$AGE_KEY" -e "secrets/age/matrix.env.age" 128 + local reg mac tmp 129 + reg=$(run_cmd pwgen -s 64 1) 130 + mac=$(run_cmd pwgen -s 64 1) 131 + 132 + tmp=$(mktemp) 133 + printf "REGISTRATION_SHARED_SECRET=%s\nMACAROON_SECRET_KEY=%s\n" "$reg" "$mac" > "$tmp" 134 + sops_encrypt_binary "$tmp" "$dst" 128 135 rm "$tmp" 136 + 129 137 ok "Matrix secrets encrypted." 130 138 } 131 139 132 - # ── Step 3: Tunnel Setup ────────────────────────────────────────────────────── 140 + # ── Step 3: Cloudflare tunnel ────────────────────────────────────────────────── 133 141 step_tunnel() { 134 - log "Step 3: Cloudflare Tunnel (shared)" 135 - ensure_secrets_rules 136 - 137 - local uuid=$(run_cmd cloudflared tunnel list | grep "server" | awk '{print $1}' || echo "") 138 - 142 + log "Step 3: Cloudflare tunnel (shared for all services)" 143 + local dst="$SECRETS_DIR/cf-tunnel.json" 144 + 145 + local uuid 146 + uuid=$(run_cmd cloudflared tunnel list 2>/dev/null | awk '/server/{print $1}' || true) 147 + 139 148 if [[ -z "$uuid" ]] || [[ "$FORCE_TUNNEL" == true ]]; then 140 - [[ -n "$uuid" ]] && run_cmd cloudflared tunnel delete -f "$uuid" 141 - log "Creating new tunnel 'server'..." 142 - local output=$(run_cmd cloudflared tunnel create server 2>&1 || true) 149 + if [[ -n "$uuid" ]]; then 150 + warn "Deleting existing 'server' tunnel: $uuid" 151 + run_cmd cloudflared tunnel delete -f "$uuid" || true 152 + fi 153 + log "Creating new tunnel 'server'…" 154 + local output 155 + output=$(run_cmd cloudflared tunnel create server 2>&1) 143 156 uuid=$(echo "$output" | grep -oE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' | head -1) 157 + [[ -n "$uuid" ]] || fail "Could not parse tunnel UUID from cloudflared output." 144 158 fi 145 - 159 + 146 160 local creds="$HOME/.cloudflared/$uuid.json" 147 161 if [[ -f "$creds" ]]; then 148 - cd "$ROOT" 149 - EDITOR="cp $creds" run_cmd ragenix --rules "secrets/secrets.nix" --identity "$AGE_KEY" -e "secrets/age/cf-tunnel.json.age" 162 + sops_encrypt_binary "$creds" "$dst" 163 + ok "Tunnel credentials encrypted → $dst" 164 + else 165 + warn "Credentials file $creds not found — did cloudflared tunnel create succeed?" 150 166 fi 151 167 152 - # Update tunnelId in BOTH configs if they exist 153 - [[ -f "$ROOT/settings/config/cloudflare.nix" ]] && sedi "s|tunnelId = \".*\";|tunnelId = \"$uuid\";|" "$ROOT/settings/config/cloudflare.nix" 154 - [[ -f "$ROOT/settings/config/pds.nix" ]] && sedi "s|tunnelId = \".*\";|tunnelId = \"$uuid\";|" "$ROOT/settings/config/pds.nix" 155 - 168 + # Update tunnelId default in modules/options.nix 169 + local opts="$ROOT/modules/options.nix" 170 + if [[ -f "$opts" ]]; then 171 + if [[ "$(uname -s)" == Darwin ]]; then 172 + sed -i '' "s|default = \"[0-9a-f-]*\"; *# *tunnelId\|tunnelId.*default = \"[0-9a-f-]*\"|default = \"$uuid\"|g" "$opts" 2>/dev/null || true 173 + # More targeted: find the tunnelId mkOption block and update its default 174 + sed -i '' "/tunnelId/,/};/{s/default = \"[^\"]*\";/default = \"$uuid\";/}" "$opts" 175 + else 176 + sed -i "/tunnelId/,/};/{s/default = \"[^\"]*\";/default = \"$uuid\";/}" "$opts" 177 + fi 178 + ok "Updated tunnelId in modules/options.nix → $uuid" 179 + fi 180 + 156 181 export TUNNEL_UUID="$uuid" 157 - ok "Tunnel configured: $uuid" 182 + ok "Tunnel UUID: $uuid" 158 183 } 159 184 160 - # ── Step 4: DNS Automation ──────────────────────────────────────────────────── 185 + # ── Step 4: DNS records ──────────────────────────────────────────────────────── 161 186 step_dns() { 162 - log "Step 4: Cloudflare DNS Records" 163 - for sub in "matrix" "pds"; do 164 - log " Setting $sub.$DOMAIN -> $TUNNEL_UUID" 165 - curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE/dns_records" \ 187 + log "Step 4: Cloudflare DNS CNAME records" 188 + for sub in git matrix pds; do 189 + echo " Setting $sub.$DOMAIN → $TUNNEL_UUID.cfargotunnel.com" 190 + local result 191 + result=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE/dns_records" \ 166 192 -H "Authorization: Bearer $CF_TOKEN" \ 167 193 -H "Content-Type: application/json" \ 168 - -d "{\"type\":\"CNAME\",\"name\":\"$sub\",\"content\":\"$TUNNEL_UUID.cfargotunnel.com\",\"proxied\":true}" | grep -q "success" || warn "$sub record already exists." 194 + -d "{\"type\":\"CNAME\",\"name\":\"$sub\",\"content\":\"$TUNNEL_UUID.cfargotunnel.com\",\"proxied\":true}" 2>&1) 195 + if echo "$result" | grep -q '"success":true'; then 196 + ok " $sub.$DOMAIN created" 197 + else 198 + warn " $sub.$DOMAIN may already exist or failed: $(echo "$result" | grep -o '"message":"[^"]*"' | head -1)" 199 + fi 169 200 done 170 201 } 171 202 172 - # ── Step 5: Website Well-Known ──────────────────────────────────────────────── 203 + # ── Step 5: Matrix .well-known delegation ────────────────────────────────────── 173 204 step_wellknown() { 174 - log "Step 5: Matrix Delegation (.well-known)" 175 - if [[ ! -d "$WEBSITE_DIR" ]]; then warn "Website dir not found, skipping Step 5"; return 0; fi 176 - 205 + log "Step 5: Matrix .well-known delegation files" 206 + if [[ ! -d "$WEBSITE_DIR" ]]; then 207 + warn "Website directory not found ($WEBSITE_DIR) — skipping." 208 + return 0 209 + fi 210 + 177 211 local wk="$WEBSITE_DIR/static/.well-known/matrix" 178 212 mkdir -p "$wk" 179 213 echo '{"m.server":"matrix.ewancroft.uk:443"}' > "$wk/server" 180 214 echo '{"m.homeserver":{"base_url":"https://matrix.ewancroft.uk"}}' > "$wk/client" 181 - 215 + 182 216 cd "$WEBSITE_DIR" 183 - git add . && git commit -m "docs: matrix delegation" && git push || true 184 - ok "Well-known files pushed to website repository." 217 + git add . && git commit -m "docs: add Matrix .well-known delegation" && git push || true 218 + ok "Well-known files pushed." 219 + } 220 + 221 + # ── Forgejo secrets (optional, run separately if needed) ───────────────────── 222 + step_forgejo_secrets() { 223 + log "Forgejo secrets (secrets/forgejo.env)" 224 + local dst="$SECRETS_DIR/forgejo.env" 225 + if [[ -f "$dst" ]] && [[ "$RESUME" == true ]]; then ok "Skipping (exists)"; return 0; fi 226 + 227 + local secret_key internal_token tmp 228 + secret_key=$(openssl rand -hex 32) 229 + internal_token=$(openssl rand -hex 32) 230 + 231 + tmp=$(mktemp) 232 + printf "SECRET_KEY=%s\nINTERNAL_TOKEN=%s\n" "$secret_key" "$internal_token" > "$tmp" 233 + sops_encrypt_binary "$tmp" "$dst" 234 + rm "$tmp" 235 + ok "Forgejo secrets encrypted." 185 236 } 186 237 187 - # ── Execution ───────────────────────────────────────────────────────────────── 238 + # ── Main ─────────────────────────────────────────────────────────────────────── 188 239 main() { 240 + echo "${BOLD}${CYAN}" 241 + echo " ┌────────────────────────────────────────┐" 242 + echo " │ PDS + Matrix + Cloudflare Setup │" 243 + echo " └────────────────────────────────────────┘" 244 + echo "${RESET}" 245 + 246 + [[ -f "$AGE_KEY" ]] || fail "Age key not found at $AGE_KEY. Run: age-keygen -o $AGE_KEY" 247 + 189 248 load_cf_creds 190 249 step_pds_secrets 191 250 step_matrix_secrets 192 251 step_tunnel 193 252 step_dns 194 253 step_wellknown 195 - 196 - log "Final Rekeying..." 197 - cd "$ROOT" 198 - run_cmd ragenix --rules "secrets/secrets.nix" --identity "$AGE_KEY" -r 199 - 200 - echo -e "\n${BOLD}${GREEN}Deployment Ready!${RESET}" 201 - echo "1. Git add and push your nix-config." 202 - echo "2. On the server: nixos-rebuild switch --flake .#server" 254 + 255 + echo 256 + echo "${BOLD}${GREEN}✨ Setup complete!${RESET}" 257 + echo 258 + echo "Next steps:" 259 + echo " 1. Review modules/options.nix — verify tunnelId was updated correctly" 260 + echo " 2. Commit and push: git add -A && git commit -m 'chore: initial server secrets setup'" 261 + echo " 3. On server: sudo nixos-rebuild switch --flake .#server" 262 + echo 263 + echo "To also set up Forgejo secrets:" 264 + echo " source this script and call: step_forgejo_secrets" 203 265 } 204 266 205 - main 267 + main
-13
secrets/age/cf-tunnel.json.age
··· 1 - -----BEGIN AGE ENCRYPTED FILE----- 2 - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxQ2Y2MTlTQ1NmWnN5YklM 3 - Wnhwd01OOWpyVTB2TytOVzRVQStReVhqZXpvCklFKzQrNVdEOU40cmNIMVBUQVA3 4 - UGZpc0xNd1hlZnprNlF2ZGtIRkp3SzgKLT4gLmx6Yi1ncmVhc2UKNm83ZWVYYzRh 5 - ZW5pZ3YrbHRWZWxpbTQvS0tiSTFMOUJSK2RjUWdTbUU5WFhkalJKdWFCaEVxUU9G 6 - SllSWEdnZAo1c3Q3RjYwbDAwbXNXc0N2czNiNHY4Tk5RbUQxWHVpS0FQZE82T1kw 7 - bTZUTkVvMXIKLS0tIDcydFBJNDhyZ1hlSC9JLzI4cStNeW90MjUzc052dkhSam9L 8 - LzhUV1dyTXMK5piN4PHMJDQK20ChEWcU2jBhMdRlY0Bgvyz6pRXDuaW2Y5wJ9cnV 9 - IzNCmoCfDjP0pb2tq/vonOGDBaYY8hl67BvhMCoCR4MIq9TVN10rADlBCxlfwNOu 10 - qQymCv3S0GWPhUhTiapZrspoonW1p2SngTZZIYjr99woVHy3zuJhWgddFFdHFTOv 11 - h0htUdr7AuWcIfn/zf2DcR20jq5z88olCarVXcI1yDToM5ZbZIR4PASidoQ8EtgI 12 - n/6xeetl7kj9ulpSRMm6Jn0JlzRMABQT 13 - -----END AGE ENCRYPTED FILE-----
-815
secrets/age/claude.json.age
··· 1 - -----BEGIN AGE ENCRYPTED FILE----- 2 - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3TVZQNU8yQ05VM09SeTdD 3 - SmJEZitvR21UbU5tRkNCU1NndzYxcnBOdkVvCi9hZCtqcW91M0NXSVc5bFhpdysw 4 - S2hEMTRIUm9oMmxmaktKdkdyRXRQcWMKLT4gWDI1NTE5IDljSjlTK3c0NVphMDVK 5 - dWd6ZkxSYWpZSW9VUlFGUnhNZktJalVqbktEUkUKZ3pHVThMVVQyRm4vVmwvb1Nj 6 - ZGZyTVUyQzFKemZWalA4ajNpalJVaGx4awotPiBYMjU1MTkgUTZiL0pFbUo2L1Ns 7 - ekF0Q0FaRFpaMnVMRFhZYkgzcVpQL3pobjFvTTZtTQo3bUdxRjlnNnFGOEpmMFo1 8 - ZklxQzljd3RSQ0EzVEcwZnVlbGprVktKVFJVCi0+IGpzUGktZ3JlYXNlCjc3OVBs 9 - Ri9LMWI5Q2RRCi0tLSB4UDBDaG1xbFVaRXZsY2wvQzRxaGhyLytadzEyL0N2L3FX 10 - Z0xDOFdteXlzCsaRZKBDrVTmHl3Nxknk5lrt3+2WEoFwn6VmTYI1AsScrT3T80YG 11 - ym7rwVy3VBc5S4JsAuGysw8kPbTYhNLHEGgu0d64/sbCmbfeU/+zpIEKrLYqU8n0 12 - Re/NbF8FkqnP7ILP9iREkfBnLmOBPS8v08AlFtJj78ODodyEperwHDNngUrAUjY9 13 - lCKAItQPd2WaQGhMi3mMasUcy3Pct/dFG4fKOOW8ZqRz1PRycDWJridLLu1uHdQ8 14 - ppnqjLYrRLRcCpOG+IBakzvpuZvfN/1HeP/QVL1nlaR26YkLCiVY/BFdDedwuCl1 15 - LOZgg2OzcUReH1mdeKHS8GwkpFfV9QyU8Tr/WAV5dZrLpIZEcBAZL3ORyITDeT/G 16 - OlPPRgxaAegnxJ3nZFUuakYE5adVUmyWyFSfFJXcfBcnfaevNGGZZiI4LZQ/KZtK 17 - VmjkzIyNaJKTg70XOVJPWBVOyBjeLyWhkunY1zj26bP872t1tHfpC1Lb5vmK22Ij 18 - UjBFK1G4QcNBtl7ghyrUZT+yQJUra2SYRhkajH0p9mTHvPsFTQaGt9ae7YmqwbqK 19 - R4sO5OFM2Mt+AioEgSl6OqMhqg5bb52xayKBTsTsYyadBCmVlA5hkn7ov4v37KtZ 20 - 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 814 - VnaDo1CZ6oZo4IQ= 815 - -----END AGE ENCRYPTED FILE-----
-11
secrets/age/cloudflare.token.age
··· 1 - -----BEGIN AGE ENCRYPTED FILE----- 2 - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpMythQzZ2MnM5ZUJ3SjF6 3 - Wk15T1NpbStLLzZqYUFyelpMWkREOUdRVVQ0CmZyRVhTTFNRdkFNalpMbHhKNUlG 4 - clFUaWJzbFovWU00MWdZQW83TnYvWDgKLT4gKG1EcitNakMtZ3JlYXNlIFh9TCB4 5 - IHEwLFVYCkxyRG81NzkrM3paY1VNRGVRK0tXUzRnajJzTVhESm8wS1MyYmtHcHV3 6 - dzVYVTZGRGE3ZnpmUjFDNCszcHBvMVAKWGxxRTdiNkl6MDMrdjFhS3Z1a0toQQot 7 - LS0gSU80S3QzbTUvbEo0K1VCZHFnV1R1Q3VGWWN1QmhKQnVqMjBXeURveFBCawrC 8 - cMAkGky/kmfBo/eUFTBGGpE9PXUXPJgugxHhNyluSXwXc31LbTU/QBEuCZNhS9Bj 9 - xvwioVCwI9+2NwEKTRJ8MrRs1i1s8jWl2WFiPG5Hsqu0j9FJvLi1nYqCxMmJRSDJ 10 - /aV6NHnUI6iR 11 - -----END AGE ENCRYPTED FILE-----
-15
secrets/age/docker-config.json.age
··· 1 - -----BEGIN AGE ENCRYPTED FILE----- 2 - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPakd2bzJkTDNiZHlabTF2 3 - Q1Jzc1dpbm1IQ3hzRWwzeVJsTE1VMm54SEI0CjUycDNGRVh2MTJzeTRScy9EclBN 4 - VUJnQ3B3aXh2ejEzaTZaRGZJekJjMWcKLT4gWDI1NTE5IDZSRlI3eE9BaTRCcjly 5 - WUU3djZ1WHJHNkt5V1hiN0pBNHd2andJdU8rWFUKQjR5QzcwQ1EyZ1NleGcwTXd6 6 - QWlmWXVyWVJEQjU0UkVzYXYrdTVDMWd0ZwotPiBYMjU1MTkgbktJbytaUnJOOXlB 7 - ZlFOcDRCbEtNYnZYdTA1em1WNDRrbjlFa2c4Z3R6dwpyb2xYV2hYSFZ0Z09QRFZq 8 - SGd1SzhXVktncnRDVW96dy9pNUJXeER3RDh3Ci0+IFFEdD5PLWdyZWFzZSBfYShO 9 - J2t4MSBKVzpeIiBfMkZhLFUKbzE5bktNNkxQSFU0bjJXcURiM1RFRFZZc1pZL2Rt 10 - REZyUkZUYndqT0ZQN091cVdUNkZCRXdDbzlGbldHYWFiRAo4b0EKLS0tIHpJeXdX 11 - cEtIVHVob3lITXlWNGJaR1VVc3QwS1hTcGxtNWZDS0h2blpib3cKSPNmi3CriPtt 12 - JTvDuset5CgUv09FseAyLEYgE/byZn+P66qIs4Q2DPDa1BP6ts10+xFZWt9ANpPw 13 - cTyg5uW5Q3nUWVCo9q/UMClay7pMbA9Rv3xAZ3M3MWKfxzP3XMaQzQdic1ywwQ4q 14 - JGAcZw== 15 - -----END AGE ENCRYPTED FILE-----
-18
secrets/age/duckdns.tar.gz.age
··· 1 - -----BEGIN AGE ENCRYPTED FILE----- 2 - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqdzRSd1ExTDhRT2F0T09E 3 - Uy9lTHhkY3Y3eVExOEl2TytSV1ArUEhtK1R3CllRa0RUR09vaEppVkNUQ2Fxd0pG 4 - WE16cG9VUWNRSXFENFNDZENMMFN3UWsKLT4gWDI1NTE5IEZXWGRscGE5cEpIb3M0 5 - aUx4aDluRVVGcmVkdVV1UnZ1UmVwQXliSWdQVm8KSHNhTEVoZ2c2V3FnUTdqdnVm 6 - b3hOUi9BYmMyMkYvbkdyL2xyNmU5bUdRZwotPiBYMjU1MTkgUWNNS2kxYXFmU0lp 7 - bm1CUzYxZFlEVnRCSjlkLzJPZW16aitkeHY0cTNrMAp3Z3RXWUVlSGZXSHJPTDZM 8 - VGd2QysvZWg4VjkrTzIvT2VBTWtRVUlsWHF3Ci0+IFlBW2ItZ3JlYXNlIFprSCBq 9 - IGgjICcKY0EyczRHYmFwdzVDTmlPTkY5N3JtbFpsZm02R1ZZWWl4MjNQRTA4VzJp 10 - K01QOGpwR1h0Y1VadU9leUR4bkQ3QwovTXFSOWVEUURjeUNjaVcwRmMxR1YrV0h3 11 - ejlwOHRPRWdhTGpSOE5ROUZodUU1RWo3K09hZzhTTjR3Ci0tLSA0WnM3YVJTelg5 12 - SmhIVDNRS09KUmVJM1VlL1U1WjJzYTBFNXpBUjBiRVJJCqm/0uyXwhkvkTp9tAXz 13 - 0W0pD6OVeaUZmOhNsGqTx0S79t07XH86MmxmkOWos62bia8gG6C9e7UWKUq9DFIT 14 - +PoXawlFZfQn8uqRTakAHHmZx+91suYiXglpaqwjKpPIRdQVZCI9vOhImD4BGDCh 15 - EfwDP8an8GFII49Nid/7EMku5Z7fyM+tMyIAESxIB34MaVLvNQ/ClTJcMNRgOjUz 16 - 0XdLnBPqWHw51Bj5sfPF31ab8g7Ymw3MkBznXINuxMkOrfTwxwNPA+MD5I8Jrzid 17 - Aa3I/kJUOrLQpbFBML9xkGFa+PFDx2uaPSJcZ+3AYE1JghDoMQ== 18 - -----END AGE ENCRYPTED FILE-----
-11
secrets/age/forgejo.env.age
··· 1 - -----BEGIN AGE ENCRYPTED FILE----- 2 - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLT2VXUnBWM2FkbXYvQS84 3 - cisrdlVQdUk1SS9KVHMrOS9EVFljRGtCYXhRCjNQcHlHNDE1UDZqbmplNE9rayts 4 - U3lZU3BnWDlCYTQ2STh4Mm10Y1ZmL3cKLT4gOlJTfH1MLWdyZWFzZSAveV5eIVI5 5 - IFFud30ybHAKeWl4ME4wOFBjWGFkM3orU1Jxblh6bFo2OWtEN2hzcwotLS0gRVVw 6 - WUNTSnBEMXp3NW9wRGhjMm5NWUtrVk41TFJ2aFpOaS91a2E1VEJYMAqtqhWZHbb5 7 - +FgvtNZpOVZ48uGjetqn0rseyQtmsAp+os54/T4JSo0uP8R1Gfd2PWXHcAou9a6O 8 - Uuw1SBQTDoB/B91UcYj/Hc9KSt5Ouwtf/SoPzrH4SCZostdqvVnvKXcehdnqqkaQ 9 - AzPxsf7iI5CkcXjSEtVSZd7f5PisNfWR5oLauwv9s8rBovyIIeCIUgWegikYz3eg 10 - TuB2l+pwLYRkRh019i5gq/W6nRLUob/BGiA82pjXx1LlpiIEAA== 11 - -----END AGE ENCRYPTED FILE-----
-12
secrets/age/matrix.env.age
··· 1 - -----BEGIN AGE ENCRYPTED FILE----- 2 - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWMkgzSCt1UXpmRUN1ekJU 3 - ckN5bmJ0VXY2VHBFZnhqOEVIOThRR1dwY0RNCldGWnJzTFZBV0M1azVxbnMrYVht 4 - OGxQZ3V0cVhGamlXRXNjQlIrWkhhV1UKLT4geC1ncmVhc2UgJCpVUApkUUQ3QVVE 5 - b095VjMvSVFhNDhrK3FPYnBGdHZ1WFBheDRSM1hab2J4QTZjWlJ1emZmSFpYNzdP 6 - c3ZENnJkMStKCjkxUTJCTXc2N1ZzCi0tLSBmbng1Z1lybUluNkt5WHowWjFyLzZl 7 - RkxmMHVHV01zOVhIYWVpNHdZWWNzCj30yCYo9Ki46zqhJC/CJngoPq1Xl3/Hrr5R 8 - zLtMFbCA2Drl9xtotq2kdOI7BtCcQax9D67+5ad9PLKhInnJ7VLqqnuQ9bI2PFPk 9 - tsjNGRc5uhLcDUrY6IqsLpvn7cqwFe9nmO9Cbkskex2T6wZ0YPLnHJX9PhUa/ZWk 10 - JoM1NgbErgyrl2U8BWuazR/edZNQ8a6yyfPuVK6H7o5WUyERAWXbIgKzz0tDhPyC 11 - bGZ7shCyM+TLbiSGnnAtanNZIngLiwATH+6fm76B9Dm0QEfHmlYq 12 - -----END AGE ENCRYPTED FILE-----
-12
secrets/age/pds.env.age
··· 1 - -----BEGIN AGE ENCRYPTED FILE----- 2 - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBocnFzdUViVnd6dzlKWndD 3 - bjhJQmxhWEpQamVsUmRqekhQenhQWWV1OTJjCk9leEI5enc0ZDJVcnU3djlFOTF0 4 - OVpHSHlOUjVuaWlUNEVTMzVkQjhwcFEKLT4gK0M2KnRxRC8tZ3JlYXNlIFA6MH5r 5 - CkFJUUZobXhWYUpIQ2JMcHFNcFRJeW9hY2ZodGV5U2QvTVRXNWEyb2MxUGZqMDhp 6 - MDZsWG9WWFB4WjlmeGt0QmkKbmZqSDA2RHRvd3B6c285NWJuQlV1amZQU0xXU01I 7 - NWI0d2FWeGZHR0VMZU1qTTNjUTNySFNOMmRTN2xjQkp5RQp4QQotLS0gNDV6U2Qw 8 - THZldmRDYTdZek9KRUVhV3JFeHpYQ0RFT0dKWU80VEJGOXVXawqslWRtxF2LB2yJ 9 - 9qBcG2FLMqT46AHqrH+71MgFkpJsD0jh5K4sMRNPJUFIXUkuAi5z6x5tJ7IrcU5z 10 - hEaUBLJXxga+eGkdOe/xUaQ57Q3JtiDb02tzVAoER0AJQ8BZGVJO8JEiwPPo9GVs 11 - jRyUgCUL5ezt5cpQSWGWwgboxfQngNe4/+s= 12 - -----END AGE ENCRYPTED FILE-----
-13
secrets/age/ssh-passphrase.age
··· 1 - -----BEGIN AGE ENCRYPTED FILE----- 2 - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4WDF2SEVwRmNSMllIT055 3 - MzFrVkZwRFI4TkhYaEtOQWRFTGJIZi9hWjFnClNLNHpPNjFnWUVLOHNIcUZXYTFD 4 - K0RZOWpORTlUanU5VVIwVWh2MUc0QWsKLT4gWDI1NTE5IERYV3BkcVEzYysxbzFZ 5 - QnZPaStGaElFdG42R2o1QkVjczl2NXF6eDRDa1kKbG14Y3RkNHhEUHlVYlluOWQz 6 - ZitjZStmK3lkVEYrVURRSGt2SlhWMHV0RQotPiBYMjU1MTkgcjZMd1AyL24wYUl1 7 - d082K0crTElVSE54b0JRWlM0UUYvTkE3Mzczcll6NApaZysyV1J1cEJsVENjTy9t 8 - RUExbDZyRGdRQzdHSk9uQWJLUjNsVVpDM3hRCi0+ID9DRzpvLWdyZWFzZQpEVE9q 9 - N3BVY3ZmbDFHUjlEVVpTd2VRaU5UeWFuCi0tLSBWMEd2QzVRZGpVNXRUOXNweTdi 10 - QS9LUGlkSmZJd2MvRXlab3dYMUpFdHFRCiQxI2Onp5SAzKr0hHY2KMT3pTu0kTIW 11 - 5S3kC4fCa88S7RAnc5lMlOFwfwHrDwZgtk6uf1sgYLg/KTEq+7aPWt16rBkM8UOA 12 - AzCciwm1u80= 13 - -----END AGE ENCRYPTED FILE-----
-15
secrets/age/wifi-home.age
··· 1 - -----BEGIN AGE ENCRYPTED FILE----- 2 - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBKQ1U3TXA0Z2Rrb2I1RHVo 3 - VysrNnM1bTJSZWZZaEtXenpyUW5vYUhoQmkwCm5xcm5FemJrcjM3M1hmVldOZjN2 4 - SGE5ZWQxQk54dmRBbWZQdURvc3hhNUEKLT4gWDI1NTE5IFpYRnhEcTRyRElNQnRR 5 - SzUrNWZra3pEcVcyTlBTSmN6azRsc0F5dmNZUmcKVWxXOGpRTXlDZGVGam9sTUpE 6 - TU9jVnduNjloa2QvN0sveUozR0pFdktCSQotPiBYMjU1MTkgZ2wrTjJXVjU3NExL 7 - MWNjNWZJVFZZd3hsQkVIUmF3NFA2YzA4SVkwSkZTbwoxZ1RoT0pFZEwrYzNxYXAz 8 - d3c2MkpGa2NwRldzdlJGZ3BFa3RoRFpWTml3Ci0+IHd2cFBXfi1ncmVhc2UgQEgg 9 - d0FHVyo6Q0EKMFVDaWF2RGd6SXpjVzg1U1I2UlRPTHlnTi9oREdpeUtxUUl3MTdk 10 - OGhrYUN3bnAxdlhxV1ppajdCVmpJZU5IcQpDek9iRStxSmlNQnR5UVdXalFpM09s 11 - aUxpTXlERk1zCi0tLSBHa1RmbjB5d0k3MG1OVDZFZFpSZ084SjR4bkd5TWpTbXJR 12 - UTFGZ1FQcUZnCgjZ4VT45qmYDKsHTdmT9FuVEdYLBPgRYQ3HP0goRNngdGHkk3Rf 13 - 8VS8cNNQUpNGseqJetx4mC+oMnQhalxzDE2x4ivi3gG0IU/I+w5yuRRmaUHmBoMV 14 - 9G6EzgD7 15 - -----END AGE ENCRYPTED FILE-----
+2
secrets/cf-tunnel.json
··· 1 + # PLACEHOLDER — replace with: sops --encrypt --age <key> cf-tunnel.json > secrets/cf-tunnel.json 2 + # Source: cloudflared tunnel create server → ~/.cloudflared/<UUID>.json
+2
secrets/claude.json
··· 1 + # PLACEHOLDER — replace with: sops --encrypt --age <key> claude.json > secrets/claude.json 2 + # Source: ~/.claude.json (Claude API/app config)
+2
secrets/docker-config.json
··· 1 + # PLACEHOLDER — replace with: sops --encrypt --age <key> docker-config.json > secrets/docker-config.json 2 + # Source: ~/.docker/config.json (contains registry auth tokens)
+2
secrets/duckdns.tar.gz
··· 1 + # PLACEHOLDER — replace with: sops --encrypt --age <key> duckdns.tar.gz > secrets/duckdns.tar.gz 2 + # Source: tar -czf duckdns.tar.gz ~/.duckdns/ (DuckDNS credentials/config)
+4
secrets/forgejo.env
··· 1 + # PLACEHOLDER — replace with: sops --encrypt --age <key> forgejo.env > secrets/forgejo.env 2 + # Required keys: 3 + # SECRET_KEY=<openssl rand -hex 32> 4 + # INTERNAL_TOKEN=<openssl rand -hex 32>
+4
secrets/matrix.env
··· 1 + # PLACEHOLDER — replace with: sops --encrypt --age <key> matrix.env > secrets/matrix.env 2 + # Required keys: 3 + # REGISTRATION_SHARED_SECRET=<pwgen -s 64 1> 4 + # MACAROON_SECRET_KEY=<pwgen -s 64 1>
+7
secrets/pds.env
··· 1 + # PLACEHOLDER — replace with: sops --encrypt --age <key> pds.env > secrets/pds.env 2 + # Required keys: 3 + # PDS_JWT_SECRET=<openssl rand --hex 16> 4 + # PDS_ADMIN_PASSWORD=<openssl rand --hex 16> 5 + # PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX=<see atproto PDS docs> 6 + # PDS_EMAIL_SMTP_URL=<optional> 7 + # PDS_EMAIL_FROM_ADDRESS=<optional>
-1
tools/Cargo.toml
··· 6 6 [dependencies] 7 7 dialoguer = { version = "0.11", features = ["completion"] } 8 8 console = "0.15" 9 - regex = "1" 10 9 11 10 [lib] 12 11 name = "tools_common"
+277 -198
tools/src/bin/server-config.rs
··· 1 1 /// server-config — interactive configurator for the NixOS server settings. 2 2 /// 3 - /// Reads the current values from settings/config/{server,forgejo,matrix,pds,cloudflare}.nix, 4 - /// presents an interactive menu to change them, then writes the modified files back in-place. 3 + /// Reads defaults from modules/options.nix and host overrides from 4 + /// hosts/server/default.nix, then writes any changes back as 5 + /// `myConfig.X.Y = value;` override attributes in the host file. 6 + /// 7 + /// modules/options.nix is never modified — it is the canonical default source. 5 8 /// 6 9 /// Usage: 7 - /// nix run .#server-config # interactive (full menu) 8 - /// nix run .#server-config -- --show # print current config and exit 10 + /// nix run .#server-config # interactive (full menu) 11 + /// nix run .#server-config -- --show # print current config and exit 9 12 use console::Style; 10 13 use dialoguer::{theme::ColorfulTheme, Confirm, Input, MultiSelect, Select}; 11 14 use regex::Regex; 12 - use std::fmt::Write as _; 13 15 use tools_common::*; 14 16 15 17 // ── helpers ────────────────────────────────────────────────────────────────── 16 18 17 19 fn theme() -> ColorfulTheme { ColorfulTheme::default() } 18 20 19 - /// Replace the value of a Nix attribute in-place. 20 - /// key = the bare attribute name (e.g. `"device"`) 21 - /// value = the new Nix literal to write (e.g. `"\"/dev/sdb1\""`) 22 - /// 23 - /// Handles: 24 - /// key = "string"; 25 - /// key = true; / key = false; 26 - /// key = 1234; 27 - fn nix_set_scalar(src: &str, key: &str, value: &str) -> String { 28 - // Match `key = <anything up to semicolon>;` with optional whitespace 29 - let pattern = format!(r"(?m)(\b{key}\s*=\s*)([^;]+)(;)"); 30 - let re = Regex::new(&pattern).unwrap(); 31 - if re.is_match(src) { 32 - re.replace(src, format!("${{1}}{value}${{3}}")).into_owned() 33 - } else { 34 - eprintln!("⚠️ key '{key}' not found — skipping"); 35 - src.to_string() 36 - } 37 - } 38 - 39 - /// Read a scalar value from a Nix file. 40 - fn nix_get_scalar<'a>(src: &'a str, key: &str) -> Option<&'a str> { 41 - let pattern = format!(r"(?m)\b{key}\s*=\s*([^;]+);"); 42 - let re = Regex::new(&pattern).unwrap(); 43 - re.captures(src).map(|c| { 44 - // We can't return a lifetime-bound reference from a local Regex, 45 - // so we find the match start manually. 46 - let m = re.find(src).unwrap(); 47 - let cap_start = m.start() + c.get(0).unwrap().as_str().find(c.get(1).unwrap().as_str()).unwrap(); 48 - &src[cap_start..cap_start + c.get(1).unwrap().as_str().len()] 49 - }) 50 - } 51 - 52 - fn strip_nix_string(s: &str) -> String { 53 - s.trim().trim_matches('"').to_string() 54 - } 55 - 56 21 fn read_file(path: &Path) -> String { 57 22 fs::read_to_string(path).unwrap_or_else(|e| { 58 23 eprintln!("❌ Cannot read {}: {}", path.display(), e); ··· 67 32 }); 68 33 } 69 34 70 - // ── config representation ──────────────────────────────────────────────────── 35 + fn strip_nix_string(s: &str) -> String { 36 + s.trim().trim_matches('"').to_string() 37 + } 38 + 39 + // ── options.nix readers ─────────────────────────────────────────────────────── 40 + // 41 + // modules/options.nix structure (4-space top-level sections, 6-space keys): 42 + // 43 + // forgejo = { 44 + // hostname = mkOption { 45 + // type = str; 46 + // default = "git.ewancroft.uk"; 47 + // }; 48 + // }; 49 + // 50 + // For doubly-nested sections (server.storage.srv, server.cockpit) the 51 + // indentation is 6/8/10 spaces. 52 + 53 + /// Extract the `default = ` value for a key inside a top-level section. 54 + /// `section` = "forgejo", `key` = "hostname" → returns `"git.ewancroft.uk"` 55 + fn opts_get(src: &str, section: &str, key: &str) -> Option<String> { 56 + let sec_marker = format!("\n {section} = {{"); 57 + let sec_start = src.find(&sec_marker)? + sec_marker.len(); 58 + let rest = &src[sec_start..]; 59 + 60 + // Key at 6-space indent inside the section 61 + let key_marker = format!("\n {key} = mkOption {{"); 62 + let key_rel = rest.find(&key_marker)?; 63 + let after_key = &rest[key_rel..]; 64 + 65 + // The mkOption block closes at the next ` };` 66 + let block_end = after_key.find("\n };")?; 67 + let block = &after_key[..block_end]; 68 + 69 + let dp = block.find("default = ")?; 70 + let after_def = &block[dp + "default = ".len()..]; 71 + let end = after_def.find(';')?; 72 + Some(after_def[..end].trim().to_string()) 73 + } 74 + 75 + /// Like opts_get but for keys one level deeper (e.g. server.storage.srv.device). 76 + /// `outer` = "server", `inner_block` = "storage.srv", `key` = "device" 77 + fn opts_get_nested(src: &str, outer: &str, inner_block: &str, key: &str) -> Option<String> { 78 + let outer_marker = format!("\n {outer} = {{"); 79 + let outer_start = src.find(&outer_marker)? + outer_marker.len(); 80 + let outer_rest = &src[outer_start..]; 81 + 82 + let inner_marker = format!("\n {inner_block} = {{"); 83 + let inner_rel = outer_rest.find(&inner_marker)?; 84 + let after_inner = &outer_rest[inner_rel..]; 85 + 86 + // Key at 8-space indent 87 + let key_marker = format!("\n {key} = mkOption {{"); 88 + let key_rel = after_inner.find(&key_marker)?; 89 + let after_key = &after_inner[key_rel..]; 90 + 91 + let block_end = after_key.find("\n };")?; 92 + let block = &after_key[..block_end]; 93 + 94 + let dp = block.find("default = ")?; 95 + let after_def = &block[dp + "default = ".len()..]; 96 + let end = after_def.find(';')?; 97 + Some(after_def[..end].trim().to_string()) 98 + } 99 + 100 + // ── host file readers/writers ───────────────────────────────────────────────── 101 + // 102 + // hosts/server/default.nix contains overrides like: 103 + // myConfig.services.forgejo.enable = true; 104 + // myConfig.forgejo.hostname = "git.ewancroft.uk"; 105 + // 106 + // If no override is present the options.nix default applies. 107 + 108 + /// Read a `myConfig.<dotted_path> = value;` line from the host file. 109 + fn host_get(src: &str, dotted_path: &str) -> Option<String> { 110 + let pattern = format!("myConfig.{dotted_path} = "); 111 + let pos = src.find(&pattern)?; 112 + let after = &src[pos + pattern.len()..]; 113 + let end = after.find(';')?; 114 + Some(after[..end].trim().to_string()) 115 + } 116 + 117 + /// Add or update a `myConfig.<dotted_path> = <value>;` line in the host file. 118 + /// Inserts before `system.stateVersion` if the line doesn't exist yet. 119 + fn host_set(src: &mut String, dotted_path: &str, value: &str) { 120 + let search = format!("myConfig.{dotted_path} = "); 121 + let new_line = format!(" myConfig.{dotted_path} = {value};"); 122 + 123 + if let Some(pos) = src.find(&search) { 124 + let line_start = src[..pos].rfind('\n').map(|i| i + 1).unwrap_or(0); 125 + let line_end = src[pos..].find('\n').map(|i| pos + i).unwrap_or(src.len()); 126 + src.replace_range(line_start..line_end, &new_line); 127 + } else { 128 + // Insert before ` system.stateVersion` to keep the file tidy 129 + let anchor = " system.stateVersion"; 130 + if let Some(pos) = src.find(anchor) { 131 + src.insert_str(pos, &format!("{new_line}\n\n ")); 132 + } else { 133 + // Fall back: insert before the closing `}` 134 + if let Some(pos) = src.rfind('}') { 135 + src.insert_str(pos, &format!(" {new_line}\n")); 136 + } 137 + } 138 + } 139 + } 140 + 141 + /// Resolve the effective value: host override → options.nix default → fallback. 142 + fn resolve_str( 143 + opts: &str, host: &str, 144 + section: &str, key: &str, dotted_path: &str, 145 + fallback: &str, 146 + ) -> String { 147 + if let Some(v) = host_get(host, dotted_path) { 148 + return strip_nix_string(&v); 149 + } 150 + if let Some(v) = opts_get(opts, section, key) { 151 + return strip_nix_string(&v); 152 + } 153 + fallback.to_string() 154 + } 155 + 156 + fn resolve_u16( 157 + opts: &str, host: &str, 158 + section: &str, key: &str, dotted_path: &str, 159 + fallback: u16, 160 + ) -> u16 { 161 + let s = resolve_str(opts, host, section, key, dotted_path, ""); 162 + s.parse().unwrap_or(fallback) 163 + } 164 + 165 + fn resolve_bool( 166 + opts: &str, host: &str, 167 + dotted_path: &str, 168 + fallback: bool, 169 + ) -> bool { 170 + if let Some(v) = host_get(host, dotted_path) { 171 + return v.trim() == "true"; 172 + } 173 + fallback 174 + } 175 + 176 + // ── config structs ──────────────────────────────────────────────────────────── 71 177 72 178 #[derive(Debug, Clone)] 73 179 struct ServiceToggles { ··· 119 225 tunnel_id: String, 120 226 } 121 227 122 - // ── readers ────────────────────────────────────────────────────────────────── 123 - 124 - fn parse_bool(s: &str) -> bool { s.trim() == "true" } 125 - fn parse_u16(s: &str) -> u16 { s.trim().parse().unwrap_or(0) } 228 + // ── readers ─────────────────────────────────────────────────────────────────── 126 229 127 - fn read_services(src: &str) -> ServiceToggles { 230 + fn read_services(host_src: &str) -> ServiceToggles { 128 231 ServiceToggles { 129 - forgejo: parse_bool(nix_get_scalar(src, "forgejo").unwrap_or("true")), 130 - pds: parse_bool(nix_get_scalar(src, "pds").unwrap_or("true")), 131 - matrix: parse_bool(nix_get_scalar(src, "matrix").unwrap_or("true")), 132 - cloudflare: parse_bool(nix_get_scalar(src, "cloudflare").unwrap_or("true")), 232 + forgejo: host_get(host_src, "services.forgejo.enable").map(|v| v == "true").unwrap_or(false), 233 + pds: host_get(host_src, "services.pds.enable").map(|v| v == "true").unwrap_or(false), 234 + matrix: host_get(host_src, "services.matrix.enable").map(|v| v == "true").unwrap_or(false), 235 + cloudflare: host_get(host_src, "services.cloudflare.enable").map(|v| v == "true").unwrap_or(false), 133 236 } 134 237 } 135 238 136 - fn read_storage(src: &str) -> StorageConfig { 239 + fn read_storage(opts_src: &str, host_src: &str) -> StorageConfig { 137 240 StorageConfig { 138 - device: strip_nix_string(nix_get_scalar(src, "device").unwrap_or("\"/dev/sdb\"")), 139 - fs_type: strip_nix_string(nix_get_scalar(src, "fsType").unwrap_or("\"ext4\"")), 241 + device: { 242 + host_get(host_src, "server.storage.srv.device") 243 + .map(|v| strip_nix_string(&v)) 244 + .or_else(|| opts_get_nested(opts_src, "server", "storage.srv", "device").map(|v| strip_nix_string(&v))) 245 + .unwrap_or_else(|| "/dev/sdb".to_string()) 246 + }, 247 + fs_type: { 248 + host_get(host_src, "server.storage.srv.fsType") 249 + .map(|v| strip_nix_string(&v)) 250 + .or_else(|| opts_get_nested(opts_src, "server", "storage.srv", "fsType").map(|v| strip_nix_string(&v))) 251 + .unwrap_or_else(|| "ext4".to_string()) 252 + }, 140 253 } 141 254 } 142 255 143 - fn read_cockpit(src: &str) -> CockpitConfig { 144 - // cockpit.enable lives alongside other booleans so we need to find it 145 - // after the "cockpit" heading comment 146 - let enable = if let Some(pos) = src.find("cockpit = {") { 147 - parse_bool(nix_get_scalar(&src[pos..], "enable").unwrap_or("true")) 148 - } else { true }; 149 - let port = if let Some(pos) = src.find("cockpit = {") { 150 - parse_u16(nix_get_scalar(&src[pos..], "port").unwrap_or("9090")) 151 - } else { 9090 }; 256 + fn read_cockpit(opts_src: &str, host_src: &str) -> CockpitConfig { 257 + let enable = host_get(host_src, "server.cockpit.enable") 258 + .map(|v| v == "true") 259 + .or_else(|| opts_get_nested(opts_src, "server", "cockpit", "enable").map(|v| v == "true")) 260 + .unwrap_or(true); 261 + let port = host_get(host_src, "server.cockpit.port") 262 + .and_then(|v| v.trim().parse().ok()) 263 + .or_else(|| opts_get_nested(opts_src, "server", "cockpit", "port").and_then(|v| v.trim().parse().ok())) 264 + .unwrap_or(9090); 152 265 CockpitConfig { enable, port } 153 266 } 154 267 155 - fn read_forgejo(src: &str) -> ForgejoConfig { 268 + fn read_forgejo(opts_src: &str, host_src: &str) -> ForgejoConfig { 156 269 ForgejoConfig { 157 - hostname: strip_nix_string(nix_get_scalar(src, "hostname").unwrap_or("\"git.ewancroft.uk\"")), 158 - port: parse_u16(nix_get_scalar(src, "port").unwrap_or("3001")), 159 - caddy_port: parse_u16(nix_get_scalar(src, "caddyPort").unwrap_or("3002")), 160 - app_name: strip_nix_string(nix_get_scalar(src, "appName").unwrap_or("\"Forgejo\"")), 161 - disable_registration: parse_bool(nix_get_scalar(src, "disableRegistration").unwrap_or("true")), 270 + hostname: resolve_str(opts_src, host_src, "forgejo", "hostname", "forgejo.hostname", "git.ewancroft.uk"), 271 + port: resolve_u16(opts_src, host_src, "forgejo", "port", "forgejo.port", 3001), 272 + caddy_port: resolve_u16(opts_src, host_src, "forgejo", "caddyPort", "forgejo.caddyPort", 3002), 273 + app_name: resolve_str(opts_src, host_src, "forgejo", "appName", "forgejo.appName", "Ewan's Git"), 274 + disable_registration: { 275 + host_get(host_src, "forgejo.disableRegistration").map(|v| v == "true") 276 + .or_else(|| opts_get(opts_src, "forgejo", "disableRegistration").map(|v| v == "true")) 277 + .unwrap_or(true) 278 + }, 162 279 } 163 280 } 164 281 165 - fn read_matrix(src: &str) -> MatrixConfig { 282 + fn read_matrix(opts_src: &str, host_src: &str) -> MatrixConfig { 166 283 MatrixConfig { 167 - hostname: strip_nix_string(nix_get_scalar(src, "hostname").unwrap_or("\"matrix.ewancroft.uk\"")), 168 - server_name: strip_nix_string(nix_get_scalar(src, "serverName").unwrap_or("\"ewancroft.uk\"")), 169 - port: parse_u16(nix_get_scalar(src, "port").unwrap_or("8008")), 170 - caddy_port: parse_u16(nix_get_scalar(src, "caddyPort").unwrap_or("8448")), 284 + hostname: resolve_str(opts_src, host_src, "matrix", "hostname", "matrix.hostname", "matrix.ewancroft.uk"), 285 + server_name: resolve_str(opts_src, host_src, "matrix", "serverName", "matrix.serverName", "ewancroft.uk"), 286 + port: resolve_u16(opts_src, host_src, "matrix", "port", "matrix.port", 8008), 287 + caddy_port: resolve_u16(opts_src, host_src, "matrix", "caddyPort", "matrix.caddyPort", 8448), 171 288 } 172 289 } 173 290 174 - fn read_pds(src: &str) -> PdsConfig { 291 + fn read_pds(opts_src: &str, host_src: &str) -> PdsConfig { 175 292 PdsConfig { 176 - hostname: strip_nix_string(nix_get_scalar(src, "hostname").unwrap_or("\"pds.ewancroft.uk\"")), 177 - port: parse_u16(nix_get_scalar(src, "port").unwrap_or("3000")), 178 - caddy_port: parse_u16(nix_get_scalar(src, "caddyPort").unwrap_or("2020")), 179 - admin_email: strip_nix_string(nix_get_scalar(src, "adminEmail").unwrap_or("\"admin@example.com\"")), 293 + hostname: resolve_str(opts_src, host_src, "pds", "hostname", "pds.hostname", "pds.ewancroft.uk"), 294 + port: resolve_u16(opts_src, host_src, "pds", "port", "pds.port", 3000), 295 + caddy_port: resolve_u16(opts_src, host_src, "pds", "caddyPort", "pds.caddyPort", 2020), 296 + admin_email: resolve_str(opts_src, host_src, "pds", "adminEmail", "pds.adminEmail", "pds@ewancroft.uk"), 180 297 } 181 298 } 182 299 183 - fn read_cloudflare(src: &str) -> CloudflareConfig { 300 + fn read_cloudflare(opts_src: &str, host_src: &str) -> CloudflareConfig { 184 301 CloudflareConfig { 185 - tunnel_id: strip_nix_string(nix_get_scalar(src, "tunnelId").unwrap_or("\"<unset>\"")), 302 + tunnel_id: resolve_str(opts_src, host_src, "cloudflare", "tunnelId", "cloudflare.tunnelId", "<unset>"), 186 303 } 187 304 } 188 305 189 - // ── writers ────────────────────────────────────────────────────────────────── 306 + // ── writers ─────────────────────────────────────────────────────────────────── 307 + // All writes go to hosts/server/default.nix as myConfig.X.Y = value; overrides. 190 308 191 - fn write_services(src: &str, s: &ServiceToggles) -> String { 192 - // The service toggles sit inside a `services = { … }` block. Because all 193 - // four keys are bare booleans we can replace them by key name directly. 194 - // We scope each replacement to avoid touching unrelated `enable` fields. 195 - let src = nix_set_scalar(src, "forgejo", &s.forgejo.to_string()); 196 - let src = nix_set_scalar(&src, "pds", &s.pds.to_string()); 197 - let src = nix_set_scalar(&src, "matrix", &s.matrix.to_string()); 198 - nix_set_scalar(&src, "cloudflare", &s.cloudflare.to_string()) 309 + fn write_services(host_src: &mut String, s: &ServiceToggles) { 310 + host_set(host_src, "services.forgejo.enable", &s.forgejo.to_string()); 311 + host_set(host_src, "services.pds.enable", &s.pds.to_string()); 312 + host_set(host_src, "services.matrix.enable", &s.matrix.to_string()); 313 + host_set(host_src, "services.cloudflare.enable", &s.cloudflare.to_string()); 199 314 } 200 315 201 - fn write_storage(src: &str, st: &StorageConfig) -> String { 202 - let src = nix_set_scalar(src, "device", &format!("\"{}\"", st.device)); 203 - nix_set_scalar(&src, "fsType", &format!("\"{}\"", st.fs_type)) 316 + fn write_storage(host_src: &mut String, st: &StorageConfig) { 317 + host_set(host_src, "server.storage.srv.device", &format!("\"{}\"", st.device)); 318 + host_set(host_src, "server.storage.srv.fsType", &format!("\"{}\"", st.fs_type)); 204 319 } 205 320 206 - fn write_cockpit(src: &str, c: &CockpitConfig) -> String { 207 - // Cockpit block comes AFTER the storage block in server.nix so we 208 - // replace only within the cockpit = { … } section. 209 - let block_start = src.find("cockpit = {").unwrap_or(0); 210 - let (before, after) = src.split_at(block_start); 211 - let after = nix_set_scalar(after, "enable", &c.enable.to_string()); 212 - let after = nix_set_scalar(&after, "port", &c.port.to_string()); 213 - format!("{before}{after}") 321 + fn write_cockpit(host_src: &mut String, c: &CockpitConfig) { 322 + host_set(host_src, "server.cockpit.enable", &c.enable.to_string()); 323 + host_set(host_src, "server.cockpit.port", &c.port.to_string()); 214 324 } 215 325 216 - fn write_forgejo(src: &str, f: &ForgejoConfig) -> String { 217 - let src = nix_set_scalar(src, "hostname", &format!("\"{}\"", f.hostname)); 218 - let src = nix_set_scalar(&src, "port", &f.port.to_string()); 219 - let src = nix_set_scalar(&src, "caddyPort", &f.caddy_port.to_string()); 220 - let src = nix_set_scalar(&src, "appName", &format!("\"{}\"", f.app_name)); 221 - nix_set_scalar(&src, "disableRegistration", &f.disable_registration.to_string()) 326 + fn write_forgejo(host_src: &mut String, f: &ForgejoConfig) { 327 + host_set(host_src, "forgejo.hostname", &format!("\"{}\"", f.hostname)); 328 + host_set(host_src, "forgejo.port", &f.port.to_string()); 329 + host_set(host_src, "forgejo.caddyPort", &f.caddy_port.to_string()); 330 + host_set(host_src, "forgejo.appName", &format!("\"{}\"", f.app_name)); 331 + host_set(host_src, "forgejo.disableRegistration", &f.disable_registration.to_string()); 222 332 } 223 333 224 - fn write_matrix(src: &str, m: &MatrixConfig) -> String { 225 - let src = nix_set_scalar(src, "hostname", &format!("\"{}\"", m.hostname)); 226 - let src = nix_set_scalar(&src, "serverName",&format!("\"{}\"", m.server_name)); 227 - let src = nix_set_scalar(&src, "port", &m.port.to_string()); 228 - nix_set_scalar(&src, "caddyPort", &m.caddy_port.to_string()) 334 + fn write_matrix(host_src: &mut String, m: &MatrixConfig) { 335 + host_set(host_src, "matrix.hostname", &format!("\"{}\"", m.hostname)); 336 + host_set(host_src, "matrix.serverName", &format!("\"{}\"", m.server_name)); 337 + host_set(host_src, "matrix.port", &m.port.to_string()); 338 + host_set(host_src, "matrix.caddyPort", &m.caddy_port.to_string()); 229 339 } 230 340 231 - fn write_pds(src: &str, p: &PdsConfig) -> String { 232 - let src = nix_set_scalar(src, "hostname", &format!("\"{}\"", p.hostname)); 233 - let src = nix_set_scalar(&src, "port", &p.port.to_string()); 234 - let src = nix_set_scalar(&src, "caddyPort", &p.caddy_port.to_string()); 235 - nix_set_scalar(&src, "adminEmail", &format!("\"{}\"", p.admin_email)) 341 + fn write_pds(host_src: &mut String, p: &PdsConfig) { 342 + host_set(host_src, "pds.hostname", &format!("\"{}\"", p.hostname)); 343 + host_set(host_src, "pds.port", &p.port.to_string()); 344 + host_set(host_src, "pds.caddyPort", &p.caddy_port.to_string()); 345 + host_set(host_src, "pds.adminEmail", &format!("\"{}\"", p.admin_email)); 236 346 } 237 347 238 - fn write_cloudflare(src: &str, c: &CloudflareConfig) -> String { 239 - nix_set_scalar(src, "tunnelId", &format!("\"{}\"", c.tunnel_id)) 348 + fn write_cloudflare(host_src: &mut String, c: &CloudflareConfig) { 349 + host_set(host_src, "cloudflare.tunnelId", &format!("\"{}\"", c.tunnel_id)); 240 350 } 241 351 242 352 // ── display ─────────────────────────────────────────────────────────────────── ··· 248 358 fg: &ForgejoConfig, mx: &MatrixConfig, pd: &PdsConfig, cf: &CloudflareConfig, 249 359 ) { 250 360 let h1 = Style::new().bold().cyan(); 251 - let kv = |k: &str, v: &str| println!(" {:<26} {}", format!("{k}:"), v); 361 + let kv = |k: &str, v: &str| println!(" {:<28} {}", format!("{k}:"), v); 252 362 253 363 println!("\n{}", h1.apply_to(" ── Service toggles ──────────────────────")); 254 364 kv("forgejo", bool_str(svc.forgejo)); ··· 292 402 // ── interactive sections ────────────────────────────────────────────────────── 293 403 294 404 fn edit_services(svc: &mut ServiceToggles) { 295 - let names = ["forgejo", "pds (Bluesky ATProto)", "matrix", "cloudflare tunnel"]; 296 - let current = [svc.forgejo, svc.pds, svc.matrix, svc.cloudflare]; 297 - let defaults: Vec<bool> = current.to_vec(); 298 - 405 + let names = ["forgejo", "pds (Bluesky ATProto)", "matrix", "cloudflare tunnel"]; 406 + let defaults = vec![svc.forgejo, svc.pds, svc.matrix, svc.cloudflare]; 299 407 let selected = MultiSelect::with_theme(&theme()) 300 408 .with_prompt("Select services to ENABLE (space = toggle, enter = confirm)") 301 409 .items(&names) 302 410 .defaults(&defaults) 303 411 .interact() 304 412 .unwrap(); 305 - 306 413 svc.forgejo = selected.contains(&0); 307 414 svc.pds = selected.contains(&1); 308 415 svc.matrix = selected.contains(&2); ··· 311 418 312 419 fn edit_storage(st: &mut StorageConfig) { 313 420 st.device = Input::with_theme(&theme()) 314 - .with_prompt("/srv block device (e.g. /dev/sdb, /dev/sdb1)") 421 + .with_prompt("/srv block device (e.g. /dev/sdb, /dev/nvme0n1p2)") 315 422 .with_initial_text(&st.device) 316 423 .interact_text().unwrap(); 317 424 318 425 let fs_opts = ["ext4", "xfs", "btrfs"]; 319 - let current_idx = fs_opts.iter().position(|&f| f == st.fs_type).unwrap_or(0); 426 + let idx = fs_opts.iter().position(|&f| f == st.fs_type).unwrap_or(0); 320 427 let sel = Select::with_theme(&theme()) 321 428 .with_prompt("Filesystem type") 322 429 .items(&fs_opts) 323 - .default(current_idx) 430 + .default(idx) 324 431 .interact().unwrap(); 325 432 st.fs_type = fs_opts[sel].to_string(); 326 433 } ··· 330 437 .with_prompt("Enable Cockpit dashboard?") 331 438 .default(ck.enable) 332 439 .interact().unwrap(); 333 - 334 440 if ck.enable { 335 - let new_port: String = Input::with_theme(&theme()) 336 - .with_prompt("Cockpit port (accessible over Tailscale only)") 441 + let p: String = Input::with_theme(&theme()) 442 + .with_prompt("Cockpit port (Tailscale-only access)") 337 443 .with_initial_text(&ck.port.to_string()) 338 444 .interact_text().unwrap(); 339 - ck.port = new_port.trim().parse().unwrap_or(ck.port); 445 + ck.port = p.trim().parse().unwrap_or(ck.port); 340 446 } 341 447 } 342 448 ··· 345 451 .with_prompt("Forgejo public hostname") 346 452 .with_initial_text(&fg.hostname) 347 453 .interact_text().unwrap(); 348 - 349 454 fg.app_name = Input::with_theme(&theme()) 350 455 .with_prompt("Forgejo display name") 351 456 .with_initial_text(&fg.app_name) 352 457 .interact_text().unwrap(); 353 - 354 458 let p: String = Input::with_theme(&theme()) 355 459 .with_prompt("Forgejo internal port") 356 460 .with_initial_text(&fg.port.to_string()) 357 461 .interact_text().unwrap(); 358 462 fg.port = p.trim().parse().unwrap_or(fg.port); 359 - 360 463 let cp: String = Input::with_theme(&theme()) 361 464 .with_prompt("Caddy internal port (tunnel → Caddy → Forgejo)") 362 465 .with_initial_text(&fg.caddy_port.to_string()) 363 466 .interact_text().unwrap(); 364 467 fg.caddy_port = cp.trim().parse().unwrap_or(fg.caddy_port); 365 - 366 468 fg.disable_registration = Confirm::with_theme(&theme()) 367 469 .with_prompt("Disable public registration?") 368 470 .default(fg.disable_registration) ··· 371 473 372 474 fn edit_matrix(mx: &mut MatrixConfig) { 373 475 mx.hostname = Input::with_theme(&theme()) 374 - .with_prompt("Matrix public hostname (e.g. matrix.example.com)") 476 + .with_prompt("Matrix public hostname") 375 477 .with_initial_text(&mx.hostname) 376 478 .interact_text().unwrap(); 377 - 378 479 mx.server_name = Input::with_theme(&theme()) 379 480 .with_prompt("Matrix server name (used in @user:domain IDs)") 380 481 .with_initial_text(&mx.server_name) 381 482 .interact_text().unwrap(); 382 - 383 483 let p: String = Input::with_theme(&theme()) 384 484 .with_prompt("Synapse internal port") 385 485 .with_initial_text(&mx.port.to_string()) 386 486 .interact_text().unwrap(); 387 487 mx.port = p.trim().parse().unwrap_or(mx.port); 388 - 389 488 let cp: String = Input::with_theme(&theme()) 390 489 .with_prompt("Caddy internal port") 391 490 .with_initial_text(&mx.caddy_port.to_string()) ··· 395 494 396 495 fn edit_pds(pd: &mut PdsConfig) { 397 496 pd.hostname = Input::with_theme(&theme()) 398 - .with_prompt("PDS public hostname (e.g. pds.example.com)") 497 + .with_prompt("PDS public hostname") 399 498 .with_initial_text(&pd.hostname) 400 499 .interact_text().unwrap(); 401 - 402 500 pd.admin_email = Input::with_theme(&theme()) 403 501 .with_prompt("PDS admin email") 404 502 .with_initial_text(&pd.admin_email) 405 503 .interact_text().unwrap(); 406 - 407 504 let p: String = Input::with_theme(&theme()) 408 505 .with_prompt("PDS internal port") 409 506 .with_initial_text(&pd.port.to_string()) 410 507 .interact_text().unwrap(); 411 508 pd.port = p.trim().parse().unwrap_or(pd.port); 412 - 413 509 let cp: String = Input::with_theme(&theme()) 414 510 .with_prompt("Caddy internal port") 415 511 .with_initial_text(&pd.caddy_port.to_string()) ··· 430 526 let args: Vec<String> = env::args().collect(); 431 527 let show_only = args.iter().any(|a| a == "--show"); 432 528 433 - let root = git_root(); 434 - let cfg = root.join("settings/config"); 529 + let root = git_root(); 530 + let opts_path = root.join("modules/options.nix"); 531 + let host_path = root.join("hosts/server/default.nix"); 435 532 436 - let server_path = cfg.join("server.nix"); 437 - let forgejo_path = cfg.join("forgejo.nix"); 438 - let matrix_path = cfg.join("matrix.nix"); 439 - let pds_path = cfg.join("pds.nix"); 440 - let cloudflare_path = cfg.join("cloudflare.nix"); 533 + let opts_src = read_file(&opts_path); 534 + let mut host_src = read_file(&host_path); 441 535 442 - // Read all files 443 - let mut server_src = read_file(&server_path); 444 - let mut forgejo_src = read_file(&forgejo_path); 445 - let mut matrix_src = read_file(&matrix_path); 446 - let mut pds_src = read_file(&pds_path); 447 - let mut cloudflare_src = read_file(&cloudflare_path); 448 - 449 - // Parse current values 450 - let mut svc = read_services(&server_src); 451 - let mut st = read_storage(&server_src); 452 - let mut ck = read_cockpit(&server_src); 453 - let mut fg = read_forgejo(&forgejo_src); 454 - let mut mx = read_matrix(&matrix_src); 455 - let mut pd = read_pds(&pds_src); 456 - let mut cf = read_cloudflare(&cloudflare_src); 536 + let mut svc = read_services(&host_src); 537 + let mut st = read_storage(&opts_src, &host_src); 538 + let mut ck = read_cockpit(&opts_src, &host_src); 539 + let mut fg = read_forgejo(&opts_src, &host_src); 540 + let mut mx = read_matrix(&opts_src, &host_src); 541 + let mut pd = read_pds(&opts_src, &host_src); 542 + let mut cf = read_cloudflare(&opts_src, &host_src); 457 543 458 544 let title = Style::new().bold().green(); 459 545 println!("\n{}", title.apply_to(" 🖥️ Server configurator")); 460 - println!(" Repo: {}\n", root.display()); 546 + println!(" Options : {}", opts_path.display()); 547 + println!(" Host : {}\n", host_path.display()); 548 + println!(" (defaults from modules/options.nix; overrides written to hosts/server/default.nix)\n"); 461 549 462 550 if show_only { 463 551 print_summary(&svc, &st, &ck, &fg, &mx, &pd, &cf); 464 552 return; 465 553 } 466 554 467 - // ── interactive menu loop ───────────────────────────────────────────────── 468 555 let menu_items = [ 469 - "Service toggles (forgejo / pds / matrix / cloudflare)", 470 - "/srv storage (block device, filesystem)", 471 - "Cockpit dashboard (enable, port)", 472 - "Forgejo (hostname, ports, app name, registration)", 473 - "Matrix Synapse (hostname, server name, ports)", 474 - "Bluesky PDS (hostname, ports, admin email)", 475 - "Cloudflare Tunnel (tunnel UUID)", 556 + "Service toggles (forgejo / pds / matrix / cloudflare)", 557 + "/srv storage (block device, filesystem)", 558 + "Cockpit dashboard (enable, port)", 559 + "Forgejo (hostname, ports, app name, registration)", 560 + "Matrix Synapse (hostname, server name, ports)", 561 + "Bluesky PDS (hostname, ports, admin email)", 562 + "Cloudflare Tunnel (tunnel UUID)", 476 563 "── Show current config", 477 564 "── Save and exit", 478 565 "── Exit without saving", ··· 496 583 6 => edit_cloudflare(&mut cf), 497 584 7 => print_summary(&svc, &st, &ck, &fg, &mx, &pd, &cf), 498 585 8 => { 499 - // Apply changes to source strings 500 - server_src = write_services(&server_src, &svc); 501 - server_src = write_storage(&server_src, &st); 502 - server_src = write_cockpit(&server_src, &ck); 503 - forgejo_src = write_forgejo(&forgejo_src, &fg); 504 - matrix_src = write_matrix(&matrix_src, &mx); 505 - pds_src = write_pds(&pds_src, &pd); 506 - cloudflare_src = write_cloudflare(&cloudflare_src, &cf); 586 + write_services(&mut host_src, &svc); 587 + write_storage(&mut host_src, &st); 588 + write_cockpit(&mut host_src, &ck); 589 + write_forgejo(&mut host_src, &fg); 590 + write_matrix(&mut host_src, &mx); 591 + write_pds(&mut host_src, &pd); 592 + write_cloudflare(&mut host_src, &cf); 507 593 508 - // Write files 509 - write_file(&server_path, &server_src); 510 - write_file(&forgejo_path, &forgejo_src); 511 - write_file(&matrix_path, &matrix_src); 512 - write_file(&pds_path, &pds_src); 513 - write_file(&cloudflare_path, &cloudflare_src); 594 + write_file(&host_path, &host_src); 595 + println!("\n✅ Saved to {}.", host_path.display()); 596 + println!(" modules/options.nix was NOT modified — it is the default source."); 597 + println!(" Run `nrs` or `sudo nixos-rebuild switch --flake .#server` to apply.\n"); 514 598 515 - println!("\n✅ Saved. Run `nrs` to apply changes."); 516 - 517 - // Optionally rebuild immediately 518 599 if Confirm::with_theme(&theme()) 519 600 .with_prompt("Run nixos-rebuild switch now?") 520 601 .default(false) ··· 522 603 .unwrap() 523 604 { 524 605 let status = Command::new("sudo") 525 - .args(["nixos-rebuild", "switch", "--flake", &format!("{}#server", root.display())]) 606 + .args(["nixos-rebuild", "switch", "--flake", 607 + &format!("{}#server", root.display())]) 526 608 .status(); 527 609 match status { 528 610 Ok(s) if s.success() => println!("✅ Rebuild succeeded."), ··· 532 614 } 533 615 break; 534 616 } 535 - 9 => { 536 - println!("Exiting without saving."); 537 - break; 538 - } 617 + 9 => { println!("Exiting without saving."); break; } 539 618 _ => {} 540 619 } 541 620 }