refactor(modules): move base modules under modules #70
@@ -65,6 +65,7 @@ One flake builds every machine I own.
|
|||||||
|
|
||||||
- Guest modules are host-agnostic wiring, while host files own deployment-specific service configuration such as served volumes and host paths.
|
- Guest modules are host-agnostic wiring, while host files own deployment-specific service configuration such as served volumes and host paths.
|
||||||
For example, `guests/copyparty.nix` should expose options and translate them into guest mounts/service settings, while `hosts/pikachu/default.nix` chooses `/inbox`, `/media`, and their backing paths.
|
For example, `guests/copyparty.nix` should expose options and translate them into guest mounts/service settings, while `hosts/pikachu/default.nix` chooses `/inbox`, `/media`, and their backing paths.
|
||||||
|
Guest addresses and routes are host-level configuration because a guest module can be used on multiple hosts.
|
||||||
- `self.lib.registry.collect { hosts = self.nixosConfigurations; }` reads only top-level host `config.registry` declarations.
|
- `self.lib.registry.collect { hosts = self.nixosConfigurations; }` reads only top-level host `config.registry` declarations.
|
||||||
Registry declarations inside guest interiors live under `config.containers.<guest>.config.registry`.
|
Registry declarations inside guest interiors live under `config.containers.<guest>.config.registry`.
|
||||||
The collected registry does not include those guest-interior declarations.
|
The collected registry does not include those guest-interior declarations.
|
||||||
|
|||||||
91
base.nix
91
base.nix
@@ -1,91 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
inputs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
# The shared foundation both the host base and the guest-base build on: the
|
|
||||||
# primary user, home-manager, and the fresher/pinned package overlays.
|
|
||||||
let
|
|
||||||
inherit (lib) mkOption types;
|
|
||||||
user = config.user;
|
|
||||||
|
|
||||||
# Args to instantiate an extra nixpkgs source on the base platform.
|
|
||||||
pinArgs = prev: {
|
|
||||||
inherit (prev.stdenv.hostPlatform) system;
|
|
||||||
config.allowUnfree = true;
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
imports = [ inputs.home-manager.nixosModules.home-manager ];
|
|
||||||
|
|
||||||
options.user = {
|
|
||||||
name = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "alexion";
|
|
||||||
description = ''
|
|
||||||
The primary interactive user this system is built for. Drives both the
|
|
||||||
system account and the home-manager user in lockstep.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
description = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "Alexion";
|
|
||||||
description = "Human-readable description (GECOS field) for the primary user.";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
# Reach fresher packages with `unstable.<name>` or pin with `stable.<name>`.
|
|
||||||
nixpkgs.overlays = [
|
|
||||||
(_final: prev: {
|
|
||||||
unstable = import inputs.nixpkgs-unstable (pinArgs prev);
|
|
||||||
stable = import inputs.nixpkgs-stable (pinArgs prev);
|
|
||||||
})
|
|
||||||
];
|
|
||||||
nixpkgs.config.allowUnfree = true;
|
|
||||||
|
|
||||||
# Flakes, so `nixos-rebuild switch` works from the console and a direnv
|
|
||||||
# `use flake` resolves inside a guest.
|
|
||||||
nix.settings.experimental-features = [
|
|
||||||
"nix-command"
|
|
||||||
"flakes"
|
|
||||||
];
|
|
||||||
|
|
||||||
# Primary user.
|
|
||||||
# The wheel group is the way in, since root is locked.
|
|
||||||
# No password is set here, since that is host-only.
|
|
||||||
# A guest therefore has none and is reached by SSH key or `machinectl`.
|
|
||||||
users.users.${user.name} = {
|
|
||||||
isNormalUser = true;
|
|
||||||
description = user.description;
|
|
||||||
extraGroups = [
|
|
||||||
"wheel"
|
|
||||||
"storage"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
# The shared write group.
|
|
||||||
# Its gid is fixed, so a host and every guest carry the same number.
|
|
||||||
# An identity-mapped container write then lands on the pool as this group, sparing every service the permission juggling.
|
|
||||||
# 10000 clears the system-group ids assigned automatically and leaves headroom above the primary user, so nothing else claims it.
|
|
||||||
users.groups.storage.gid = 10000;
|
|
||||||
|
|
||||||
# home-manager as a NixOS module: one build produces the system and user
|
|
||||||
# environment together, sharing the system's pkgs and installing user
|
|
||||||
# packages into the system profile.
|
|
||||||
home-manager = {
|
|
||||||
useGlobalPkgs = true;
|
|
||||||
useUserPackages = true;
|
|
||||||
extraSpecialArgs = {
|
|
||||||
inherit inputs;
|
|
||||||
my = inputs.self.lib;
|
|
||||||
};
|
|
||||||
users.${user.name} = {
|
|
||||||
home.username = user.name;
|
|
||||||
home.homeDirectory = "/home/${user.name}";
|
|
||||||
home.stateVersion = "26.05";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
32
guest.nix
32
guest.nix
@@ -1,32 +0,0 @@
|
|||||||
{
|
|
||||||
my,
|
|
||||||
inputs,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
# The guest-base: the slim foundation every nested guest's interior stands on.
|
|
||||||
# It imports the full modules tree so any module is available to enable inside a
|
|
||||||
# guest, and stands on the same shared base a host does.
|
|
||||||
{
|
|
||||||
imports = my.collectNixFiles (inputs.self + "/modules") ++ [
|
|
||||||
(inputs.self + "/base.nix")
|
|
||||||
|
|
||||||
# The modules tree reaches for these option namespaces, so they must be
|
|
||||||
# declared for the tree to evaluate even where a guest leaves them off.
|
|
||||||
my.registry.module
|
|
||||||
inputs.sops-nix.nixosModules.sops
|
|
||||||
inputs.stylix.nixosModules.stylix
|
|
||||||
];
|
|
||||||
|
|
||||||
# A nested container has no per-host `default.nix` to pin its release.
|
|
||||||
system.stateVersion = "26.05";
|
|
||||||
|
|
||||||
# The baseline toolset and SSH access, so any guest shelled into is a workable
|
|
||||||
# environment without per-guest wiring.
|
|
||||||
modules.toolkit.enable = lib.mkDefault true;
|
|
||||||
modules.ssh.enable = lib.mkDefault true;
|
|
||||||
|
|
||||||
# A guest carries no host identity, so it presents a self-generated host key
|
|
||||||
# rather than restoring one from secrets.
|
|
||||||
modules.ssh.hostKeys.restore = lib.mkDefault false;
|
|
||||||
}
|
|
||||||
@@ -40,8 +40,6 @@
|
|||||||
modules.ssh.hostKeys.sopsFile = ../../secrets/neogaia.yaml;
|
modules.ssh.hostKeys.sopsFile = ../../secrets/neogaia.yaml;
|
||||||
modules.ssh.userKey.sopsFile = ../../secrets/neogaia.yaml;
|
modules.ssh.userKey.sopsFile = ../../secrets/neogaia.yaml;
|
||||||
|
|
||||||
modules.toolkit.enable = true;
|
|
||||||
|
|
||||||
# The walking-skeleton guest, enabled like any module: proves the guest path
|
# The walking-skeleton guest, enabled like any module: proves the guest path
|
||||||
# end to end through this host's `nix flake check`.
|
# end to end through this host's `nix flake check`.
|
||||||
# Modest caps keep the skeleton guest from starving the laptop.
|
# Modest caps keep the skeleton guest from starving the laptop.
|
||||||
|
|||||||
@@ -79,8 +79,6 @@
|
|||||||
modules.ssh.userKey.sopsFile = ../../secrets/pikachu.yaml;
|
modules.ssh.userKey.sopsFile = ../../secrets/pikachu.yaml;
|
||||||
|
|
||||||
modules.git.enable = true;
|
modules.git.enable = true;
|
||||||
modules.toolkit.enable = true;
|
|
||||||
|
|
||||||
guests.actualbudget = {
|
guests.actualbudget = {
|
||||||
enable = true;
|
enable = true;
|
||||||
vlan = 20;
|
vlan = 20;
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ let
|
|||||||
) (builtins.readDir dir)
|
) (builtins.readDir dir)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
moduleFiles = collectNixFiles (self + "/modules");
|
||||||
|
guestFiles = collectNixFiles (self + "/guests");
|
||||||
|
|
||||||
specialArgs = {
|
specialArgs = {
|
||||||
inherit inputs self;
|
inherit inputs self;
|
||||||
my = self.lib;
|
my = self.lib;
|
||||||
@@ -42,10 +45,13 @@ let
|
|||||||
|
|
||||||
guests = import ./guests.nix {
|
guests = import ./guests.nix {
|
||||||
inherit
|
inherit
|
||||||
|
inputs
|
||||||
lib
|
lib
|
||||||
self
|
self
|
||||||
specialArgs
|
specialArgs
|
||||||
bridgeName
|
bridgeName
|
||||||
|
moduleFiles
|
||||||
|
registry
|
||||||
;
|
;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -57,17 +63,19 @@ let
|
|||||||
inputs.nixpkgs.lib.nixosSystem {
|
inputs.nixpkgs.lib.nixosSystem {
|
||||||
inherit system specialArgs;
|
inherit system specialArgs;
|
||||||
modules =
|
modules =
|
||||||
(collectNixFiles (self + "/modules"))
|
moduleFiles
|
||||||
++ (collectNixFiles (self + "/guests"))
|
++ guestFiles
|
||||||
++ [
|
++ [
|
||||||
inputs.chaotic.nixosModules.default
|
inputs.chaotic.nixosModules.default
|
||||||
inputs.disko.nixosModules.disko
|
inputs.disko.nixosModules.disko
|
||||||
inputs.sops-nix.nixosModules.sops
|
inputs.sops-nix.nixosModules.sops
|
||||||
inputs.stylix.nixosModules.stylix
|
inputs.stylix.nixosModules.stylix
|
||||||
registry.module
|
registry.module
|
||||||
(self + "/system.nix")
|
|
||||||
(self + "/hosts/${hostName}")
|
(self + "/hosts/${hostName}")
|
||||||
{ networking.hostName = hostName; }
|
{
|
||||||
|
networking.hostName = hostName;
|
||||||
|
modules.host.enable = true;
|
||||||
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
{
|
{
|
||||||
|
inputs,
|
||||||
lib,
|
lib,
|
||||||
self,
|
self,
|
||||||
specialArgs,
|
specialArgs,
|
||||||
bridgeName,
|
bridgeName,
|
||||||
|
moduleFiles,
|
||||||
|
registry,
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib) escapeShellArg mapAttrsToList;
|
inherit (lib) escapeShellArg mapAttrsToList;
|
||||||
@@ -345,8 +348,15 @@ let
|
|||||||
inherit specialArgs;
|
inherit specialArgs;
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
imports = [
|
imports =
|
||||||
(self + "/guest.nix")
|
moduleFiles
|
||||||
|
++ [
|
||||||
|
registry.module
|
||||||
|
inputs.sops-nix.nixosModules.sops
|
||||||
|
inputs.stylix.nixosModules.stylix
|
||||||
|
{
|
||||||
|
modules.guest.enable = true;
|
||||||
|
}
|
||||||
guestNet
|
guestNet
|
||||||
interior
|
interior
|
||||||
];
|
];
|
||||||
|
|||||||
126
modules/default.nix
Normal file
126
modules/default.nix
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
inputs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
# The shared foundation for every host and guest.
|
||||||
|
let
|
||||||
|
inherit (lib) mkOption types;
|
||||||
|
user = config.user;
|
||||||
|
|
||||||
|
pinArgs = prev: {
|
||||||
|
inherit (prev.stdenv.hostPlatform) system;
|
||||||
|
config.allowUnfree = true;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [ inputs.home-manager.nixosModules.home-manager ];
|
||||||
|
|
||||||
|
options.user = {
|
||||||
|
name = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "alexion";
|
||||||
|
description = ''
|
||||||
|
Primary interactive user for this system.
|
||||||
|
This drives the system account and Home Manager user together.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
description = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "Alexion";
|
||||||
|
description = "Human-readable description for the primary user.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
nixpkgs.overlays = [
|
||||||
|
(_final: prev: {
|
||||||
|
unstable = import inputs.nixpkgs-unstable (pinArgs prev);
|
||||||
|
stable = import inputs.nixpkgs-stable (pinArgs prev);
|
||||||
|
})
|
||||||
|
];
|
||||||
|
nixpkgs.config.allowUnfree = true;
|
||||||
|
|
||||||
|
nix.settings.experimental-features = [
|
||||||
|
"nix-command"
|
||||||
|
"flakes"
|
||||||
|
];
|
||||||
|
|
||||||
|
users.users.${user.name} = {
|
||||||
|
isNormalUser = true;
|
||||||
|
description = user.description;
|
||||||
|
extraGroups = [
|
||||||
|
"wheel"
|
||||||
|
"storage"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
users.groups.storage.gid = 10000;
|
||||||
|
|
||||||
|
home-manager = {
|
||||||
|
useGlobalPkgs = true;
|
||||||
|
useUserPackages = true;
|
||||||
|
extraSpecialArgs = {
|
||||||
|
inherit inputs;
|
||||||
|
my = inputs.self.lib;
|
||||||
|
};
|
||||||
|
users.${user.name} = {
|
||||||
|
home.username = user.name;
|
||||||
|
home.homeDirectory = "/home/${user.name}";
|
||||||
|
home.stateVersion = "26.05";
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
eza
|
||||||
|
wget
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
registry.shell-shortcut.${config.networking.hostName} = {
|
||||||
|
ls = {
|
||||||
|
command = "eza -alg --color=always --group-directories-first --icons=always";
|
||||||
|
abbreviation = false;
|
||||||
|
};
|
||||||
|
la = {
|
||||||
|
command = "eza -a --color=always --group-directories-first --icons=always";
|
||||||
|
abbreviation = false;
|
||||||
|
};
|
||||||
|
ll = {
|
||||||
|
command = "eza -lg --color=always --group-directories-first --icons=always";
|
||||||
|
abbreviation = false;
|
||||||
|
};
|
||||||
|
lt = {
|
||||||
|
command = "eza -aT -I '.git' --color=always --group-directories-first --icons=always";
|
||||||
|
abbreviation = false;
|
||||||
|
};
|
||||||
|
"l." = {
|
||||||
|
command = "eza -a | grep -e '^\\.'";
|
||||||
|
abbreviation = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
".." = "cd ..";
|
||||||
|
"..." = "cd ../..";
|
||||||
|
"...." = "cd ../../..";
|
||||||
|
|
||||||
|
cp = "cp -v";
|
||||||
|
tarnow = "tar -acf ";
|
||||||
|
untar = "tar -zxvf ";
|
||||||
|
wget = "wget -c ";
|
||||||
|
grep = "grep --color=auto";
|
||||||
|
fgrep = "fgrep --color=auto";
|
||||||
|
egrep = "egrep --color=auto";
|
||||||
|
jctl = "journalctl -p 3 -xb";
|
||||||
|
|
||||||
|
update = "sudo nixos-rebuild switch --flake .#${config.networking.hostName}";
|
||||||
|
cleanup = "sudo nix-collect-garbage -d";
|
||||||
|
};
|
||||||
|
|
||||||
|
modules.fish.enable = lib.mkDefault true;
|
||||||
|
modules.fish.defaultShell = lib.mkDefault true;
|
||||||
|
modules.tmux.enable = lib.mkDefault true;
|
||||||
|
modules.nvim.enable = lib.mkDefault true;
|
||||||
|
modules.git.enable = lib.mkDefault true;
|
||||||
|
modules.direnv.enable = lib.mkDefault true;
|
||||||
|
};
|
||||||
|
}
|
||||||
14
modules/guest.nix
Normal file
14
modules/guest.nix
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{ config, lib, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.modules.guest;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.modules.guest.enable = lib.mkEnableOption "nested-guest base configuration";
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
system.stateVersion = "26.05";
|
||||||
|
|
||||||
|
modules.ssh.enable = lib.mkDefault true;
|
||||||
|
modules.ssh.hostKeys.restore = lib.mkDefault false;
|
||||||
|
};
|
||||||
|
}
|
||||||
42
modules/host.nix
Normal file
42
modules/host.nix
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
cfg = config.modules.host;
|
||||||
|
user = config.user;
|
||||||
|
passwordSecret = "${user.name}-password";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.modules.host.enable = lib.mkEnableOption "physical-host base configuration";
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
nix.settings.extra-substituters = [ "https://nyx-cache.chaotic.cx/" ];
|
||||||
|
nix.settings.extra-trusted-public-keys = [
|
||||||
|
"nyx-cache.chaotic.cx:dJxTrgMC3V3cFfyIiBQDQorG6k1LsqurH/srpMSq7qk="
|
||||||
|
];
|
||||||
|
|
||||||
|
nix.gc.automatic = true;
|
||||||
|
nix.gc.dates = "Mon 03:15";
|
||||||
|
nix.gc.options = "--delete-older-than 30d";
|
||||||
|
|
||||||
|
nix.optimise.automatic = true;
|
||||||
|
nix.optimise.dates = [ "Thu 03:45" ];
|
||||||
|
|
||||||
|
boot.loader.systemd-boot.configurationLimit = 15;
|
||||||
|
|
||||||
|
services.xserver.xkb.layout = "us";
|
||||||
|
services.xserver.xkb.options = "caps:escape_shifted_capslock";
|
||||||
|
console.useXkbConfig = true;
|
||||||
|
|
||||||
|
sops.defaultSopsFile = ../secrets/shared.yaml;
|
||||||
|
sops.age.keyFile = "/var/lib/sops-nix/key.txt";
|
||||||
|
sops.age.sshKeyPaths = [ ];
|
||||||
|
sops.gnupg.sshKeyPaths = [ ];
|
||||||
|
|
||||||
|
users.mutableUsers = false;
|
||||||
|
sops.secrets.${passwordSecret}.neededForUsers = true;
|
||||||
|
users.users.${user.name}.hashedPasswordFile = config.sops.secrets.${passwordSecret}.path;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
# The baseline interactive toolset as one deliberate bundle.
|
|
||||||
let
|
|
||||||
cfg = config.modules.toolkit;
|
|
||||||
user = config.user.name;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.modules.toolkit.enable =
|
|
||||||
lib.mkEnableOption "the baseline interactive environment — fish, tmux, nvim, git, and direnv — as one unit";
|
|
||||||
|
|
||||||
# Each piece is turned on at default priority, so a host can still override any one of them.
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
home-manager.users.${user}.home.packages = with pkgs; [
|
|
||||||
eza
|
|
||||||
wget
|
|
||||||
];
|
|
||||||
|
|
||||||
registry.shell-shortcut.${config.networking.hostName} = {
|
|
||||||
ls = {
|
|
||||||
command = "eza -alg --color=always --group-directories-first --icons=always";
|
|
||||||
abbreviation = false;
|
|
||||||
};
|
|
||||||
la = {
|
|
||||||
command = "eza -a --color=always --group-directories-first --icons=always";
|
|
||||||
abbreviation = false;
|
|
||||||
};
|
|
||||||
ll = {
|
|
||||||
command = "eza -lg --color=always --group-directories-first --icons=always";
|
|
||||||
abbreviation = false;
|
|
||||||
};
|
|
||||||
lt = {
|
|
||||||
command = "eza -aT -I '.git' --color=always --group-directories-first --icons=always";
|
|
||||||
abbreviation = false;
|
|
||||||
};
|
|
||||||
"l." = {
|
|
||||||
command = "eza -a | grep -e '^\\.'";
|
|
||||||
abbreviation = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
# Walk up the tree.
|
|
||||||
".." = "cd ..";
|
|
||||||
"..." = "cd ../..";
|
|
||||||
"...." = "cd ../../..";
|
|
||||||
|
|
||||||
cp = "cp -v";
|
|
||||||
tarnow = "tar -acf ";
|
|
||||||
untar = "tar -zxvf ";
|
|
||||||
wget = "wget -c ";
|
|
||||||
grep = "grep --color=auto";
|
|
||||||
fgrep = "fgrep --color=auto";
|
|
||||||
egrep = "egrep --color=auto";
|
|
||||||
jctl = "journalctl -p 3 -xb";
|
|
||||||
|
|
||||||
# Rebuild the system, and reclaim disk from old generations.
|
|
||||||
update = "sudo nixos-rebuild switch --flake .#${config.networking.hostName}";
|
|
||||||
cleanup = "sudo nix-collect-garbage -d";
|
|
||||||
};
|
|
||||||
|
|
||||||
modules.fish.enable = lib.mkDefault true;
|
|
||||||
# fish is also the login shell, so the bundled environment is what a shell drops into.
|
|
||||||
modules.fish.defaultShell = lib.mkDefault true;
|
|
||||||
modules.tmux.enable = lib.mkDefault true;
|
|
||||||
modules.nvim.enable = lib.mkDefault true;
|
|
||||||
modules.git.enable = lib.mkDefault true;
|
|
||||||
modules.direnv.enable = lib.mkDefault true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
75
system.nix
75
system.nix
@@ -1,75 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
# The host base: the host-only machinery a physical machine needs on top of the
|
|
||||||
# shared base — bootloader, secret decryption, and the maintenance timers.
|
|
||||||
let
|
|
||||||
user = config.user;
|
|
||||||
|
|
||||||
passwordSecret = "${user.name}-password";
|
|
||||||
in
|
|
||||||
{
|
|
||||||
imports = [ ./base.nix ];
|
|
||||||
|
|
||||||
# chaotic's binary cache, so the CachyOS kernel is fetched rather than compiled.
|
|
||||||
# The `extra-` prefix keeps cache.nixos.org alongside it.
|
|
||||||
nix.settings.extra-substituters = [ "https://nyx-cache.chaotic.cx/" ];
|
|
||||||
nix.settings.extra-trusted-public-keys = [
|
|
||||||
"nyx-cache.chaotic.cx:dJxTrgMC3V3cFfyIiBQDQorG6k1LsqurH/srpMSq7qk="
|
|
||||||
];
|
|
||||||
|
|
||||||
# A month of generations is kept, because on a rolling channel with a
|
|
||||||
# third-party kernel an old generation is a known-good system to boot when
|
|
||||||
# an update breaks something.
|
|
||||||
nix.gc.automatic = true;
|
|
||||||
nix.gc.dates = "Mon 03:15";
|
|
||||||
nix.gc.options = "--delete-older-than 30d";
|
|
||||||
|
|
||||||
# Deduplication runs on a timer, off the rebuild path, so it never adds
|
|
||||||
# latency to a `nixos-rebuild switch`.
|
|
||||||
# It falls on a different day from collection, so the two never contend.
|
|
||||||
nix.optimise.automatic = true;
|
|
||||||
nix.optimise.dates = [ "Thu 03:45" ];
|
|
||||||
|
|
||||||
# The EFI system partition holds a kernel and an initrd per entry at roughly
|
|
||||||
# 70 MiB apiece, and is fixed in size.
|
|
||||||
# An exhausted one fails at bootloader installation, after the build has
|
|
||||||
# already succeeded.
|
|
||||||
boot.loader.systemd-boot.configurationLimit = 15;
|
|
||||||
|
|
||||||
environment.systemPackages = [ pkgs.git ];
|
|
||||||
|
|
||||||
# Caps Lock is a second Escape.
|
|
||||||
# Shift+Caps Lock still toggles Caps Lock.
|
|
||||||
services.xserver.xkb.layout = "us";
|
|
||||||
services.xserver.xkb.options = "caps:escape_shifted_capslock";
|
|
||||||
|
|
||||||
# Compile the console keymap from the layout above, so the remap holds on a
|
|
||||||
# bare TTY and not only under a graphical session.
|
|
||||||
console.useXkbConfig = true;
|
|
||||||
|
|
||||||
# Decryption machinery every host depends on.
|
|
||||||
# The identity sits on the encrypted root, which is mounted early enough to
|
|
||||||
# satisfy the secret below.
|
|
||||||
# Clearing both `sshKeyPaths` defaults keeps the SSH host keys out of the
|
|
||||||
# decryption path.
|
|
||||||
sops.defaultSopsFile = ./secrets/shared.yaml;
|
|
||||||
sops.age.keyFile = "/var/lib/sops-nix/key.txt";
|
|
||||||
sops.age.sshKeyPaths = [ ];
|
|
||||||
sops.gnupg.sshKeyPaths = [ ];
|
|
||||||
|
|
||||||
# A password set by hand on a running machine otherwise takes precedence.
|
|
||||||
# That leaves the declared `hashedPasswordFile` below silently inert.
|
|
||||||
# Root has no declared password and is therefore locked.
|
|
||||||
# `sudo` from the wheel group is the way in.
|
|
||||||
users.mutableUsers = false;
|
|
||||||
|
|
||||||
# Decrypted in an earlier activation stage than ordinary secrets.
|
|
||||||
# That is early enough to precede the account that reads it.
|
|
||||||
sops.secrets.${passwordSecret}.neededForUsers = true;
|
|
||||||
|
|
||||||
users.users.${user.name}.hashedPasswordFile = config.sops.secrets.${passwordSecret}.path;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user