refactor: move host configs under hosts/{jupiter,vps}

- git-mv jupiter/ vps/ into hosts/; fix ../ -> ../../ for common/services/secrets
- flake.nix + deploy point at hosts/<config>/
- README structure updated
- verified: jupiter/vps/vbox all eval
This commit is contained in:
erik
2026-07-13 19:34:27 +02:00
parent fb782cb9fe
commit b6c393ff98
12 changed files with 47 additions and 38 deletions
+58
View File
@@ -0,0 +1,58 @@
{ config, pkgs, lib, ... }:
# ZimaBlade NAS host: hardware + disk + the services it runs.
{
imports = [
./hardware-configuration.nix
./disk-config.nix # disko: OS-disk partitions + filesystems
./secrets.nix # sops-nix: samba password, tailscale key, ...
../../common.nix # shared base: user / ssh / nix / firewall
../../services/samba.nix
../../services/avahi.nix
../../services/audiobookshelf.nix
../../services/containers.nix
../../services/caddy.nix
../../services/tailscale.nix
];
# ---- Host identity ----
networking.hostName = "jupiter";
networking.networkmanager.enable = true;
users.users.darman.extraGroups = [ "docker" ]; # merges with common.nix
# ---- Boot ----
# systemd-boot for UEFI. If ZimaBlade boots legacy/BIOS, switch to grub.
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
# Root lives on the ZimaBlade eMMC (mmcblk0). nixos-generate-config runs in
# the RAM installer and does NOT detect these, so pin them here (merged with
# hardware-configuration.nix) or stage-1 can't mount root and the box panics.
boot.initrd.availableKernelModules = [ "mmc_block" "sdhci_pci" "sdhci_acpi" ];
# Warm reboot hangs at firmware reset on this board (cold power-cycle works).
# Force the PCI-chipset reset method. If a warm `reboot` still hangs, try the
# next value: acpi -> bios -> cold -> efi.
boot.kernelParams = [ "reboot=pci" ];
# ---- NAS data array ----
# Existing ext4 on the mdadm RAID0 over sda+sdb (md0, 29.1T).
# Mounted, NOT formatted; kept out of disko so it is never wiped.
# ⚠️ RAID0 = no redundancy: either 16TB disk failing loses ALL data.
boot.swraid.enable = true; # assemble the mdadm array at boot
fileSystems."/mnt/data" = {
# fs UUID (stable) — the array may enumerate as /dev/md127, so avoid /dev/md0.
device = "/dev/disk/by-uuid/dadbff6f-652e-49b2-bfed-eb1308ab8b78";
fsType = "ext4";
options = [ "nofail" ]; # don't block boot if the array is degraded/absent
};
# ---- Caddy vhosts (LAN) ----
# whoami on :80, audiobookshelf via a pihole local-DNS name -> jupiter IP.
services.caddy.virtualHosts = {
"http://localhost".extraConfig = "reverse_proxy localhost:8080";
"http://audiobookshelf.jupiter.sol".extraConfig = "reverse_proxy localhost:8000";
};
system.stateVersion = "26.05";
}
+43
View File
@@ -0,0 +1,43 @@
{ ... }:
# 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";
# ZimaBlade internal eMMC (29.1G). NOT the data RAID (sda/sdb/md0).
device = "/dev/disk/by-id/mmc-C9A551_0xaa057ad0";
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 = "/";
};
};
};
};
};
}
+18
View File
@@ -0,0 +1,18 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "sd_mod" "sdhci_pci" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}
+28
View File
@@ -0,0 +1,28 @@
{ config, ... }:
# sops-nix secret wiring (real host only; not imported by vm.nix).
# Encrypted values live in ../../secrets/jupiter.yaml, decrypted at activation to
# /run/secrets/<name>.
#
# The host decrypts with its OWN SSH host key (age identity derived via
# ssh-to-age, recipient listed in ../../.sops.yaml). The key is pre-generated on
# the laptop and shipped once at install as /etc/ssh/ssh_host_ed25519_key
# (nixos-anywhere --extra-files) — so decryption works on boot #1 and there is
# no separate sops-only key to manage.
{
sops.defaultSopsFile = ../../secrets/jupiter.yaml;
sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
# Decrypts to /run/secrets/samba_password (root-only by default).
sops.secrets.samba_password = { };
# darman's login password (a sha-512 hash, not plaintext — generate with
# `mkpasswd -m sha-512`, edit via ./edit_secrets). neededForUsers makes it
# available before user setup, at /run/secrets-for-users/darman_password.
sops.secrets.darman_password.neededForUsers = true;
users.users.darman.hashedPasswordFile =
config.sops.secrets.darman_password.path;
# Headscale pre-auth key for tailscale auto-registration (see configuration.nix).
sops.secrets.tailscale_authkey = { };
}
+49
View File
@@ -0,0 +1,49 @@
{ config, pkgs, lib, modulesPath, ... }:
# VirtualBox test image — mirrors jupiter's services (minus tailscale/sops/disk)
# and adds console/SSH login credentials. Disk + bootloader come from the
# virtualbox-image module, so hardware-configuration.nix is NOT imported.
{
imports = [
(modulesPath + "/virtualisation/virtualbox-image.nix")
../../common.nix # shared base: user / ssh / nix / firewall
../../services/samba.nix
../../services/avahi.nix
../../services/audiobookshelf.nix
../../services/containers.nix
../../services/caddy.nix
];
networking.hostName = "jupiter";
networking.networkmanager.enable = true;
users.users.darman.extraGroups = [ "docker" ];
# Allow password login for testing (real host is key-only).
services.openssh.settings.PasswordAuthentication = lib.mkForce true;
# Login: darman / test (change or remove for anything but local testing).
users.users.darman.initialPassword = "test";
users.users.root.initialPassword = "test";
# Throwaway SMB password for testing (samba-smbd login = darman / test).
# Single line — the provisioning oneshot feeds it twice for smbpasswd.
# Real host must NOT do this — plaintext lands in the world-readable Nix
# store. It uses sops-nix (secrets.nix) instead.
environment.etc."samba/smb-password" = {
text = "test\n";
mode = "0600";
};
# Caddy vhosts (same as the LAN host, so the proxy path is testable).
services.caddy.virtualHosts = {
"http://localhost".extraConfig = "reverse_proxy localhost:8080";
"http://audiobookshelf.jupiter.sol".extraConfig = "reverse_proxy localhost:8000";
};
# Guest additions for clipboard/resize (optional).
virtualisation.virtualbox.guest.enable = true;
# Smaller virtual disk = faster image assembly + VMDK compression.
# Size in MiB (default is ~50G).
virtualisation.diskSize = 6144; # 6 GiB total disk
}