diff --git a/flake.lock b/flake.lock index adf8293..54525eb 100644 --- a/flake.lock +++ b/flake.lock @@ -36,6 +36,26 @@ "type": "github" } }, + "disko": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1756733629, + "narHash": "sha256-dwWGlDhcO5SMIvMSTB4mjQ5Pvo2vtxvpIknhVnSz2I8=", + "owner": "nix-community", + "repo": "disko", + "rev": "a5c4f2ab72e3d1ab43e3e65aa421c6f2bd2e12a1", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "disko", + "type": "github" + } + }, "firefox-addons": { "inputs": { "nixpkgs": [ @@ -283,6 +303,7 @@ "root": { "inputs": { "claude-code": "claude-code", + "disko": "disko", "firefox-addons": "firefox-addons", "home-manager": "home-manager", "nix-darwin": "nix-darwin", diff --git a/flake.nix b/flake.nix index a4d4eaf..c565112 100644 --- a/flake.nix +++ b/flake.nix @@ -15,9 +15,11 @@ inputs.nixpkgs.follows = "nixpkgs"; }; nix-homebrew.url = "github:zhaofengli/nix-homebrew"; + disko.url = "github:nix-community/disko"; + disko.inputs.nixpkgs.follows = "nixpkgs"; }; - outputs = inputs@{ self, nix-darwin, nixpkgs, home-manager, nixvim, claude-code, firefox-addons, nix-homebrew }: + outputs = inputs@{ self, nix-darwin, nixpkgs, home-manager, nixvim, claude-code, firefox-addons, nix-homebrew, disko }: { darwinConfigurations."imac" = nix-darwin.lib.darwinSystem { modules = [ @@ -33,6 +35,23 @@ specialArgs = { inherit nix-homebrew; }; }; + nixosConfigurations."hs" = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + disko.nixosModules.disko + ./hosts/nixos/hs/system.nix + ./hosts/nixos/hs/disk-config.nix + ]; + }; + + nixosConfigurations."hs-iso" = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + disko.nixosModules.disko + ./hosts/nixos/hs/iso.nix + ]; + }; + homeConfigurations = { "yanlin@imac" = home-manager.lib.homeManagerConfiguration { pkgs = nixpkgs.legacyPackages.aarch64-darwin; diff --git a/hosts/nixos/hs/BUILD_ISO_GUIDE.md b/hosts/nixos/hs/BUILD_ISO_GUIDE.md new file mode 100644 index 0000000..81c8af6 --- /dev/null +++ b/hosts/nixos/hs/BUILD_ISO_GUIDE.md @@ -0,0 +1,208 @@ +# Building NixOS ISO for `hs` Host + +This guide explains how to build a custom NixOS ISO for the `hs` host configuration on a VPS and install it on the target machine. + +## Prerequisites + +- An x86_64 Linux VPS (recommended: at least 2GB RAM, 20GB storage) +- SSH access to the VPS +- Git repository with your nix configuration + +## Step 1: Set up the VPS + +### 1.1 Create a VPS + +Choose a provider that offers x86_64 Linux VPS: +- Hetzner Cloud (recommended, affordable) +- DigitalOcean +- Vultr +- Linode + +Create an Ubuntu 22.04 or Debian 12 VPS with at least: +- 2 vCPUs +- 4GB RAM (more is better for faster builds) +- 40GB storage + +### 1.2 Install Nix on the VPS + +SSH into your VPS and run: + +```bash +# Install Nix (multi-user installation) +sh <(curl -L https://nixos.org/nix/install) --daemon + +# Source nix profile +. /etc/profile.d/nix.sh + +# Enable flakes and nix-command +mkdir -p ~/.config/nix +echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf + +# Verify installation +nix --version +``` + +## Step 2: Build the ISO + +### 2.1 Clone your configuration + +```bash +# Clone your nix configuration repository +git clone https://github.com/YOUR_USERNAME/YOUR_REPO.git +cd YOUR_REPO + +# Or if using a private repository +git clone git@github.com:YOUR_USERNAME/YOUR_REPO.git +cd YOUR_REPO +``` + +### 2.2 Build the ISO + +```bash +# Build the ISO image +nix build .#nixosConfigurations.hs-iso.config.system.build.isoImage + +# The ISO will be created in ./result/iso/ +ls -la ./result/iso/ +``` + +The build process may take 15-30 minutes depending on your VPS resources. + +## Step 3: Download ISO to your local machine + +From your local machine (iMac): + +```bash +# Download the ISO +rsync root@YOUR_VPS_IP:~/.config/nix/result/iso/nixos-hs.iso ~/Downloads +``` + +## Step 4: Create Bootable Media + +### Option A: USB Drive (Physical Installation) + +```bash +# On macOS, find your USB device +diskutil list + +# Unmount the USB drive (replace diskN with your disk) +diskutil unmountDisk /dev/diskN + +# Write ISO to USB (replace diskN with your disk number) +sudo dd if=nixos-hs.iso of=/dev/rdiskN bs=4m status=progress + +# Eject the USB +diskutil eject /dev/diskN +``` + +### Option B: Remote Installation Methods + +1. **IPMI/iDRAC/iLO**: Upload ISO through management interface +2. **Proxmox/VMware**: Upload ISO to datastore +3. **Dedicated Server Rescue Mode**: Some providers allow custom ISO boot + +## Step 5: Install NixOS on Target Machine + +### 5.1 Boot from ISO + +1. Insert USB or configure remote boot +2. Boot the target machine from the ISO +3. Wait for the system to boot (you'll see a login prompt) + +### 5.2 Connect via SSH + +The installer has SSH enabled with: +- Root password: `nixos` (change immediately!) +- Your SSH key is already authorized + +```bash +# From your iMac, SSH into the installer +ssh root@TARGET_MACHINE_IP + +# First, change the root password +passwd +``` + +### 5.3 Partition the Disks + +The ISO includes disko for automated partitioning: + +```bash +# Run disko to partition and format the disks +# This will DESTROY ALL DATA on the target disks! +disko --mode disko /etc/nixos/disk-config.nix + +# Verify the partitions +lsblk +zpool status +``` + +### 5.4 Install NixOS + +```bash +# Generate hardware configuration +nixos-generate-config --root /mnt + +# Install NixOS from your flake +nixos-install --flake github:YOUR_USERNAME/YOUR_REPO#hs --root /mnt + +# Or if you want to use a local flake +git clone https://github.com/YOUR_USERNAME/YOUR_REPO.git /mnt/etc/nixos +nixos-install --flake /mnt/etc/nixos#hs --root /mnt +``` + +### 5.5 Reboot + +```bash +# Reboot into the installed system +reboot +``` + +## Post-Installation + +After rebooting: + +1. SSH into the system using your key: `ssh yanlin@TARGET_MACHINE_IP` +2. Verify the system is working correctly +3. Update the configuration as needed +4. Set up any additional services + +## Troubleshooting + +### Build Failures + +- Ensure you have enough disk space on the VPS +- Try increasing VPS resources (RAM/CPU) +- Check for network issues when downloading packages + +### Boot Issues + +- Verify UEFI/BIOS settings support both UEFI and Legacy boot +- Check that both drives are detected in BIOS +- Try booting with only one drive connected initially + +### ZFS Issues + +- If ZFS pool import fails, try: `zpool import -f rpool` +- Check disk IDs match those in disk-config.nix: `ls -la /dev/disk/by-id/` + +### Network Issues in Installer + +- Check network with: `ip a` +- Restart networking: `systemctl restart systemd-networkd` +- Check DHCP: `journalctl -u systemd-networkd` + +## Cleanup + +After successful installation: + +1. Delete the ISO from VPS +2. Terminate the VPS if no longer needed +3. Secure wipe the USB drive if used + +## Security Notes + +- Change the default installer password immediately +- The ISO includes your SSH public key - keep it secure +- Consider using a private Git repository for your configurations +- Delete the ISO after installation to prevent unauthorized access diff --git a/hosts/nixos/hs/disk-config.nix b/hosts/nixos/hs/disk-config.nix new file mode 100644 index 0000000..d2b387a --- /dev/null +++ b/hosts/nixos/hs/disk-config.nix @@ -0,0 +1,132 @@ +{ + disko.devices = { + disk = { + # First drive of ZFS mirror pair (ZHITAI 1TB #1) + main1 = { + type = "disk"; + device = "/dev/disk/by-id/ata-ZHITAI_SC001_XT_1000GB_ZTB401TAB244431J4R"; + content = { + type = "gpt"; + partitions = { + # GRUB BIOS boot partition + boot = { + size = "1M"; + type = "EF02"; + }; + # EFI System Partition (mirrored manually) + esp1 = { + size = "500M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "umask=0077" ]; + }; + }; + # ZFS partition + zfs = { + size = "100%"; + content = { + type = "zfs"; + pool = "rpool"; + }; + }; + }; + }; + }; + + # Second drive of ZFS mirror pair (ZHITAI 1TB #2) + main2 = { + type = "disk"; + device = "/dev/disk/by-id/ata-ZHITAI_SC001_XT_1000GB_ZTB401TAB244431KEG"; + content = { + type = "gpt"; + partitions = { + # GRUB BIOS boot partition + boot = { + size = "1M"; + type = "EF02"; + }; + # EFI System Partition (backup) + esp2 = { + size = "500M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + }; + }; + # ZFS partition + zfs = { + size = "100%"; + content = { + type = "zfs"; + pool = "rpool"; + }; + }; + }; + }; + }; + }; + + zpool = { + rpool = { + type = "zpool"; + mode = "mirror"; + rootFsOptions = { + compression = "lz4"; + acltype = "posixacl"; + xattr = "sa"; + relatime = "on"; + normalization = "formD"; + canmount = "off"; + dnodesize = "auto"; + }; + mountpoint = "/"; + + datasets = { + # Root dataset + root = { + type = "zfs_fs"; + options = { + canmount = "off"; + mountpoint = "none"; + }; + }; + + # Root filesystem + "root/nixos" = { + type = "zfs_fs"; + mountpoint = "/"; + options = { + canmount = "noauto"; + mountpoint = "/"; + }; + }; + + # Home directory + "root/home" = { + type = "zfs_fs"; + mountpoint = "/home"; + options = { + canmount = "on"; + mountpoint = "/home"; + }; + }; + + # Nix store (no snapshots needed) + "root/nix" = { + type = "zfs_fs"; + mountpoint = "/nix"; + options = { + canmount = "on"; + mountpoint = "/nix"; + "com.sun:auto-snapshot" = "false"; + }; + }; + }; + }; + }; + }; +} \ No newline at end of file diff --git a/hosts/nixos/hs/hardware-configuration.nix b/hosts/nixos/hs/hardware-configuration.nix new file mode 100644 index 0000000..cd57d58 --- /dev/null +++ b/hosts/nixos/hs/hardware-configuration.nix @@ -0,0 +1,40 @@ +# Hardware configuration for home server (hs) +# Generated by nixos-generate-config and customized for this system + +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; + + # Boot configuration - detected kernel modules for this hardware + boot.initrd.availableKernelModules = [ + "xhci_pci" + "ahci" + "usb_storage" + "sd_mod" + "sdhci_pci" + ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + # ZFS filesystems are managed by disko configuration + # No filesystem declarations needed here - disko handles all mounts + + # No swap devices configured + swapDevices = [ ]; + + # Networking hardware + networking.useDHCP = lib.mkDefault true; + + # Hardware-specific settings + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + + # CPU microcode updates + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + # For AMD systems, use this instead: + # hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + + # Enable firmware updates + hardware.enableRedistributableFirmware = lib.mkDefault true; +} \ No newline at end of file diff --git a/hosts/nixos/hs/iso.nix b/hosts/nixos/hs/iso.nix new file mode 100644 index 0000000..9c953c6 --- /dev/null +++ b/hosts/nixos/hs/iso.nix @@ -0,0 +1,85 @@ +{ config, pkgs, lib, modulesPath, ... }: + +{ + imports = [ + # Use the ISO image generator + (modulesPath + "/installer/cd-dvd/installation-cd-minimal.nix") + + # Include your disk configuration so disko is available + ./disk-config.nix + ]; + + # Override ISO settings + image.baseName = lib.mkForce "nixos-hs"; + isoImage.volumeID = lib.mkForce "NIXOS_HS"; + isoImage.makeEfiBootable = true; + isoImage.makeUsbBootable = true; + + # Enable SSH in the installer for remote installation + services.openssh = { + enable = true; + settings = { + PermitRootLogin = "yes"; + PasswordAuthentication = true; # Allow password for initial connection + }; + openFirewall = true; + }; + + # Set a known root password for the installer + # You should change this immediately after installation + users.users.root.initialPassword = "nixos"; + + # Include your SSH key for passwordless access + users.users.root.openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG35m0DgTrEOAM+1wAlYZ8mvLelNTcx65cFccGPQcxmo yanlin@imac" + ]; + + # Networking + networking = { + useDHCP = lib.mkForce true; + hostName = "nixos-installer"; + wireless.enable = false; # Disable wireless if not needed + networkmanager.enable = lib.mkForce false; # Disable NetworkManager in installer + }; + + # Include essential tools for installation + environment.systemPackages = with pkgs; [ + vim + git + wget + curl + rsync + gptfdisk + disko + # ZFS tools + zfs + ]; + + # Enable ZFS support in the installer + boot.supportedFilesystems = [ "zfs" ]; + boot.zfs.forceImportRoot = false; + + # Make sure we have network access + systemd.services.sshd.wantedBy = lib.mkForce [ "multi-user.target" ]; + + # Add a helpful message + services.getty.helpLine = '' + + The NixOS installer for host 'hs' has been started. + + SSH is enabled. Default root password is: nixos + SSH keys for yanlin@imac are already authorized. + + To install: + 1. Change root password: passwd + 2. Run disko to partition: disko --mode disko /etc/nixos/disk-config.nix + 3. Install NixOS: nixos-install --flake github:YOUR_USERNAME/YOUR_REPO#hs + + ''; + + # Ensure the installer has enough memory + boot.kernelParams = [ "copytoram" ]; + + # Include the disk configuration in the ISO + environment.etc."nixos/disk-config.nix".source = ./disk-config.nix; +} \ No newline at end of file diff --git a/hosts/nixos/hs/system.nix b/hosts/nixos/hs/system.nix new file mode 100644 index 0000000..6ba0f96 --- /dev/null +++ b/hosts/nixos/hs/system.nix @@ -0,0 +1,118 @@ +{ config, pkgs, ... }: { + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + ]; + + # GRUB bootloader with ZFS support + boot.loader.grub = { + enable = true; + devices = [ + "/dev/disk/by-id/ata-ZHITAI_SC001_XT_1000GB_ZTB401TAB244431J4R" + "/dev/disk/by-id/ata-ZHITAI_SC001_XT_1000GB_ZTB401TAB244431KEG" + ]; # Install GRUB on both ZFS mirror drives + efiSupport = true; + efiInstallAsRemovable = true; + zfsSupport = true; + }; + + # Enable systemd stage-1 and ZFS support + boot.initrd.systemd.enable = true; + boot.supportedFilesystems = [ "zfs" ]; + boot.zfs.forceImportRoot = false; + + # Network configuration + networking = { + hostName = "hs"; + hostId = "12345678"; # Required for ZFS, good practice for any system + networkmanager.enable = true; + firewall.enable = false; + # firewall.allowedTCPPorts = [ 22 ]; # SSH + }; + + # Set your time zone + time.timeZone = "Europe/Copenhagen"; # Adjust to your timezone + + # Select internationalisation properties + i18n.defaultLocale = "en_US.UTF-8"; + + # Enable the OpenSSH daemon + services.openssh = { + enable = true; + settings = { + PermitRootLogin = "yes"; + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + }; + openFirewall = true; + }; + + # Define a user account + users.users.root = { + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG35m0DgTrEOAM+1wAlYZ8mvLelNTcx65cFccGPQcxmo yanlin@imac" + ]; + }; + + # Optional: Create a regular user account + users.users.yanlin = { + isNormalUser = true; + description = "yanlin"; + extraGroups = [ "networkmanager" "wheel" ]; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG35m0DgTrEOAM+1wAlYZ8mvLelNTcx65cFccGPQcxmo yanlin@imac" + ]; + }; + + # Enable sudo for wheel group + security.sudo.wheelNeedsPassword = false; + + # List packages installed in system profile + environment.systemPackages = with pkgs; [ + vim + git + htop + curl + wget + rsync + tmux + tree + lsof + tcpdump + iotop + smartmontools # For monitoring disk health + zfs # ZFS utilities + ]; + + # ZFS services configuration + services.zfs = { + autoScrub = { + enable = true; + interval = "monthly"; + }; + autoSnapshot = { + enable = true; + frequent = 4; # Keep 4 15-minute snapshots + hourly = 24; # Keep 24 hourly snapshots + daily = 7; # Keep 7 daily snapshots + weekly = 4; # Keep 4 weekly snapshots + monthly = 12; # Keep 12 monthly snapshots + }; + trim = { + enable = true; + interval = "weekly"; + }; + }; + + # Enable smartd for disk health monitoring + services.smartd = { + enable = true; + autodetect = true; + }; + + # This value determines the NixOS release from which the default + # settings for stateful data, like file locations and database versions + # on your system were taken. It's perfectly fine and recommended to leave + # this value at the release version of the first install of this system. + system.stateVersion = "24.05"; # Did you read the comment? +}