From bb4823efe901b1ff4cff49340acfaa6b3b561870 Mon Sep 17 00:00:00 2001 From: erik Date: Sat, 11 Jul 2026 16:09:32 +0200 Subject: [PATCH] feat: flake NixOS config for jupiter + VirtualBox test image Co-Authored-By: Claude Opus 4.8 --- .gitignore | 3 + README.md | 50 +++++++++++++ flake.nix | 30 ++++++++ jupiter/configuration.nix | 14 ++++ jupiter/hardware-configuration.nix | 42 +++++++++++ jupiter/services.nix | 116 +++++++++++++++++++++++++++++ jupiter/vm.nix | 22 ++++++ 7 files changed, 277 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 flake.nix create mode 100644 jupiter/configuration.nix create mode 100644 jupiter/hardware-configuration.nix create mode 100644 jupiter/services.nix create mode 100644 jupiter/vm.nix diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ce7b4b1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +result +result-* +.direnv/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..bd88a3b --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ +# homelab + +Flake-based NixOS config. Host: `jupiter` (ZimaBlade, NAS + services). + +## Structure + +``` +flake.nix # inputs + nixosConfigurations.jupiter +jupiter/configuration.nix # system, users, ssh, samba, containers, caddy +jupiter/hardware-configuration.nix # PLACEHOLDER — regenerate on real machine +``` + +## First install (on the ZimaBlade) + +1. Boot NixOS minimal ISO, partition + mount disks at `/mnt`. +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 +``` + +Remote from laptop: +``` +nixos-rebuild switch --flake .#jupiter \ + --target-host erik@jupiter --use-remote-sudo +``` + +## Adding a service + +Copy the `whoami` block in `oci-containers.containers`, swap image/ports/volumes. +Native NixOS module exists for many apps (Nextcloud, Jellyfin, Grafana...) — +prefer `services.` over a container when available. + +## Notes + +- Backend is Podman with `dockerCompat` — `docker` CLI works, no daemon. +- Set correct `time.timeZone` and Samba `path` for your data mount. +- `system.stateVersion` = `26.05`, install-time schema. Do NOT bump on upgrades. +``` diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..3221c77 --- /dev/null +++ b/flake.nix @@ -0,0 +1,30 @@ +{ + description = "Homelab NixOS configuration"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05"; + }; + + outputs = { self, nixpkgs, ... }@inputs: + let + system = "x86_64-linux"; + in + { + nixosConfigurations = { + # Real host — install on the ZimaBlade. + jupiter = nixpkgs.lib.nixosSystem { + inherit system; + specialArgs = { inherit inputs; }; + modules = [ ./jupiter/configuration.nix ]; + }; + + # VirtualBox test image. Build the OVA with: + # nix build .#nixosConfigurations.jupiter-vbox.config.system.build.virtualBoxOVA + jupiter-vbox = nixpkgs.lib.nixosSystem { + inherit system; + specialArgs = { inherit inputs; }; + modules = [ ./jupiter/vm.nix ]; + }; + }; + }; +} diff --git a/jupiter/configuration.nix b/jupiter/configuration.nix new file mode 100644 index 0000000..3c04458 --- /dev/null +++ b/jupiter/configuration.nix @@ -0,0 +1,14 @@ +{ config, pkgs, lib, ... }: + +# Real-host config: hardware + bootloader + shared services. +{ + imports = [ + ./hardware-configuration.nix + ./services.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; +} diff --git a/jupiter/hardware-configuration.nix b/jupiter/hardware-configuration.nix new file mode 100644 index 0000000..2d571d7 --- /dev/null +++ b/jupiter/hardware-configuration.nix @@ -0,0 +1,42 @@ +# PLACEHOLDER — do not use as-is. +# +# Generate the real file ON the ZimaBlade after booting the NixOS installer: +# +# sudo nixos-generate-config --root /mnt +# +# then copy /mnt/etc/nixos/hardware-configuration.nix over this file. +# It contains machine-specific disk UUIDs, filesystems, and kernel modules. +# +# 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, ... }: + +{ + imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usbhid" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ ]; + boot.extraModulePackages = [ ]; + + # Example root — replace UUID with real value from generated config. + fileSystems."/" = { + 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 = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; +} diff --git a/jupiter/services.nix b/jupiter/services.nix new file mode 100644 index 0000000..52a9c45 --- /dev/null +++ b/jupiter/services.nix @@ -0,0 +1,116 @@ +{ config, pkgs, lib, ... }: + +# Portable system + service config. Contains NO bootloader or filesystem +# settings, so it can be reused by both the real host (configuration.nix) +# and the VirtualBox test image (see flake.nix). + +{ + # ---- Networking ---- + networking.hostName = "jupiter"; + networking.networkmanager.enable = true; + + networking.firewall = { + enable = true; + allowedTCPPorts = [ + 22 # ssh + 445 139 # samba + 80 443 # reverse proxy (caddy) + ]; + }; + + # ---- Locale / time ---- + time.timeZone = "Europe/Berlin"; + i18n.defaultLocale = "en_US.UTF-8"; + + # ---- Users ---- + users.users.erik = { + isNormalUser = true; + description = "erik"; + extraGroups = [ "wheel" "networkmanager" "docker" ]; + # Replace with your real public key. Password login for ssh is disabled below. + openssh.authorizedKeys.keys = [ + # "ssh-ed25519 AAAA... erik@laptop" + ]; + }; + + security.sudo.wheelNeedsPassword = false; + + # ---- SSH ---- + services.openssh = { + enable = true; + settings = { + PasswordAuthentication = false; + PermitRootLogin = "no"; + }; + }; + + # ---- Storage / NAS ---- + services.samba = { + enable = true; + openFirewall = true; + settings = { + global = { + "workgroup" = "WORKGROUP"; + "server string" = "jupiter"; + "security" = "user"; + }; + data = { + "path" = "/mnt/data"; + "browseable" = "yes"; + "read only" = "no"; + "guest ok" = "no"; + "valid users" = "erik"; + }; + }; + }; + services.avahi = { + enable = true; + nssmdns4 = true; + publish = { + enable = true; + userServices = true; + }; + }; + + # ---- Containers ---- + virtualisation.podman = { + enable = true; + dockerCompat = true; + defaultNetwork.settings.dns_enabled = true; + }; + + virtualisation.oci-containers = { + backend = "podman"; + containers = { + whoami = { + image = "traefik/whoami:latest"; + ports = [ "8080:80" ]; + autoStart = true; + }; + }; + }; + + # ---- Reverse proxy ---- + services.caddy = { + enable = true; + }; + + # ---- System packages ---- + environment.systemPackages = with pkgs; [ + vim + git + htop + tmux + curl + ]; + + # ---- Nix settings ---- + nix.settings.experimental-features = [ "nix-command" "flakes" ]; + nix.gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 30d"; + }; + + system.stateVersion = "26.05"; +} diff --git a/jupiter/vm.nix b/jupiter/vm.nix new file mode 100644 index 0000000..581b673 --- /dev/null +++ b/jupiter/vm.nix @@ -0,0 +1,22 @@ +{ config, pkgs, lib, modulesPath, ... }: + +# VirtualBox test image. Reuses services.nix but adds console/SSH login +# credentials so you can actually get into the VM. Disk + bootloader are +# provided by the virtualbox-image module, so hardware-configuration.nix +# is intentionally NOT imported here. +{ + imports = [ + (modulesPath + "/virtualisation/virtualbox-image.nix") + ./services.nix + ]; + + # Allow password login for testing (real host is key-only). + services.openssh.settings.PasswordAuthentication = lib.mkForce true; + + # Login: erik / test (change or remove for anything but local testing). + users.users.erik.initialPassword = "test"; + users.users.root.initialPassword = "test"; + + # Guest additions for clipboard/resize (optional). + virtualisation.virtualbox.guest.enable = true; +}