{ modulesPath, config, lib, pkgs, inputs, ... }: let # Find all mount points that start with "/mnt/data-" dataDiskMounts = lib.attrsets.attrNames ( lib.attrsets.filterAttrs (name: value: lib.strings.hasPrefix "/mnt/data-" name) config.fileSystems ); # Find all mount points that start with "/mnt/parity-" parityDiskMounts = lib.attrsets.attrNames ( lib.attrsets.filterAttrs (name: value: lib.strings.hasPrefix "/mnt/parity-" name) config.fileSystems ); # Create an attribute set for snapraid data disks, e.g. { d1 = "/mnt/data-1"; d2 = "/mnt/data-2"; } snapraidDataDisks = lib.lists.foldl' (acc: path: acc // { "d${toString (acc.i + 1)}" = path; i = acc.i + 1; }) { i = 0; } dataDiskMounts; in { imports = [ (modulesPath + "/installer/scan/not-detected.nix") (modulesPath + "/profiles/qemu-guest.nix") inputs.sops-nix.nixosModules.sops ./disk-config.nix ]; # Hardware settings hardware.enableRedistributableFirmware = true; hardware.cpu.intel.updateMicrocode = true; hardware.cpu.amd.updateMicrocode = true; # Secrets management sops.defaultSopsFile = ./secrets/secrets.yaml; sops.age.sshKeyPaths = [ "/home/numbus-admin/.ssh/id_ed25519" ]; sops.age.keyFile = "/var/lib/sops-nix/key.txt"; sops.age.generateKey = true; sops.secrets."ssh-public-keys" = { owner = "numbus-admin"; path = "/etc/ssh/authorized_keys.d/numbus-admin"; }; sops.secrets."docker/frigate" = { owner = "numbus-admin"; path = "/etc/docker-compose/frigate/.env"; }; sops.secrets."docker/traefik" = { owner = "numbus-admin"; path = "/etc/docker-compose/traefik/.env"; }; sops.secrets."docker/nextcloud" = { owner = "numbus-admin"; path = "/etc/docker-compose/nextcloud/.env"; }; sops.secrets."docker/passbolt" = { owner = "numbus-admin"; path = "/etc/docker-compose/passbolt/.env"; }; sops.secrets."docker/hass" = { owner = "numbus-admin"; path = "/etc/docker-compose/hass/.env"; }; sops.secrets."docker/pihole" = { owner = "numbus-admin"; path = "/etc/docker-compose/pihole/.env"; }; sops.secrets."disks/data-disk-1" = { owner = "root"; }; sops.secrets."disks/data-disk-2" = { owner = "root"; }; sops.secrets."disks/data-disk-3" = { owner = "root"; }; sops.secrets."disks/data-disk-4" = { owner = "root"; }; sops.secrets."disks/data-disk-5" = { owner = "root"; }; sops.secrets."disks/data-disk-6" = { owner = "root"; }; sops.secrets."disks/parity-disk-1" = { owner = "root"; }; sops.secrets."disks/parity-disk-2" = { owner = "root"; }; sops.secrets."disks/parity-disk-3" = { owner = "root"; }; # Bootloader options boot.initrd.systemd.enable = true; boot.loader.systemd-boot.enable = true; boot.loader.efi.canTouchEfiVariables = true; # Timezone time.timeZone = "Europe/Paris"; # Internationalisation properties. i18n.defaultLocale = "fr_FR.UTF-8"; i18n.extraLocaleSettings = { LC_ADDRESS = "fr_FR.UTF-8"; LC_IDENTIFICATION = "fr_FR.UTF-8"; LC_MEASUREMENT = "fr_FR.UTF-8"; LC_MONETARY = "fr_FR.UTF-8"; LC_NAME = "fr_FR.UTF-8"; LC_NUMERIC = "fr_FR.UTF-8"; LC_PAPER = "fr_FR.UTF-8"; LC_TELEPHONE = "fr_FR.UTF-8"; LC_TIME = "fr_FR.UTF-8"; }; # Keyboard mapping console.keyMap = "fr"; services.xserver.xkb = { layout = "fr"; variant = ""; }; # Enable SSH services.openssh = { enable = true; }; # Allow unfree packages nixpkgs.config.allowUnfree = true; # Install packages environment.systemPackages = with pkgs; [ ncdu fastfetch tpm2-tss sops age powertop pciutils hdparm hd-idle hddtemp smartmontools cpufrequtils intel-gpu-tools ]; # Power savings services.autoaspm.enable = true; powerManagement.powertop.enable = true; boot.kernelParams = [ "pcie_aspm=force" "consoleblank=60" ]; # Enable cron service services.cron = { enable = true; systemCronJobs = [ ]; }; # Enable docker virtualisation.docker.enable = true; virtualisation.docker.daemon.settings = { data-root = "/mnt/config-storage/docker-data/docker-volumes/"; }; # Enable networking and firewall networking.interfaces.eth0.ipv4.addresses = [ { address = "HOME_SERVER_IP"; prefixLength = 24; } ]; networking.defaultGateway = "HOME_ROUTER_IP"; networking.nameservers = [ "HOME_SERVER_IP" "9.9.9.9" ]; networking.networkmanager.enable = true; networking.firewall.enable = true; # Open ports in the firewall networking.firewall.allowPing = false; networking.firewall.allowedTCPPorts = [ 53 80 443 ]; networking.firewall.allowedUDPPorts = [ 53 ]; # Hostname networking.hostName = "numbus-server"; # User account users.users.numbus-admin = { isNormalUser = true; description = "Numbus Admin"; extraGroups = [ "networkmanager" "wheel" "docker" ]; uid = 1000; initialPassword = "nixos-at-numbus"; }; # Login message environment.loginShellInit = '' if [ "$(id -u)" -eq 1000 ]; then if [ -n "$SSH_TTY" ]; then fastfetch echo -e "\n\nWelcome to numbus.eu server !\n\n- This system is managed by NixOS\n- All changes are futile\n- Please consider buying support if you can't get your server running\n- Have a nice day and enjoy !" fi fi ''; # Enable auto updates system.autoUpgrade = { enable = true; allowReboot = true; flake = inputs.self.outPath; flags = [ "--print-build-logs" ]; dates = "02:00"; randomizedDelaySec = "45min"; }; # Enable NixOS flakes nix.settings.experimental-features = [ "nix-command" "flakes" ]; # --- Storage Configuration (MergerFS & SnapRAID) --- # Create the mount point for the MergerFS pool fileSystems."/mnt/data-storage" = { device = "mergerfs"; fsType = "fuse"; options = [ "defaults" "allow_other" "use_ino" "cache.files=off" "moveonenospc=true" "category.create=mfs" "srcmounts=${lib.strings.concatStringsSep ":" dataDiskMounts}" ]; }; # SnapRAID for data redundancy services.snapraid = { enable = true; contentFiles = map (disk: "${disk}/snapraid.content") dataDiskMounts; parityFiles = map (disk: "${disk}/snapraid.parity") parityDiskMounts; dataDisks = builtins.removeAttrs snapraidDataDisks [ "i" ]; # This correctly creates the required attribute set. # Using default sync and scrub schedules: # Sync runs daily at 01:00. # Scrub runs weekly on Monday at 02:00. }; system.stateVersion = "25.05"; }