6.5 KiB
title, impact, impactDescription, tags
| title | impact | impactDescription | tags |
|---|---|---|---|
| Host Configuration Organization | HIGH | Prevents configuration chaos across multiple hosts | hosts,modules,base-config,directory-structure |
Why This Matters
Proper host configuration organization prevents duplication, makes maintenance easier, and ensures consistency across multiple machines.
Directory Structure
nixos-config/
├── flake.nix # Top-level flake
├── hosts/
│ ├── laptop/
│ │ ├── default.nix # Host-specific config
│ │ ├── hardware-configuration.nix # Generated (don't edit)
│ │ └── home.nix # Home Manager config
│ ├── desktop/
│ │ ├── default.nix
│ │ ├── hardware-configuration.nix
│ │ └── home.nix
│ └── base.nix # Shared by all hosts (optional)
├── modules/ # Reusable NixOS modules
├── overlays/ # Custom overlays
├── home-manager/ # Shared Home Manager configs
│ ├── shell/
│ ├── applications/
│ └── common.nix
└── secrets/ # Age-encrypted secrets
Host Configuration Pattern
Incorrect: Everything in one file
# hosts/laptop/default.nix
{ config, pkgs, ... }:
{
# Hardware config (copied from hardware-configuration.nix)
boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" ];
# ... 50 lines of hardware config ...
# Network config
networking.hostName = "laptop";
networking.networkmanager.enable = true;
# User config
users.users.john = {
isNormalUser = true;
extraGroups = [ "wheel" "networkmanager" ];
};
# Packages
environment.systemPackages = with pkgs; [ vim git wget ];
# Services
services.openssh.enable = true;
# Home Manager
imports = [
./home.nix # Or inline the entire home config
];
}
Problems:
- Hardware config duplicated (should import hardware-configuration.nix)
- User config duplicated across hosts
- No shared configuration
- Hard to maintain
Correct: Modular structure
# hosts/laptop/default.nix
{ inputs, pkgs, pkgs-stable, system, ... }:
{
imports = [
./hardware-configuration.nix # Import hardware config
../base.nix # Import shared config
inputs.home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.john = import ./home.nix;
home-manager.extraSpecialArgs = {
inherit inputs pkgs-stable system;
};
nixpkgs.overlays = [ inputs.some-overlay.overlays.default ];
}
];
# Host-specific config only
networking.hostName = "laptop";
}
Shared Base Configuration
# hosts/base.nix
{ config, pkgs, inputs, ... }:
{
# Network
networking.networkmanager.enable = true;
# Time and locale
time.timeZone = "America/New_York";
i18n.defaultLocale = "en_US.UTF-8";
# Users (shared across all hosts)
users.users.john = {
isNormalUser = true;
extraGroups = [ "wheel" "networkmanager" ];
};
# Common packages
environment.systemPackages = with pkgs; [
vim
git
wget
tmux
];
# Common services
services.openssh.enable = true;
# Nix settings
nix.settings.experimental-features = [ "nix-command" "flakes" ];
}
Hardware Configuration
# hosts/laptop/default.nix
{ ... }:
{
imports = [
./hardware-configuration.nix # Generated by nixos-generate-config
../base.nix
# ...
];
networking.hostName = "laptop";
}
Important: Don't edit hardware-configuration.nix manually. It's generated by nixos-generate-config and should be replaced when hardware changes.
Home Manager Configuration
Host-specific home.nix
# hosts/laptop/home.nix
{ config, pkgs, inputs, ... }:
{
imports = [
../../home-manager/shell
../../home-manager/applications
../../home-manager/common.nix
];
# Host-specific user config
home.packages = with pkgs; [
laptop-specific-package
];
}
Shared Home Manager configs
# home-manager/shell/default.nix
{ config, pkgs, ... }:
{
imports = [
./fish
./neovim
./git
];
}
# home-manager/common.nix
{ config, pkgs, ... }:
{
home.packages = with pkgs; [
jq
ripgrep
fzf
];
programs.git.enable = true;
programs.git.userName = "John Doe";
programs.git.userEmail = "john@example.com";
}
Multiple Hosts Example
# flake.nix
outputs = { self, nixpkgs, home-manager, ... }@inputs: {
nixosConfigurations.laptop = nixpkgs.lib.nixosSystem {
specialArgs = { inherit inputs; };
modules = [ ./hosts/laptop ];
};
nixosConfigurations.desktop = nixpkgs.lib.nixosSystem {
specialArgs = { inherit inputs; };
modules = [ ./hosts/desktop ];
};
nixosConfigurations.server = nixpkgs.lib.nixosSystem {
specialArgs = { inherit inputs; };
modules = [ ./hosts/server ];
};
};
Each host uses the same base.nix but can override settings:
# hosts/server/default.nix
{ ... }:
{
imports = [ ../base.nix ./hardware-configuration.nix ];
# Override time zone for server
time.timeZone = "UTC";
# Add server-specific packages
environment.systemPackages = with pkgs; [
htop
iotop
];
}
Module Pattern
For reusable functionality, create modules:
# modules/docker.nix
{ config, pkgs, ... }:
{
virtualisation.docker = {
enable = true;
enableOnBoot = true;
};
users.users.john.extraGroups = [ "docker" ];
}
Use in host config:
# hosts/laptop/default.nix
{ ... }:
{
imports = [
../base.nix
../../modules/docker # Import module
./hardware-configuration.nix
];
}
Common Mistakes
-
Editing hardware-configuration.nix: Changes are lost when regenerating. Put host-specific config in
default.nixinstead. -
Duplicating config across hosts: Use
base.nixor modules for shared configuration. -
Not separating host-specific and user-specific: Keep host config in
hosts/*/default.nix, user config inhome.nixorhome-manager/. -
Mixing concerns: Don't put shell config in system packages. Use Home Manager for user-level packages.
Quick Checklist
- Each host imports hardware-configuration.nix
- Shared config in base.nix or modules
- Home Manager configured in host file
- Host-specific settings only in host's default.nix
- User config in home.nix or home-manager/
- No duplication of hardware config
- No duplication of user config