diff --git a/CLAUDE.md b/CLAUDE.md index 7538956..43d0038 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,8 +6,9 @@ # macOS (from ~/dotfiles/nixos) darwin-rebuild switch --flake . -# NixOS server (SSH from mac, or on server) +# NixOS servers (SSH from mac, or on server) sudo nixos-rebuild switch --flake .#sunken-ship +sudo nixos-rebuild switch --flake .#phantom-ship # WSL sudo nixos-rebuild switch --flake ~/dotfiles/nixos#wsl @@ -29,9 +30,10 @@ cd ~/dotfiles/nixos && nix build .#installer-iso - **Inputs:** nixpkgs-unstable, nix-darwin, home-manager, nixos-wsl, disko, zen-browser - **Host configs** in `nixos/hosts/`: - `daniel-macbook-air.nix` — hostname `Daniel-Macbook-Air` (aarch64-darwin, nix-darwin) - - `sunken-ship.nix` — NixOS home server (x86_64-linux) + - `sunken-ship.nix` — NixOS home server (x86_64-linux, WiFi + AirPlay) + - `phantom-ship.nix` — NixOS home server (x86_64-linux, Ethernet) - `wsl.nix` — WSL (x86_64-linux) - - `server-install.nix` — disko-install target (LUKS + WiFi) + - `server-install.nix` — disko-install target (LUKS) - **Home Manager:** integrated on macOS, WSL, and sunken-ship; user config in `nixos/home/danny/home.nix` - **Shared modules:** `nixos/fish.nix` (fish + bash), `nixos/ollama.nix` - **Darwin config name:** `Daniel-Macbook-Air` (must match in rebuild commands) @@ -46,8 +48,16 @@ cd ~/dotfiles/nixos && nix build .#installer-iso - SSH: `ssh -i ~/.ssh/id_ed25519_sunken_ship danny@sunken-ship` - Remote rebuild: `ssh ... 'cd /etc/dotfiles/nixos && sudo nixos-rebuild switch --flake .#sunken-ship'` -- Auto-rebuild timer: `dotfiles-rebuild` — only active after flake config switch. Check with `systemctl is-active dotfiles-rebuild.timer`. -- Server has WiFi; stays reachable when ethernet is unplugged. +- Auto-rebuild timer: `dotfiles-rebuild` — every 15 min. Check with `systemctl is-active dotfiles-rebuild.timer`. +- WiFi connected; stays reachable when ethernet is unplugged. +- Services: UxPlay (AirPlay receiver on Scarlett Solo) + +## Server (phantom-ship) + +- SSH: `ssh danny@phantom-ship` +- Remote rebuild: `ssh ... 'cd /etc/dotfiles/nixos && sudo nixos-rebuild switch --flake .#phantom-ship'` +- Auto-rebuild timer: same pattern as sunken-ship. +- Ethernet only (no WiFi). ## Ollama diff --git a/docs/server-installer-usb.md b/docs/server-installer-usb.md index bcd320d..4377f22 100644 --- a/docs/server-installer-usb.md +++ b/docs/server-installer-usb.md @@ -1,79 +1,100 @@ -# Server installer USB (NixOS + LUKS + WiFi) +# Server installer USB (NixOS + LUKS) -Bootable USB that installs NixOS on a new server with disk encryption (LUKS) and optional WiFi from first boot. Only required input is the hostname (and LUKS passphrase when disko creates the volume). Existing hosts are not modified. +Bootable USB that installs NixOS on a new server with disk encryption (LUKS). The install script handles partitioning, encryption, dotfiles cloning, SSH key setup, and hardware config generation. Only required inputs: hostname, LUKS passphrase, and target disk. -## Quick path: boot USB → WiFi → SSH in → run bootstrap +## Quick path (Ethernet server like phantom-ship) -1. Boot the target machine from the NixOS installer USB. -2. On the live system, connect to Wi‑Fi (or plug in Ethernet). Check internet (e.g. `ping -c 2 8.8.8.8`). -3. On the **live** system, start SSH and set a password for the `nixos` user so you can log in from your Mac: +### Prep (on sunken-ship or any Linux box) + +1. Download the [NixOS minimal ISO](https://nixos.org/download.html#nixos-iso) on sunken-ship. +2. Plug in USB and write the ISO: + ```bash + # Find your USB device (e.g. /dev/sdc) + lsblk + sudo dd if=nixos-minimal-*.iso of=/dev/sdX status=progress bs=4M + sync + ``` + +### Install (on the new server) + +3. Boot the new machine from USB, plug in Ethernet, verify connectivity (`ping 8.8.8.8`). +4. Start SSH on the live system so you can paste commands from your Mac: ```bash sudo systemctl start sshd sudo passwd nixos - hostname -I + hostname -I # note the IP ``` - Note the IP from `hostname -I`. -4. From your **Mac**: `ssh nixos@` (use the password you set). Now you can paste the bootstrap command instead of typing on the machine. -5. In that SSH session, run the bootstrap (installs NixOS with LUKS; prompts for hostname, disk, **danny password**, LUKS passphrase, then once more LUKS to set the password on disk): +5. From your **Mac**, scp your SSH public key and SSH in: ```bash - curl -sL https://raw.githubusercontent.com/DannyDannyDanny/dotfiles/server-installer-usb/scripts/bootstrap-install.sh | sudo bash + scp ~/.ssh/id_ed25519_phantom_ship.pub nixos@:/tmp/key.pub + ssh nixos@ ``` -6. When it finishes, reboot and remove the USB. Unlock LUKS at boot, then log in as **danny** with the password you set during the install. +6. Run the bootstrap (one command): + ```bash + curl -sL https://raw.githubusercontent.com/DannyDannyDanny/dotfiles/main/scripts/bootstrap-install.sh | \ + INSTALLER_HOSTNAME=phantom-ship SSH_PUBKEY_FILE=/tmp/key.pub sudo -E bash + ``` + This will prompt for: target disk, optional danny password, confirmation, and LUKS passphrase (twice: once for disko, once for post-install provisioning). -## Option A: Official NixOS ISO (works from macOS) + The script automatically: + - Partitions and encrypts the disk (LUKS + ext4) + - Installs NixOS with the hostname + - Clones dotfiles to `/etc/dotfiles` + - Installs your SSH public key + - Generates `phantom-ship-hardware.nix` -You **cannot** build the custom installer ISO on macOS (it is x86_64-linux only and `--system` is restricted). Use the official NixOS minimal ISO instead: +7. Reboot, remove USB, unlock LUKS. -1. Download the [minimal ISO](https://nixos.org/download.html#nixos-iso) (e.g. `nixos-minimal-*-x86_64-linux.iso`). -2. Write it to your USB (on macOS: `diskutil unmountDisk diskN`, then `sudo dd if=path/to/nixos-minimal-*.iso of=/dev/rdiskN bs=4m`). -3. Boot the server from the USB. Attach Ethernet or use the **graphical** ISO if you need Wi‑Fi on the live system. -4. On the live system, clone this repo and run the install script (see [Install on the server](#install-on-the-server) below). The script runs `disko-install` and does LUKS + hostname; no custom ISO needed. +### After first boot + +8. SSH in: `ssh danny@phantom-ship` +9. First rebuild to switch from generic `server-install` to `phantom-ship` config: + ```bash + cd /etc/dotfiles/nixos && sudo nixos-rebuild switch --flake .#phantom-ship + ``` +10. Commit the generated `phantom-ship-hardware.nix` back to the repo. + +## Environment variables + +All optional; skip interactive prompts or add automation: + +| Variable | Description | +|----------|-------------| +| `INSTALLER_HOSTNAME` | Skip hostname prompt | +| `INSTALLER_DISK` | Skip disk prompt (validated as block device) | +| `SSH_PUBKEY_FILE` | Path to `.pub` file; installed to danny's `authorized_keys` | +| `FLAKE_REF` | Override flake reference (default: auto-detect from repo) | +| `INSTALLER_SYSTEM_CONFIG_FILE` | JSON file merged into `--system-config` (e.g. WiFi config) | + +## Option A: Official NixOS ISO (recommended) + +Cannot build the custom ISO on macOS (x86_64-linux only). Use the official NixOS minimal ISO: + +1. Download from [nixos.org](https://nixos.org/download.html#nixos-iso). +2. Write to USB from sunken-ship or any Linux box. +3. Boot, connect Ethernet, run bootstrap. ## Option B: Custom ISO (build on Linux only) -The custom ISO adds Wi‑Fi kernel modules and optional live Wi‑Fi; it must be built on **x86_64-linux** (or with a Nix remote builder configured for that system). Building on macOS will fail. +Adds WiFi kernel modules for servers that need WiFi on the live system. -### Build from sunken-ship (one command from your Mac) - -When the server is on the same network, run from the dotfiles repo: +### Build from sunken-ship ```bash ./scripts/build-installer-iso-on-server.sh ``` -This pushes the branch, SSHs to sunken-ship, clones the repo there, runs `nix build .#installer-iso`, and copies the ISO back to the current directory. Optional: `./scripts/build-installer-iso-on-server.sh sunken-ship /path/to/output`. - -### Build directly on a Linux machine - -From a Linux box (or on sunken-ship after SSH in): +### Build directly on Linux ```bash -cd ~/dotfiles/nixos -nix build .#installer-iso +cd ~/dotfiles/nixos && nix build .#installer-iso +# Write to USB: +sudo dd if=result/iso/nixos-minimal-*.iso of=/dev/sdX status=progress bs=4M ``` -The image is at `result/iso/nixos-minimal-*.iso`. Write it to a USB stick (replace `sdX` with your device, e.g. `sda`): +## Live-system WiFi (optional, custom ISO only) -```bash -# Linux -sudo dd if=result/iso/nixos-minimal-*.iso of=/dev/sdX status=progress -sync -``` - -On macOS, use the disk number (e.g. `4` for `disk4`): - -```bash -sudo dd if=result/iso/nixos-minimal-*.iso of=/dev/rdisk4 bs=4m -diskutil eject disk4 -``` - -Or adapt [scripts/make-ubuntu-usb.sh](../scripts/make-ubuntu-usb.sh) for the NixOS ISO path. - -## Live-system WiFi (optional) - -So the live system can reach the network (and fetch the flake) without Ethernet, add WiFi to the ISO at **build time**. Do not put SSID/PSK in the repo. - -1. Create **`nixos/installer-wifi.nix`** (gitignored) with your network: +Create `nixos/installer-wifi.nix` (gitignored): ```nix { @@ -82,77 +103,18 @@ So the live system can reach the network (and fetch the flake) without Ethernet, } ``` -2. Add it to the flake for the installer ISO only. In `nixos/flake.nix`, change the `installer-iso` modules to: +Add to flake's installer-iso modules, rebuild ISO on Linux. -```nix -installer-iso = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; - modules = [ ./installer-iso.nix ./installer-wifi.nix ]; # add installer-wifi.nix -}; -``` +## Installed-system WiFi (optional) -3. Ensure `nixos/installer-wifi.nix` is in `.gitignore`, then rebuild the ISO. - -If you skip this, use Ethernet on the live system or the graphical NixOS installer to join Wi‑Fi, then run the install script. - -## Install on the server - -1. Boot the server from the USB. -2. If you did not bake WiFi into the ISO, attach Ethernet or (on graphical installer) join Wi‑Fi so the machine has network. -3. Run **one** of the following (shortest first). - -**Shortest — fetch and run (no clone step):** -Exact URL (watch for typos: **.com** not .con, **usb** not ush, **DannyDannyDanny** with three capital Ds): +Pass a JSON file with wireless config: ```bash -curl -sL https://raw.githubusercontent.com/DannyDannyDanny/dotfiles/server-installer-usb/scripts/bootstrap-install.sh | sudo bash +sudo INSTALLER_SYSTEM_CONFIG_FILE=/path/to/wifi.json INSTALLER_HOSTNAME=my-server ./scripts/nixos-server-install.sh ``` -If you see `bash: 404: command not found`, the URL was wrong or the branch doesn’t exist. Check the URL, or verify first: `curl -sL "THE_URL_ABOVE" | head -1` should show `#!/bin/bash`, not HTML. - -To type less, create a [git.io](https://git.io) short link once (paste the raw URL above), then on the machine run: `curl -sL https://git.io/YOUR_CODE | sudo bash`. - -**Alternative — clone then run** (if you prefer not to pipe curl to bash): - -```bash -nix run --extra-experimental-features "nix-command flakes" nixpkgs#git -- clone https://github.com/USER/REPO.git /tmp/dotfiles && cd /tmp/dotfiles && git checkout server-installer-usb && sudo ./scripts/nixos-server-install.sh -``` - -If you see `command not found` when running the script, use `sudo bash ./scripts/nixos-server-install.sh` instead of `sudo ./scripts/...`. - -4. When prompted: enter **hostname** (e.g. `phantom-ship`), then **target disk** (default `/dev/sda`), then **y** to proceed. When disko creates the LUKS volume, enter your encryption passphrase. -5. When the script finishes, remove the USB and reboot. The new NixOS system will have LUKS root and the hostname you chose. - -## WiFi on the installed system (optional) - -To have WiFi configured from first boot (no manual step after reboot): - -1. Create a JSON file **outside the repo** with the config to merge (hostname is set by the script from the prompt): - -```json -{ - "networking": { - "wireless": { - "networks": { - "YourSSID": { "psk": "your-password" } - } - } - } -} -``` - -2. Copy that file onto the live system (e.g. put it on the USB or scp it). If the script is run with `jq` available and `INSTALLER_SYSTEM_CONFIG_FILE` set to that file, the script will merge it and set the hostname: - -```bash -sudo INSTALLER_SYSTEM_CONFIG_FILE=/path/to/wifi-config.json ./scripts/nixos-server-install.sh -``` - -If you omit this, the installed system still has `networking.wireless.enable = true`. Add credentials after first boot (e.g. [imperative wpa_supplicant config](sunken-ship-wifi.md)). - ## Manual install (without the script) -You can run disko-install yourself: - ```bash sudo nix run github:nix-community/disko/latest#disko-install -- \ --flake 'path:/tmp/dotfiles/nixos#server-install' \ @@ -160,21 +122,13 @@ sudo nix run github:nix-community/disko/latest#disko-install -- \ --system-config '{"networking":{"hostName":"my-server"}}' ``` -Adjust the flake path and `--system-config` (e.g. add WiFi) as needed. - -## After install - -- Add your SSH key: from your machine `scp ~/.ssh/id_ed25519_servers.pub danny@NEW-SERVER:/tmp/`, then on the server `mkdir -p ~/.ssh; cat /tmp/*.pub >> ~/.ssh/authorized_keys`. -- To switch this machine to another host config in the same flake (e.g. a full server profile), clone the repo on the new system and run `sudo nixos-rebuild switch --flake /path/to/nixos#other-host`. - ## Summary | Step | Action | |------|--------| -| **From macOS** | Use Option A: download official NixOS minimal ISO, write to USB, boot server, clone repo, run install script. | -| **From Linux** | Option B: `nix build .#installer-iso` in `nixos/`, then write `result/iso/*.iso` to USB. | -| Optional live WiFi | (Custom ISO only) Add `installer-wifi.nix` (gitignored), include in flake, rebuild on Linux. | -| Boot | Boot server from USB | -| Install | On live system: `curl -sL https://raw.githubusercontent.com/.../server-installer-usb/scripts/bootstrap-install.sh | sudo bash` (or clone then `sudo ./scripts/nixos-server-install.sh`) | -| Optional installed WiFi | Set `INSTALLER_SYSTEM_CONFIG_FILE` to a JSON file with wireless config | -| Reboot | Remove USB, reboot; set root password if needed, add SSH keys | +| **Prep** | Download NixOS minimal ISO on sunken-ship, write to USB | +| **Boot** | Boot new server from USB, plug Ethernet | +| **Install** | `curl ... \| INSTALLER_HOSTNAME=phantom-ship SSH_PUBKEY_FILE=/tmp/key.pub sudo -E bash` | +| **Reboot** | Remove USB, unlock LUKS | +| **First rebuild** | `sudo nixos-rebuild switch --flake /etc/dotfiles/nixos#phantom-ship` | +| **Commit** | Push generated `phantom-ship-hardware.nix` to repo | diff --git a/nixos/flake.nix b/nixos/flake.nix index e55b552..f74750f 100644 --- a/nixos/flake.nix +++ b/nixos/flake.nix @@ -72,6 +72,26 @@ ]; }; + phantom-ship = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + ./hosts/phantom-ship.nix + + # Home Manager on NixOS + home-manager.nixosModules.home-manager + ({ lib, ... }: { + home-manager.useGlobalPkgs = true; + home-manager.useUserPackages = true; + home-manager.backupFileExtension = "backup"; + home-manager.users.danny = { ... }: { + home.username = "danny"; + home.homeDirectory = lib.mkForce "/home/danny"; + home.stateVersion = "25.11"; + }; + }) + ]; + }; + # For disko-install: LUKS + WiFi; hostname/WiFi via --system-config. server-install = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; diff --git a/nixos/hosts/phantom-ship-hardware.nix b/nixos/hosts/phantom-ship-hardware.nix new file mode 100644 index 0000000..19413f8 --- /dev/null +++ b/nixos/hosts/phantom-ship-hardware.nix @@ -0,0 +1,17 @@ +# STUB — replace with output of: nixos-generate-config --show-hardware-config +# The install script saves the real config here automatically. +# Filesystems are managed by disko during install; only boot/initrd config here. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; + + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + + boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "usb_storage" "sd_mod" ]; + boot.kernelModules = [ "kvm-intel" ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/nixos/hosts/phantom-ship.nix b/nixos/hosts/phantom-ship.nix new file mode 100644 index 0000000..6d52cad --- /dev/null +++ b/nixos/hosts/phantom-ship.nix @@ -0,0 +1,65 @@ +# NixOS server: bare config with SSH, auto-rebuild, Ethernet. +# Services (OpenClaw, etc.) to be added later. +{ config, lib, pkgs, ... }: + +let + dotfilesDir = "/etc/dotfiles"; + flakeRef = "${dotfilesDir}/nixos#phantom-ship"; +in +{ + imports = [ ./phantom-ship-hardware.nix ]; + + networking.hostName = "phantom-ship"; + networking.useDHCP = lib.mkDefault true; # Ethernet; no wireless + time.timeZone = "Europe/Copenhagen"; + + nix.settings.experimental-features = [ "nix-command" "flakes" ]; + programs.nix-ld.enable = true; # run dynamically linked binaries (e.g. Claude Code remote CLI) + system.stateVersion = "24.11"; + + users.users.danny = { + isNormalUser = true; + extraGroups = [ "wheel" ]; + }; + + # Key-only auth; no password or keyboard-interactive. + services.openssh = { + enable = true; + settings = { + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + }; + }; + + # Passwordless sudo for wheel. + security.sudo.wheelNeedsPassword = false; + environment.systemPackages = with pkgs; [ + git # clone/bootstrap and dotfiles-rebuild timer + ]; + + # Pull dotfiles and rebuild if the repo has new commits. + systemd.services.dotfiles-rebuild = { + description = "Pull dotfiles and run nixos-rebuild if repo changed"; + path = with pkgs; [ git nix ]; + environment.GIT_CONFIG_COUNT = "1"; + environment.GIT_CONFIG_KEY_0 = "safe.directory"; + environment.GIT_CONFIG_VALUE_0 = dotfilesDir; + script = '' + set -euo pipefail + cd ${dotfilesDir} + git fetch origin + if [ "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)" ]; then + exit 0 + fi + git pull origin main + exec nixos-rebuild switch --flake ${flakeRef} + ''; + serviceConfig.Type = "oneshot"; + }; + + systemd.timers.dotfiles-rebuild = { + wantedBy = [ "timers.target" ]; + timerConfig.OnCalendar = "*-*-* *:00/15:00"; # every 15 minutes + timerConfig.RandomizedDelaySec = "2min"; + }; +} diff --git a/scripts/bootstrap-install.sh b/scripts/bootstrap-install.sh index 66c1c58..617c8fc 100755 --- a/scripts/bootstrap-install.sh +++ b/scripts/bootstrap-install.sh @@ -1,13 +1,13 @@ #!/bin/bash # Fetch with curl and run to install NixOS (clone + run nixos-server-install.sh). # On the live system, run only: -# curl -sL https://raw.githubusercontent.com/DannyDannyDanny/dotfiles/server-installer-usb/scripts/bootstrap-install.sh | sudo bash +# curl -sL https://raw.githubusercontent.com/DannyDannyDanny/dotfiles/main/scripts/bootstrap-install.sh | sudo bash # # Optional: REPO_URL=... BRANCH=... (default repo and server-installer-usb) set -euo pipefail REPO_URL="${REPO_URL:-https://github.com/DannyDannyDanny/dotfiles.git}" -BRANCH="${BRANCH:-server-installer-usb}" +BRANCH="${BRANCH:-main}" DEST="/tmp/dotfiles" INSTALL_SCRIPT="$DEST/scripts/nixos-server-install.sh" diff --git a/scripts/nixos-server-install.sh b/scripts/nixos-server-install.sh index a70960b..f5a67e2 100644 --- a/scripts/nixos-server-install.sh +++ b/scripts/nixos-server-install.sh @@ -1,16 +1,17 @@ #!/bin/bash -# Run on a NixOS minimal live system (or installer ISO) to install NixOS with -# disko (LUKS + root). Prompts for hostname and target disk; optionally use -# INSTALLER_SYSTEM_CONFIG_FILE for WiFi etc. +# Install NixOS with disko (LUKS + root) on a live system. +# Prompts for hostname and target disk, then provisions the installed system +# (clones dotfiles, installs SSH key, generates hardware config). # # Usage (from repo root, e.g. /tmp/dotfiles): # sudo ./scripts/nixos-server-install.sh -# If you see "command not found", use: sudo bash ./scripts/nixos-server-install.sh # -# Optional: FLAKE_REF=github:User/dotfiles or path:/path/to/dotfiles/nixos -# -# Optional: INSTALLER_SYSTEM_CONFIG_FILE=/path/to/json with full --system-config -# (e.g. hostName + networking.wireless.networks). If unset, only hostname is passed. +# Environment variables (all optional): +# INSTALLER_HOSTNAME — skip hostname prompt +# INSTALLER_DISK — skip disk prompt (validated as block device) +# SSH_PUBKEY_FILE — path to .pub file; installed to danny's authorized_keys +# FLAKE_REF — override flake reference (default: auto-detect from repo) +# INSTALLER_SYSTEM_CONFIG_FILE — JSON file merged into --system-config set -euo pipefail FLAKE_REF="${FLAKE_REF:-}" @@ -30,21 +31,29 @@ if [[ "$EUID" -ne 0 ]]; then exit 1 fi -read -r -p "Hostname (e.g. my-server): " hostname +# --- Hostname --- +hostname="${INSTALLER_HOSTNAME:-}" +if [[ -z "$hostname" ]]; then + read -r -p "Hostname (e.g. phantom-ship): " hostname +fi if [[ -z "$hostname" ]]; then echo "Hostname cannot be empty." exit 1 fi -read -r -p "Target disk [default: /dev/sda]: " disk -disk="${disk:-/dev/sda}" +# --- Target disk --- +disk="${INSTALLER_DISK:-}" +if [[ -z "$disk" ]]; then + read -r -p "Target disk [default: /dev/sda]: " disk + disk="${disk:-/dev/sda}" +fi if [[ ! -b "$disk" ]]; then echo "Not a block device: $disk" exit 1 fi +# --- System config (hostname + optional extras) --- if [[ -n "${INSTALLER_SYSTEM_CONFIG_FILE:-}" ]] && [[ -f "$INSTALLER_SYSTEM_CONFIG_FILE" ]]; then - # Use provided JSON; ensure hostname is set if command -v jq &>/dev/null; then SYSTEM_CONFIG=$(jq --arg h "$hostname" '.networking.hostName = $h' "$INSTALLER_SYSTEM_CONFIG_FILE") else @@ -55,8 +64,9 @@ else SYSTEM_CONFIG='{"networking":{"hostName":"'"$hostname"'"}}' fi -# Prompt for password for danny so you can log in at console after reboot (no rescue needed) -read -r -p "Set a password for user danny (console/SSH login)? [y/N] " set_pass +# --- Optional: danny password --- +danny_pass="" +read -r -p "Set a password for user danny? [y/N] " set_pass if [[ "${set_pass,,}" == "y" || "${set_pass,,}" == "yes" ]]; then read -s -r -p "Password for danny: " danny_pass echo @@ -70,23 +80,27 @@ if [[ "${set_pass,,}" == "y" || "${set_pass,,}" == "yes" ]]; then echo "Password cannot be empty. Aborted." exit 1 fi - HASH=$(echo -n "$danny_pass" | openssl passwd -6 -stdin 2>/dev/null) || HASH=$(mkpasswd -6 -m sha-512 "$danny_pass" 2>/dev/null) - if [[ -z "$HASH" ]]; then - echo "Could not hash password (need openssl or mkpasswd). Skipping password." - else + HASH=$(echo -n "$danny_pass" | openssl passwd -6 -stdin 2>/dev/null) || HASH=$(mkpasswd -6 -m sha-512 "$danny_pass" 2>/dev/null) || true + if [[ -n "${HASH:-}" ]]; then if command -v jq &>/dev/null; then SYSTEM_CONFIG=$(echo "$SYSTEM_CONFIG" | jq --arg h "$HASH" '. + {"users":{"users":{"danny":{"hashedPassword":$h}}}}') else NEW_CONFIG=$(echo "$SYSTEM_CONFIG" | nix run nixpkgs#jq -- --arg h "$HASH" '. + {"users":{"users":{"danny":{"hashedPassword":$h}}}}' 2>/dev/null) - [[ -n "$NEW_CONFIG" ]] && SYSTEM_CONFIG="$NEW_CONFIG" || echo "Could not merge password (jq not found). Set after boot: passwd danny" + [[ -n "$NEW_CONFIG" ]] && SYSTEM_CONFIG="$NEW_CONFIG" || echo "Could not merge password. Set after boot: passwd danny" fi - [[ -n "$SYSTEM_CONFIG" ]] && echo "Password will be set for danny." + echo "Password will be set for danny." + else + echo "Could not hash password (need openssl or mkpasswd). Set after boot: passwd danny" fi fi +# --- Confirm and install --- +echo "" +echo "=== Install Summary ===" echo "Flake: ${FLAKE_REF}#server-install" echo "Disk: $disk" echo "Hostname: $hostname" +echo "SSH pubkey: ${SSH_PUBKEY_FILE:-none}" echo "System config: $SYSTEM_CONFIG" read -r -p "Proceed? [y/N] " confirm if [[ "${confirm,,}" != "y" && "${confirm,,}" != "yes" ]]; then @@ -100,33 +114,84 @@ nix run --extra-experimental-features "nix-command flakes" \ --disk main "$disk" \ --system-config "$SYSTEM_CONFIG" -# Set danny password directly on disk (Nix merge can fail); re-open LUKS and chroot -if [[ -n "${danny_pass:-}" ]]; then - echo "Setting password for danny on installed system (re-enter LUKS passphrase once)..." - read -s -r -p "LUKS passphrase: " luks_pass - echo - LUKS_DEV="/dev/disk/by-partlabel/disk-main-luks" - ESP_DEV="/dev/disk/by-partlabel/disk-main-ESP" - if [[ ! -b "$LUKS_DEV" ]]; then - LUKS_DEV="${disk}2" - ESP_DEV="${disk}1" - fi - if [[ -b "$LUKS_DEV" ]]; then - if ! echo -n "$luks_pass" | cryptsetup open "$LUKS_DEV" crypted --key-file -; then - echo "Wrong LUKS passphrase; set danny password after boot: passwd danny" - else - mount /dev/mapper/crypted /mnt - [[ -b "$ESP_DEV" ]] && mount "$ESP_DEV" /mnt/boot - mount --bind /dev /mnt/dev - mount --bind /proc /mnt/proc - mount --bind /sys /mnt/sys - echo "danny:${danny_pass}" | chroot /mnt chpasswd - umount -R /mnt - cryptsetup close crypted - echo "Password for danny set. Reboot and log in." - fi - unset luks_pass - else - echo "Could not find LUKS partition; set password after boot: passwd danny" - fi +echo "" +echo "=== Post-install provisioning ===" +echo "Re-opening LUKS to provision the installed system..." +read -s -r -p "LUKS passphrase: " luks_pass +echo + +LUKS_DEV="/dev/disk/by-partlabel/disk-main-luks" +ESP_DEV="/dev/disk/by-partlabel/disk-main-ESP" +if [[ ! -b "$LUKS_DEV" ]]; then + LUKS_DEV="${disk}2" + ESP_DEV="${disk}1" fi + +if [[ ! -b "$LUKS_DEV" ]]; then + echo "Could not find LUKS partition. Complete these steps manually after boot:" + echo " 1. Clone dotfiles: sudo git clone ... /etc/dotfiles" + echo " 2. Add SSH key: mkdir -p ~/.ssh && cat /tmp/key.pub >> ~/.ssh/authorized_keys" + echo " 3. Generate hardware config: nixos-generate-config --show-hardware-config > /etc/dotfiles/nixos/hosts/${hostname}-hardware.nix" + exit 0 +fi + +if ! echo -n "$luks_pass" | cryptsetup open "$LUKS_DEV" crypted --key-file -; then + echo "Wrong LUKS passphrase. Complete provisioning manually after boot." + unset luks_pass + exit 0 +fi +unset luks_pass + +mount /dev/mapper/crypted /mnt +[[ -b "$ESP_DEV" ]] && mount "$ESP_DEV" /mnt/boot +mount --bind /dev /mnt/dev +mount --bind /proc /mnt/proc +mount --bind /sys /mnt/sys + +# 1. Set danny password (belt-and-suspenders; Nix merge can fail) +if [[ -n "$danny_pass" ]]; then + echo "danny:${danny_pass}" | chroot /mnt chpasswd + echo " [ok] danny password set" +fi +unset danny_pass + +# 2. Clone dotfiles +if [[ ! -d /mnt/etc/dotfiles ]]; then + chroot /mnt nix run --extra-experimental-features "nix-command flakes" nixpkgs#git -- \ + clone https://github.com/DannyDannyDanny/dotfiles.git /etc/dotfiles + echo " [ok] dotfiles cloned to /etc/dotfiles" +else + echo " [skip] /etc/dotfiles already exists" +fi + +# 3. Install SSH public key +if [[ -n "${SSH_PUBKEY_FILE:-}" ]] && [[ -f "$SSH_PUBKEY_FILE" ]]; then + mkdir -p /mnt/home/danny/.ssh + cat "$SSH_PUBKEY_FILE" >> /mnt/home/danny/.ssh/authorized_keys + chmod 700 /mnt/home/danny/.ssh + chmod 600 /mnt/home/danny/.ssh/authorized_keys + chroot /mnt chown -R danny:users /home/danny/.ssh + echo " [ok] SSH public key installed" +elif [[ -n "${SSH_PUBKEY_FILE:-}" ]]; then + echo " [warn] SSH_PUBKEY_FILE set but file not found: $SSH_PUBKEY_FILE" +fi + +# 4. Generate hardware config +HW_CONFIG="/mnt/etc/dotfiles/nixos/hosts/${hostname}-hardware.nix" +if nixos-generate-config --show-hardware-config --root /mnt > "$HW_CONFIG" 2>/dev/null; then + echo " [ok] hardware config saved to hosts/${hostname}-hardware.nix" + echo " NOTE: Commit this file to the repo after first boot." +else + echo " [warn] nixos-generate-config failed; run manually after boot:" + echo " nixos-generate-config --show-hardware-config > /etc/dotfiles/nixos/hosts/${hostname}-hardware.nix" +fi + +umount -R /mnt +cryptsetup close crypted + +echo "" +echo "=== Done! ===" +echo "Remove the USB and reboot. After unlocking LUKS:" +echo " 1. SSH in: ssh danny@${hostname}" +echo " 2. First rebuild: cd /etc/dotfiles/nixos && sudo nixos-rebuild switch --flake .#${hostname}" +echo " 3. Commit ${hostname}-hardware.nix back to the repo"