feat: disko OS-disk layout + nixos-anywhere install flow
- add disko input; jupiter partitions/formats OS disk declaratively - hardware-configuration.nix carries kernel modules only (disko owns fileSystems) - data disk stays a plain unformatted mount, out of disko - vbox unchanged (virtualbox-image supplies its own disk) - README: nixos-anywhere remote install + daily rebuild loop Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -5,46 +5,78 @@ Flake-based NixOS config. Host: `jupiter` (ZimaBlade, NAS + services).
|
|||||||
## Structure
|
## Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
flake.nix # inputs + nixosConfigurations.jupiter
|
flake.nix # inputs (nixpkgs, disko) + nixosConfigurations
|
||||||
jupiter/configuration.nix # system, users, ssh, samba, containers, caddy
|
jupiter/configuration.nix # real host: imports + bootloader + data mount
|
||||||
jupiter/hardware-configuration.nix # PLACEHOLDER — regenerate on real machine
|
jupiter/disk-config.nix # disko: OS-disk partitions + filesystems
|
||||||
|
jupiter/hardware-configuration.nix # PLACEHOLDER — kernel modules, regenerate on target
|
||||||
|
jupiter/services.nix # shared: users, ssh, samba, containers, caddy
|
||||||
|
jupiter/vm.nix # VirtualBox test image (jupiter-vbox)
|
||||||
```
|
```
|
||||||
|
|
||||||
## First install (on the ZimaBlade)
|
Two configs from one service definition: `jupiter` (real host, disko-partitioned)
|
||||||
|
and `jupiter-vbox` (test OVA). Both import `services.nix`.
|
||||||
|
|
||||||
1. Boot NixOS minimal ISO, partition + mount disks at `/mnt`.
|
## Test in VirtualBox (no hardware needed)
|
||||||
2. Generate hardware config:
|
|
||||||
```
|
|
||||||
sudo nixos-generate-config --root /mnt
|
|
||||||
```
|
|
||||||
Copy `/mnt/etc/nixos/hardware-configuration.nix` into `jupiter/`.
|
|
||||||
3. Add your SSH public key to `users.users.erik.openssh.authorizedKeys.keys`.
|
|
||||||
4. Install:
|
|
||||||
```
|
|
||||||
sudo nixos-install --flake .#jupiter
|
|
||||||
```
|
|
||||||
|
|
||||||
## Rebuild after changes
|
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo nixos-rebuild switch --flake .#jupiter
|
nix build .#nixosConfigurations.jupiter-vbox.config.system.build.virtualBoxOVA
|
||||||
|
VBoxManage import result/*.ova --vsys 0 --vmname jupiter-vbox
|
||||||
|
VBoxManage startvm jupiter-vbox --type headless
|
||||||
```
|
```
|
||||||
|
Login `darman` / `test`. Forward ports with `VBoxManage modifyvm ... --natpf1`.
|
||||||
|
|
||||||
|
## First install on the ZimaBlade — nixos-anywhere + disko
|
||||||
|
|
||||||
|
Wipes the OS disk and installs the flake over SSH. No USB needed if the box
|
||||||
|
already runs Linux (ZimaOS) reachable by root SSH — nixos-anywhere kexecs into
|
||||||
|
an installer, partitions via disko, installs.
|
||||||
|
|
||||||
|
> ⚠️ The OS disk in `disk-config.nix` is WIPED. Set `device` to the OS disk
|
||||||
|
> ONLY (by-id). Back up / physically identify the NAS data disk first — it must
|
||||||
|
> NOT appear in disko. `lsblk -o NAME,SERIAL,SIZE,MODEL` to identify.
|
||||||
|
|
||||||
|
1. Set the real OS disk id in `jupiter/disk-config.nix`
|
||||||
|
(`ls -l /dev/disk/by-id`), and the data-disk mount in `configuration.nix`.
|
||||||
|
2. Add your SSH pubkey to `users.users.darman.openssh.authorizedKeys.keys`.
|
||||||
|
3. Wire the samba secret (see Notes) — real password, not the VM's plaintext.
|
||||||
|
4. Run from your laptop:
|
||||||
|
```
|
||||||
|
nix run github:nix-community/nixos-anywhere -- \
|
||||||
|
--flake .#jupiter \
|
||||||
|
--generate-hardware-config nixos-generate-config ./jupiter/hardware-configuration.nix \
|
||||||
|
--target-host root@<zimablade-ip>
|
||||||
|
```
|
||||||
|
`--generate-hardware-config` pulls the target's real kernel modules into the
|
||||||
|
placeholder for you. Commit the result. Reboot into NixOS.
|
||||||
|
|
||||||
|
Manual alternative (USB ISO): boot installer, `disko` the disk, then
|
||||||
|
`nixos-install --flake .#jupiter`.
|
||||||
|
|
||||||
|
## Rebuild after changes (the daily loop)
|
||||||
|
|
||||||
Remote from laptop:
|
|
||||||
```
|
```
|
||||||
|
# from laptop, build + activate on jupiter over SSH:
|
||||||
nixos-rebuild switch --flake .#jupiter \
|
nixos-rebuild switch --flake .#jupiter \
|
||||||
--target-host erik@jupiter --use-remote-sudo
|
--target-host darman@jupiter --use-remote-sudo
|
||||||
```
|
```
|
||||||
|
Rollback: `nixos-rebuild switch --rollback`, or pick a prior generation at boot.
|
||||||
|
|
||||||
## Adding a service
|
## Adding a service
|
||||||
|
|
||||||
Copy the `whoami` block in `oci-containers.containers`, swap image/ports/volumes.
|
Copy the `whoami` block in `oci-containers.containers`, swap image/ports/volumes.
|
||||||
Native NixOS module exists for many apps (Nextcloud, Jellyfin, Grafana...) —
|
Native NixOS module exists for many apps (Nextcloud, Jellyfin, Grafana...) —
|
||||||
prefer `services.<app>` over a container when available.
|
prefer `services.<app>` over a container when available. Add a `caddy`
|
||||||
|
`virtualHosts` block to expose it.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
- Backend is Podman with `dockerCompat` — `docker` CLI works, no daemon.
|
- Backend is Podman with `dockerCompat` — `docker` CLI works, no daemon.
|
||||||
- Set correct `time.timeZone` and Samba `path` for your data mount.
|
- Samba keeps its own password DB. `services.samba` never sets it; a systemd
|
||||||
|
oneshot (`samba-smbpasswd`) provisions it from `/etc/samba/smb-password`.
|
||||||
|
Real host: supply that file via **sops-nix / agenix**, never commit plaintext.
|
||||||
|
- Data disk: plain `fileSystems."/mnt/data"` in configuration.nix — kept out of
|
||||||
|
disko so it is never formatted. Reference by `by-id` / `by-uuid`.
|
||||||
- `system.stateVersion` = `26.05`, install-time schema. Do NOT bump on upgrades.
|
- `system.stateVersion` = `26.05`, install-time schema. Do NOT bump on upgrades.
|
||||||
|
- Terraform is not used: a single bare-metal box has no provider API. disko +
|
||||||
|
nixos-anywhere cover provisioning natively.
|
||||||
```
|
```
|
||||||
|
|||||||
Generated
+21
@@ -1,5 +1,25 @@
|
|||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
|
"disko": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1781152676,
|
||||||
|
"narHash": "sha256-RxWs5ND31KzTG7wvMM+PMfUjyNpmIEr999lqNARaM5o=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "disko",
|
||||||
|
"rev": "ff8702b4de27f72b4c78573dfb89ec74e36abdf1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "disko",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1783703440,
|
"lastModified": 1783703440,
|
||||||
@@ -18,6 +38,7 @@
|
|||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"disko": "disko",
|
||||||
"nixpkgs": "nixpkgs"
|
"nixpkgs": "nixpkgs"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,23 +3,32 @@
|
|||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";
|
||||||
|
disko = {
|
||||||
|
url = "github:nix-community/disko";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, ... }@inputs:
|
outputs = { self, nixpkgs, disko, ... }@inputs:
|
||||||
let
|
let
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
nixosConfigurations = {
|
nixosConfigurations = {
|
||||||
# Real host — install on the ZimaBlade.
|
# Real host — install on the ZimaBlade.
|
||||||
|
# disko owns the OS-disk partitioning + filesystems (see disk-config.nix).
|
||||||
jupiter = nixpkgs.lib.nixosSystem {
|
jupiter = nixpkgs.lib.nixosSystem {
|
||||||
inherit system;
|
inherit system;
|
||||||
specialArgs = { inherit inputs; };
|
specialArgs = { inherit inputs; };
|
||||||
modules = [ ./jupiter/configuration.nix ];
|
modules = [
|
||||||
|
disko.nixosModules.disko
|
||||||
|
./jupiter/configuration.nix
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# VirtualBox test image. Build the OVA with:
|
# VirtualBox test image. Build the OVA with:
|
||||||
# nix build .#nixosConfigurations.jupiter-vbox.config.system.build.virtualBoxOVA
|
# nix build .#nixosConfigurations.jupiter-vbox.config.system.build.virtualBoxOVA
|
||||||
|
# NOTE: no disko here — the virtualbox-image module supplies the disk.
|
||||||
jupiter-vbox = nixpkgs.lib.nixosSystem {
|
jupiter-vbox = nixpkgs.lib.nixosSystem {
|
||||||
inherit system;
|
inherit system;
|
||||||
specialArgs = { inherit inputs; };
|
specialArgs = { inherit inputs; };
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
{ config, pkgs, lib, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
# Real-host config: hardware + bootloader + shared services.
|
# Real-host config: hardware + disk layout + bootloader + shared services.
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./hardware-configuration.nix
|
./hardware-configuration.nix
|
||||||
|
./disk-config.nix # disko: OS-disk partitions + filesystems
|
||||||
./services.nix
|
./services.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -11,4 +12,12 @@
|
|||||||
# systemd-boot for UEFI. If ZimaBlade boots legacy/BIOS, switch to grub.
|
# systemd-boot for UEFI. If ZimaBlade boots legacy/BIOS, switch to grub.
|
||||||
boot.loader.systemd-boot.enable = true;
|
boot.loader.systemd-boot.enable = true;
|
||||||
boot.loader.efi.canTouchEfiVariables = true;
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
|
|
||||||
|
# ---- NAS data disk ----
|
||||||
|
# Existing data filesystem — mounted, NOT formatted (kept out of disko).
|
||||||
|
# Set the id from `ls -l /dev/disk/by-id` (or by-uuid). Adjust fsType.
|
||||||
|
# fileSystems."/mnt/data" = {
|
||||||
|
# device = "/dev/disk/by-id/CHANGE-ME-data-disk";
|
||||||
|
# fsType = "ext4";
|
||||||
|
# };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{ ... }:
|
||||||
|
|
||||||
|
# Declarative OS-disk layout (disko). UEFI: GPT with an ESP + ext4 root.
|
||||||
|
# disko both PARTITIONS/FORMATS this disk and generates the NixOS
|
||||||
|
# `fileSystems.*` entries, so hardware-configuration.nix must NOT define
|
||||||
|
# fileSystems for "/" or "/boot".
|
||||||
|
#
|
||||||
|
# ⚠️ This disk is WIPED on install. Set `device` to the OS disk ONLY.
|
||||||
|
# Your NAS data disk is NOT listed here — keep it out of disko so it is
|
||||||
|
# never formatted; mount it as a plain read-write fileSystem instead
|
||||||
|
# (see configuration.nix, /mnt/data).
|
||||||
|
#
|
||||||
|
# Find the stable id: ls -l /dev/disk/by-id (use by-id, never /dev/sdX)
|
||||||
|
{
|
||||||
|
disko.devices.disk.os = {
|
||||||
|
type = "disk";
|
||||||
|
device = "/dev/disk/by-id/CHANGE-ME-os-disk";
|
||||||
|
content = {
|
||||||
|
type = "gpt";
|
||||||
|
partitions = {
|
||||||
|
ESP = {
|
||||||
|
size = "512M";
|
||||||
|
type = "EF00";
|
||||||
|
content = {
|
||||||
|
type = "filesystem";
|
||||||
|
format = "vfat";
|
||||||
|
mountpoint = "/boot";
|
||||||
|
mountOptions = [ "umask=0077" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
root = {
|
||||||
|
size = "100%";
|
||||||
|
content = {
|
||||||
|
type = "filesystem";
|
||||||
|
format = "ext4";
|
||||||
|
mountpoint = "/";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
# PLACEHOLDER — do not use as-is.
|
# PLACEHOLDER — replace on the real machine.
|
||||||
#
|
#
|
||||||
# Generate the real file ON the ZimaBlade after booting the NixOS installer:
|
# disko (disk-config.nix) owns the OS-disk filesystems, so this file should
|
||||||
|
# only carry kernel modules + platform. Get the real values from the target:
|
||||||
#
|
#
|
||||||
# sudo nixos-generate-config --root /mnt
|
# # during install, or via nixos-anywhere --generate-hardware-config:
|
||||||
|
# sudo nixos-generate-config --no-filesystems --root /mnt
|
||||||
#
|
#
|
||||||
# then copy /mnt/etc/nixos/hardware-configuration.nix over this file.
|
# `--no-filesystems` omits the fileSystems.* blocks (disko provides them).
|
||||||
# It contains machine-specific disk UUIDs, filesystems, and kernel modules.
|
# Copy the generated file over this one. Keep the imports/kernel-module lines.
|
||||||
#
|
|
||||||
# The block below is a minimal example so `nix flake check` does not fail on a
|
|
||||||
# workstation. REPLACE it entirely with the generated output.
|
|
||||||
{ config, lib, pkgs, modulesPath, ... }:
|
{ config, lib, pkgs, modulesPath, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -19,22 +18,8 @@
|
|||||||
boot.kernelModules = [ ];
|
boot.kernelModules = [ ];
|
||||||
boot.extraModulePackages = [ ];
|
boot.extraModulePackages = [ ];
|
||||||
|
|
||||||
# Example root — replace UUID with real value from generated config.
|
# NO fileSystems here — disko defines "/" and "/boot" (see disk-config.nix).
|
||||||
fileSystems."/" = {
|
# The NAS data mount lives in configuration.nix.
|
||||||
device = "/dev/disk/by-label/nixos";
|
|
||||||
fsType = "ext4";
|
|
||||||
};
|
|
||||||
|
|
||||||
fileSystems."/boot" = {
|
|
||||||
device = "/dev/disk/by-label/BOOT";
|
|
||||||
fsType = "vfat";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Example NAS data mount. Point at your storage disk/pool.
|
|
||||||
# fileSystems."/mnt/data" = {
|
|
||||||
# device = "/dev/disk/by-label/data";
|
|
||||||
# fsType = "ext4";
|
|
||||||
# };
|
|
||||||
|
|
||||||
swapDevices = [ ];
|
swapDevices = [ ];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user