Hey everyone!
I have been setting up Nixos with the intention of running it with the same configuration across all my devices. I intend to use disko for hard drive partitioning, flakes to ensure reproducibility and home manager to make transferring (some) gui configs easier.
I would like ask you to have a brief look and tell me, if this is a sane (or even smart) way of doing this. The configs build and run on a spare laptop right now, so my question isn’t about finding actual errors, but about the general logic of what I’m doing.
Less importantly, I do have two specific questions, too.
First, I would love to replace the explicit hostnames in flake.nix with ${HOSTNAME}. I could even have a ${HOSTNAME}-disks.nix. That would allow me to only have a single entry instead of one for every machine. However, I assume I would run into trouble if I ever chroot into one of the machines and run nixos-rebuild or a similar command. Is there a way to do this sanely?
Second, I’m wondering how to best integrate enabling unfree software into my flake. I haven’t found a way to place config.allowUnfree = true; or variations of it in what I have written so far.
First of all an overview of the file structure:
flake.nix - sets the release version for Nix packages
┃ - enables home-manager
┃ - enables disko
┃ - imports configuration.nix,
┃ system.nix, wayland.nix,
┃ home.nix, disks.nix
┃
┣━ configuration.nix - imports hardware-configuration.nix
┃ ┃ - determines the hostname
┃ ┃ - defines the boot loader
┃ ┃ - defines the user
┃ ┃ - enables flakes support
┃ ┃
┃ ┗━ hardware-configuration.nix - enables kernel modules
┃ - enables microcode
┃ - blacklists kernel modules
┃ - enables OpenTabletDriver
┃
┣━ system.nix - enables garbage collection for Nixos
┃ - sets time zone
┃ - enables networkmanager
┃ - installs basic terminal programs
┃
┣━ wayland.nix - enables Wayland
┃ - sets keyboard layout and enables touchpads
┃ - enables printing
┃ - enables sound
┃ - sets up hyprland
┃ - installs graphical programs
┃
┣━ ${HOSTNAME}.nix - device-specific settings
┃
┣━ home.nix - sets bash shell aliases
┃ - enables hyprland on tty login
┃
┣━ disks.nix - governs hard disk partitioning
┃
┗━ flake.lock - autogenerated by the flake, locking app versions
I will share only the first three of these files and home.nix. Just FYI, system.nix contains the base system configs and tty programs, wayland.nix contains the graphical user interface related stuff, and the ${HOSTNAME}.nix files contain machine specific settings and applications.
flake.nix:
{
description = "NixOS flake governing the entire Nixos system";
inputs = {
# Set branch of NixOS packages.
nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";
home-manager = {
url = "github:nix-community/home-manager/release-26.05";
# Make home-manager remain consistent with inputs.nixpkgs through inheritance.
inputs.nixpkgs.follows = "nixpkgs";
};
disko = {
url = "github:nix-community/disko/latest";
# Make disko remain consistent with inputs.nixpkgs through inheritance.
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = { nixpkgs, home-manager, disko, ... }: {
nixosConfigurations = {
# Here go specific sections for each machine, identified by hostname, enabling custom configs.
nixpad = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
# Configuration.nix is reduced to calling hardware-configuration.nix, setting hostname & activating Nixos flakes.
./configuration.nix
./system.nix
./wayland.nix
./nixpad.nix
home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.backupFileExtension = "backup";
home-manager.users.garnix = import ./home.nix;
}
# agenix.nixosModules.default
disko.nixosModules.disko
./disks.nix
];
};
nixbook = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
# Configuration.nix is reduced to calling hardware-configuration.nix, setting hostname & activating Nixos flakes.
./configuration.nix
./system.nix
./wayland.nix
./nixbook.nix
home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.backupFileExtension = "backup";
home-manager.users.garnix = import ./home.nix;
}
# agenix.nixosModules.default
disko.nixosModules.disko
./disks.nix
];
};
};
};
}
configuration.nix:
{ config, lib, pkgs, ... }:
{
imports =
[
./hardware-configuration.nix
];
# Use the systemd-boot EFI boot loader.
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
networking.hostName = "nixpad"; # Define your hostname.
# Define a user account. Don't forget to set a password with ‘passwd’.
users.users.garnix = {
isNormalUser = true;
home = "/home/garnix";
shell = pkgs.bash;
extraGroups = [ "wheel" "networkmanager" ];
packages = with pkgs; [
];
};
# enable flakes
nix.settings.experimental-features = [ "nix-command" "flakes" ];
system.stateVersion = "26.05";
}
hardware-configuration.nix:
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "usb_storage" "sd_mod" "rtsx_pci_sdmmc" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-intel" "uinput" ]; # uinput is required by OpenTabletDriver below
boot.blacklistedKernelModules = [ "wacom" "hid_uclogic" ]; # blacklist modules interfering with access to the uinput tablet
boot.extraModulePackages = [ ];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
# Enable OpenTabletDriver
hardware.opentabletdriver.enable = true;
hardware.uinput.enable = true;
# Enable hardware graphics for Steam
hardware.graphics.enable = true;
hardware.graphics.enable32Bit = true;
}
home.nix:
{ config, libs, pkgs, ... }:
{
home.username = "garnix";
home.homeDirectory = "/home/garnix";
home.stateVersion = "26.05";
programs.home-manager.enable = true;
programs.bash = {
enable = true;
shellAliases = {
testhome = "echo home.nix successfully loaded";
};
# Make a login of user garnix into TTY2 test for the existence of a Wayland session.
# Start hyprland if no Wayland session exists and replace TTY2 with the graphical session
# and log the user out when the graphical session is exited.
profileExtra = ''
if [ -z "$WAYLAND_DISPLAY" ] && [ "$XDG_VTNR" = 2 ]; then
exec uwsm start hyprland-uwsm.desktop
fi
'';
};
programs.fzf.enableBashIntegration = true;
}
Thanks a bunch to anyone reading or skimming this far! I’d love to hear your thoughts.