feat(install): LUKS by default → auto-login, snapper snapshots, hibernation swapfile
- LUKS2 is the installer default; in exchange the generated config sets
the new nomarchy.system.greeter.autoLogin (greetd initial_session) —
the disk passphrase already gates the machine.
- @snapshots subvolume + nomarchy.system.snapper.enable: hourly/daily
timeline snapshots of / and the nixos-rebuild-snap helper, ported from
the previous iteration (3bdfc35), guarded to no-op on non-BTRFS roots.
- @swap subvolume with a swapfile sized to RAM by default (disko
mkswapfile handles NOCOW); the installer computes the resume offset
and wires boot.resumeDevice + resume_offset for hibernation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
17
README.md
17
README.md
@@ -89,13 +89,16 @@ the locked inputs into the ISO store — so theme switching (including the
|
|||||||
installed system. Verification checklist: [docs/TESTING.md](docs/TESTING.md).
|
installed system. Verification checklist: [docs/TESTING.md](docs/TESTING.md).
|
||||||
|
|
||||||
Like what you see? **`nomarchy-install`** (in a terminal) walks you through
|
Like what you see? **`nomarchy-install`** (in a terminal) walks you through
|
||||||
installing to disk: pick a disk, optional LUKS2 full-disk encryption, user +
|
installing to disk: pick a disk, LUKS2 full-disk encryption **by default**
|
||||||
hostname + timezone, hardware autodetection (DMI → nixos-hardware profile),
|
(in exchange the desktop logs in passwordless — the passphrase already
|
||||||
then disko partitions (GPT + ESP + BTRFS subvolumes) and `nixos-install`
|
gates the machine), user + hostname + timezone, hardware autodetection
|
||||||
runs — **without a network** when the ISO was built from a clean tree (the
|
(DMI → nixos-hardware profile), a hibernation-ready swapfile sized to RAM,
|
||||||
target's `flake.lock` is composed from the rev the ISO carries). The
|
then disko partitions (GPT + ESP + BTRFS subvolumes incl. `@snapshots` —
|
||||||
installed machine gets the standard downstream layout: the flake at
|
snapper timeline snapshots are on) and `nixos-install` runs — **without a
|
||||||
`~/.nomarchy` (`/etc/nixos` symlinks to it), one `mkFlake` call, your
|
network** when the ISO was built from a clean tree (the target's
|
||||||
|
`flake.lock` is composed from the rev the ISO carries). The installed
|
||||||
|
machine gets the standard downstream layout: the flake at `~/.nomarchy`
|
||||||
|
(`/etc/nixos` symlinks to it), one `mkFlake` call, your
|
||||||
`system.nix`/`home.nix`. First boot lands in the fully themed desktop —
|
`system.nix`/`home.nix`. First boot lands in the fully themed desktop —
|
||||||
the installer pre-activates the Home Manager generation. UEFI only for now.
|
the installer pre-activates the Home Manager generation. UEFI only for now.
|
||||||
|
|
||||||
|
|||||||
@@ -77,11 +77,13 @@ terminal:
|
|||||||
```sh
|
```sh
|
||||||
sudo NOMARCHY_UNATTENDED=1 NOMARCHY_DISK=/dev/vda \
|
sudo NOMARCHY_UNATTENDED=1 NOMARCHY_DISK=/dev/vda \
|
||||||
NOMARCHY_USERNAME=me NOMARCHY_PASSWORD=test \
|
NOMARCHY_USERNAME=me NOMARCHY_PASSWORD=test \
|
||||||
|
NOMARCHY_LUKS_PASSPHRASE=testtest1 \
|
||||||
NOMARCHY_FINISH=poweroff nomarchy-install
|
NOMARCHY_FINISH=poweroff nomarchy-install
|
||||||
```
|
```
|
||||||
|
|
||||||
Then boot the VM again **from the target disk** (drop `-cdrom`). The
|
Then boot the VM again **from the target disk** (drop `-cdrom`). After
|
||||||
machine must reach the themed desktop on its own — greeter autostart,
|
typing the LUKS passphrase at the initrd prompt, the machine must reach
|
||||||
|
the themed desktop **without a login prompt** (LUKS implies auto-login) —
|
||||||
wallpaper, Waybar — and `nomarchy-theme-sync apply <x>` must work. For the
|
wallpaper, Waybar — and `nomarchy-theme-sync apply <x>` must work. For the
|
||||||
offline claim, add `restrict=on` to the `-netdev` and re-run the whole
|
offline claim, add `restrict=on` to the `-netdev` and re-run the whole
|
||||||
flow: it must behave identically (requires an ISO built from a clean git
|
flow: it must behave identically (requires an ISO built from a clean git
|
||||||
|
|||||||
@@ -26,9 +26,16 @@ in
|
|||||||
|
|
||||||
services.greetd = lib.mkIf cfg.greeter.enable {
|
services.greetd = lib.mkIf cfg.greeter.enable {
|
||||||
enable = lib.mkDefault true;
|
enable = lib.mkDefault true;
|
||||||
settings.default_session = {
|
settings = {
|
||||||
command = lib.mkDefault "${pkgs.tuigreet}/bin/tuigreet --time --remember --cmd Hyprland";
|
default_session = {
|
||||||
user = "greeter";
|
command = lib.mkDefault "${pkgs.tuigreet}/bin/tuigreet --time --remember --cmd Hyprland";
|
||||||
|
user = "greeter";
|
||||||
|
};
|
||||||
|
# Boot straight into the session once; logout → normal greeter.
|
||||||
|
initial_session = lib.mkIf (cfg.greeter.autoLogin != null) {
|
||||||
|
command = "Hyprland";
|
||||||
|
user = cfg.greeter.autoLogin;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -53,6 +60,24 @@ in
|
|||||||
hardware.bluetooth.enable = lib.mkDefault cfg.bluetooth.enable;
|
hardware.bluetooth.enable = lib.mkDefault cfg.bluetooth.enable;
|
||||||
services.blueman.enable = lib.mkDefault cfg.bluetooth.enable;
|
services.blueman.enable = lib.mkDefault cfg.bluetooth.enable;
|
||||||
|
|
||||||
|
# ── BTRFS timeline snapshots (ported from the previous iteration) ─
|
||||||
|
# Guarded on the actual filesystem so enabling it on an ext4 machine
|
||||||
|
# is a clean no-op rather than a failing timer.
|
||||||
|
services.snapper.configs = lib.mkIf
|
||||||
|
(cfg.snapper.enable && (config.fileSystems."/".fsType or "") == "btrfs")
|
||||||
|
{
|
||||||
|
root = {
|
||||||
|
SUBVOLUME = "/";
|
||||||
|
TIMELINE_CREATE = true;
|
||||||
|
TIMELINE_CLEANUP = true;
|
||||||
|
TIMELINE_LIMIT_HOURLY = "5";
|
||||||
|
TIMELINE_LIMIT_DAILY = "7";
|
||||||
|
TIMELINE_LIMIT_WEEKLY = "0";
|
||||||
|
TIMELINE_LIMIT_MONTHLY = "0";
|
||||||
|
TIMELINE_LIMIT_YEARLY = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
# ── Fonts ────────────────────────────────────────────────────────
|
# ── Fonts ────────────────────────────────────────────────────────
|
||||||
fonts = {
|
fonts = {
|
||||||
packages = with pkgs; [
|
packages = with pkgs; [
|
||||||
@@ -82,7 +107,21 @@ in
|
|||||||
wl-clipboard
|
wl-clipboard
|
||||||
grim
|
grim
|
||||||
slurp
|
slurp
|
||||||
];
|
] ++ lib.optional (cfg.snapper.enable && (config.fileSystems."/".fsType or "") == "btrfs")
|
||||||
|
# Snapshot, then rebuild — rollback material for system changes
|
||||||
|
# (theme changes don't need it; HM generations already roll back).
|
||||||
|
(pkgs.writeShellScriptBin "nixos-rebuild-snap" ''
|
||||||
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
|
echo "This script must be run as root (use sudo)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Creating pre-rebuild snapshot..."
|
||||||
|
${pkgs.snapper}/bin/snapper -c root create \
|
||||||
|
-d "Pre-rebuild $(date +'%Y-%m-%d %H:%M:%S')" \
|
||||||
|
--cleanup-algorithm number
|
||||||
|
echo "Rebuilding..."
|
||||||
|
nixos-rebuild switch --flake /etc/nixos#default "$@"
|
||||||
|
'');
|
||||||
|
|
||||||
# ── Nix itself ───────────────────────────────────────────────────
|
# ── Nix itself ───────────────────────────────────────────────────
|
||||||
nix = {
|
nix = {
|
||||||
|
|||||||
@@ -8,7 +8,26 @@
|
|||||||
{
|
{
|
||||||
options.nomarchy.system = {
|
options.nomarchy.system = {
|
||||||
greeter.enable = lib.mkEnableOption "the greetd/tuigreet login screen" // { default = true; };
|
greeter.enable = lib.mkEnableOption "the greetd/tuigreet login screen" // { default = true; };
|
||||||
|
|
||||||
|
greeter.autoLogin = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.str;
|
||||||
|
default = null;
|
||||||
|
example = "ada";
|
||||||
|
description = ''
|
||||||
|
Log this user straight into Hyprland on boot (greetd
|
||||||
|
initial_session); logging out lands on the normal greeter.
|
||||||
|
The installer sets it on LUKS-encrypted machines — the disk
|
||||||
|
passphrase already gates access, a second prompt is ceremony.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
audio.enable = lib.mkEnableOption "the Pipewire audio stack" // { default = true; };
|
audio.enable = lib.mkEnableOption "the Pipewire audio stack" // { default = true; };
|
||||||
bluetooth.enable = lib.mkEnableOption "Bluetooth support with blueman" // { default = true; };
|
bluetooth.enable = lib.mkEnableOption "Bluetooth support with blueman" // { default = true; };
|
||||||
|
|
||||||
|
snapper.enable = lib.mkEnableOption ''
|
||||||
|
hourly/daily BTRFS timeline snapshots of / via snapper, plus the
|
||||||
|
`nixos-rebuild-snap` pre-rebuild-snapshot helper. No-op unless the
|
||||||
|
root filesystem is BTRFS with a /.snapshots subvolume (the installer
|
||||||
|
creates one)'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
, cryptsetup
|
, cryptsetup
|
||||||
, lvm2 # dmsetup
|
, lvm2 # dmsetup
|
||||||
, pciutils # lspci
|
, pciutils # lspci
|
||||||
|
, btrfs-progs # inspect-internal map-swapfile (hibernation offset)
|
||||||
# Baked metadata — what this installer installs and where it came from.
|
# Baked metadata — what this installer installs and where it came from.
|
||||||
, templateDir # templates/downstream (home.nix, theme-state.json)
|
, templateDir # templates/downstream (home.nix, theme-state.json)
|
||||||
, nomarchyLock # the distro's flake.lock (for offline lock composition)
|
, nomarchyLock # the distro's flake.lock (for offline lock composition)
|
||||||
@@ -51,7 +52,7 @@ stdenvNoCC.mkDerivation {
|
|||||||
wrapProgram $out/bin/nomarchy-install \
|
wrapProgram $out/bin/nomarchy-install \
|
||||||
--prefix PATH : ${lib.makeBinPath [
|
--prefix PATH : ${lib.makeBinPath [
|
||||||
bash gum disko whois git python3
|
bash gum disko whois git python3
|
||||||
util-linux gptfdisk parted cryptsetup lvm2 pciutils
|
util-linux gptfdisk parted cryptsetup lvm2 pciutils btrfs-progs
|
||||||
]} \
|
]} \
|
||||||
--set NOMARCHY_INSTALL_SHARE "$share" \
|
--set NOMARCHY_INSTALL_SHARE "$share" \
|
||||||
--set NOMARCHY_FLAKE_URL ${lib.escapeShellArg flakeUrl} \
|
--set NOMARCHY_FLAKE_URL ${lib.escapeShellArg flakeUrl} \
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
# disko --mode destroy,format,mount \
|
# disko --mode destroy,format,mount \
|
||||||
# --argstr mainDrive /dev/nvme0n1 \
|
# --argstr mainDrive /dev/nvme0n1 \
|
||||||
# --arg withLuks true \
|
# --arg withLuks true \
|
||||||
|
# --argstr swapSize 16G \
|
||||||
# disko-config.nix
|
# disko-config.nix
|
||||||
#
|
#
|
||||||
# Ported from the previous iteration's golden-path config (multi-disk
|
# Ported from the previous iteration's golden-path config (multi-disk
|
||||||
@@ -14,6 +15,7 @@
|
|||||||
# proved fragile twice before.
|
# proved fragile twice before.
|
||||||
{ mainDrive
|
{ mainDrive
|
||||||
, withLuks ? true
|
, withLuks ? true
|
||||||
|
, swapSize ? "0" # "0" = no swap; otherwise e.g. "16G" (sized for hibernation)
|
||||||
, ...
|
, ...
|
||||||
}:
|
}:
|
||||||
|
|
||||||
@@ -28,7 +30,16 @@ let
|
|||||||
"@home" = { mountpoint = "/home"; mountOptions = btrfsMountOptions; };
|
"@home" = { mountpoint = "/home"; mountOptions = btrfsMountOptions; };
|
||||||
"@nix" = { mountpoint = "/nix"; mountOptions = btrfsMountOptions; };
|
"@nix" = { mountpoint = "/nix"; mountOptions = btrfsMountOptions; };
|
||||||
"@log" = { mountpoint = "/var/log"; mountOptions = btrfsMountOptions; };
|
"@log" = { mountpoint = "/var/log"; mountOptions = btrfsMountOptions; };
|
||||||
};
|
# snapper timeline snapshots (nomarchy.system.snapper.enable)
|
||||||
|
"@snapshots" = { mountpoint = "/.snapshots"; mountOptions = btrfsMountOptions; };
|
||||||
|
} // (if swapSize == "0" then { } else {
|
||||||
|
# Hibernation-ready swapfile on its own subvolume; disko's
|
||||||
|
# mkswapfile handles the BTRFS NOCOW requirements.
|
||||||
|
"@swap" = {
|
||||||
|
mountpoint = "/swap";
|
||||||
|
swap.swapfile.size = swapSize;
|
||||||
|
};
|
||||||
|
});
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
# NOMARCHY_UNATTENDED=1 NOMARCHY_DISK=/dev/vda NOMARCHY_USERNAME=me \
|
# NOMARCHY_UNATTENDED=1 NOMARCHY_DISK=/dev/vda NOMARCHY_USERNAME=me \
|
||||||
# NOMARCHY_PASSWORD=secret [NOMARCHY_HOSTNAME=nomarchy] \
|
# NOMARCHY_PASSWORD=secret [NOMARCHY_HOSTNAME=nomarchy] \
|
||||||
# [NOMARCHY_TIMEZONE=UTC] [NOMARCHY_LUKS_PASSPHRASE=...] \
|
# [NOMARCHY_TIMEZONE=UTC] [NOMARCHY_LUKS_PASSPHRASE=...] \
|
||||||
|
# [NOMARCHY_SWAP_GB=N (default: RAM size; 0 = none)] \
|
||||||
# [NOMARCHY_HW="auto"|"none"|"mod1 mod2"] [NOMARCHY_FINISH=none|reboot|poweroff]
|
# [NOMARCHY_HW="auto"|"none"|"mod1 mod2"] [NOMARCHY_FINISH=none|reboot|poweroff]
|
||||||
# nomarchy-install
|
# nomarchy-install
|
||||||
|
|
||||||
@@ -87,10 +88,12 @@ info "Target: $TARGET_DISK"
|
|||||||
# ─── Encryption ─────────────────────────────────────────────────────────
|
# ─── Encryption ─────────────────────────────────────────────────────────
|
||||||
section "Disk encryption"
|
section "Disk encryption"
|
||||||
|
|
||||||
|
# LUKS is the default: full-disk encryption, and in exchange the machine
|
||||||
|
# logs you straight into the desktop (the passphrase already gates access).
|
||||||
LUKS_PASSPHRASE=""
|
LUKS_PASSPHRASE=""
|
||||||
if [[ "$UNATTENDED" == "1" ]]; then
|
if [[ "$UNATTENDED" == "1" ]]; then
|
||||||
LUKS_PASSPHRASE="${NOMARCHY_LUKS_PASSPHRASE:-}"
|
LUKS_PASSPHRASE="${NOMARCHY_LUKS_PASSPHRASE:-}"
|
||||||
elif gum confirm "Encrypt the disk with LUKS? (recommended for laptops)"; then
|
elif gum confirm --default=yes "Encrypt the disk with LUKS? (default — also enables passwordless desktop login)"; then
|
||||||
while true; do
|
while true; do
|
||||||
p1=$(gum input --password --placeholder "LUKS passphrase (min 8 chars)")
|
p1=$(gum input --password --placeholder "LUKS passphrase (min 8 chars)")
|
||||||
[[ ${#p1} -ge 8 ]] || { warn "Too short."; continue; }
|
[[ ${#p1} -ge 8 ]] || { warn "Too short."; continue; }
|
||||||
@@ -100,7 +103,20 @@ elif gum confirm "Encrypt the disk with LUKS? (recommended for laptops)"; then
|
|||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
WITH_LUKS=false; [[ -n "$LUKS_PASSPHRASE" ]] && WITH_LUKS=true
|
WITH_LUKS=false; [[ -n "$LUKS_PASSPHRASE" ]] && WITH_LUKS=true
|
||||||
info "Encryption: $([[ $WITH_LUKS == true ]] && echo LUKS2 || echo none)"
|
info "Encryption: $([[ $WITH_LUKS == true ]] && echo "LUKS2 (desktop auto-login)" || echo none)"
|
||||||
|
|
||||||
|
# ─── Swap / hibernation ─────────────────────────────────────────────────
|
||||||
|
# A swapfile ≥ RAM on its own BTRFS subvolume makes hibernation possible;
|
||||||
|
# the resume offset is wired into the config below.
|
||||||
|
ram_gb=$(awk '/MemTotal/ {print int(($2 + 1048575) / 1048576)}' /proc/meminfo)
|
||||||
|
if [[ "$UNATTENDED" == "1" ]]; then
|
||||||
|
SWAP_GB="${NOMARCHY_SWAP_GB:-$ram_gb}"
|
||||||
|
else
|
||||||
|
SWAP_GB=$(gum input --value "$ram_gb" \
|
||||||
|
--placeholder "swap size in GiB (≥ RAM enables hibernation, 0 = none)")
|
||||||
|
fi
|
||||||
|
[[ "$SWAP_GB" =~ ^[0-9]+$ ]] || fail "Swap size must be a whole number of GiB."
|
||||||
|
info "Swap: $([[ "$SWAP_GB" == "0" ]] && echo none || echo "${SWAP_GB}G swapfile (hibernation-ready)")"
|
||||||
|
|
||||||
# ─── User account ───────────────────────────────────────────────────────
|
# ─── User account ───────────────────────────────────────────────────────
|
||||||
section "Your account"
|
section "Your account"
|
||||||
@@ -178,12 +194,14 @@ section "Review"
|
|||||||
|
|
||||||
gum style --border normal --padding "0 2" \
|
gum style --border normal --padding "0 2" \
|
||||||
"Disk: $TARGET_DISK (WILL BE ERASED)" \
|
"Disk: $TARGET_DISK (WILL BE ERASED)" \
|
||||||
"Encryption: $([[ $WITH_LUKS == true ]] && echo LUKS2 || echo none)" \
|
"Encryption: $([[ $WITH_LUKS == true ]] && echo "LUKS2 + desktop auto-login" || echo none)" \
|
||||||
|
"Swap: $([[ "$SWAP_GB" == "0" ]] && echo none || echo "${SWAP_GB}G (hibernation)")" \
|
||||||
"User: $USERNAME" \
|
"User: $USERNAME" \
|
||||||
"Hostname: $HOSTNAME_" \
|
"Hostname: $HOSTNAME_" \
|
||||||
"Timezone: $TIMEZONE" \
|
"Timezone: $TIMEZONE" \
|
||||||
"Hardware: ${HW_PROFILES[*]:-none}" \
|
"Hardware: ${HW_PROFILES[*]:-none}" \
|
||||||
"Offline: $([[ -n "${NOMARCHY_REV:-}" ]] && echo "yes (pinned $NOMARCHY_REV)" || echo "no (will fetch nomarchy from GitHub)")"
|
"Snapshots: snapper timeline on /" \
|
||||||
|
"Offline: $([[ -n "${NOMARCHY_REV:-}" ]] && echo "yes (pinned ${NOMARCHY_REV:0:12})" || echo "no (will fetch nomarchy over the network)")"
|
||||||
|
|
||||||
if [[ "$UNATTENDED" != "1" ]]; then
|
if [[ "$UNATTENDED" != "1" ]]; then
|
||||||
typed=$(gum input --placeholder "type the disk name ($(basename "$TARGET_DISK")) to confirm the wipe")
|
typed=$(gum input --placeholder "type the disk name ($(basename "$TARGET_DISK")) to confirm the wipe")
|
||||||
@@ -241,6 +259,7 @@ disko_log=$(mktemp --suffix=.disko.log)
|
|||||||
if ! disko --mode destroy,format,mount --yes-wipe-all-disks \
|
if ! disko --mode destroy,format,mount --yes-wipe-all-disks \
|
||||||
--argstr mainDrive "$TARGET_DISK" \
|
--argstr mainDrive "$TARGET_DISK" \
|
||||||
--arg withLuks "$WITH_LUKS" \
|
--arg withLuks "$WITH_LUKS" \
|
||||||
|
--argstr swapSize "${SWAP_GB}G" \
|
||||||
"$SHARE/disko-config.nix" >"$disko_log" 2>&1; then
|
"$SHARE/disko-config.nix" >"$disko_log" 2>&1; then
|
||||||
tail -n 30 "$disko_log"
|
tail -n 30 "$disko_log"
|
||||||
fail "disko failed — full log: $disko_log"
|
fail "disko failed — full log: $disko_log"
|
||||||
@@ -248,6 +267,25 @@ fi
|
|||||||
rm -f "$LUKS_KEY_PATH" "$disko_log"
|
rm -f "$LUKS_KEY_PATH" "$disko_log"
|
||||||
success "Disk partitioned and mounted at /mnt"
|
success "Disk partitioned and mounted at /mnt"
|
||||||
|
|
||||||
|
# Hibernation plumbing: the swapfile's physical offset goes into the
|
||||||
|
# kernel cmdline. Deactivate swap first so nixos-generate-config doesn't
|
||||||
|
# also emit a swapDevices entry (we write our own, with resume wiring).
|
||||||
|
RESUME_CONFIG=""
|
||||||
|
if [[ "$SWAP_GB" != "0" ]]; then
|
||||||
|
swapoff -a 2>/dev/null || true
|
||||||
|
resume_offset=$(btrfs inspect-internal map-swapfile -r /mnt/swap/swapfile)
|
||||||
|
root_uuid=$(findmnt -no UUID /mnt)
|
||||||
|
RESUME_CONFIG=$(cat <<NIX
|
||||||
|
|
||||||
|
# Swapfile (hibernation-ready: resume points into it).
|
||||||
|
swapDevices = [{ device = "/swap/swapfile"; }];
|
||||||
|
boot.resumeDevice = "/dev/disk/by-uuid/$root_uuid";
|
||||||
|
boot.kernelParams = [ "resume_offset=$resume_offset" ];
|
||||||
|
NIX
|
||||||
|
)
|
||||||
|
success "Swapfile created (resume offset $resume_offset)"
|
||||||
|
fi
|
||||||
|
|
||||||
# ─── Configuration generation ───────────────────────────────────────────
|
# ─── Configuration generation ───────────────────────────────────────────
|
||||||
section "Generating configuration"
|
section "Generating configuration"
|
||||||
|
|
||||||
@@ -284,6 +322,17 @@ cat > "$FLAKE_DIR/flake.nix" <<EOF
|
|||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
AUTOLOGIN_CONFIG=""
|
||||||
|
if [[ $WITH_LUKS == true ]]; then
|
||||||
|
AUTOLOGIN_CONFIG=$(cat <<NIX
|
||||||
|
|
||||||
|
# The LUKS passphrase already gates this machine — skip the second
|
||||||
|
# password prompt and boot straight into the desktop.
|
||||||
|
nomarchy.system.greeter.autoLogin = "$USERNAME";
|
||||||
|
NIX
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
# initialHashedPassword is safe to template: mkpasswd's alphabet is
|
# initialHashedPassword is safe to template: mkpasswd's alphabet is
|
||||||
# [a-zA-Z0-9./$] — no Nix string metacharacters.
|
# [a-zA-Z0-9./$] — no Nix string metacharacters.
|
||||||
cat > "$FLAKE_DIR/system.nix" <<EOF
|
cat > "$FLAKE_DIR/system.nix" <<EOF
|
||||||
@@ -306,6 +355,9 @@ cat > "$FLAKE_DIR/system.nix" <<EOF
|
|||||||
extraGroups = [ "wheel" "networkmanager" "video" "input" ];
|
extraGroups = [ "wheel" "networkmanager" "video" "input" ];
|
||||||
initialHashedPassword = "$HASHED_PASSWORD";
|
initialHashedPassword = "$HASHED_PASSWORD";
|
||||||
};
|
};
|
||||||
|
$AUTOLOGIN_CONFIG$RESUME_CONFIG
|
||||||
|
# Hourly/daily BTRFS timeline snapshots + nixos-rebuild-snap.
|
||||||
|
nomarchy.system.snapper.enable = true;
|
||||||
|
|
||||||
system.stateVersion = "26.05";
|
system.stateVersion = "26.05";
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user