Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions modules/genebean/home/default.nix
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
imports = [
./kiosk-hardware.nix
./plasma.nix
./programs/angry-ip-scanner.nix
./programs/askpass.nix
Expand Down Expand Up @@ -56,6 +57,7 @@
./programs/zsh.nix
./services/chromium-kiosk.nix
./services/flatpak.nix
./services/kiosk-backups.nix
./services/tailscale.nix
];
}
11 changes: 11 additions & 0 deletions modules/genebean/home/kiosk-hardware.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{ lib, ... }:
{
options.genebean.kiosk-hardware = {
enable = lib.mkEnableOption "shared NixOS-level config for small headless kiosk boxes";

wirelessInterface = lib.mkOption {
type = lib.types.str;
description = "Wireless interface name (e.g. wlan0, wlp3s0). Feeds networking.wireless.interfaces directly. genebean.services.chromium-kiosk has its own wirelessInterface option for its wpa_supplicant dependency - set that to config.genebean.kiosk-hardware.wirelessInterface at the call site rather than duplicating the value.";
};
};
}
6 changes: 6 additions & 0 deletions modules/genebean/home/services/chromium-kiosk.nix
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ in
description = "wlr-randr --transform value (e.g. \"90\", \"flipped-90\"). null = no --transform flag.";
};

wirelessInterface = lib.mkOption {
type = lib.types.str;
description = "Wireless interface name (e.g. wlan0, wlp3s0) - the NixOS side depends on wpa_supplicant-<interface>.service before starting the kiosk. Normally set to config.genebean.kiosk-hardware.wirelessInterface at the call site rather than duplicated.";
example = "wlan0";
};

wlrRandrOutput = lib.mkOption {
type = lib.types.str;
default = "HDMI-A-1";
Expand Down
16 changes: 16 additions & 0 deletions modules/genebean/home/services/kiosk-backups.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{ lib, username, ... }:
{
options.genebean.services.kiosk-backups = {
enable = lib.mkEnableOption "restic-based disaster-recovery backups for kiosk state (chromium profile, atuin session, tailscale identity)";

paths = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [
"/home/${username}/.config/chromium"
"/home/${username}/.local/share/atuin"
"/var/lib/tailscale"
];
description = "Paths to back up daily and make available to kiosk-restic-full-restore. Must NOT include a /persist prefix - the NixOS side (modules/genebean/nixos/services/kiosk-backups.nix) adds that automatically when the host uses impermanence (environment.persistence.\"/persist\".enable). A path already starting with /persist is a configuration error - see that module's assertions.";
};
};
}
2 changes: 2 additions & 0 deletions modules/genebean/nixos/default.nix
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
imports = [
./kiosk-hardware.nix
./plasma.nix
./ports.nix
./programs/askpass.nix
Expand All @@ -11,6 +12,7 @@
./programs/xfce4-terminal.nix
./services/chromium-kiosk.nix
./services/flatpak.nix
./services/kiosk-backups.nix
./services/tailscale.nix
];
}
55 changes: 55 additions & 0 deletions modules/genebean/nixos/kiosk-hardware.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
config,
lib,
username,
...
}:
let
cfg = config.home-manager.users.${username}.genebean.kiosk-hardware;
in
{
config = lib.mkIf cfg.enable {
boot.supportedFilesystems = lib.mkForce [
"ext4"
"f2fs"
"vfat"
]; # kiosk-gene-desk's full list - small enough to just share as-is rather than juggle per-host overrides

hardware = {
enableRedistributableFirmware = true;
graphics.enable = true;
};

networking = {
firewall.enable = false;
useNetworkd = true;
wireless = {
enable = true;
interfaces = [ cfg.wirelessInterface ];
secretsFile = config.sops.secrets.wifi_creds.path;
};
};

sops.secrets.wifi_creds = {
sopsFile = ../../shared/secrets.yaml; # two levels up from modules/genebean/nixos/, not three - this file lives at the nixos/ top level, not nested under programs/ or services/
owner = "wpa_supplicant";
restartUnits = [ "wpa_supplicant-${cfg.wirelessInterface}.service" ];
};

users.users.${username} = {
isNormalUser = true;
description = "Gene Liverman";
extraGroups = [
"networkmanager"
"wheel"
];
linger = true;
};

zramSwap = {
enable = true;
algorithm = "zstd";
memoryPercent = 90;
};
};
}
15 changes: 13 additions & 2 deletions modules/genebean/nixos/services/chromium-kiosk.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,23 @@
}:
let
cfg = config.home-manager.users.${username}.genebean.services.chromium-kiosk;
wifiInterface = lib.elemAt config.networking.wireless.interfaces 0;
in
{
config = lib.mkIf cfg.enable {
environment.systemPackages = [ pkgs.wlr-randr ];

fonts = {
fontconfig = {
enable = true;
useEmbeddedBitmaps = true;
};
packages = with pkgs; [
noto-fonts
noto-fonts-color-emoji
noto-fonts-cjk-sans
];
};

services.cage = {
enable = true;
environment.WLR_LIBINPUT_NO_DEVICES = "1"; # boot up even if no mouse/keyboard connected
Expand Down Expand Up @@ -56,7 +67,7 @@ in
# chromium/cage instance running.
restartIfChanged = lib.mkForce true;
wants = [
"wpa_supplicant-${wifiInterface}.service"
"wpa_supplicant-${cfg.wirelessInterface}.service"
"network-online.target"
];
};
Expand Down
58 changes: 58 additions & 0 deletions modules/genebean/nixos/services/kiosk-backups.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
config,
lib,
username,
...
}:
let
cfg = config.home-manager.users.${username}.genebean.services.kiosk-backups;
usesImpermanence = config.environment.persistence."/persist".enable or false;
prefixedPaths = map (path: if usesImpermanence then "/persist${path}" else path) cfg.paths;
in
{
config = lib.mkIf cfg.enable {
assertions = [
{
assertion = !(lib.any (lib.hasPrefix "/persist") cfg.paths);
message = "genebean.services.kiosk-backups.paths must not include a /persist prefix - it's added automatically when the host uses impermanence.";
}
];

services.restic.backups = {
daily = {
paths = prefixedPaths;
# Avoid a boot-triggered catch-up backup capturing the wrong state
# as "latest" before a chance to restore after a reinstall -
# confirmed on kiosk-gene-desk hardware, see its original comment.
timerConfig = {
OnCalendar = "daily";
Persistent = false;
};
};

pre-reinstall-cleanup = {
environmentFile = config.sops.secrets.restic_env.path;
passwordFile = config.sops.secrets.restic_password.path;
repositoryFile = config.sops.secrets.restic_repo.path;
pruneOpts = [
"--tag pre-reinstall"
"--host ${config.networking.hostName}"
"--keep-within 45d"
];
timerConfig = {
OnCalendar = "daily";
Persistent = false;
};
};
};

genebean.programs.kiosk-restic-full-restore = {
enable = true;
restorePaths = prefixedPaths;
stopServices = [
"cage-tty1"
"tailscaled"
];
};
};
}
67 changes: 7 additions & 60 deletions modules/hosts/nixos/kiosk-entryway/default.nix
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
{
config,
lib,
pkgs,
username,
...
}:
Expand All @@ -10,45 +8,17 @@
./disk-config.nix
./hardware-configuration.nix
./monitoring.nix
../../../shared/nixos/restic.nix
];

