Files
KioskConfig/configuration.nix
T

263 lines
8.9 KiB
Nix

{ pkgs, radiantwave, upgradeFlakeRef, radiantwavePlymouth, ... }:
let
radiantApp = radiantwave.packages.${pkgs.system}.default;
myKey = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL4qWNZnYU5JaqR9c2qh6oFZktzVNBOx42PfDaGofCL6 cnclack@pm.me macbook" ];
in
{
############################################################
# System configuration
############################################################
# Included packages
environment.systemPackages = [
pkgs.cage pkgs.rsync pkgs.dbus pkgs.mesa pkgs.git pkgs.tailscale pkgs.sqlite pkgs.wireplumber
radiantApp
];
# This populates the EFI partition and tells the NUC how to start NixOS.
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
# Boot straight into the splash screen without waiting on the bootloader menu.
boot.loader.timeout = 0;
# Hardware-specific: NUC 14 needs these for the NVMe and Graphics
boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" "i915" "drm" "drm_kms_helper" ];
# --- RadiantWave splash: Plymouth from boot until the app's first frame ---
boot.plymouth.enable = true;
boot.plymouth.theme = "radiantwave";
boot.plymouth.themePackages = [ radiantwavePlymouth ];
# Silence the kernel/initrd output behind the splash. The module adds
# "splash" itself; we keep "quiet" plus show_status=false and loglevel 0.
boot.consoleLogLevel = 0;
boot.initrd.verbose = false;
boot.kernelParams = [ "quiet" "splash" "systemd.show_status=false" ];
# Hold the splash until the app is ready to take over the display, instead of
# quitting at multi-user.target (which would flash a black/console screen
# during the login shell's network wait). The kiosk login shell runs
# `sudo -n plymouth quit --wait` immediately before exec'ing cage.
systemd.services.plymouth-quit.wantedBy = pkgs.lib.mkForce [ ];
systemd.services.plymouth-quit-wait.wantedBy = pkgs.lib.mkForce [ ];
# Allow the kiosk user to quit Plymouth (NOPASSWD, command-scoped).
security.sudo.extraRules = [
{
users = [ "kiosk" ];
commands = [
{
command = "/run/current-system/sw/bin/plymouth";
options = [ "NOPASSWD" ];
}
];
}
];
hardware.graphics.enable = true;
time.timeZone = "America/Chicago";
networking.networkmanager.enable = true;
nix.settings.access-tokens = {
"gitea.radiantwavetech.com" = "ff524968d31acc5c4da350d0884a87264d0e8881";
};
system.autoUpgrade = {
enable = true;
flake = upgradeFlakeRef;
dates = "*:00/10";
flags = [ "--refresh" "-L" ];
operation = "switch";
};
system.activationScripts.cleanRadiantFiles = ''
rm -rf /home/kiosk/.local/share/radiantwave/audio
'';
# Virtual machine declaration
virtualisation.vmVariant = {
boot.loader.systemd-boot.enable = pkgs.lib.mkForce false;
boot.loader.efi.canTouchEfiVariables = pkgs.lib.mkForce false;
virtualisation.forwardPorts = [
{ from = "host"; host.port = 2222; guest.port = 22; }
];
virtualisation.qemu.options = [
"-device intel-hda"
"-device hda-duplex"
"-vga virtio"
];
virtualisation = {
cores = 8;
memorySize = 8192;
};
services.logrotate.enable = false;
};
virtualisation.diskSize = 10485760;
# NixOS settings.
nix.settings.experimental-features = [ "nix-command" "flakes" ];
nix.settings.accept-flake-config = true;
system.stateVersion = "24.05";
############################################################
# User configuration
############################################################
users.users.root.openssh.authorizedKeys.keys = myKey;
users.users.kiosk = {
isNormalUser = true;
uid = 1000;
extraGroups = ["audio" "video" "input" "networkmanager" "wheel"];
openssh.authorizedKeys.keys = myKey;
password = "Fuckp@ssw0rds";
};
services.getty.autologinUser = "kiosk";
# --- The Kiosk Startup Script ---
environment.loginShellInit = ''
if [ "$(tty)" = "/dev/tty1" ]; then
export GODEBUG=netdns=cgo
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
# Smart Network Wait
for i in {1..10}; do
if ${pkgs.iputils}/bin/ping -c 1 8.8.8.8 &> /dev/null; then
break
fi
sleep 1
done
# Graphics fixes
export SDL_VIDEODRIVER=wayland
export QT_QPA_PLATFORM=wayland
export XDG_SESSION_TYPE=wayland
export WLR_RENDERER=pixman
export WLR_NO_HARDWARE_CURSORS=1
# Pin system audio to 100% and unmute before launching RadiantWave
${pkgs.systemd}/bin/systemctl --user start radiantwave-audio-init.service || true
# Release the splash screen right before the compositor takes over the display
sudo -n plymouth quit --wait || true
exec dbus-run-session cage -- /run/current-system/sw/bin/radiantwave -d -s > /tmp/kiosk.log 2>&1
fi
'';
############################################################
# Service configuration
############################################################
services.pipewire = { enable = true; alsa.enable = true; pulse.enable = true; };
# New sinks with no stored volume default to ~40% in WirePlumber 0.5+.
# Force every newly-created sink to 100% so switching the default sink
# never changes the volume.
services.pipewire.wireplumber.extraConfig."99-kiosk-audio" = {
"wireplumber.settings"."device.routes.default-sink-volume" = 1.0;
};
# --- Pin all system audio sinks to 100% before RadiantWave launches ---
# User unit (PipeWire runs per-user in the kiosk session), owned by this
# system config. Ordered after PipeWire/WirePlumber; the retry loop covers
# sink readiness at boot. Pins every connected sink (not just the default)
# and unmutes them, so switching the default sink never changes the volume.
# RadiantWave's loginShellInit waits on this before exec'ing cage.
systemd.user.services.radiantwave-audio-init = {
description = "Pin all system audio sinks to 100% and unmute";
after = [ "pipewire.service" "wireplumber.service" ];
wants = [ "pipewire.service" "wireplumber.service" ];
serviceConfig = {
Type = "oneshot";
};
script = ''
# Wait until WirePlumber exposes at least one sink
sinks=""
for i in {1..30}; do
sinks=$(${pkgs.wireplumber}/bin/wpctl list audio sinks 2>/dev/null \
| ${pkgs.gnused}/bin/sed -nE 's/^.*[^0-9]([0-9]+)\. .*$/\1/p')
if [ -n "$sinks" ]; then
break
fi
sleep 1
done
# Pin and unmute every connected sink
for sink_id in $sinks; do
${pkgs.wireplumber}/bin/wpctl set-volume "$sink_id" 1.0 2>/dev/null || true
${pkgs.wireplumber}/bin/wpctl set-mute "$sink_id" 0 2>/dev/null || true
done
# Fallback in case the sink list came up empty
${pkgs.wireplumber}/bin/wpctl set-volume @DEFAULT_AUDIO_SINK@ 1.0 2>/dev/null || true
${pkgs.wireplumber}/bin/wpctl set-mute @DEFAULT_AUDIO_SINK@ 0 2>/dev/null || true
'';
};
services.seatd.enable = true;
services.openssh.enable = true;
services.openssh.settings.PermitRootLogin = "prohibit-password";
# Networking Network-Manager
services.resolved.enable = false;
systemd.services.NetworkManager-wait-online.enable = false;
systemd.network.wait-online.enable = false;
# --- Set ownership of Radiantwave files ---
systemd.tmpfiles.rules = [
"d /home/kiosk/.local/share/radiantwave 0770 kiosk kiosk -"
];
# --- Backup service: runs before nixos-upgrade ---
systemd.services.radiantwave-backup = {
description = "Backup RadiantWave user data before upgrade";
before = [ "nixos-upgrade.service" ];
wantedBy = [ "nixos-upgrade.service" ];
serviceConfig = {
Type = "oneshot";
User = "kiosk";
};
script = ''
BACKUP_DIR="/home/kiosk/.local/share/radiantwave-backup"
SOURCE_DIR="/home/kiosk/.local/share/radiantwave"
mkdir -p "$BACKUP_DIR"
${pkgs.rsync}/bin/rsync -a \
--exclude='audio/' \
"$SOURCE_DIR/" "$BACKUP_DIR/"
echo "Backup completed at $(date)" > "$BACKUP_DIR/.backup-timestamp"
'';
};
# --- Health check service: runs after nixos-upgrade ---
systemd.services.radiantwave-healthcheck = {
description = "Verify RadiantWave is running after upgrade, rollback if not";
after = [ "nixos-upgrade.service" ];
wantedBy = [ "nixos-upgrade.service" ];
serviceConfig = {
Type = "oneshot";
# Give cage time to start radiantwave after the switch
ExecStartPre = "${pkgs.coreutils}/bin/sleep 90";
};
script = ''
if ${pkgs.procps}/bin/pgrep -x radiantwave > /dev/null; then
echo "RadiantWave is running, upgrade successful"
exit 0
fi
echo "RadiantWave not found after upgrade, rolling back..."
# Roll back to previous NixOS generation
/run/current-system/sw/bin/nixos-rebuild switch --rollback
echo "Rollback completed at $(date)"
'';
};
}