me like nix
1{ pkgs, lib, ... }:
2
3{
4 imports = [ ../pi-common/wifi.nix ];
5
6 networking.hostName = "kodi-pi";
7
8 # Use the new generational bootloader (matches nixos-raspberrypi installer)
9 boot.loader.raspberry-pi.bootloader = "kernel";
10
11 # Force 4K30 output when EDID read fails (TV may not be ready at boot)
12 boot.kernelParams = [ "video=HDMI-A-1:3840x2160@30D" ];
13
14 # Filesystems (matching nixos-raspberrypi installer layout)
15 fileSystems."/" = {
16 device = "/dev/disk/by-label/NIXOS_SD";
17 fsType = "ext4";
18 options = [ "noatime" ];
19 };
20 fileSystems."/boot/firmware" = {
21 device = "/dev/disk/by-label/FIRMWARE";
22 fsType = "vfat";
23 options = [ "noatime" "noauto" "x-systemd.automount" "x-systemd.idle-timeout=1min" ];
24 };
25
26 # Graphics
27 hardware.graphics.enable = true;
28
29 # Pi firmware config.txt settings
30 hardware.raspberry-pi.config.all.options = {
31 gpu_mem = { enable = true; value = 256; };
32 hdmi_force_hotplug = { enable = true; value = true; };
33 };
34
35 # Audio via PipeWire (needed for Jellyfin media player)
36 services.pipewire = {
37 enable = true;
38 alsa.enable = true;
39 pulse.enable = true;
40 };
41
42 # Jellyfin Media Player in TV mode via cage (Wayland kiosk compositor)
43 services.cage = {
44 enable = true;
45 user = "kiosk";
46 program = "${pkgs.jellyfin-media-player}/bin/jellyfinmediaplayer --tv";
47 };
48
49 # Kiosk user
50 users.users.kiosk = {
51 isNormalUser = true;
52 extraGroups = [ "video" "audio" "input" "render" ];
53 };
54
55 # Admin user
56 users.users.sean = {
57 isNormalUser = true;
58 extraGroups = [ "wheel" ];
59 openssh.authorizedKeys.keys = [
60 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDCIqgZ7kedxo+mOW7YG73Vp3zel3h180y3GKvHtRsXfGlpIIvRDy7pgCBQ4AGXYD4y78URQmFohYSAPqCPOPaWcU2un3XG9KvCzEsHmsbskPonitUmCiKvrKkb6oW4jCBtd7AEtBn+AiajAQFtPZ7NN2Df3AmTypvR6Irg7R+nxnfc9NTIHmGvxSDyWcbb4pguL20sctUSqGL6xGh8q/bqhdOThSimM+z9bEUNxK/5rPhwkNniMrp4pJcUrUiAh5/4DiRFG6KT+oeg+/myoz/Z1sPvAs7u/8JDQI4RshRD8Hu0oTkRBN6Hxj478q2SXbeBUZlD6IdjP3RhGpmSecoDdtWqKbpuV3eVRtQtba3KL86GBeV/bugaOdJ1Aud+1SOFJreAAuvxzMMKT+cdQZk6oOPP148DA/No+mDm/2S43lcdCXh79wA6YRAmKQ8jmZxTCtPutrvuZK1rguvvUlEoG/vhdNHh7eDa4Td07V6bjCRPUl8qk/e4M0E3pwsTlZc="
61 "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIOIgEteUEW06dnBHe2z8vNLwz2iMKe8bba6JgMmOUpcBAAAABHNzaDo= sean@framework16"
62 ];
63 };
64
65 # SSH
66 services.openssh = {
67 enable = true;
68 settings = {
69 PasswordAuthentication = false;
70 PermitRootLogin = "no";
71 };
72 };
73
74 # Accept unsigned store paths from local builds
75 nix.settings.require-sigs = false;
76
77 # Binary caches
78 nix.settings.substituters = [
79 "https://nixos-raspberrypi.cachix.org"
80 "https://seanaye.cachix.org"
81 ];
82 nix.settings.trusted-public-keys = [
83 "nixos-raspberrypi.cachix.org-1:4iMO9LXa8BqhU+Rpg6LQKiGa2lsNh/j2oiYLNOQ5sPI="
84 "seanaye.cachix.org-1:0Qf3cZ1SwnTwqaiNGltYySksjGHnemzRPiodThnvibA="
85 ];
86
87 # Networking
88 networking.useDHCP = true;
89 security.sudo.wheelNeedsPassword = false;
90
91 # Firewall
92 networking.firewall.allowedTCPPorts = [
93 22 # SSH
94 ];
95
96 environment.systemPackages = [ pkgs.jellyfin-media-player ];
97
98 system.stateVersion = "24.11";
99}