Archived
LXC containers have no raw disk visible from inside them, only their already-mounted root filesystem, so hosts like lxc-minimal have no disko config and auto-install.sh's disko branch was a no-op. With nothing pointing /mnt at anything, nixos-install (which defaults to --root /mnt) built the new system into a disconnected empty directory on the container's own root — never the filesystem it actually boots from. After reboot, Proxmox just re-execs the *original* /sbin/init, so the container silently keeps running the installer environment forever, with the "installed" system sitting inert and unused. Confirmed on a real lxc-minimal attempt: /etc/flake-target (stamped by every nixos flake target) didn't exist post-"install", the only SSH key present matched this installer's own common.nix rather than the target flake's modules/common/configuration.nix, and sshd was still socket-activated (nixpkgs' proxmox-lxc.nix default) rather than running as the target's plain sshd.service. Fix: bind-mount / onto /mnt when there's no disko config, so nixos-install actually lands on the filesystem the container boots from — installing NixOS in place rather than into a void. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
191 lines
6.7 KiB
Nix
191 lines
6.7 KiB
Nix
{ pkgs, lib, ... }:
|
|
|
|
{
|
|
networking.useDHCP = lib.mkDefault true;
|
|
|
|
time.timeZone = "Australia/Brisbane";
|
|
|
|
# Without this, the installer only ever sees cache.nixos.org, which
|
|
# doesn't carry sops-install-secrets (it's built straight from the
|
|
# sops-nix flake's own Go source, not part of nixpkgs) — every install
|
|
# would otherwise compile it from scratch, which is what ran an 8GB LXC
|
|
# container's disk out of space. Push a built copy to nix-cache once
|
|
# (from a machine with real disk headroom) and every future install,
|
|
# of any type, fetches instead of rebuilding.
|
|
nix.settings = {
|
|
substituters = [
|
|
"http://nix-cache"
|
|
"https://cache.nixos.org/"
|
|
];
|
|
trusted-public-keys = [
|
|
"cache.local-1:usoWYanY3Kpq2+kDIS2nhWoLZiRxanmdysdzqCFBHW4="
|
|
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
|
|
];
|
|
};
|
|
|
|
environment.systemPackages = with pkgs; [
|
|
git
|
|
curl
|
|
jq
|
|
parted
|
|
e2fsprogs
|
|
btrfs-progs
|
|
util-linux
|
|
disko
|
|
];
|
|
|
|
programs.git = {
|
|
enable = true;
|
|
|
|
config = {
|
|
credential.helper = "store --file=/etc/git-credentials";
|
|
};
|
|
};
|
|
|
|
environment.etc."git-credentials".text =
|
|
"https://beatzaplenty:294be99829703536e02fdeed893137f1d8d96b76@gitea.lan.ddnsgeek.com";
|
|
|
|
# Run the installer on first login. Previously this copied an /etc file
|
|
# into the nixos user's ~/.bash_profile via an activation script that
|
|
# got dropped in a refactor (and only ever worked for that one user
|
|
# anyway) — loginShellInit is NixOS's native hook for this, applies to
|
|
# any user's login shell (root included), and needs no home-directory
|
|
# file-copying/chown.
|
|
programs.bash.loginShellInit = ''
|
|
if [ -n "$PS1" ] && [ ! -e "$HOME/.auto_install_ran" ]; then
|
|
sudo /etc/auto-install.sh
|
|
touch "$HOME/.auto_install_ran"
|
|
fi
|
|
'';
|
|
|
|
|
|
services.openssh.enable = true;
|
|
|
|
services.openssh.settings = {
|
|
PermitRootLogin = "yes";
|
|
PasswordAuthentication = true;
|
|
};
|
|
|
|
|
|
users.users.root = {
|
|
hashedPassword =
|
|
"$6$Kwv9KAyvcurAViQF$H4.u3feqGE7lVoNgkFXhE3n2Pmo//9JYDTCz8ifrVHBxPjwa1xMby7tEZ8Bpt5MXs9Rkx6/YbZWxs5CpH0s/70";
|
|
};
|
|
|
|
|
|
users.users.nixos = {
|
|
isNormalUser = true;
|
|
|
|
extraGroups = [
|
|
"wheel"
|
|
];
|
|
|
|
shell = pkgs.bashInteractive;
|
|
|
|
hashedPassword =
|
|
"$6$Kwv9KAyvcurAViQF$H4.u3feqGE7lVoNgkFXhE3n2Pmo//9JYDTCz8ifrVHBxPjwa1xMby7tEZ8Bpt5MXs9Rkx6/YbZWxs5CpH0s/70";
|
|
|
|
openssh.authorizedKeys.keys = [
|
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCq/Q5LvIXlZwO2kdeAN5nLGZ59nZB7JHYMEszHxmNtGMzv1lM31jiPNsr0z2EKVZhE7OOfa2IF9rhWYD7JUA9G0yzdZ4WTXFNGVVOJoOVH6vAF3XCxoVilOEwTc7h2Wiy+rzd0B28/3spffzQQWJhY6GRQVa8j+6xAGF60Fcvl1vLosYT9Bn2ZbK4TCWOwAn2jqXIieGpZdn/UNZbGOeKRiCvhktDfMAzuQzN/9jMu/oF4pkPn2X1UrsQdNlvp0Ci8md612MozIpncQJyAF1ADhunr3sMx0isUXiqD29R5DS4TftpekqLNLak+zcxFa8N7DcRNp3DcKfJvyTkwQrR4r+b7lFLYOLHLagSso9CzeW/paAS2q9I5SBm/2DtE1diLLg2jZikYcstsu/G5RgvbzbKqjiaMwTdXC3AMvDxQrs7U5pDRZFzoofG3cpODbTm+uy3m0kP70z0M1K45UbDG0p+itnTu9x40JbQEgefbx38AItNvAIx1A8HO4I1VX28= wayne@stream"
|
|
];
|
|
};
|
|
|
|
|
|
system.stateVersion = "26.05";
|
|
|
|
# Write auto-install script to /root
|
|
environment.etc."auto-install.sh".text = ''
|
|
#!/run/current-system/sw/bin/bash
|
|
set -eux
|
|
|
|
set -euo pipefail
|
|
|
|
export FLAKE_BASE_URL="git+https://gitea.lan.ddnsgeek.com/beatzaplenty/nixos.git"
|
|
|
|
echo "Fetching available NixOS hosts from flake..."
|
|
mapfile -t options < <(
|
|
nix eval --json --no-use-registries --no-accept-flake-config --extra-experimental-features "flakes nix-command" \
|
|
"''${FLAKE_BASE_URL}#nixosConfigurations" \
|
|
--apply builtins.attrNames \
|
|
| jq -r '.[]'
|
|
)
|
|
|
|
if [[ ''${#options[@]} -eq 0 ]]; then
|
|
echo "ERROR: No NixOS hosts found in ''${FLAKE_BASE_URL}#nixosConfigurations" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "Choose the flake profile to install:"
|
|
select choice in "''${options[@]}"; do
|
|
if [[ -n "$choice" ]]; then
|
|
echo "You selected: $choice"
|
|
break
|
|
else
|
|
echo "Invalid selection. Try again."
|
|
fi
|
|
done
|
|
|
|
echo "Starting install with flake: ''${FLAKE_BASE_URL}#''${choice}"
|
|
|
|
# Optional: confirm before proceeding
|
|
read -rp "Proceed with installation? (y/N): " confirm
|
|
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
|
|
echo "Aborted."
|
|
exit 1
|
|
fi
|
|
|
|
if nix eval --refresh --json --extra-experimental-features "flakes nix-command" "''${FLAKE_BASE_URL}#nixosConfigurations.''${choice}.config.disko.devices.disk.main.device" >/dev/null 2>&1; then
|
|
disko --mode destroy,format,mount \
|
|
--flake "''${FLAKE_BASE_URL}#''${choice}" --yes
|
|
else
|
|
# No raw disk to partition — true for every LXC container, which has
|
|
# no block device visible from inside it, only its already-mounted
|
|
# root filesystem. nixos-install defaults to installing into /mnt; if
|
|
# nothing points /mnt at the real root, the new system gets built and
|
|
# written to a disconnected empty directory, never actually becomes
|
|
# bootable, and the container silently keeps running this installer
|
|
# environment forever. Bind-mount / onto /mnt so the install actually
|
|
# lands on the filesystem this container boots from.
|
|
echo "Selected host has no Disko configuration — installing in place via bind mount."
|
|
mount --bind / /mnt
|
|
fi
|
|
|
|
# sops-nix derives this host's decryption key from its own SSH host key
|
|
# at *activation* time, which runs before systemd would otherwise
|
|
# generate one on first boot. Without pre-seeding it here, secrets
|
|
# (including the login password) fail to decrypt on first boot.
|
|
# Generate the key + register it with `nixos`'s sops-nix setup ahead of
|
|
# time (see nix-auto-installer/scripts/prepare-host-key.sh), then scp it
|
|
# to /root/host-keys/ on this machine before continuing.
|
|
mkdir -p /root/host-keys
|
|
if [[ -f "/root/host-keys/''${choice}_ssh_host_ed25519_key" ]]; then
|
|
echo "Found pre-seeded SSH host key for ''${choice}, installing to target..."
|
|
install -D -m 0600 "/root/host-keys/''${choice}_ssh_host_ed25519_key" /mnt/etc/ssh/ssh_host_ed25519_key
|
|
install -D -m 0644 "/root/host-keys/''${choice}_ssh_host_ed25519_key.pub" /mnt/etc/ssh/ssh_host_ed25519_key.pub
|
|
else
|
|
echo "WARNING: no pre-seeded host key found at /root/host-keys/''${choice}_ssh_host_ed25519_key"
|
|
echo "sops-nix secrets (including the login password) will NOT decrypt on first boot."
|
|
echo "Run scripts/prepare-host-key.sh for host ''${choice} on your admin workstation first,"
|
|
echo "then scp the result here, if this host needs sops-nix secrets."
|
|
read -rp "Continue without a pre-seeded key anyway? (y/N): " skip_key
|
|
if [[ ! "$skip_key" =~ ^[Yy]$ ]]; then
|
|
echo "Aborted."
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
mkdir -p /mnt/install-tmp
|
|
export TMPDIR=/mnt/install-tmp
|
|
|
|
nixos-install \
|
|
--flake "''${FLAKE_BASE_URL}#''${choice}" \
|
|
--no-root-password
|
|
|
|
|
|
rm -rf /mnt/install-tmp
|
|
sleep 10
|
|
reboot
|
|
'';
|
|
|
|
environment.etc."auto-install.sh".mode = "0755";
|
|
} |