From b1954ba5be105423f9970b4d63e8283570b5bf2a Mon Sep 17 00:00:00 2001 From: moons Date: Tue, 28 Jul 2026 00:19:14 +0900 Subject: [PATCH] add hosts --- AGENTS.md | 100 +++++++-- hosts/default.nix | 53 +++++ hosts/installer/nixos.nix | 189 ++++++++++++++++++ .../hardware-configuration.nix | 36 ++++ hosts/internal-app-01/nixos.nix | 3 + hosts/nix-example/hardware-configuration.nix | 36 ++++ hosts/nix-example/nixos.nix | 3 + hosts/ops/hardware-configuration.nix | 36 ++++ hosts/ops/nixos.nix | 51 +++++ modules/profiles/README.md | 48 ++--- modules/profiles/platform/vm/meta.nix | 4 +- 11 files changed, 519 insertions(+), 40 deletions(-) create mode 100644 hosts/installer/nixos.nix create mode 100644 hosts/internal-app-01/hardware-configuration.nix create mode 100644 hosts/internal-app-01/nixos.nix create mode 100644 hosts/nix-example/hardware-configuration.nix create mode 100644 hosts/nix-example/nixos.nix create mode 100644 hosts/ops/hardware-configuration.nix create mode 100644 hosts/ops/nixos.nix diff --git a/AGENTS.md b/AGENTS.md index 027dbe1..a892064 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -487,6 +487,59 @@ A host registry may use a specification like this: ```nix # hosts/default.nix { + nix-example = { + system = "x86_64-linux"; + stateVersion = "26.05"; + user = "moons"; + path = ./nix-example; + + profiles = [ + "base" + "interface.cli" + "platform.vm" + "workload.development" + "workload.remote-access" + ]; + }; + + ops = { + system = "x86_64-linux"; + stateVersion = "26.05"; + user = "moons"; + path = ./ops; + + profiles = [ + "base" + "interface.cli" + "platform.vm" + "workload.remote-access" + ]; + }; + + internal-app-01 = { + system = "x86_64-linux"; + stateVersion = "26.05"; + user = "moons"; + path = ./internal-app-01; + + profiles = [ + "base" + "interface.cli" + "platform.vm" + "workload.server" + ]; + }; + + installer = { + system = "x86_64-linux"; + stateVersion = "26.05"; + user = "moons"; + path = ./installer; + homeManager = false; + + profiles = [ "base" ]; + }; + x1g9 = { system = "x86_64-linux"; stateVersion = "26.05"; @@ -544,14 +597,16 @@ A host registry may use a specification like this: } ``` -The current role assignment is intentional: x1g9 is a full NixOS desktop with -niri, GNOME, ly, the shared Linux desktop applications, and the personal -workload. x1g13 is the secure NixOS development and personal ThinkPad, with the -same desktop sessions plus Tailscale client, SOPS, Secure Boot, and TPM-backed -disk unlock. m2 is the daily-use macOS development and personal machine with -the macOS interface defaults. Keep the desktop sessions independently -selectable, and keep the development and personal profiles usable across NixOS -and Darwin. +The current role assignment is intentional: nix-example is the development VM; +ops is the remote-access VM with host-specific static networking; +internal-app-01 is the container server VM; and installer builds the minimal +installation ISO without Home Manager. x1g9 is a full NixOS desktop with niri, +GNOME, ly, the shared Linux desktop applications, and the personal workload. +x1g13 is the secure NixOS development and personal ThinkPad, with the same +desktop sessions plus Tailscale client, SOPS, Secure Boot, and TPM-backed disk +unlock. m2 is the daily-use macOS development and personal machine with the +macOS interface defaults. Keep the desktop sessions independently selectable, +and keep the development and personal profiles usable across NixOS and Darwin. Treat entries in `profiles` and the exceptional `applications` field as IDs relative to their respective category roots. Add the category prefixes during @@ -581,6 +636,17 @@ configuration fragments. For example: ```text hosts/ +├── installer/ +│ └── nixos.nix +├── internal-app-01/ +│ ├── nixos.nix +│ └── hardware-configuration.nix +├── nix-example/ +│ ├── nixos.nix +│ └── hardware-configuration.nix +├── ops/ +│ ├── nixos.nix +│ └── hardware-configuration.nix ├── x1g9/ │ ├── nixos.nix │ └── hardware-configuration.nix @@ -606,9 +672,10 @@ Derive the system class from the host's `system`: - A host with integrated Home Manager additionally receives `home.nix`. Home Manager is additive, not a system class mutually exclusive with NixOS or -nix-darwin. The supported combinations are NixOS plus Home Manager and -nix-darwin plus Home Manager. If standalone Home Manager is supported later, add -an explicit host kind because `system` alone cannot distinguish it from NixOS. +nix-darwin. Normal machine configurations combine NixOS or nix-darwin with Home +Manager; the installer ISO explicitly sets `homeManager = false`. If standalone +Home Manager is supported later, add an explicit host kind because `system` +alone cannot distinguish it from NixOS. Do not duplicate reusable settings in hosts, but do not force genuinely machine-specific values into a common unit merely to remove a host-local line. @@ -694,10 +761,13 @@ For profile changes, additionally: required host-owned values. - When adding a Darwin application fragment, verify the resulting `homebrew.casks` selection as well as module evaluation. -- Preserve the intended host roles: x1g9 provides niri, GNOME, ly, and the - personal application set; x1g13 additionally provides the development, - Tailscale client, secrets, Secure Boot, and TPM storage roles; m2 remains the - daily-use development and personal machine. +- Preserve the intended host roles: nix-example remains the development VM; + ops remains the statically networked remote-access VM; internal-app-01 remains + the container server VM; installer remains the Home Manager-free installation + ISO; x1g9 provides niri, GNOME, ly, and the personal application set; x1g13 + additionally provides the development, Tailscale client, secrets, Secure Boot, + and TPM storage roles; m2 remains the daily-use development and personal + machine. ## Commit and Pull Request Guidelines diff --git a/hosts/default.nix b/hosts/default.nix index fdb725c..5a90604 100644 --- a/hosts/default.nix +++ b/hosts/default.nix @@ -1,4 +1,57 @@ { + nix-example = { + system = "x86_64-linux"; + stateVersion = "26.05"; + user = "moons"; + path = ./nix-example; + + profiles = [ + "base" + "interface.cli" + "platform.vm" + "workload.development" + "workload.remote-access" + ]; + }; + + ops = { + system = "x86_64-linux"; + stateVersion = "26.05"; + user = "moons"; + path = ./ops; + + profiles = [ + "base" + "interface.cli" + "platform.vm" + "workload.remote-access" + ]; + }; + + internal-app-01 = { + system = "x86_64-linux"; + stateVersion = "26.05"; + user = "moons"; + path = ./internal-app-01; + + profiles = [ + "base" + "interface.cli" + "platform.vm" + "workload.server" + ]; + }; + + installer = { + system = "x86_64-linux"; + stateVersion = "26.05"; + user = "moons"; + path = ./installer; + homeManager = false; + + profiles = [ "base" ]; + }; + x1g9 = { system = "x86_64-linux"; stateVersion = "26.05"; diff --git a/hosts/installer/nixos.nix b/hosts/installer/nixos.nix new file mode 100644 index 0000000..d6ce7e5 --- /dev/null +++ b/hosts/installer/nixos.nix @@ -0,0 +1,189 @@ +{ + pkgs, + lib, + modulesPath, + ... +}: +{ + imports = [ "${modulesPath}/installer/cd-dvd/installation-cd-minimal.nix" ]; + + boot.zfs.forceImportRoot = false; + + networking = { + hostName = "nixos-installer"; + + networkmanager = { + enable = true; + wifi.powersave = false; + }; + }; + + services.openssh = { + enable = true; + settings = { + PermitRootLogin = "prohibit-password"; + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + PubkeyAuthentication = "yes"; + }; + }; + + users.users.root.openssh.authorizedKeys.keys = [ + "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIKhxDkucmeCor6CKoXAua7DgDSzuXrZOtpdkyzQxz5+aAAAABHNzaDo= moons@moons14.com" + "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIN6hZJyng/5LgFKPjR6uZAd/00UkO0vN0uQOoIvfSELdAAAABHNzaDo= moons@moons14.com" + ]; + + environment.systemPackages = with pkgs; [ + git + disko + sops + age + ssh-to-age + age-plugin-yubikey + yubikey-manager + pcsc-tools + mkpasswd + rsync + vim + wget + curl + jq + parted + cryptsetup + btrfs-progs + ]; + + services.pcscd.enable = true; + + environment.etc."installer-help.txt".text = '' + + ╔══════════════════════════════════════════════════════════════╗ + ║ NixOS Installer ISO ║ + ╠══════════════════════════════════════════════════════════════╣ + ║ ║ + ║ SSH Access: ║ + ║ ssh root@ ║ + ║ ║ + ║ Network Setup: ║ + ║ Wired: Auto-configured via DHCP ║ + ║ WiFi: nmcli device wifi connect --ask ║ + ║ ║ + ║ Installation Workflow: ║ + ║ ║ + ║ 1. Clone dotfiles: ║ + ║ git clone git@github.com:moons-14/dotfiles.git ~/dotfiles║ + ║ ║ + ║ 2. Generate SSH host key for new host: ║ + ║ ssh-keygen -t ed25519 -f /tmp/ssh_host_ed25519_key -N "" ║ + ║ ║ + ║ 3. Get age public key from SSH host key: ║ + ║ ssh-to-age -i /tmp/ssh_host_ed25519_key.pub ║ + ║ ║ + ║ 4. Add age key to .sops.yaml: ║ + ║ cd ~/dotfiles ║ + ║ # Edit .sops.yaml and add the age key ║ + ║ # Add new host entry to creation_rules ║ + ║ ║ + ║ 5. Re-encrypt secrets: ║ + ║ sops updatekeys secrets/common/system.yaml ║ + ║ sops updatekeys secrets/hosts//*.yaml ║ + ║ ║ + ║ 6. Create disko.nix for new host: ║ + ║ # Check disk devices ║ + ║ lsblk -f ║ + ║ ║ + ║ # Create hosts//disko.nix ║ + ║ # Example: LUKS + btrfs ║ + ║ # See hosts/x1g13/disko.nix for reference ║ + ║ ║ + ║ 7. Partition disk with disko: ║ + ║ nix run github:nix-community/disko -- \ ║ + ║ --mode disko hosts//disko.nix ║ + ║ ║ + ║ 8. Copy host key to installed system: ║ + ║ mkdir -p /mnt/etc/ssh ║ + ║ cp /tmp/ssh_host_ed25519_key* /mnt/etc/ssh/ ║ + ║ chmod 600 /mnt/etc/ssh/ssh_host_ed25519_key ║ + ║ ║ + ║ 9. Install NixOS: ║ + ║ nixos-install --flake ~/dotfiles# ║ + ║ ║ + ║ Disko Configuration Examples: ║ + ║ ║ + ║ Simple (no encryption): ║ + ║ disko.devices.disk.main = { ║ + ║ type = "disk"; ║ + ║ device = "/dev/sda"; ║ + ║ content = { ║ + ║ type = "gpt"; ║ + ║ partitions = { ║ + ║ ESP = { size = "512M"; type = "EF00"; ║ + ║ content = { type = "filesystem"; ║ + ║ format = "vfat"; mountpoint = "/boot"; }; }; ║ + ║ root = { size = "100%"; ║ + ║ content = { type = "filesystem"; ║ + ║ format = "ext4"; mountpoint = "/"; }; }; ║ + ║ }; ║ + ║ }; ║ + ║ }; ║ + ║ ║ + ║ LUKS + btrfs (see hosts/x1g13/disko.nix): ║ + ║ - Use partuuid for device path ║ + ║ - Set askPassword = true for LUKS ║ + ║ - Configure btrfs subvolumes ║ + ║ ║ + ╚══════════════════════════════════════════════════════════════╝ + + ''; + + systemd.services.installer-banner = { + description = "Display installer help on console"; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${pkgs.coreutils}/bin/cat /etc/installer-help.txt"; + StandardOutput = "tty"; + TTYPath = "/dev/tty1"; + }; + }; + + systemd.services.display-ip = { + description = "Display IP address on console"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = pkgs.writeShellScript "display-ip" '' + sleep 2 + echo "" + echo "=== Network Interfaces ===" + ${pkgs.iproute2}/bin/ip -4 addr show | ${pkgs.gnugrep}/bin/grep inet + echo "" + echo "=== SSH Access ===" + for ip in $(${pkgs.iproute2}/bin/ip -4 addr show | ${pkgs.gnugrep}/bin/grep -oP 'inet \K[\d.]+' | ${pkgs.gnugrep}/bin/grep -v '127.0.0.1'); do + echo " ssh root@$ip" + done + echo "" + ''; + StandardOutput = "tty"; + TTYPath = "/dev/tty1"; + }; + }; + + nix = { + settings = { + experimental-features = [ + "nix-command" + "flakes" + ]; + trusted-users = [ "root" ]; + }; + + extraOptions = '' + experimental-features = nix-command flakes + ''; + }; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; +} diff --git a/hosts/internal-app-01/hardware-configuration.nix b/hosts/internal-app-01/hardware-configuration.nix new file mode 100644 index 0000000..fda7e06 --- /dev/null +++ b/hosts/internal-app-01/hardware-configuration.nix @@ -0,0 +1,36 @@ +# Do not modify this file! It was generated by `nixos-generate-config` and may +# be overwritten by future invocations. +{ lib, modulesPath, ... }: +{ + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + boot.initrd.availableKernelModules = [ + "ata_piix" + "uhci_hcd" + "virtio_pci" + "virtio_scsi" + "sd_mod" + "sr_mod" + ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = { + device = "/dev/disk/by-uuid/1b12ab98-2537-4207-a3f4-bb8ba7b53b00"; + fsType = "ext4"; + }; + + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/8365-C778"; + fsType = "vfat"; + options = [ + "fmask=0077" + "dmask=0077" + ]; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; +} diff --git a/hosts/internal-app-01/nixos.nix b/hosts/internal-app-01/nixos.nix new file mode 100644 index 0000000..2260952 --- /dev/null +++ b/hosts/internal-app-01/nixos.nix @@ -0,0 +1,3 @@ +{ + imports = [ ./hardware-configuration.nix ]; +} diff --git a/hosts/nix-example/hardware-configuration.nix b/hosts/nix-example/hardware-configuration.nix new file mode 100644 index 0000000..5d0be28 --- /dev/null +++ b/hosts/nix-example/hardware-configuration.nix @@ -0,0 +1,36 @@ +# Do not modify this file! It was generated by `nixos-generate-config` and may +# be overwritten by future invocations. +{ lib, modulesPath, ... }: +{ + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + boot.initrd.availableKernelModules = [ + "ata_piix" + "uhci_hcd" + "virtio_pci" + "virtio_scsi" + "sd_mod" + "sr_mod" + ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = { + device = "/dev/disk/by-uuid/8f0eaec6-5dc9-4821-aa8d-fb6809b5a5bf"; + fsType = "ext4"; + }; + + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/201C-961B"; + fsType = "vfat"; + options = [ + "fmask=0077" + "dmask=0077" + ]; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; +} diff --git a/hosts/nix-example/nixos.nix b/hosts/nix-example/nixos.nix new file mode 100644 index 0000000..2260952 --- /dev/null +++ b/hosts/nix-example/nixos.nix @@ -0,0 +1,3 @@ +{ + imports = [ ./hardware-configuration.nix ]; +} diff --git a/hosts/ops/hardware-configuration.nix b/hosts/ops/hardware-configuration.nix new file mode 100644 index 0000000..8a2f794 --- /dev/null +++ b/hosts/ops/hardware-configuration.nix @@ -0,0 +1,36 @@ +# Do not modify this file! It was generated by `nixos-generate-config` and may +# be overwritten by future invocations. +{ lib, modulesPath, ... }: +{ + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + boot.initrd.availableKernelModules = [ + "ata_piix" + "uhci_hcd" + "virtio_pci" + "virtio_scsi" + "sd_mod" + "sr_mod" + ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = { + device = "/dev/disk/by-uuid/69fa2193-1e4f-438a-8898-5de8a3f36e5b"; + fsType = "ext4"; + }; + + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/D09B-4277"; + fsType = "vfat"; + options = [ + "fmask=0077" + "dmask=0077" + ]; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; +} diff --git a/hosts/ops/nixos.nix b/hosts/ops/nixos.nix new file mode 100644 index 0000000..6db5d94 --- /dev/null +++ b/hosts/ops/nixos.nix @@ -0,0 +1,51 @@ +{ + imports = [ ./hardware-configuration.nix ]; + + networking = { + useDHCP = false; + + interfaces = { + ens18 = { + useDHCP = false; + ipv4.addresses = [ + { + address = "10.50.128.20"; + prefixLength = 24; + } + ]; + }; + + ens19 = { + useDHCP = false; + ipv4.addresses = [ + { + address = "10.50.7.101"; + prefixLength = 24; + } + ]; + }; + + ens20 = { + useDHCP = false; + ipv4.routes = [ + { + address = "10.50.64.0"; + prefixLength = 24; + via = "10.50.82.1"; + } + ]; + ipv4.addresses = [ + { + address = "10.50.82.10"; + prefixLength = 24; + } + ]; + }; + }; + + defaultGateway = { + address = "10.50.128.1"; + interface = "ens18"; + }; + }; +} diff --git a/modules/profiles/README.md b/modules/profiles/README.md index 1156fb8..8a509b0 100644 --- a/modules/profiles/README.md +++ b/modules/profiles/README.md @@ -20,30 +20,30 @@ when removing it from any supported host would make that host invalid. ## Compatibility -| Profile | Supported host class | -| ------------------------------------ | ------------------------------------- | -| `base` | NixOS, macOS | -| `interface.cli` | NixOS, macOS with Home Manager | -| `interface.gui` | NixOS, macOS with Home Manager | -| `interface.macos` | macOS | -| `interface.linux-desktop` | NixOS with Home Manager | -| `interface.gnome` | NixOS with Home Manager | -| `interface.niri` | NixOS with Home Manager | -| `platform.nixos` | NixOS | -| `platform.desktop` | Physical NixOS desktop | -| `platform.laptop` | Physical NixOS laptop | -| `platform.thinkpad-x1` | Intel ThinkPad X1 running NixOS | -| `platform.vm` | QEMU NixOS guest | -| `workload.development` | NixOS, macOS with Home Manager | -| `workload.personal` | NixOS, macOS with Home Manager | -| `workload.remote-access` | NixOS, macOS | -| `workload.server` | NixOS, macOS with Home Manager | -| `networking.tailscale-client` | NixOS, macOS | -| `networking.tailscale-subnet-router` | NixOS | -| `security.fingerprint` | NixOS, macOS | -| `security.secrets` | NixOS, macOS | -| `security.secure-boot` | NixOS | -| `security.tpm-storage` | NixOS with a host-defined LUKS device | +| Profile | Supported host class | +| ------------------------------------ | --------------------------------------------- | +| `base` | NixOS, macOS | +| `interface.cli` | NixOS, macOS with Home Manager | +| `interface.gui` | NixOS, macOS with Home Manager | +| `interface.macos` | macOS | +| `interface.linux-desktop` | NixOS with Home Manager | +| `interface.gnome` | NixOS with Home Manager | +| `interface.niri` | NixOS with Home Manager | +| `platform.nixos` | NixOS | +| `platform.desktop` | Physical NixOS desktop | +| `platform.laptop` | Physical NixOS laptop | +| `platform.thinkpad-x1` | Intel ThinkPad X1 running NixOS | +| `platform.vm` | UEFI QEMU NixOS guest with NFS client support | +| `workload.development` | NixOS, macOS with Home Manager | +| `workload.personal` | NixOS, macOS with Home Manager | +| `workload.remote-access` | NixOS, macOS | +| `workload.server` | NixOS, macOS with Home Manager | +| `networking.tailscale-client` | NixOS, macOS | +| `networking.tailscale-subnet-router` | NixOS | +| `security.fingerprint` | NixOS, macOS | +| `security.secrets` | NixOS, macOS | +| `security.secure-boot` | NixOS | +| `security.tpm-storage` | NixOS with a host-defined LUKS device | Select independent concerns independently in `hosts/default.nix`. For example, a NixOS desktop can combine `interface.gnome` and `interface.niri` to provide diff --git a/modules/profiles/platform/vm/meta.nix b/modules/profiles/platform/vm/meta.nix index 8c7f6a3..0bf42d5 100644 --- a/modules/profiles/platform/vm/meta.nix +++ b/modules/profiles/platform/vm/meta.nix @@ -1,8 +1,10 @@ { - description = "QEMU NixOS guest"; + description = "UEFI QEMU NixOS guest with NFS client support"; includes = [ "profiles.platform.nixos" "hardwares.qemu-guest" + "systems.boot.nfs" + "systems.boot.uefi" ]; }