system.stateVersion = "24.11";

boot.supportedFilesystems = lib.mkForce [
"vfat"
"ext4"
];

fonts = {
fontconfig = {
enable = true;
useEmbeddedBitmaps = true;
};
packages = with pkgs; [
noto-fonts
noto-fonts-color-emoji
noto-fonts-cjk-sans
];
};

hardware = {
enableRedistributableFirmware = true;
graphics.enable = true;
};

networking = {
firewall.enable = false;
useNetworkd = true;
wireless = {
enable = true;
# Specify the interface explicitly so wpa_supplicant doesn't try to
# auto-detect via /sys/class/net, which is not mounted in the 26.05
# hardening sandbox (RootDirectory=/run/wpa_supplicant).
interfaces = [ "wlp3s0" ];
secretsFile = "${config.sops.secrets.wifi_creds.path}";
};
};

# Not part of genebean.kiosk-hardware: nixpkgs.overlays helps construct
# `pkgs` itself, so gating it behind a home-manager-sourced cfg.enable
# check creates a genuine circular dependency (evaluating cfg.enable
# pulls in pkgs, which depends on nixpkgs.overlays, which is what we're
# trying to compute) - confirmed via a real "infinite recursion" eval
# error when this was tried. Stays per-host, unconditional.
nixpkgs.overlays = [
(_final: super: {
makeModulesClosure = x: super.makeModulesClosure (x // { allowMissing = true; });
Expand Down Expand Up @@ -78,29 +48,6 @@
owner = "${username}";
path = "${config.users.users.${username}.home}/.private-env";
};
wifi_creds = {
sopsFile = ../../../shared/secrets.yaml;
owner = "wpa_supplicant";
restartUnits = [
"wpa_supplicant-wlp3s0.service"
];
};
};
};

users.users.${username} = {
isNormalUser = true;
description = "Gene Liverman";
extraGroups = [
"networkmanager"
"wheel"
];
linger = true;
};

zramSwap = {
enable = true;
algorithm = "zstd";
memoryPercent = 90;
};
}
23 changes: 19 additions & 4 deletions modules/hosts/nixos/kiosk-entryway/home-gene.nix
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
{
config,
...
}:
{
home.stateVersion = "24.11";

genebean.services.chromium-kiosk = {
enable = true;
dashboardUrl = "http://192.168.22.22:8123/kiosk-entryway/immich?kiosk";
extraCommandLineArgs = [ "--hide-scrollbars" ];
genebean = {
kiosk-hardware = {
enable = true;
wirelessInterface = "wlp3s0";
};

services = {
chromium-kiosk = {
enable = true;
dashboardUrl = "http://192.168.22.22:8123/kiosk-entryway/immich?kiosk";
extraCommandLineArgs = [ "--hide-scrollbars" ];
wirelessInterface = config.genebean.kiosk-hardware.wirelessInterface;
};
kiosk-backups.enable = true;
};
};
}
Loading
Loading