diff options
Diffstat (limited to 'hosts')
79 files changed, 3766 insertions, 0 deletions
diff --git a/hosts/T430/configuration.nix b/hosts/T430/configuration.nix new file mode 100644 index 0000000..cc530d6 --- /dev/null +++ b/hosts/T430/configuration.nix @@ -0,0 +1,78 @@ +{ config, lib, pkgs, ... }: { + imports = [ ./wg.nix ]; + + # Setup bootloader + boot._loader.enable = true; + + # Enable common options + _archetypes = { + profiles = { + desktop = { + enable = true; + home.users.timmy.enable = true; + }; + btrfs.enable = true; + }; + collections = { + desktop = { + extraUtilities.enable = true; + cad.enable = true; + chromium.enable = true; + crypto.enable = true; + graphics.enable = true; + office.enable = true; + }; + }; + }; + + # Configure charge threshold for battery + services.tlp = { + enable = true; + settings = { + START_CHARGE_THRESH_BAT0 = 55; + STOP_CHARGE_THRESH_BAT0 = 80; + }; + }; + + # Enable user timmy + _users.timmy = { + enable = true; + autologin.enable = true; + wifi.enable = true; + nas = { + enable = true; + home.enable = true; + }; + }; + + # Configure home + home-manager.users.timmy = { + gtk._mintTheme = { + dark = true; + color = "Purple"; + icons.color = "Purple"; + }; + gtk = { + font.name = "monospace"; + font.size = 8; + cursorTheme.size = 24; + }; + programs._st = { + enable = true; + font = { + name = "TamzenForPowerline"; + attrs = { + pixelsize = 14; + }; + }; + }; + programs._seasonalwallpaper.wallpapers.download = true; + fonts.fontconfig = { + defaultFonts.monospace = [ "TamzenForPowerline" ]; + subpixelRendering = "rgb"; + hinting = "slight"; + }; + }; + + system.stateVersion = "24.05"; +} diff --git a/hosts/T430/hardware-configuration.nix b/hosts/T430/hardware-configuration.nix new file mode 100644 index 0000000..78b0160 --- /dev/null +++ b/hosts/T430/hardware-configuration.nix @@ -0,0 +1,46 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "ehci_pci" "ahci" "usb_storage" "sd_mod" "sr_mod" "sdhci_pci" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/mapper/cryptroot"; + fsType = "btrfs"; + options = [ "subvol=@" ]; + }; + + boot.initrd.luks.devices."cryptroot".device = "/dev/disk/by-uuid/222813d7-cd5e-473a-9cdb-1a2bae74e904"; + + fileSystems."/home" = + { device = "/dev/mapper/cryptroot"; + fsType = "btrfs"; + options = [ "subvol=@home" ]; + }; + + fileSystems."/nix" = + { device = "/dev/mapper/cryptroot"; + fsType = "btrfs"; + options = [ "subvol=@nix" ]; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/117A-6AB4"; + fsType = "vfat"; + options = [ "fmask=0022" "dmask=0022" ]; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/T430/resources/secrets/wg.yaml b/hosts/T430/resources/secrets/wg.yaml new file mode 100644 index 0000000..3e29c4c --- /dev/null +++ b/hosts/T430/resources/secrets/wg.yaml @@ -0,0 +1,18 @@ +wg-office: ENC[AES256_GCM,data:Ft2P1nSMqs+0obsZdulyIV5oCxid019t++A0bAHTkcpysmwCuECHODZL2EHgpbmvomMKQyzKPPdrSgGS9H+Dar/+Qko70zPSs8uQit2j6yhceSwNtb2ivD2hFCTtQr9pvSr8HgpxKtmw22tGpfXXHTmu+xBlHFizvTMEAqKdz+bvspLk/ANbcbmLVYXrb5NwksF0vaZSOkzKnpeyDyhvb8Z5GGmvWTPzP3ILK7RzpPb11/9vgyBjyyMkQfT0QpwkE7OlaH4ffX/Qg1d0T4tWOA4Fsi3h853FZ1Rukh5f3YPSsEqgLNJpClDrprYM3m2d3dDUYen4F3+58MvF8K1CWLigs9RwxqH2F5ztloHDpLAzKp/9l3xOt869uNiOqKF68102lYdCP20AQDt34Xory8Qls7QMYo0auUb7m/XVdhHQD/ohyjDHIGZG6BrbuRtuMgAu8PZh8MpdeZw1xe+5oPb2XrL3dpR7xZ/eHpcy58zVBl8SQaoCP85e1uBabnqN0fbiVFDdUNL52xTEyRknrK7RISX0zPiwDvdMRIAa172C,iv:92BzIjqwiCIfLzl9El4QoU701Q7XZE6JgpPbZZCh4ZY=,tag:+KUlo0fF5h3kMveoU4NQ9g==,type:str] +wg-home: ENC[AES256_GCM,data:BJ29Dvv7I2nKKqpmKkUu5xrvyRXcTGURnGTmqwWbp3vbKchC1DnAyqLIeTFp7opB1kZItVTUpjvR7J8jn+48Y/xGnRNaEGdIPZwAIXPRdgX0QHFBUdw4YjBYVA82+/QqfIUBvzp/iHOsBRLkG1UNTKMozytFR6OZJNUHH8pukx5vO/ioEVOR26lfYuHH47+KOEktLpu5VlpdY7DXkYLY0/yof7MT3/9NY1KD2PWEZIq9yquPWnA+yTvm9cyhkNOQWsCC/0K5FjN/oKtf/SCt3Jb2LzuxF09+xVvzbvewhTnc3QVF0Hhf9OruJymrICNGAqYFFZCBL48nzfA7eSgaU6bg8Toq9XIuHxQ3NIrr8k7D3KmRGq2cDFL11SUolnouTgSmkfv+JBulpaOY8IjgCDZT2lmHiHdGjVKcq9MGSIUb7K6M8oXi9nbev8QZQIhdgQXRE3HZ1HJQE/3VcFTlEsJ2Y6kAIEEiAHaLK9wyrpQVYPQplVVVTapCYoE=,iv:afhs9kQqstlhmBKXQ7okSENzNt2Y9VXsQVzvENoe/Fo=,tag:hJJkQH75rNeSfs8mOkdxVg==,type:str] +wg-office-alt: ENC[AES256_GCM,data:Wk6di/P4yh0PhhfdUUB3af326glrnaqGepNoJmBkuVptmPZi0GdnrBL5/dXxTKLI3ZjGLonwf5JCX7VcXZTRzXwv8ntv0ts87pgaQcueDE7BFqlYjdlmQz6Rv+58ETCnm5yMu1F2oRkHp93ONPpZumyNmqV6lhzQlzf2XgSzVSI/eNPJ6eb2UmQHFs4hjyl3WUPKI21VlNIwNwikQXBVo4si9SUNOIvLkSYzfurkfqQLRWt6O2OJdRx1ZWMFcHp5YKuUDHFRwKym2226I16vvic0XOJfi6Sic6uZQ5GwuiPGB938uectXyfasOC0YQ2Fzj0HqR/mpQJvwj49ulwljDvDqFDjMQMmKYPa3EiTFegaUgEMOLjnQySJpAwThkZHEOo9M298L5TZKIIHiKWTsJa6PX82SeNOw0+3FDNdFEM9gQbGUIlQmRadlQYEY7VE,iv:XwM1xtriFkQLNzSIVhA/FtON9HccFh2qR4SSmSDF7r0=,tag:O/+m9RQbtYmGsQnxsF/OsA==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4NEN4NGxDR1oreGVoSGhE + TzMxSEY0QVBhS2Z6MW15ci9aVlJ0a3IyVlZBCldPRVNvcUhJSHhWSEk3akd4RjN0 + ajhUV2d1ZWRsRFU4cTE2dGl6RmM4MGsKLS0tIFhnUjl5aDJqWVB1NE15SlNzR2Iv + YTNydURsOUMrSXZGdk9UOUdUQlA0SFUKxEDJRR6tpYva9qpWo9NxwCxk/xpRVoTl + YJkmDZzMcXikXXiro96AprP9dXJXvMPKYPGl2Zsal8PlGFPBoHW2GA== + -----END AGE ENCRYPTED FILE----- + recipient: age1w80rc0dnuu8nw99gw64c596qqetm78jdnsqajr0u7ephykekr39qfz8vnv + lastmodified: "2026-10-05T19:03:13Z" + mac: ENC[AES256_GCM,data:17HpRszIH6PbDBOV91Q9J3fQvGJnqdCG32X5OU5kzBR7sA/zMVZSNGpT/Qz7J+11ZvWn+LzErnLpZSdfg+HIBUdmxgmTaKBSPHL34O5N0vHkbt5L1Vbys+RHiK1Gb/JnqfCSu5CSwSQRmbC5GIpimHL/Ke3iaMyTvmb0nxWqG/0=,iv:I84zf/PYlSIRpUaEj7TjzqslbYJj3RfC1BhC/FaT1zI=,tag:O/YK/FVCzE3hIAl/xh1hYA==,type:str] + unencrypted_suffix: _unencrypted + version: 3.13.3 diff --git a/hosts/T430/wg.nix b/hosts/T430/wg.nix new file mode 100644 index 0000000..d6a5e47 --- /dev/null +++ b/hosts/T430/wg.nix @@ -0,0 +1,11 @@ +{ config, pkgs, inputs, ... }: { + sops.secrets.wg-office.sopsFile = ./resources/secrets/wg.yaml; + sops.secrets.wg-office-alt.sopsFile = ./resources/secrets/wg.yaml; + sops.secrets.wg-home.sopsFile = ./resources/secrets/wg.yaml; + + networking.wg-quick.interfaces = { + wg-office = { autostart = false; configFile = config.sops.secrets.wg-office.path; }; + wg-office-alt = { autostart = false; configFile = config.sops.secrets.wg-office-alt.path; }; + wg-home = { autostart = false; configFile = config.sops.secrets.wg-home.path; }; + }; +} diff --git a/hosts/X230/configuration.nix b/hosts/X230/configuration.nix new file mode 100644 index 0000000..f54b174 --- /dev/null +++ b/hosts/X230/configuration.nix @@ -0,0 +1,65 @@ +{ config, lib, pkgs, ... }: { + imports = [ ./wg.nix ]; + + # Setup bootloader + boot._loader.enable = true; + + # Enable common options + _archetypes = { + profiles = { + desktop = { + enable = true; + home.users.timmy.enable = true; + }; + btrfs.enable = true; + }; + collections = { + desktop = { + crypto.enable = true; + graphics.enable = true; + office.enable = true; + }; + }; + }; + + # Enable user timmy + _users.timmy = { + enable = true; + autologin.enable = true; + wifi.enable = true; + }; + + # Use intel driver for better performance and vsync + #services.xserver.videoDrivers = [ "intel" ]; + + # Configure home + home-manager.users.timmy = { + gtk._mintTheme = { + dark = true; + color = "Teal"; + icons.color = "Teal"; + }; + fonts.fontconfig.defaultFonts.monospace = [ "TamzenForPowerline" ]; + gtk = { + font.name = "monospace"; + font.size = 8; + cursorTheme.size = 24; + }; + programs._st = { + enable = true; + font = { + name = "TamzenForPowerline"; + attrs = { + pixelsize = 14; + }; + }; + }; + programs._seasonalwallpaper.wallpapers.download = true; + fonts.fontconfig = { + subpixelRendering = "rgb"; + hinting = "full"; + }; + }; + + system.stateVersion = "24.05"; +} diff --git a/hosts/X230/hardware-configuration.nix b/hosts/X230/hardware-configuration.nix new file mode 100644 index 0000000..0791585 --- /dev/null +++ b/hosts/X230/hardware-configuration.nix @@ -0,0 +1,48 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "ehci_pci" "ahci" "usb_storage" "sd_mod" "sdhci_pci" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/41036740-73bc-4004-a302-01233b4d83b8"; + fsType = "btrfs"; + options = [ "subvol=@" ]; + }; + + boot.initrd.luks.devices."enc".device = "/dev/disk/by-uuid/6019772f-4a1c-4abd-9c70-b1d71cc2de65"; + + fileSystems."/home" = + { device = "/dev/disk/by-uuid/41036740-73bc-4004-a302-01233b4d83b8"; + fsType = "btrfs"; + options = [ "subvol=@home" ]; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/72D4-F66A"; + fsType = "vfat"; + options = [ "fmask=0022" "dmask=0022" ]; + }; + + swapDevices = [ ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.enp0s25.useDHCP = lib.mkDefault true; + # networking.interfaces.wlp3s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/X230/resources/secrets/wg0.yaml b/hosts/X230/resources/secrets/wg0.yaml new file mode 100644 index 0000000..5941b70 --- /dev/null +++ b/hosts/X230/resources/secrets/wg0.yaml @@ -0,0 +1,16 @@ +wg0: ENC[AES256_GCM,data:wcgowNptTdrJNjzH6n/ulbec5+GPkuRAUNidWFy4dhClioTg8vdrXhhwP+sykwEZYOjsLurkU0Rw1w9ds+AGe3J+FnW1qKdskcY+8t/CyNY51pUbzMCKxexnNj52+0+VlH6FAUyplo6ESg/vlWCFyuyACWjQfdqDW/1PxJzrYqZ7MIwbCdntjE/84F52BqxePt3LolzvzTGUOx5Lr6Jbv9i3tv1R9NmZxt5t2gwaGbIIPWMVZh972w5HJYa8bfx67vuyj6HE46tMiu8WdQbHfjRvVIA+0OtHihpDGHfi5Q6iXpO/rk4YJZjsiEgTMTqD08HD5Gm+wBFwHSJjCOBpBsq3GsspDLNI+EXel7Gmtk+BhL1tFQdpYPwz7bHd03Znawr4Br7R0gHJg4FXnhKlG+SyDqXKirnCyCTfUotIBmU0dX4tzmwiOMyvImgXZA==,iv:GAk27qkZDopzdWnBeL7yTmyn9dM2wSzKd41NRhsyNNY=,tag:Ba7jZhqEa8dUedIvVFBbHA==,type:str] +sops: + age: + - recipient: age1w80rc0dnuu8nw99gw64c596qqetm78jdnsqajr0u7ephykekr39qfz8vnv + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4NEN4NGxDR1oreGVoSGhE + TzMxSEY0QVBhS2Z6MW15ci9aVlJ0a3IyVlZBCldPRVNvcUhJSHhWSEk3akd4RjN0 + ajhUV2d1ZWRsRFU4cTE2dGl6RmM4MGsKLS0tIFhnUjl5aDJqWVB1NE15SlNzR2Iv + YTNydURsOUMrSXZGdk9UOUdUQlA0SFUKxEDJRR6tpYva9qpWo9NxwCxk/xpRVoTl + YJkmDZzMcXikXXiro96AprP9dXJXvMPKYPGl2Zsal8PlGFPBoHW2GA== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-03-09T12:36:15Z" + mac: ENC[AES256_GCM,data:T8hQbFrPOGYQl8tbqUMLdQN3qjhcAXmKfwqEsLQkDjr2nxUXDz8d58TUsaRvkHC4jPo9lXyPL5SSpua2kzJIcDDLPkiPB/3qV8ksJQ0dgcfLkUnrI1mtoo9AOPnHrTjstSAR2cmiFbCTqRpkLnGwI+NoCLjNjd/GNSAlMl00QMg=,iv:boSHzNAuKGkAhtkApOOJEtW4gt13mMmCin24gf3dXIs=,tag:1+4+BE8ZPgvgf4RlH6Wmhw==,type:str] + unencrypted_suffix: _unencrypted + version: 3.12.1 diff --git a/hosts/X230/wg.nix b/hosts/X230/wg.nix new file mode 100644 index 0000000..3881b63 --- /dev/null +++ b/hosts/X230/wg.nix @@ -0,0 +1,7 @@ +{ config, pkgs, inputs, ... }: { + sops.secrets.wg0.sopsFile = ./resources/secrets/wg0.yaml; + + networking.wg-quick.interfaces = { + wg0.configFile = config.sops.secrets.wg0.path; + }; +} diff --git a/hosts/flex-wg-router/configuration.nix b/hosts/flex-wg-router/configuration.nix new file mode 100644 index 0000000..3f6ad06 --- /dev/null +++ b/hosts/flex-wg-router/configuration.nix @@ -0,0 +1,99 @@ +{ config, lib, pkgs, ... }: let + ipAddress = "10.1.1.1"; +in { + imports = [ ./wg.nix ]; + + # Setup bootloader + boot._loader.enable = true; + + # Enable common options + _archetypes = { + profiles = { + headless = { + enable = true; + home.users.timmy.enable = true; + }; + btrfs.enable = true; + }; + }; + + # Network config + networking = { + # Label lan and wan interfaces + _interfaceLabels = { + enable = true; + interfaces = { + lan0 = "98:b7:85:22:9b:43"; # External + wan0 = "54:ee:75:8c:4b:2d"; # Internal + }; + }; + # Set ip addresses + interfaces = { + lan0.ipv4.addresses = [ + { address = ipAddress; prefixLength = 24; } + { address = "192.168.77.4"; prefixLength = 24; } + ]; + wan0.ipv4.addresses = [{ + address = "46.110.173.163"; # Reserved static ip for wg-router + prefixLength = 31; + }]; + }; + defaultGateway = { + address = "46.110.173.161"; + interface = "wan0"; + }; + # Firewall rules + firewall = { + interfaces.wan0 = { + allowedUDPPorts = [ 51820 ]; + }; + }; + # NAT/masquerade lan0 allowing wg0 clients to access lan0 + nftables.tables.wg-nat = { + family = "ip"; + content = '' + chain post { + type nat hook postrouting priority srcnat; policy accept; + iifname "wg0" oifname "lan0" masquerade comment "wg0 => lan0" + } + ''; + }; + }; + + # Router config + services._router = { + routing = { + enable = true; + interfaces = { + lan = [ "lan0" ]; + wan = "wan0"; + }; + }; + dnsDhcpConfig = { + dhcp.enable = false; + # Point to separate dns server at pls.lan for local resolution + localResolution = { + localDomain = "pls.lan"; + localDnsAddress = "192.168.77.1@53"; + localReverseZone = "77.168.192.in-addr.arpa"; + }; + #dhcp = { + # defaultGateway = ipAddress; + # localhostIp = ipAddress; + # rangeStart = "10.1.1.100"; + # rangeEnd = "10.1.1.250"; + # staticLeases = { + # idrac-8HT2W52 = { + # macAddress = "18:fb:7b:9d:16:b3"; + # staticIp = "10.1.1.10"; + # }; + # }; + #}; + }; + }; + + # Enable user timmy + _users.timmy.enable = true; + + system.stateVersion = "25.05"; +} diff --git a/hosts/flex-wg-router/hardware-configuration.nix b/hosts/flex-wg-router/hardware-configuration.nix new file mode 100644 index 0000000..01cff6d --- /dev/null +++ b/hosts/flex-wg-router/hardware-configuration.nix @@ -0,0 +1,45 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/01eae5fd-a46e-4a36-8a9d-247a0b16bcef"; + fsType = "btrfs"; + options = [ "subvol=@" ]; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/345A-436A"; + fsType = "vfat"; + options = [ "fmask=0022" "dmask=0022" ]; + }; + + fileSystems."/home" = + { device = "/dev/disk/by-uuid/01eae5fd-a46e-4a36-8a9d-247a0b16bcef"; + fsType = "btrfs"; + options = [ "subvol=@home" ]; + }; + + swapDevices = [ ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.enp3s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/flex-wg-router/resources/secrets/wg.yaml b/hosts/flex-wg-router/resources/secrets/wg.yaml new file mode 100644 index 0000000..dc80ca3 --- /dev/null +++ b/hosts/flex-wg-router/resources/secrets/wg.yaml @@ -0,0 +1,17 @@ +wg1: ENC[AES256_GCM,data:GDmORbMvBY9vQ0eppWM71eABSVFgGeoGD7CTu5otyAWr/fGKraGaRKHnj3i/wTQV2oxeI1eBKJoAcNI4vdoS584pffo9qXi5A8xQ6UppqEdqbMGqsoiVElGbJXoZxx9Lgl0abgy9DOvMNFhWQzEPnqW/QRXxzClsazB0oveafqx1cXMnU4WestLKvCyK7UL5GVCrp18qw2UzIeuoTY9zyQ3Dt9/Tmlg9tsjLy4bWmTyrgyeYOKc2x0Aocxz6yvadN76Vp6vm9Fcxvu0szxBrVauIxCzqpL6pyy3wvLm+aka6CkLhviZ38GtZ8GXXSqB1Lf52mz3udKqLZAau1ANqfAhzKqUapKPxn+fpo+JIIRw4+boXtO/3Z8YPjiyUQcFrhRkSCI7cm2w+rCcm/p+2YiBPpMGSCDcyJqZeKbgM8MPkpbr3EEg4ruqNJYN/cnk=,iv:O8QYsHCEzTW6Y4s31OKjjcAxAToQwLfAIEzCtUZT6IM=,tag:M0Juai3qMJiabN1kgYLvOA==,type:str] +wg0: ENC[AES256_GCM,data:/tipovCGtQ6XKdxejML3DYj2FwA8LOi8Zrj+f5zAABJ8aubSJRrVOrel9kb36h8NC0IIbYEOVuWEzIAok+k3ZvybIkUfDM+kNcTGQeb15EPunonbSyVN2g0POZBY/+gGCLwm4OaN1aLtmwDqhJD8hCj9Gq1mzpeUU0PKmaClY37MHb1IgR0YRnEsjVL5AT2JYCTgWylSmvwPEXz32dABqdOPbGzTP24coHv5HVFXf9ljiZGZQlFkHVMn7/fpQnh/5NyP6EePIps7hfpOHmnjn1kFhhXwVKQAzZmRZYmhbGB297uyUpMFoQbEV8R9q1ON+B1ZCe+cXOsKB65ls5dFVSDgLkEZiA141H3yGrsIjWB3nQiU5MmJXVEzW2BXt37YLc6xQiUMHcHLZru8TR6FfJ6Y6jen7w9pPAtY78DL64R/m4wvvvJhxI4h/GMCo7RZdqoWZAm8KNj0U4sSlbJjVCbvToUyqBydgPyZc62o8s+Bi0TC6RTxCX/vDLrudh7S8Bvy6QSpqMXE4bjBPJEwccu/F2Awf2oz1u+QfnpUYI6LcW+rhgfjQfFFM117biRbmfwTFyImnMwXsxmycJL9OrykuvOAvHNhop58GJ+S1lGbTA8CAfbzwgyk7HGiAbNg3EA0GvB2sMJg+7vLDNrHgKgKChU7o9/Nk3NyxR7ML7otbRQr9RTH4OncQv2iJvlclM5E7R9sfzI7er8fPRxSSDrDavwxetQM5lgP9EidpTLGOtw2sNmmq4w9ImoLtpYgTtw1v2oVTbNalerkLpI1qcCwD5j/PIevg2xa9CPlmbrWmpis0hM1k/QwnquUWKbwIweGK8QJT5V71KKc1gtWX0Euuy/ISU3radLnsmSh,iv:9Qs0+6rx+er8HfkGMFZA8aYGvqk46kDaE3Pyd7kJ/aY=,tag:QbV9n9kSX9ftEBL9LO4pRw==,type:str] +sops: + age: + - recipient: age1f0tmpy2nam58skmznjyqd3zf54rxtfrk6fda0vlpq9y3yg6wac7sjf0vja + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoNVZ5dmNSd1NRQUhURkl2 + dnk3MkNjMFUyNnU5L1FFNTV0a1NUbUZ6ZUEwCmNNUldIdnoycVpwUHJrcXZvZXp5 + NGVHcUlHUm1uK0QxV1JmdDVyQVoxZDgKLS0tIDJhSHhkYjNML045SHNobytucnVZ + L25wUWRJbzZMZDFseXdvOFJXQVRxN28KJjC3ola24tTEV8tFYpnsId4d0S+jHkS9 + ME6i4jorWRlQKdYn/gTUoqgMAvJEc73hjTfgX6bFshhuhflfGxXQQw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-10-06T18:10:05Z" + mac: ENC[AES256_GCM,data:zR2u6zFW/MVI5pH3w909JLvAEsAHK2Sb5mNzFFQMzLcPsSjZf6CZQWUS7WVbvtMYF9gJFNEikYs7hGR5q7IG98Najcc4Jht0J6nmv812gptB78CtX3MXv06QP8LBjXkIDTg2pCSAqdifn9BmWD8ObrHfNciUn/OO9c+bR5+lGg8=,iv:h3KtOUnMeuR6PA2SerfyyAV7uMtrujsizu1KC47Ngtw=,tag:l8Of/f7TgHmjbvHh4EwhOQ==,type:str] + unencrypted_suffix: _unencrypted + version: 3.12.1 diff --git a/hosts/flex-wg-router/wg.nix b/hosts/flex-wg-router/wg.nix new file mode 100644 index 0000000..9ff9395 --- /dev/null +++ b/hosts/flex-wg-router/wg.nix @@ -0,0 +1,7 @@ +{ config, pkgs, inputs, ... }: { + sops.secrets.wg0.sopsFile = ./resources/secrets/wg.yaml; + + networking.wg-quick.interfaces = { + wg0.configFile = config.sops.secrets.wg0.path; + }; +} diff --git a/hosts/gnuslashprinter/configuration.nix b/hosts/gnuslashprinter/configuration.nix new file mode 100644 index 0000000..9e1f734 --- /dev/null +++ b/hosts/gnuslashprinter/configuration.nix @@ -0,0 +1,29 @@ +{ + imports = [ + ./flask-relay-ctl.nix + ./klipper.nix + ]; + + boot._loader.enable = true; + + _archetypes = { + profiles = { + headless = { + enable = true; + home.users.timmy.enable = true; + }; + btrfs.enable = true; + }; + }; + + # Enable user timmy + _users.timmy.enable = true; + + # Name devices + services.udev.extraRules = '' + SUBSYSTEM=="tty", KERNELS=="3-9", SYMLINK+="gsp-power" + SUBSYSTEM=="tty", KERNELS=="3-10", SYMLINK+="gsp-control" + ''; + + system.stateVersion = "25.11"; +} diff --git a/hosts/gnuslashprinter/flask-relay-ctl.nix b/hosts/gnuslashprinter/flask-relay-ctl.nix new file mode 100644 index 0000000..27507b6 --- /dev/null +++ b/hosts/gnuslashprinter/flask-relay-ctl.nix @@ -0,0 +1,37 @@ +{ pkgs, ... }: let + flaskrelayctl = pkgs.python3Packages.buildPythonApplication { + pname = "flaskrelayctl"; + version = "1.0"; + src = ./resources/flaskrelayctl; + pyproject = true; + build-system = with pkgs.python3Packages; [ setuptools ]; + dependencies = with pkgs.python3Packages; [ + flask + pyserial + ]; + }; +in { + users.users.relay-api = { + isSystemUser = true; + group = "relay-api"; + extraGroups = [ "dialout" ]; + }; + users.groups.relay-api = {}; + + systemd.services.relay-api = let + RELAYCTL_DEV = "/dev/gsp-power"; + in { + description = "USB Relay Flask API"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + User = "relay-api"; + Group = "relay-api"; + ExecStart = "${flaskrelayctl}/bin/flaskrelayctl"; + Restart = "always"; + DeviceAllow = [ "${RELAYCTL_DEV} rw" ]; + }; + }; + + environment.systemPackages = [ flaskrelayctl ]; +} diff --git a/hosts/gnuslashprinter/hardware-configuration.nix b/hosts/gnuslashprinter/hardware-configuration.nix new file mode 100644 index 0000000..278d6e6 --- /dev/null +++ b/hosts/gnuslashprinter/hardware-configuration.nix @@ -0,0 +1,44 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "ehci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/416a481f-d656-4bd1-acdb-bd0a6f2d2c3a"; + fsType = "btrfs"; + options = [ "subvol=@" ]; + }; + + fileSystems."/home" = + { device = "/dev/disk/by-uuid/416a481f-d656-4bd1-acdb-bd0a6f2d2c3a"; + fsType = "btrfs"; + options = [ "subvol=@home" ]; + }; + + fileSystems."/nix" = + { device = "/dev/disk/by-uuid/416a481f-d656-4bd1-acdb-bd0a6f2d2c3a"; + fsType = "btrfs"; + options = [ "subvol=@nix" ]; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/18C4-6D53"; + fsType = "vfat"; + options = [ "fmask=0022" "dmask=0022" ]; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/gnuslashprinter/klipper.nix b/hosts/gnuslashprinter/klipper.nix new file mode 100644 index 0000000..331a0c7 --- /dev/null +++ b/hosts/gnuslashprinter/klipper.nix @@ -0,0 +1,100 @@ +{ + # Klipper firmware + services.klipper = { + enable = true; + firmwares = { + mcu = { + enable = true; + # Serial port connected to the microcontroller + serial = "/dev/gsp-control"; + # Klipper flash must be enabled in order to build mcu firmware + # The resulting `klipper-flash-mcu` command will show the location of the firmware bin in the nix store + enableKlipperFlash = true; + # Run klipper-genconf to generate this + configFile = ./resources/klipper/mcu/config; + }; + }; + configFile = ./resources/klipper/printer.cfg; + logFile = "/var/lib/klipper/klipper.log"; + }; + # Mutable config + services.klipper.mutableConfig = true; + #configDir = "/var/lib/moonraker/config"; # Accessible by moonraker # TODO + + # Moonraker web-api + security.polkit.enable = true; # required for services.moonraker.allowSystemControl + services.moonraker = { + user = "root"; + enable = true; + address = "0.0.0.0"; + allowSystemControl = true; + settings = { + authorization = { + force_logins = true; + cors_domains = [ + "*.local" + "*.lan" + "*://app.fluidd.xyz" + "*://my.mainsail.xyz" + ]; + trusted_clients = [ + "10.0.0.0/8" + "127.0.0.0/8" + "169.254.0.0/16" + "172.16.0.0/12" + "192.168.0.0/16" + "FE80::/10" + "::1/128" + ]; + }; + #file_manager.check_klipper_config_path = false; # Disable warning when klipper config is not accessible by moonraker + # mainsail.cfg + #"update_manager mainsail-config" = { + # type = "git_repo"; + # primary_branch = "master"; + # path = "~/mainsail-config"; + # origin = "https://github.com/mainsail-crew/mainsail-config.git"; + # managed_services = "klipper"; + #}; + + "power printer" = let + relayApiHost = "http://localhost:5050"; + in { + type = "http"; + on_url = "${relayApiHost}/on"; + off_url = "${relayApiHost}/off"; + status_url = "${relayApiHost}/status"; + response_template = '' + + # The module will perform the "GET" request using the appropriate url. + # We use the `last_response` method to fetch the result and decode the + # json response. + {% set resp = http_request.last_response().json() %} + # The expression below will render "on" or "off". + {resp["state"].lower()} + ''; + off_when_shutdown = true; + on_when_job_queued = true; + locked_while_printing = true; + restart_klipper_when_powered = true; + restart_delay = "1"; + bound_services = "klipper"; + initial_state = "off"; + }; + }; + }; + + # Mainsail web-interface + services.mainsail = { + enable = true; + hostName = "0.0.0.0"; + nginx.listenAddresses = [ "0.0.0.0" ]; + }; + services.nginx.clientMaxBodySize = "1000m"; # Allow large gcodes, etc. + networking.firewall.allowedTCPPorts = [ 80 ]; # Port for mainsail via nginx + + # Webcam support in mainsail + # TODO hook to restart ustreamer when webcam is connected + services.ustreamer.enable = true; + services.mainsail.nginx.locations."/webcam/".proxyPass = "http://localhost:8080/stream"; # Default location for ustreamer stream +} diff --git a/hosts/gnuslashprinter/resources/flaskrelayctl/pyproject.toml b/hosts/gnuslashprinter/resources/flaskrelayctl/pyproject.toml new file mode 100644 index 0000000..b151b74 --- /dev/null +++ b/hosts/gnuslashprinter/resources/flaskrelayctl/pyproject.toml @@ -0,0 +1,10 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "flaskrelayctl" +version = "1.0" + +[project.scripts] +flaskrelayctl = "server:main" diff --git a/hosts/gnuslashprinter/resources/flaskrelayctl/server/__init__.py b/hosts/gnuslashprinter/resources/flaskrelayctl/server/__init__.py new file mode 100644 index 0000000..f2c0bc3 --- /dev/null +++ b/hosts/gnuslashprinter/resources/flaskrelayctl/server/__init__.py @@ -0,0 +1,54 @@ +from flask import Flask, jsonify +import serial +import os + +app = Flask(__name__) + +RELAY_DEV = os.environ.get("RELAYCTL_DEV", "/dev/ttyUSB0") +RELAY_HOST = os.environ.get("RELAYCTL_HOST", "127.0.0.1") +RELAY_PORT = os.environ.get("RELAYCTL_PORT", "5050") +RELAY_BAUD = 9600 +RELAY_ID = 1 # NOTE: multi relay boards are not supported (only relay id 1) + +def get_cmd(state: bool): + """ + LCUS relay 4-byte control command syntax is as follows: + start: always 0xA0 + relay: id of relay (counts from 1) + state: coil energized 0 or 1 + checksum: sum of previous 3 bytes + """ + start = 0xA0 + relay = RELAY_ID + state = int(state) + checksum = start + relay + state + return bytes((start, relay, state, checksum)) + +def get_serial(): + return serial.Serial(RELAY_DEV, RELAY_BAUD, timeout=1) + +@app.route("/on", methods=["GET", "POST"]) +def on(): + with get_serial() as ser: + ser.write(get_cmd(True)) + return jsonify({"state": "ON"}) + +@app.route("/off", methods=["GET", "POST"]) +def off(): + with get_serial() as ser: + ser.write(get_cmd(False)) + return jsonify({"state": "OFF"}) + +@app.route("/status", methods=["GET"]) +def status(): + with get_serial() as ser: + ser.write(bytes((0xFF,))) # write 0xFF to get status + r = ser.readline() + state = r.decode("utf-8").removeprefix("CH1: ").strip() + return jsonify({"state": state}) + +def main(): + app.run(host=RELAY_HOST, port=int(RELAY_PORT)) + +if __name__ == "__main__": + main() diff --git a/hosts/gnuslashprinter/resources/klipper/mcu/config b/hosts/gnuslashprinter/resources/klipper/mcu/config new file mode 100644 index 0000000..3e192a3 --- /dev/null +++ b/hosts/gnuslashprinter/resources/klipper/mcu/config @@ -0,0 +1,109 @@ +# CONFIG_LOW_LEVEL_OPTIONS is not set +# CONFIG_MACH_AVR is not set +# CONFIG_MACH_ATSAM is not set +# CONFIG_MACH_ATSAMD is not set +# CONFIG_MACH_LPC176X is not set +CONFIG_MACH_STM32=y +# CONFIG_MACH_HC32F460 is not set +# CONFIG_MACH_RPXXXX is not set +# CONFIG_MACH_PRU is not set +# CONFIG_MACH_AR100 is not set +# CONFIG_MACH_LINUX is not set +# CONFIG_MACH_SIMU is not set +CONFIG_BOARD_DIRECTORY="stm32" +CONFIG_MCU="stm32f103xe" +CONFIG_CLOCK_FREQ=72000000 +CONFIG_SERIAL=y +CONFIG_FLASH_SIZE=0x10000 +CONFIG_FLASH_BOOT_ADDRESS=0x8000000 +CONFIG_RAM_START=0x20000000 +CONFIG_RAM_SIZE=0x5000 +CONFIG_STACK_SIZE=512 +CONFIG_FLASH_APPLICATION_ADDRESS=0x8007000 +CONFIG_STM32_SELECT=y +CONFIG_MACH_STM32F103=y +# CONFIG_MACH_STM32F207 is not set +# CONFIG_MACH_STM32F401 is not set +# CONFIG_MACH_STM32F405 is not set +# CONFIG_MACH_STM32F407 is not set +# CONFIG_MACH_STM32F429 is not set +# CONFIG_MACH_STM32F446 is not set +# CONFIG_MACH_STM32F765 is not set +# CONFIG_MACH_STM32F031 is not set +# CONFIG_MACH_STM32F042 is not set +# CONFIG_MACH_STM32F070 is not set +# CONFIG_MACH_STM32F072 is not set +# CONFIG_MACH_STM32G070 is not set +# CONFIG_MACH_STM32G071 is not set +# CONFIG_MACH_STM32G0B0 is not set +# CONFIG_MACH_STM32G0B1 is not set +# CONFIG_MACH_STM32G431 is not set +# CONFIG_MACH_STM32G474 is not set +# CONFIG_MACH_STM32H723 is not set +# CONFIG_MACH_STM32H743 is not set +# CONFIG_MACH_STM32H750 is not set +# CONFIG_MACH_STM32L412 is not set +# CONFIG_MACH_N32G452 is not set +# CONFIG_MACH_N32G455 is not set +CONFIG_MACH_STM32F1=y +CONFIG_HAVE_STM32_USBFS=y +CONFIG_STM32_USB_DOUBLE_BUFFER_TX=y +CONFIG_HAVE_STM32_CANBUS=y +CONFIG_STM32_DFU_ROM_ADDRESS=0 +# CONFIG_STM32_FLASH_START_2000 is not set +# CONFIG_STM32_FLASH_START_5000 is not set +CONFIG_STM32_FLASH_START_7000=y +# CONFIG_STM32_FLASH_START_8000 is not set +# CONFIG_STM32_FLASH_START_8800 is not set +# CONFIG_STM32_FLASH_START_9000 is not set +# CONFIG_STM32_FLASH_START_10000 is not set +# CONFIG_STM32_FLASH_START_800 is not set +# CONFIG_STM32_FLASH_START_1000 is not set +# CONFIG_STM32_FLASH_START_4000 is not set +# CONFIG_STM32_FLASH_START_0000 is not set +CONFIG_CLOCK_REF_FREQ=8000000 +CONFIG_STM32F0_TRIM=16 +# CONFIG_STM32_USB_PA11_PA12 is not set +CONFIG_STM32_SERIAL_USART1=y +# CONFIG_STM32_CANBUS_PA11_PA12 is not set +# CONFIG_STM32_CANBUS_PA11_PB9 is not set +CONFIG_SERIAL_BAUD=250000 +CONFIG_USB_VENDOR_ID=0x1d50 +CONFIG_USB_DEVICE_ID=0x614e +CONFIG_USB_SERIAL_NUMBER="12345" +CONFIG_WANT_ADC=y +CONFIG_WANT_SPI=y +CONFIG_WANT_SOFTWARE_SPI=y +CONFIG_WANT_I2C=y +CONFIG_WANT_SOFTWARE_I2C=y +CONFIG_WANT_HARD_PWM=y +CONFIG_WANT_BUTTONS=y +CONFIG_WANT_TMCUART=y +CONFIG_WANT_NEOPIXEL=y +CONFIG_WANT_PULSE_COUNTER=y +CONFIG_WANT_ST7920=y +CONFIG_WANT_HD44780=y +CONFIG_WANT_ADXL345=y +CONFIG_WANT_LIS2DW=y +CONFIG_WANT_MPU9250=y +CONFIG_WANT_ICM20948=y +CONFIG_WANT_THERMOCOUPLE=y +CONFIG_WANT_HX71X=y +CONFIG_WANT_ADS1220=y +CONFIG_WANT_LDC1612=y +CONFIG_WANT_SENSOR_ANGLE=y +CONFIG_NEED_SENSOR_BULK=y +CONFIG_WANT_LOAD_CELL_PROBE=y +CONFIG_NEED_SOS_FILTER=y +CONFIG_CANBUS_FREQUENCY=1000000 +CONFIG_INLINE_STEPPER_HACK=y +CONFIG_HAVE_STEPPER_OPTIMIZED_BOTH_EDGE=y +CONFIG_WANT_STEPPER_OPTIMIZED_BOTH_EDGE=y +CONFIG_HAVE_GPIO=y +CONFIG_HAVE_GPIO_ADC=y +CONFIG_HAVE_GPIO_SPI=y +CONFIG_HAVE_GPIO_I2C=y +CONFIG_HAVE_GPIO_HARD_PWM=y +CONFIG_HAVE_STRICT_TIMING=y +CONFIG_HAVE_CHIPID=y +CONFIG_HAVE_BOOTLOADER_REQUEST=y diff --git a/hosts/gnuslashprinter/resources/klipper/printer.cfg b/hosts/gnuslashprinter/resources/klipper/printer.cfg new file mode 100644 index 0000000..4baba56 --- /dev/null +++ b/hosts/gnuslashprinter/resources/klipper/printer.cfg @@ -0,0 +1,180 @@ +# This file contains pin mappings for the stock 2020 Creality Ender 3 +# V2. To use this config, during "make menuconfig" select the +# STM32F103 with a "28KiB bootloader" and serial (on USART1 PA10/PA9) +# communication. + +# If you prefer a direct serial connection, in "make menuconfig" +# select "Enable extra low-level configuration options" and select +# serial (on USART3 PB11/PB10), which is broken out on the 10 pin IDC +# cable used for the LCD module as follows: +# 3: Tx, 4: Rx, 9: GND, 10: VCC + +# Flash this firmware by copying "out/klipper.bin" to a SD card and +# turning on the printer with the card inserted. The firmware +# filename must end in ".bin" and must not match the last filename +# that was flashed. + +# See docs/Config_Reference.md for a description of parameters. + +[include mainsail.cfg] + +# Default V2 config +[stepper_x] +step_pin: PC2 +dir_pin: PB9 +enable_pin: !PC3 +microsteps: 16 +rotation_distance: 40 +endstop_pin: ^PA5 +position_endstop: -20 +position_min: -20 +position_max: 235 +homing_speed: 50 + +[stepper_y] +step_pin: PB8 +dir_pin: PB7 +enable_pin: !PC3 +microsteps: 16 +rotation_distance: 40 +endstop_pin: ^PA6 +position_endstop: -8 +position_min: -8 +position_max: 235 +homing_speed: 50 + +[stepper_z] +step_pin: PB6 +dir_pin: !PB5 +enable_pin: !PC3 +microsteps: 16 +rotation_distance: 8 +endstop_pin: probe:z_virtual_endstop +#position_endstop: 0.0 +position_min: -5 +position_max: 250 + +[extruder] +max_extrude_only_distance: 100.0 +step_pin: PB4 +dir_pin: PB3 +enable_pin: !PC3 +microsteps: 16 +rotation_distance: 34.406 +nozzle_diameter: 0.400 +filament_diameter: 1.750 +heater_pin: PA1 +sensor_type: EPCOS 100K B57560G104F +sensor_pin: PC5 +control: pid +# tuned for stock hardware with 200 degree Celsius target +pid_Kp: 21.527 +pid_Ki: 1.063 +pid_Kd: 108.982 +min_temp: 0 +max_temp: 250 + +[heater_bed] +heater_pin: PA2 +sensor_type: EPCOS 100K B57560G104F +sensor_pin: PC4 +control: pid +# tuned for stock hardware with 50 degree Celsius target +pid_Kp: 54.027 +pid_Ki: 0.770 +pid_Kd: 948.182 +min_temp: 0 +max_temp: 130 + +[fan] +pin: PA0 + +[mcu] +serial: /dev/gsp-control +restart_method: command + +[printer] +kinematics: cartesian +max_velocity: 300 +max_accel: 3000 +max_z_velocity: 5 +max_z_accel: 100 + +###################################################################### +# 128x64 Full Graphic Creality CR10 / ENDER 3 stockdisplay +###################################################################### + +# This section is used for a Creality "12864" display with a single +# ribbon cable between the display's EXP3 plug and the +# micro-controller board's EXP1 connector. + +[display] +lcd_type: st7920 +cs_pin: EXP1_7 +sclk_pin: EXP1_6 +sid_pin: EXP1_8 +encoder_pins: ^EXP1_5, ^EXP1_3 +click_pin: ^!EXP1_2 + +[output_pin beeper] +pin: EXP1_1 + +[board_pins] +aliases: + EXP1_1=PC6,EXP1_3=PB10,EXP1_5=PB14,EXP1_7=PB12,EXP1_9=<GND>, + EXP1_2=PB2,EXP1_4=PB11,EXP1_6=PB13,EXP1_8=PB15,EXP1_10=<5V>, + PROBE_IN=PB1,PROBE_OUT=PB0,FIL_RUNOUT=PA6 + +[display_status] + +###### +# Bed leveling + +[bltouch] +sensor_pin: ^PROBE_IN +control_pin: PROBE_OUT +x_offset: -40 +y_offset: -12 +#z_offset: 1.1 +probe_with_touch_mode: true +stow_on_each_sample: false + +[bed_mesh] +speed: 120 +mesh_min: 10, 10 +mesh_max: 195, 220 +probe_count: 5,5 +algorithm: bicubic + +[safe_z_home] +home_xy_position: 157.5, 129.5 +speed: 75 +z_hop: 10 +z_hop_speed: 5 +move_to_previous: true + + +#*# <---------------------- SAVE_CONFIG ----------------------> +#*# DO NOT EDIT THIS BLOCK OR BELOW. The contents are auto-generated. +#*# +#*# [bed_mesh default] +#*# version = 1 +#*# points = +#*# -0.017500, 0.025000, 0.050000, 0.122500, 0.155000 +#*# -0.045000, -0.040000, 0.037500, 0.102500, 0.145000 +#*# -0.007500, -0.032500, 0.005000, 0.092500, 0.132500 +#*# -0.060000, -0.045000, -0.007500, 0.087500, 0.127500 +#*# 0.075000, 0.042500, 0.015000, 0.105000, 0.175000 +#*# x_count = 5 +#*# y_count = 5 +#*# mesh_x_pps = 2 +#*# mesh_y_pps = 2 +#*# algo = bicubic +#*# tension = 0.2 +#*# min_x = 10.0 +#*# max_x = 195.0 +#*# min_y = 10.0 +#*# max_y = 220.0 +#*# +#*# [bltouch] +#*# z_offset = 1.342 diff --git a/hosts/libreX60/bios-flashing.nix b/hosts/libreX60/bios-flashing.nix new file mode 100644 index 0000000..6117813 --- /dev/null +++ b/hosts/libreX60/bios-flashing.nix @@ -0,0 +1,8 @@ +# https://libreboot.org/docs/install/#thinkpad-t60x60x60tabletx60s + +{ pkgs, ... }: { + environment.systemPackages = [ pkgs.flashprog ]; + + boot.kernelParams = [ "iomem=relaxed" ]; +} + diff --git a/hosts/libreX60/configuration.nix b/hosts/libreX60/configuration.nix new file mode 100644 index 0000000..bf4f388 --- /dev/null +++ b/hosts/libreX60/configuration.nix @@ -0,0 +1,47 @@ +{ config, lib, pkgs, ... }: { + imports = [ + ./powertop-auto-tune.nix + # Uncomment this module and reboot to enable bios flashing + #./bios-flashing.nix + ]; + + # Use grub + boot._loader = { + enable = true; + loader = "grub"; + mode = "bios"; + grub.biosDevice = "/dev/sda"; + }; + + # NOTE libre kernel removed, check back later + # Use libre kernel + #boot.kernelPackages = pkgs.linuxPackages-libre; + + # Enable common options + _archetypes = { + profiles = { + desktop = { + enable = true; + home.users.timmy.enable = true; + }; + btrfs.enable = true; + }; + }; + + # Enable user timmy + _users.timmy = { + enable = true; + autologin.enable = true; + wifi.enable = true; + }; + + # i915 Gpu requires intel driver + services.xserver.videoDrivers = [ "intel" ]; + + # Configure home + home-manager.users.timmy = { + imports = [ ./home.nix ]; + }; + + system.stateVersion = "24.11"; +} diff --git a/hosts/libreX60/hardware-configuration.nix b/hosts/libreX60/hardware-configuration.nix new file mode 100644 index 0000000..b0a7868 --- /dev/null +++ b/hosts/libreX60/hardware-configuration.nix @@ -0,0 +1,46 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "uhci_hcd" "ehci_pci" "ata_piix" "ahci" "firewire_ohci" "usb_storage" "sd_mod" "sdhci_pci" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/91572803-436d-4f43-b41f-dfba2103752e"; + fsType = "btrfs"; + options = [ "subvol=@" ]; + }; + + fileSystems."/home" = + { device = "/dev/disk/by-uuid/91572803-436d-4f43-b41f-dfba2103752e"; + fsType = "btrfs"; + options = [ "subvol=@home" ]; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/F618-D6C2"; + fsType = "vfat"; + options = [ "fmask=0022" "dmask=0022" ]; + }; + + swapDevices = [ ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`. + networking.useDHCP = lib.mkDefault true; + networking.interfaces.enp1s0.useDHCP = lib.mkDefault true; + networking.interfaces.wlp2s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/libreX60/home-timmy/configuration.nix b/hosts/libreX60/home-timmy/configuration.nix new file mode 100644 index 0000000..a5f064c --- /dev/null +++ b/hosts/libreX60/home-timmy/configuration.nix @@ -0,0 +1,8 @@ +{ + imports = [ ../home.nix ]; + + targets.genericLinux.enable = true; + + _archetypes.profiles.desktop.enable = true; + _users.timmy.home.enable = true; +} diff --git a/hosts/libreX60/home.nix b/hosts/libreX60/home.nix new file mode 100644 index 0000000..b537fc2 --- /dev/null +++ b/hosts/libreX60/home.nix @@ -0,0 +1,22 @@ +{ + gtk._mintTheme = { + dark = true; + color = "Red"; + icons.color = "Red"; + }; + fonts.fontconfig.defaultFonts.monospace = [ "TamzenForPowerline" ]; + gtk = { + font.name = "monospace"; + font.size = 8; + cursorTheme.size = 24; + }; + programs._st = { + enable = true; + font = { + name = "TamzenForPowerline"; + attrs = { + pixelsize = 14; + }; + }; + }; +} diff --git a/hosts/libreX60/powertop-auto-tune.nix b/hosts/libreX60/powertop-auto-tune.nix new file mode 100644 index 0000000..0eb9578 --- /dev/null +++ b/hosts/libreX60/powertop-auto-tune.nix @@ -0,0 +1,17 @@ +# https://en.wikibooks.org/wiki/Libreboot/ThinkPad_X60#Remove_High_Pitched_Whining_Noise +# TLDR; running `powertop --auto-tune` is supposed to kill the high pitched noises produced by the X60 + +{ pkgs, ... }: { + environment.systemPackages = [ pkgs.powertop ]; + + # Create systemd service + systemd.services.powertop-autotune = { + description = "Powertop Auto-Tune"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${pkgs.powertop}/bin/powertop --auto-tune"; + }; + }; +} diff --git a/hosts/office-precision/configuration.nix b/hosts/office-precision/configuration.nix new file mode 100644 index 0000000..31ba38e --- /dev/null +++ b/hosts/office-precision/configuration.nix @@ -0,0 +1,123 @@ +{ config, lib, pkgs, ... }: { + imports = [ + ./g610.nix + ./wg.nix + ]; + + # Setup bootloader + boot._loader.enable = true; + + # Enable common options + _archetypes = { + profiles = { + desktop = { + enable = true; + home.users.timmy.enable = true; + }; + gnome = { + home.users.timmy.enable = true; + home.users.guest.enable = true; + enable = true; + }; + btrfs.enable = true; + }; + collections = { + desktop = { + extraUtilities.enable = true; + chromium.enable = true; + graphics.enable = true; + office.enable = true; + }; + development = { + docker.enable = true; + web = { + node.enable = true; + }; + }; + virtualization.enable = true; + }; + }; + + # Add second ip address for flex-wg-router + networking = { + _interfaceLabels = { + enable = true; + interfaces.eth0 = "48:4d:7e:f8:96:47"; + }; + interfaces.eth0 = { + useDHCP = true; + + ipv4.addresses = [{ + address = "10.1.1.3"; + prefixLength = 24; + }]; + }; + }; + + # Enable user timmy + _users.timmy = { + enable = true; + nas = { + enable = true; + office.enable = true; + office.automount = true; + }; + }; + + users.users.guest = { + description = "Guest"; + isNormalUser = true; + }; + + # Disable suspend + systemd._suspend.disable = true; + + # Allow unfree for nvidia + nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [ + "nvidia-kernel-modules" + "nvidia-settings" + "nvidia-x11" + ]; + + # Use nvidia driver + services.xserver.videoDrivers = [ "nvidia" ]; + hardware.nvidia = { + modesetting.enable = true; # Required + powerManagement.enable = false; # Can cause bugs + powerManagement.finegrained = false; # Only works on turing and newer + nvidiaSettings = true; + open = false; # Not compatible w/ GTX-1030 + package = config.boot.kernelPackages.nvidiaPackages.legacy_580; + forceFullCompositionPipeline = true; # Enables vsync + }; + + # Configure home + home-manager.users.timmy = { + gtk._mintTheme = { + dark = true; + color = "Blue"; + icons.color = "Blue"; + }; + programs._seasonalwallpaper.wallpapers.download = true; + fonts.fontconfig = { + subpixelRendering = "rgb"; + hinting = "none"; + }; + gtk.gtk3.bookmarks = [ + "file:///home/timmy/docs/src/sites/admin Admin" + "file:///media/chexx/chexx cHEXx" + ]; + }; + home-manager.users.guest = { + gtk.gtk3.bookmarks = [ + "file:///media/chexx/chexx cHEXx" + ]; + fonts.fontconfig = { + subpixelRendering = "rgb"; + hinting = "none"; + }; + home.stateVersion = "26.05"; + }; + + system.stateVersion = "24.11"; +} diff --git a/hosts/office-precision/g610.nix b/hosts/office-precision/g610.nix new file mode 100644 index 0000000..8cceafc --- /dev/null +++ b/hosts/office-precision/g610.nix @@ -0,0 +1,9 @@ +{ pkgs, ... }: { + # Turn off backlight on my G610 keyboard + systemd.services.G610DisableBacklight = { + description = "G610 disable backlight"; + wantedBy = [ "multi-user.target" ]; + + serviceConfig.ExecStart = "${pkgs.g810-led}/bin/g610-led -a 00"; + }; +} diff --git a/hosts/office-precision/hardware-configuration.nix b/hosts/office-precision/hardware-configuration.nix new file mode 100644 index 0000000..22a8c24 --- /dev/null +++ b/hosts/office-precision/hardware-configuration.nix @@ -0,0 +1,48 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "ums_realtek" "usb_storage" "usbhid" "sd_mod" "sr_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/5749d84b-690b-43a2-b834-f94675003189"; + fsType = "btrfs"; + options = [ "subvol=@" ]; + }; + + boot.initrd.luks.devices."cryptroot".device = "/dev/disk/by-uuid/4a617e54-4800-4474-b1fd-3bca5f66e55a"; + + fileSystems."/home" = + { device = "/dev/disk/by-uuid/5749d84b-690b-43a2-b834-f94675003189"; + fsType = "btrfs"; + options = [ "subvol=@home" ]; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/5E93-7CE3"; + fsType = "vfat"; + options = [ "fmask=0022" "dmask=0022" ]; + }; + + swapDevices = [ ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.enp3s0.useDHCP = lib.mkDefault true; + # networking.interfaces.wlp2s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/office-precision/resources/secrets/wg.yaml b/hosts/office-precision/resources/secrets/wg.yaml new file mode 100644 index 0000000..f3b53aa --- /dev/null +++ b/hosts/office-precision/resources/secrets/wg.yaml @@ -0,0 +1,16 @@ +wg1: ENC[AES256_GCM,data:XWdnE2QvfvFlMKUW6BoUSsEXDmYj4aNfbxvA6pFeIZM7NEtIwC4/NsplPwFIZwF372/bwDGXGocuh5gd1p/eAlsyz2DrAS+8g1+4T40EPPmXPgh++vUTvcpPlt74Qxp2yAeEU4CU7UPLvlxSvNjh5PGS68Cw7KxSB7kiWFxRWtm5oVfb+U6cBaQE6Biie7wPmXNWOobGHTfFYDeNmH6w33nH4lCV2MC0eYty9ytwHeVS7gUNrk4oxIfd+1FmNzwNHtVZvRg4wRzcc2M9fD0LuyuY6QVS/qaJG4hNNEHZ6qa0VMTnOzQ4jFHtd5jnz2vb7ckE7UWcFPjXYObcykk0End7sHVN/bD+fUv56JKZOHvVYFgs6OwCzUPAufnv10+h,iv:LMEpZW3mwGuIpJoacBYL8M0ROVNeVMzeb7ncZtfxIDA=,tag:aNCziN9CVgm0IB8VvVorEA==,type:str] +sops: + age: + - recipient: age1w80rc0dnuu8nw99gw64c596qqetm78jdnsqajr0u7ephykekr39qfz8vnv + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBhdUJRS21FeFlseWJXU1dt + MnhQRnFvZWM0M1o4bUhBWW9KRDdnZ1pGZkYwCnhPYmFHZmdnRS9lb2xsTXZBcmIx + dHF5dmlrbjJyUk84QVBLTEFwMWdESGMKLS0tIHFyZGpSeTFoNEQyZThFc2RyQkhY + Q1ZvODVWSXE1STlkZ09tVXdVeU1WaVkKhKMfJclNgHXN7pww2w3AaKwcWiBo676g + RWSkV6C+5purA0CzTu1uC3CKz8UK8mVgPfamSZdZQU8+6bGMmseWoQ== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-03-31T19:32:51Z" + mac: ENC[AES256_GCM,data:zpEYjHqta6HuRHIKijbLmAND5mCaR14ZUdEeXq/zJ8g4DgWrAkaukhYdXhLH+SEUZt8d3tmj5Eq+6oz9qEjdWhBuPykxVBmBiqIhQBgACCMhSL5v3wY1rxL2ZiQ7szEuwh0GjXpkzPno0Z2+xZ6FzVsJdGnZwykru+JWQcUIfvk=,iv:yUiP/clvI/NnDrji9eMYiTqtO1xsTc7u86V/nlQSMIA=,tag:UyMz/BdYoGxXCJIb8tITcQ==,type:str] + unencrypted_suffix: _unencrypted + version: 3.12.1 diff --git a/hosts/office-precision/wg.nix b/hosts/office-precision/wg.nix new file mode 100644 index 0000000..97a5239 --- /dev/null +++ b/hosts/office-precision/wg.nix @@ -0,0 +1,8 @@ +{ config, pkgs, inputs, ... }: { + sops.secrets.wg1.sopsFile = ./resources/secrets/wg.yaml; + + networking.wg-quick.interfaces = { + wg1.configFile = config.sops.secrets.wg1.path; + wg1.autostart = false; + }; +} diff --git a/hosts/optiplex/configuration.nix b/hosts/optiplex/configuration.nix new file mode 100644 index 0000000..cef632e --- /dev/null +++ b/hosts/optiplex/configuration.nix @@ -0,0 +1,111 @@ +{ config, lib, pkgs, home-manager, ... }: { + # Setup bootloader + boot._loader.enable = true; + + # Enable common options + _archetypes = { + profiles = { + desktop = { + enable = true; + home.users.timmy.enable = true; + }; + btrfs.enable = true; + }; + collections = { + desktop = { + extraUtilities.enable = true; + cad.enable = true; + chromium.enable = true; + crypto.enable = true; + graphics.enable = true; + office.enable = true; + video.enable = true; + }; + development = { + android.enable = true; + c.enable = true; + docker.enable = true; + lua.enable = true; + web = { + hugo = { + enable = true; + openFirewall = true; + }; + node.enable = true; + }; + }; + virtualization.enable = true; + }; + }; + + # Enable user timmy + _users.timmy = { + enable = true; + autologin.enable = true; + nas = { + enable = true; + home.enable = true; + home.automount = true; + }; + }; + + # Disable suspend + systemd._suspend.disable = true; + + # Allow unfree for nvidia + others + nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [ + "blackmagic-desktop-video" + "decklink" + "nvidia-kernel-modules" + "nvidia-settings" + "nvidia-x11" + "spotify" + "steam" + "steam-original" + "steam-run" + "steam-unwrapped" + ]; + + # Install more software + environment.systemPackages = with pkgs; [ + prismlauncher + spotify + #vintagestory + ]; + + programs.steam.enable = true; + + # Use nvidia driver + services.xserver.videoDrivers = [ "nvidia" ]; + hardware.nvidia = { + modesetting.enable = true; # Required + powerManagement.enable = false; # Can cause bugs + powerManagement.finegrained = false; # Only works on turing and newer + nvidiaSettings = true; + open = false; # Not compatible w/ GTX-1050 + package = config.boot.kernelPackages.nvidiaPackages.legacy_580; + forceFullCompositionPipeline = true; # Enables vsync + }; + + # Enable decklink support for intensity pro + services._decklink.enable = true; + services._decklink.decklinkSupport.enable = true; + + # Configure home + home-manager.users.timmy = { + gtk._mintTheme = { + dark = true; + color = "Green"; + icons.color = "Green"; + }; + programs._seasonalwallpaper.wallpapers.download = true; + fonts.fontconfig = { + subpixelRendering = "rgb"; + hinting = "none"; + }; + # Enable open-bamboo-networking plugin for OrcaSlicer + programs.openBambooNetworking.enable = true; + }; + + system.stateVersion = "25.11"; +} diff --git a/hosts/optiplex/hardware-configuration.nix b/hosts/optiplex/hardware-configuration.nix new file mode 100644 index 0000000..9485a66 --- /dev/null +++ b/hosts/optiplex/hardware-configuration.nix @@ -0,0 +1,44 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "firewire_ohci" "usbhid" "usb_storage" "sd_mod" "sr_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/e4094dd8-d1fd-4aa1-8f95-82a9144a32be"; + fsType = "btrfs"; + options = [ "subvol=root" ]; + }; + + fileSystems."/home" = + { device = "/dev/disk/by-uuid/e4094dd8-d1fd-4aa1-8f95-82a9144a32be"; + fsType = "btrfs"; + options = [ "subvol=home" ]; + }; + + fileSystems."/nix" = + { device = "/dev/disk/by-uuid/e4094dd8-d1fd-4aa1-8f95-82a9144a32be"; + fsType = "btrfs"; + options = [ "subvol=nix" ]; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/9350-1411"; + fsType = "vfat"; + options = [ "fmask=0022" "dmask=0022" ]; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/piframe/configuration.nix b/hosts/piframe/configuration.nix new file mode 100644 index 0000000..b45a293 --- /dev/null +++ b/hosts/piframe/configuration.nix @@ -0,0 +1,77 @@ +{ config, lib, pkgs, ... }: { + _archetypes = { + # Use headless and pi profiles + profiles.headless = { + enable = true; + home.users.timmy.enable = true; + home.users.piframe.enable = true; + }; + profiles.pi = { + enable = true; + home.users.timmy.enable = true; + home.users.piframe.enable = true; + }; + collections = { + desktop.xserver.enable = true; + }; + }; + + # Install twm as basic window manager to boot into and immediately go fullscreen on immich-frame + services.xserver.windowManager.twm.enable = true; + + # Install immich-frame + environment.systemPackages = with pkgs; [ + immich-frame + ]; + + # Open 8080 for immich-frame + networking.firewall.allowedTCPPorts = [ 8080 ]; + + # Enable user timmy for ssh maintenance and wifi secrets + _users.timmy = { + enable = true; + wifi.enable = true; + }; + + # Enable piframe user + users.users.piframe = { + isNormalUser = true; + }; + + # Configure automatic login with getty + services.getty.autologinUser = "piframe"; + + # Configure piframe home + home-manager.users.piframe = { + services = { + _gammastep.enable = true; + # Manual location to avoid having to mess with geoclue + gammastep = { + provider = "manual"; + latitude = 41.881832; + longitude = -87.623177; + }; + }; + programs.bash = { + enable = true; + profileExtra = '' + # startx on tty1 immediately + [ -z $DISPLAY ] && [ `tty` = /dev/tty1 ] && startx + ''; + }; + home.file.".xinitrc".text = '' + #!/bin/sh + gammastep & + unclutter --start-hidden & + immich-frame --fullscreen & + exec twm + ''; + home.file.".twmrc".text = '' + *NoTitle # Hide title bar on all windows + *NoBorder # Hide borders on all windows + ''; + home.stateVersion = "25.11"; + }; + + system.stateVersion = "25.11"; +} diff --git a/hosts/piframe/hardware-configuration.nix b/hosts/piframe/hardware-configuration.nix new file mode 100644 index 0000000..ceb755a --- /dev/null +++ b/hosts/piframe/hardware-configuration.nix @@ -0,0 +1,24 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "usbhid" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/44444444-4444-4444-8888-888888888888"; + fsType = "ext4"; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux"; +} diff --git a/hosts/poweredge-pro/cgit.nix b/hosts/poweredge-pro/cgit.nix new file mode 100644 index 0000000..6465265 --- /dev/null +++ b/hosts/poweredge-pro/cgit.nix @@ -0,0 +1,105 @@ +let + publicUrl = "git.tjkeller.xyz"; + rootTitle = "git.TJKeller.xyz"; + rootDesc = "TJK's git repositories, served by cgit"; + scanPath = "/srv/git"; + sectionFromStartpath = 0; + maxRepoCount = 100; +in { + + containers.cgit = { + autoStart = true; + privateNetwork = true; + ephemeral = true; + hostBridge = "br-lan1"; + localMacAddress = "02:00:00:00:77:08"; + + bindMounts = { + ${scanPath} = { + hostPath = "/nix/persist/cgit/srv/git"; + isReadOnly = false; + }; + }; + + config = { pkgs, lib, config, ... }: { + # Networking + networking.interfaces.eth0.useDHCP = true; + networking.firewall.allowedTCPPorts = [ 80 22 9418 ]; # nginx, ssh, git-daemon + + # Enable ssh service + services.openssh.enable = true; + + # Create git user for ssh access + # git user and group are uid/gid 41 as defined by gitDaemon & nixpkgs/nixos/modules/misc/ids.nix + users.users.git = { + isSystemUser = true; + group = "git"; + home = scanPath; # Serve from git user's home to allow cloning git@cgit:repo + createHome = true; + homeMode = "750"; # Allow read permissions for group members + shell = pkgs.bash; + #openssh = { inherit authorizedKeys; }; + }; + users.groups.git.members = [ "nginx" ]; # Create the git group and add nginx user as a member so scanPath can be served by cgit + + # Enable cgit service + services.cgit.main = { + enable = true; + inherit scanPath; + nginx.virtualHost = "cgit"; + user = "git"; + group = "git"; + gitHttpBackend.checkExportOkFiles = true; # only serve repos containing git-daemon-export-ok + settings = { + # Based on joseluisq/alpine-cgit + root-title = rootTitle; + root-desc = rootDesc; + + source-filter = "${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py"; + about-filter = "${pkgs.cgit}/lib/cgit/filters/about-formatting.sh"; + + readme = [ ":README" ":README.html" ":README.md" ":README.txt" ]; + + # Cache + #cache-root=/var/cache/cgit + #cache-size=2000 + + enable-index-links = 1; + enable-index-owner = 0; + enable-remote-branches = 1; + enable-log-filecount = 1; + enable-log-linecount = 1; + enable-git-config = 1; + snapshots = "tar.xz zip"; + + robots = "noindex, nofollow"; + + virtual-root = "/"; + section-from-path = sectionFromStartpath; + max-repo-count = maxRepoCount; + + clone-prefix = "https://${publicUrl} git://${publicUrl}"; + max-stats = "month"; + + enable-http-clone = false; # optional: let git-http-backend handle all clones + strict-export = "git-daemon-export-ok"; + }; + }; + services.nginx.virtualHosts."cgit".default = true; + + # Enable git program + programs.git.enable = true; + + # Enable git daemon + services.gitDaemon = { + enable = true; + basePath = scanPath; + exportAll = false; # only export repos containing git-daemon-export-ok + listenAddress = "0.0.0.0"; + port = 9418; + }; + + system.stateVersion = "26.05"; + }; + }; +} diff --git a/hosts/poweredge-pro/configuration.nix b/hosts/poweredge-pro/configuration.nix new file mode 100644 index 0000000..f3ea1fb --- /dev/null +++ b/hosts/poweredge-pro/configuration.nix @@ -0,0 +1,62 @@ +{ config, lib, pkgs, ... }: { + imports = [ + ./cgit.nix + ./dns.nix + ./embedtube.nix + ./filebrowser.nix + ./fileshares.nix + ./key.nix + ./networking.nix + ./searxng.nix + ]; + + # Setup bootloader + boot._loader.enable = true; + + # Enable common options + _archetypes = { + profiles = { + headless = { + enable = true; + home.users.timmy.enable = true; + }; + zfs.enable = true; + #cuda.enable = true; + }; + collections = { + virtualization.enable = true; + development.docker.enable = true; + }; + }; + + # Import zfs pools + boot.zfs.extraPools = [ "VMDisk" "Storage" ]; + + # Workaround for docker + libvirt bug + systemd.services.bridge-nf-off = { + description = "Keep bridged VM traffic out of the IP netfilter path"; + after = [ "docker.service" ]; + partOf = [ "docker.service" ]; + wantedBy = [ "multi-user.target" "docker.service" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + script = '' + ${pkgs.kmod}/bin/modprobe br_netfilter 2>/dev/null || true + for k in iptables ip6tables arptables; do + echo 0 > /proc/sys/net/bridge/bridge-nf-call-$k 2>/dev/null || true + done + ''; + }; + + networking.firewall.checkReversePath = "loose"; + + # Enable user timmy + _users.timmy.enable = true; + + # Without this, "ZFS requires networking.hostId to be set" will be raised + networking.hostId = "2c7d6b03"; + + system.stateVersion = "26.05"; +} diff --git a/hosts/poweredge-pro/dhcp-hosts.nix b/hosts/poweredge-pro/dhcp-hosts.nix new file mode 100644 index 0000000..08e3ebd --- /dev/null +++ b/hosts/poweredge-pro/dhcp-hosts.nix @@ -0,0 +1,29 @@ +let + localResolution.localDomain = "pls.lan"; + dhcp = { + inherit staticLeases; + defaultGateway = "192.168.77.1"; + localhostIp = "192.168.77.2"; + rangeStart = "192.168.77.50"; + rangeEnd = "192.168.77.250"; + }; + staticLeases = { + devel = { macAddress = "00:a0:98:79:81:5a"; staticIp = "192.168.77.3"; }; + mailcow = { macAddress = "00:a0:98:79:20:a2"; staticIp = "192.168.77.7"; }; + tjkeller = { macAddress = "00:a0:98:62:cf:86"; staticIp = "192.168.77.8"; }; + cgit = { macAddress = "02:00:00:00:77:08"; staticIp = "192.168.77.88"; }; + filebrowser = { macAddress = "02:00:00:00:77:12"; staticIp = "192.168.77.12"; }; + searxng = { macAddress = "02:00:00:00:77:13"; staticIp = "192.168.77.13"; }; + embedtube = { macAddress = "02:00:00:00:77:14"; staticIp = "192.168.77.14"; }; + WIN-BGBGC27B1PF = { macAddress = "d8:9e:f3:1c:f0:1c"; staticIp = "192.168.77.30"; }; # DACS + DESKTOP-CQ4UIF9 = { macAddress = "08:bf:b8:3f:bd:48"; staticIp = "192.168.77.31"; }; # Kyle + WIN-6FVMAFOID4G = { macAddress = "00:a0:98:58:10:85"; staticIp = "192.168.77.33"; }; # QB + office-precision = { macAddress = "48:4d:7e:f8:96:47"; staticIp = "192.168.77.34"; }; + XRX9C934E85D0A3 = { macAddress = "9c:93:4e:85:d0:a3"; staticIp = "192.168.77.40"; }; # Xerox + nvr = { macAddress = "98:8b:0a:cf:4f:5e"; staticIp = "192.168.77.176"; }; + }; +in { + services._router.dnsDhcpConfig = { + inherit localResolution dhcp; + }; +} diff --git a/hosts/poweredge-pro/dns-overrides.nix b/hosts/poweredge-pro/dns-overrides.nix new file mode 100644 index 0000000..887eac2 --- /dev/null +++ b/hosts/poweredge-pro/dns-overrides.nix @@ -0,0 +1,12 @@ +let + dns.overrides.records = { + "docs.chexx.net" = { recordType = "A"; value = "192.168.77.3"; }; + "files.chexx.net" = { recordType = "A"; value = "192.168.77.3"; }; + "vault.chexx.net" = { recordType = "A"; value = "192.168.77.3"; }; + "wg-easy.chexx.net" = { recordType = "A"; value = "192.168.77.3"; }; + }; +in { + services._router.dnsDhcpConfig = { + inherit dns; + }; +} diff --git a/hosts/poweredge-pro/dns.nix b/hosts/poweredge-pro/dns.nix new file mode 100644 index 0000000..511f9e2 --- /dev/null +++ b/hosts/poweredge-pro/dns.nix @@ -0,0 +1,57 @@ +{ pkgs, config, ... }: { + networking.nameservers = [ "192.168.77.2" ]; + + # Router container + containers.dnsdhcp = { + autoStart = true; + ephemeral = true; + privateNetwork = true; + hostBridge = "br-lan1"; + #hostBridge = "br-lan1"; + #localMacAddress = "02:00:00:00:77:01"; + + config = { lib, config, ... }: { + imports = [ + ../../nixos/services/router + #./router-hosts.nix # Contains dhcp config + static leases + overrides + ./dhcp-hosts.nix + ./dns-overrides.nix + ]; + + # Network + networking = { + enableIPv6 = false; + defaultGateway = "192.168.77.1"; + interfaces.eth0.ipv4.addresses = [{ + address = "192.168.77.2"; + prefixLength = 24; + }]; + firewall = { + # DNS+DHCP ports + allowedTCPPorts = [ 53 ]; + allowedUDPPorts = [ 53 67 ]; + }; + }; + + # Setup dns server + services._router = { + dnsDhcpConfig = { + enable = true; + #localResolution = { + # localDomain = "pls.lan"; + # localDnsAddress = "192.168.77.1@53"; + # localReverseZone = "77.168.192.in-addr.arpa"; + #}; + }; + routing.enable = false; + }; + + services.unbound._blocklists = { + enable = true; + hageziBlocklists = [ "pro" "nsfw" ]; + }; + + system.stateVersion = "26.05"; + }; + }; +} diff --git a/hosts/poweredge-pro/embedtube.nix b/hosts/poweredge-pro/embedtube.nix new file mode 100644 index 0000000..12d375e --- /dev/null +++ b/hosts/poweredge-pro/embedtube.nix @@ -0,0 +1,43 @@ +{ config, pkgs, inputs, ... }: { + # Secrets + sops.secrets.embedtube-api-key = { sopsFile = ./resources/secrets/embedtube.yaml; key = "api-key"; }; + + # Container + containers.embedtube = { + autoStart = true; + privateNetwork = true; + ephemeral = true; + hostBridge = "br-lan1"; + localMacAddress = "02:00:00:00:77:14"; + + bindMounts."/run/secrets/api-key" = { + hostPath = config.sops.secrets.embedtube-api-key.path; + isReadOnly = true; + }; + + config = { lib, pkg, config, ... }: { + # Import EmbedTube flake input + imports = [ inputs.embedtube.nixosModules.default ]; + + # Network + networking.interfaces.eth0.useDHCP = true; + networking.firewall.allowedTCPPorts = [ 80 ]; # Caddy (private + public) + + # EmbedTube + services.embedtube = { + enable = true; + apiKeyFile = "/run/secrets/api-key"; + }; + + # Reverse proxy + services.caddy = { + enable = true; + virtualHosts.":80".extraConfig = '' + reverse_proxy localhost:8080 + ''; + }; + + system.stateVersion = "26.05"; + }; + }; +} diff --git a/hosts/poweredge-pro/filebrowser.nix b/hosts/poweredge-pro/filebrowser.nix new file mode 100644 index 0000000..4c63af3 --- /dev/null +++ b/hosts/poweredge-pro/filebrowser.nix @@ -0,0 +1,55 @@ +{ pkgs, ... }: { + containers.filebrowser = { + autoStart = true; + privateNetwork = true; + hostBridge = "br-lan1"; + localMacAddress = "02:00:00:00:77:12"; + + # Host path + bindMounts = { + "/var/lib/filebrowser/data/chexx" = { + hostPath = "/VMDisk/shares/chexx"; + isReadOnly = true; + }; + "/var/lib/filebrowser/data/Scans" = { + hostPath = "/VMDisk/shares/scans/"; + isReadOnly = true; + }; + }; + + config = { lib, pkg, config, ... }: let + publicPort = 9000; + in { + # Network + networking.interfaces.eth0.useDHCP = true; + networking.firewall.allowedTCPPorts = [ 80 publicPort ]; # Caddy (private + public) + + # Filebrowser + services.filebrowser = { + enable = true; + #package = pkgs.filebrowser-quantum; # Not supported yet + }; + + # Reverse proxy + services.caddy = { + enable = true; + # Private + virtualHosts.":80".extraConfig = '' + reverse_proxy localhost:8080 + ''; + # Public (not sure why toString is needed but ok) + virtualHosts.":${toString publicPort}".extraConfig = '' + @shared { + path /share/* + path /static/* + path /api/public/* + } + + reverse_proxy @shared localhost:8080 + ''; + }; + + system.stateVersion = "26.05"; + }; + }; +} diff --git a/hosts/poweredge-pro/fileshares.nix b/hosts/poweredge-pro/fileshares.nix new file mode 100644 index 0000000..65ce84d --- /dev/null +++ b/hosts/poweredge-pro/fileshares.nix @@ -0,0 +1,92 @@ +{ pkgs, config, ... }: { + # Configure services + services._fileShares = { + enable = true; + smb.openFirewall = true; + smb.enableUnixPasswordSync = true; + nfs.openFirewall = true; + }; + + # Configure share groups + users.groups.chexx.gid = 3000; + users.groups.scans.gid = 3003; + + # Shares + services._fileShares.shares = { + chexx = { + path = "/VMDisk/shares/chexx"; + smb = { + enable = true; + allowGroup = "chexx"; + defaultFileMask = "0664"; + defaultDirectoryMask = "0775"; + }; + nfs.enable = true; + }; + scans = { + path = "/VMDisk/shares/scans"; + smb = { + enable = true; + allowGroup = "scans"; + defaultFileMask = "0664"; + defaultDirectoryMask = "0775"; + }; + nfs.enable = true; + }; + dacs = { + path = "/Storage/Users/Dacs"; + smb = { + enable = true; + allowUser = "dacs"; + }; + }; + tk = { + path = "/home/timmy/docs/shared"; + nfs.enable = true; + }; + }; + + # Configure password secrets for users + sops.secrets.smb-initial-pass = { sopsFile = ./resources/secrets/initial-pass.yaml; key = "smb-initial-pass"; }; + sops.secrets.user-hashed-pass = { sopsFile = ./resources/secrets/initial-pass.yaml; key = "user-hashed-pass"; }; + + # Configure users + users.users.timmy.extraGroups = [ "chexx" "scans" ]; + users.users.dacs = { + enable = true; + isNormalUser = true; + extraGroups = [ "chexx" "scans" ]; + hashedPasswordFile = config.sops.secrets.user-hashed-pass.path; + uid = 3001; + }; + users.users.kyle = { + enable = true; + isNormalUser = true; + extraGroups = [ "chexx" "scans" ]; + hashedPasswordFile = config.sops.secrets.user-hashed-pass.path; + uid = 3002; + }; + users.users.scanner = { + enable = true; + isSystemUser = true; + group = "scans"; + hashedPasswordFile = config.sops.secrets.user-hashed-pass.path; + uid = 3003; + }; + users.users.zfsbackup = { + isSystemUser = true; + group = "zfsbackup"; + shell = pkgs.bashInteractive; + hashedPassword = "!"; # Disallow login through standard means + openssh.authorizedKeys.keyFiles = [ ./resources/openssh/zfsbackup/truenas-10.0.0.9-rsa.pub ]; + }; + users.groups.zfsbackup = {}; + + # Configure user enrollment for samba + services._fileShares.smb.enrollUsers = { + timmy = { enable = true; passwordFile = config.sops.secrets.smb-initial-pass.path; }; + dacs = { enable = true; passwordFile = config.sops.secrets.smb-initial-pass.path; }; + kyle = { enable = true; passwordFile = config.sops.secrets.smb-initial-pass.path; }; + scanner = { enable = true; passwordFile = config.sops.secrets.smb-initial-pass.path; }; + }; +} diff --git a/hosts/poweredge-pro/hardware-configuration.nix b/hosts/poweredge-pro/hardware-configuration.nix new file mode 100644 index 0000000..e41dec5 --- /dev/null +++ b/hosts/poweredge-pro/hardware-configuration.nix @@ -0,0 +1,50 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "ahci" "ehci_pci" "megaraid_sas" "usb_storage" "usbhid" "sd_mod" "sr_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "nixos/root"; + fsType = "zfs"; + options = [ "zfsutil" ]; + }; + + fileSystems."/nix" = + { device = "nixos/nix"; + fsType = "zfs"; + options = [ "zfsutil" ]; + }; + + fileSystems."/var" = + { device = "nixos/var"; + fsType = "zfs"; + options = [ "zfsutil" ]; + }; + + fileSystems."/home" = + { device = "nixos/home"; + fsType = "zfs"; + options = [ "zfsutil" ]; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/2096-A1E5"; + fsType = "vfat"; + options = [ "fmask=0022" "dmask=0022" ]; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/poweredge-pro/key.nix b/hosts/poweredge-pro/key.nix new file mode 100644 index 0000000..40cd529 --- /dev/null +++ b/hosts/poweredge-pro/key.nix @@ -0,0 +1,23 @@ +{ pkgs, ... }: { + # Nixos root + boot.initrd.systemd.enable = true; # Default since 26.05 + boot.initrd.supportedFilesystems.ext4 = true; + + boot.initrd.systemd.mounts = [{ + what = "/dev/disk/by-label/key"; + where = "/key"; + type = "ext4"; + options = "ro"; + unitConfig.DefaultDependencies = "no"; + before = [ "zfs-import-nixos.service" ]; + requiredBy = [ "zfs-import-nixos.service" ]; + }]; + + # Storage + sops.secrets."zfs-key-storage" = { + sopsFile = ./resources/secrets/zfs-key.yaml; + key = "storage"; + path = "/etc/zfs/keys/storage.key"; + mode = "0400"; + }; +} diff --git a/hosts/poweredge-pro/networking.nix b/hosts/poweredge-pro/networking.nix new file mode 100644 index 0000000..1debc03 --- /dev/null +++ b/hosts/poweredge-pro/networking.nix @@ -0,0 +1,32 @@ +{ + networking = { + useDHCP = false; + # Label lan and wan interfaces + _interfaceLabels = { + enable = true; + interfaces.mgmt0 = "44:a8:42:35:b7:09"; + interfaces.lan0 = "44:a8:42:35:b7:0a"; + interfaces.wan0 = "44:a8:42:35:b7:0b"; + interfaces.lan1 = "44:a8:42:35:b7:0c"; + }; + # Create bridges + bridges = { + br-lan0.interfaces = [ "lan0" ]; + br-wan0.interfaces = [ "wan0" ]; + br-lan1.interfaces = [ "lan1" ]; + }; + interfaces.br-lan0.useDHCP = false; + interfaces.br-wan0.useDHCP = false; + interfaces.br-lan1.useDHCP = false; + # Setup mgmt0 + interfaces.mgmt0.ipv4.addresses = [{ + address = "192.168.77.11"; + prefixLength = 24; + }]; + defaultGateway = "192.168.77.1"; + nameservers = [ "192.168.77.1" ]; + # Firewall for vms + firewall.interfaces.mgmt0.allowedTCPPorts = [ 5900 5901 ]; + + }; +} diff --git a/hosts/poweredge-pro/resources/openssh/zfsbackup/truenas-10.0.0.9-rsa.pub b/hosts/poweredge-pro/resources/openssh/zfsbackup/truenas-10.0.0.9-rsa.pub new file mode 100644 index 0000000..d1191b9 --- /dev/null +++ b/hosts/poweredge-pro/resources/openssh/zfsbackup/truenas-10.0.0.9-rsa.pub @@ -0,0 +1 @@ +no-agent-forwarding,no-port-forwarding,no-X11-forwarding,no-pty ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQN5nXovLaKk4IaEl9X6hhcKHYtghpfzeqbKAk73EG8rQzfMoOtMU6tzYccF2VQy2LNHn0YcZRx2E/u30L4GK7GcKhPg8GZo3wBacRfD3xSsNw1vqGRmdyDwf0s+HvBdgg+SxoURzyk7MWb6f4YuH6gVP71Sq1ybFs4JwDsDxPVDJ5SRdZj0vmdwelMvGv60cQhTexHyBeYGYdJEq2Bhew88JHdgilP16fMescnbIL0AiisDlvgi0oReZ8046i3+NhFQwIVdYwlNDQ1ANdpsjmm5vrKhg1C2kQXQkRgfoRNWalbyPn1LTMQIcLelj+Y9dRAvymwjRmteekplTJlkoP3kR9kPtLbcWwoVWmkuj+PBfRWyRlvBF7bGiIjagWcn1k3M4LgO7gfrSBHuW7Rd2+2zXvRrsTN1MzOSKoYf6TvOfxDxlAasZVA6kVcnVQvHx+9xbqcJ4JZdA8k6c/cil1u0BT3QxMZ2JHELdHAo026das82Q7YdR4bAR4Ph5GUk8= root@truenas diff --git a/hosts/poweredge-pro/resources/secrets/embedtube.yaml b/hosts/poweredge-pro/resources/secrets/embedtube.yaml new file mode 100644 index 0000000..f75d6d5 --- /dev/null +++ b/hosts/poweredge-pro/resources/secrets/embedtube.yaml @@ -0,0 +1,16 @@ +api-key: ENC[AES256_GCM,data:F0/EBnAhFeJBMAG/D6gRNPwdsLy3HubjEp/Tw07s3dah+ZhWCC93,iv:nSVrGI11nx0vCtSWGbU2+vtEdQwOBihJWI8oM9sbT0o=,tag:GbsNXalVWarwmENpsFIfkA==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvTXc3S2M5dWVDbnZGRmhM + Qmo0SzM4K2tndldCYnlvZkhmYmgrdCtVSW00Cm1TVnAxdEV1V2lRN1Q1ZU5WSFRy + OXN1ZjVJMGkyL2JISlNnYURuNDZiblUKLS0tIEo4NXpHZ1BFZ29lZDhnS3RUcVh6 + eFplVVBBV011SUMwbTdzcHdDODJoQXMKjn9LtU7lK65pHW+Rcbbh8eXZgKnTe3TK + ZC/dtyBHc/esp93GiYAqMYRH9+6pfAZNNpko6PFqsVsN6eCzPrh05g== + -----END AGE ENCRYPTED FILE----- + recipient: age1q8l3g3t6qjhsmz0gju0n535pz45d2c9crla8jcd5ftjlqe4fs3eqfqay0k + lastmodified: "2026-09-22T22:34:40Z" + mac: ENC[AES256_GCM,data:7AsRul6ze58dzK00i1eA9fO4alCSXANQNaVb7mkVfcRQLr+llv/6cU1E67LnEDh4r5TMZt2L2zz4duP2uVHQP6lRG5dNUU7b3c7O/DJbLKvT7jDPxJdfPz2XZOFz1+NHCPNdhPkmuPWlIbffiw+yVA9kuS8iJJ8DS2rjTDR2/tE=,iv:rKemvVhEBluw2ZfxwlNVtQW49oLbVKdEHhrQ61e5t0M=,tag:rgCj6PPsZLkpqecPgVJ6Fw==,type:str] + unencrypted_suffix: _unencrypted + version: 3.13.3 diff --git a/hosts/poweredge-pro/resources/secrets/initial-pass.yaml b/hosts/poweredge-pro/resources/secrets/initial-pass.yaml new file mode 100644 index 0000000..a25a87d --- /dev/null +++ b/hosts/poweredge-pro/resources/secrets/initial-pass.yaml @@ -0,0 +1,17 @@ +smb-initial-pass: ENC[AES256_GCM,data:+KANYy3NLfBQMA==,iv:sqd5D4wBldOZ5FSjzDLi75JpMMGD7HX//UZr6R9rCjU=,tag:ElnYlqFTjMLdR//7jm405w==,type:str] +user-hashed-pass: ENC[AES256_GCM,data:YG51p0bCuOt1PslbeX3H9unN6FovZTL9GIZeyf4aPZXlhCdrhH9OOFTMOWRskQqyWShwATO5HY/XYzP5mVk+ljvMumK5OEsBYg==,iv:6Z6DKB0cBHt+rbW6t0nrj3uFhIdJzcMZX3Qt1FZpvdw=,tag:+I2Kui+oa9wv91CpLOo1yw==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvUzN0VDA3cGJteHJsTUp1 + U1Z6aFA1R2hMcnIxTE8rWkZEWTVWbmtlU0FFCldIdU5CYU5FS3p0QXYyczd6TmhM + alRkZUJJeVduWEtON1ZBWWk2ajgxUTAKLS0tIFM2V3hZNE95cUJ5bkF2WERZVEtQ + VWwvN3dYSzRreTY1dUF5ejY2N1BCWlkKX1OT8zm4wu5q0uLE4htS2HJzndOHLBHe + WK1XBlFQOa54oB29ehcE/1j0LtXUenAbqTTAHTsmTkokxyVemaZAjA== + -----END AGE ENCRYPTED FILE----- + recipient: age1q8l3g3t6qjhsmz0gju0n535pz45d2c9crla8jcd5ftjlqe4fs3eqfqay0k + lastmodified: "2026-08-24T23:01:03Z" + mac: ENC[AES256_GCM,data:ODXwdFn0d8z9hcdCKoXeWCpJLyWF6QnVfkGDCE1pO23K3YHTqn7qGWYiuichJLMlfUNBdm7HuXvkuSoteua6qAiL9Us+r3vjpW8hIVZDrcja+EVHzweMgUEb66nrLwtIbDIx6nr8Bec2KcQ6dYJiJ7we3jyrXGFaJQ4wtRpRvmU=,iv:TOZkTVV5Nq/5IsRuv0Gr7yrB51busEAUkKSgQO83u00=,tag:Kk/01O6iqgiaHRFcwfhdtA==,type:str] + unencrypted_suffix: _unencrypted + version: 3.13.3 diff --git a/hosts/poweredge-pro/resources/secrets/zfs-key.yaml b/hosts/poweredge-pro/resources/secrets/zfs-key.yaml new file mode 100644 index 0000000..20496b5 --- /dev/null +++ b/hosts/poweredge-pro/resources/secrets/zfs-key.yaml @@ -0,0 +1,16 @@ +storage: ENC[AES256_GCM,data:AnjXAapH0ClmXjKQCBoVtIijDIxSBVhjHXEMa7Y9RgXWQ7bfRtx3oDZIYgwLQMohr3NUu8Bj9PZ//4g6SKKCgA==,iv:OEFfEceYShoiHUoY+Q0jpPYEA6vWlLZMXVHd52gp0GI=,tag:GDnrorkbDUOLmcZeiuc9YA==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByL21EZUdwZkR5K3JVVWc4 + Sk5XRGFpSWtsWTNSVjN6cERKcDBibnZ1Z3pjCjU1S1JNcFFSakJHMnhwQ3BhcGI5 + Tzg4R2hneHNYNmF0c1EvYkVDY3RYWkUKLS0tIHlaWHRPeXhXK05MMnJ5bzlLWUds + eGZkTlFYT2JtSVRnWm4wcXJ2RFcrd1UKFZNppEmn0TvF5/w32rZLXwaR/WfZyrZ+ + d6IF1lNA1407phjt+SWsIcRpTQwcY7vdAv4Ozk8tW7LqM+T4xMVLkQ== + -----END AGE ENCRYPTED FILE----- + recipient: age1q8l3g3t6qjhsmz0gju0n535pz45d2c9crla8jcd5ftjlqe4fs3eqfqay0k + lastmodified: "2026-08-23T03:15:49Z" + mac: ENC[AES256_GCM,data:2/UdlNsj3+oihVfgalj8DfFN1XWyY14x0/H3ydDXT6rJgjuFMPwjpNCFuzRP4mT99a46HGl74INfuKXNyFPXMW+eKG81vVHZgDsoipQwI8yUveyCfGezdIz4Rab5fTzXXrvXaXhIdovqDuCUj2FCaqosFvCPC0AtDVqoHuHlU8k=,iv:aBez26rU/252xYkpBVqv8ZrO2vhQm0RJJo/H7puGHQ4=,tag:NRSyINDS4wNF8g2hVRk6Xw==,type:str] + unencrypted_suffix: _unencrypted + version: 3.13.3 diff --git a/hosts/poweredge-pro/searxng.nix b/hosts/poweredge-pro/searxng.nix new file mode 100644 index 0000000..c05af03 --- /dev/null +++ b/hosts/poweredge-pro/searxng.nix @@ -0,0 +1,179 @@ +{ pkgs, ... }: { + containers.searxng = { + autoStart = true; + privateNetwork = true; + hostBridge = "br-lan0"; + localMacAddress = "02:00:00:00:77:13"; + + config = { lib, config, ... }: let + environmentFile = "/run/searx/searxng.env"; + generateEnvironmentFile = '' + umask 077 + echo "SEARXNG_SECRET=$(head -c 56 /dev/urandom | base64)" > ${environmentFile} + ls /run/searx + ''; + in { + # Network + networking.interfaces.eth0.useDHCP = true; + networking.firewall.allowedTCPPorts = [ 80 ]; # Nginx + + # Generate secret key + systemd.services.searx-environment-file = { + description = "Generate environment file with secret key for searx"; + wantedBy = [ "searx-init.service" ]; + partOf = [ "searx-init.service" ]; + before = [ "searx-init.service" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + User = "searx"; + RuntimeDirectory = "searx"; + RuntimeDirectoryMode = "750"; + ConditionPathExists = "!${environmentFile}"; + }; + script = generateEnvironmentFile; + }; + + # Configure searxng + services.searx = { + enable = true; + redisCreateLocally = true; + #package = pkgs.unstable.searxng; + package = pkgs.searxng; + inherit environmentFile; # Provides secret key + + # Rate limiting + limiterSettings = { + real_ip = { + x_for = 1; + ipv4_prefix = 32; + ipv6_prefix = 56; + }; + + botdetection = { + ip_limit = { + filter_link_local = true; + link_token = true; + }; + }; + }; + + # UWSGI configuration + configureUwsgi = true; + + uwsgiConfig = { + socket = "/run/searx/searx.sock"; + http = "127.0.0.1:8888"; + chmod-socket = "660"; + }; + + settings = { + general = { + instance_name = "TJK Search"; + donation_url = "https://tjkeller.xyz"; + enable_metrics = false; + }; + + ui = { + static_use_hash = true; + default_locale = "en"; + query_in_title = true; + infinite_scroll = false; + center_alignment = true; + hotkeys = "vim"; + }; + + server = { + port = 8888; + bind_address = "127.0.0.1"; + method = "GET"; + secret_key = "@SEARX_SECRET_KEY@"; # Reference external secret key + limiter = true; + }; + + # Search engine settings + search = { + safe_search = 2; # Strict + autocomplete = ""; + default_lang = "en-US"; + }; + + preferences.lock = [ "safesearch" ]; # Lock safe_search at strict + + # https://docs.searxng.org/admin/plugins.html + enabled_plugins = [ + "Tor check plugin" + "Tracker URL remover" + "Basic Calculator" + "Unit converter plugin" + "Hash plugin" + "Self Information" + "Open Access DOI rewrite" + "Hostnames plugin" + ]; + + hostnames.replace = { + "(.*\.)?youtube\.com$" = "yt.tjkeller.xyz"; + "(.*\.)?youtu\.be$" = "yt.tjkeller.xyz"; + #"(.*\.)?reddit\.com$" = "old.reddit.com"; + }; + + # Enable / disabled search engines from default list + engines = lib.mapAttrsToList (name: value: { inherit name; disabled = !value; }) { + # General + "mojeek" = true; + "qwant" = true; + "bing" = true; + + # Images + "artic" = false; + "deviantart" = false; + "flickr" = false; + "library of congress" = false; + "openverse" = false; + "pinterest" = false; + "public domain image archive" = false; + "unsplash" = false; + "wallhaven" = false; + "wikicommons.images" = false; + + # Videos + "bitchute" = true; + "dailymotion" = false; + "piped" = false; + "rumble" = true; + "sepiasearch" = false; + "vimeo" = false; + "wikicommons.videos" = false; + + # Music + "piped.music" = false; + + # Files + "1337x" = true; + "annas archive" = true; + "library genesis" = true; + + # Apps + "fdroid" = true; + }; + }; + }; + + # Nginx configuration + users.users.nginx.extraGroups = [ "searx" ]; # Allow access to uwsgi socket with 660 permissions + services.nginx = { + enable = true; + virtualHosts."searx" = { + default = true; + serverName = "_"; # Catchall + locations."/".extraConfig = '' + uwsgi_pass unix:${config.services.searx.uwsgiConfig.socket}; + ''; + }; + }; + + system.stateVersion = "26.05"; + }; + }; +} diff --git a/hosts/poweredge/bitcoind.nix b/hosts/poweredge/bitcoind.nix new file mode 100644 index 0000000..17a91f2 --- /dev/null +++ b/hosts/poweredge/bitcoind.nix @@ -0,0 +1,42 @@ +{ + containers.bitcoind = { + autoStart = true; + ephemeral = true; + privateNetwork = true; + hostBridge = "br-lan0"; + localMacAddress = "02:00:00:00:00:04"; + + # Host path + bindMounts = { + "/var/lib/bitcoind-main" = { + hostPath = "/media/ingens/bitcoin"; + isReadOnly = false; + }; + }; + + config = { lib, pkgs, config, ... }: let + p2pPort = 8333; + rpcPort = 8332; + in { + # Network + networking.enableIPv6 = false; + networking.interfaces.eth0.useDHCP = true; + networking.firewall.allowedTCPPorts = [ p2pPort rpcPort ]; + + # Bitcoin + services.bitcoind."main" = { + enable = true; + port = p2pPort; + rpc.port = rpcPort; + rpc.users.timmy.passwordHMAC = "7557196eec6e3e062a57b0720abff7cf$617211e94b964f548cfbb5c23590f690c2940e424fffe72485276493f1cb0b29"; + extraConfig = '' + rpcallowip=192.168.1.0/24 + rpcbind=0.0.0.0 + upnp=0 + ''; + }; + + system.stateVersion = "25.11"; + }; + }; +} diff --git a/hosts/poweredge/configuration.nix b/hosts/poweredge/configuration.nix new file mode 100644 index 0000000..ba93a37 --- /dev/null +++ b/hosts/poweredge/configuration.nix @@ -0,0 +1,48 @@ +{ config, lib, pkgs, ... }: { + imports = [ + ./bitcoind.nix + ./ddns-updater.nix + ./filebrowser.nix + ./fileshares.nix + ./gitea.nix + ./immich.nix + ./jellyfin.nix + ./metrics.nix + ./navidrome.nix + ./networking.nix + ./nvidia.nix + ./transmission.nix + ./vpn-router.nix + ./slskd.nix + #./notification-mailer.nix # TODO move some of this stuff to archetype + ]; + + # Setup bootloader + boot._loader.enable = true; + + # Enable common options + _archetypes = { + profiles = { + headless = { + enable = true; + home.users.timmy.enable = true; + }; + zfs.enable = true; + cuda.enable = true; + }; + collections = { + music.beets.enable = true; + }; + }; + + # Import zfs pools + boot.zfs.extraPools = [ "ingens" "memoria" ]; + + # Enable user timmy + _users.timmy.enable = true; + + # Without this, "ZFS requires networking.hostId to be set" will be raised + networking.hostId = "4d9e002f"; + + system.stateVersion = "25.11"; +} diff --git a/hosts/poweredge/ddns-updater.nix b/hosts/poweredge/ddns-updater.nix new file mode 100644 index 0000000..319e3c4 --- /dev/null +++ b/hosts/poweredge/ddns-updater.nix @@ -0,0 +1,22 @@ +{ config, lib, ... }: let + credential = "config"; +in { + # Config for ddns-updater, owned by the ddns-updater systemd service user + sops.secrets.ddns-updater-config.sopsFile = ./resources/secrets/ddns-updater-config.yaml; + + # Load secret as a credential in systemd service + systemd.services.ddns-updater.serviceConfig = { + LoadCredential = [ + "${credential}:${config.sops.secrets.ddns-updater-config.path}" + ]; + }; + + # Enable ddns updater + services.ddns-updater = { + enable = true; + environment = { + SERVER_ENABLED="no"; + CONFIG_FILEPATH = "%d/${credential}"; + }; + }; +} diff --git a/hosts/poweredge/filebrowser.nix b/hosts/poweredge/filebrowser.nix new file mode 100644 index 0000000..681a6a6 --- /dev/null +++ b/hosts/poweredge/filebrowser.nix @@ -0,0 +1,36 @@ +{ + containers.filebrowser = { + autoStart = true; + privateNetwork = true; + hostBridge = "br-lan0"; + localMacAddress = "02:00:00:00:00:05"; + + # Host path + bindMounts = { + "/var/lib/filebrowser/data" = { + hostPath = "/media"; + isReadOnly = true; + }; + }; + + config = { lib, pkg, config, ... }: { + # Network + networking.interfaces.eth0.useDHCP = true; + networking.firewall.allowedTCPPorts = [ 80 8080 ]; # Caddy + filebrowser + + # Filebrowser + services.filebrowser.enable = true; + services.filebrowser.settings.address = "0.0.0.0"; + + # Reverse proxy + services.caddy = { + enable = true; + virtualHosts.":80".extraConfig = '' + reverse_proxy localhost:8080 + ''; + }; + + system.stateVersion = "26.05"; + }; + }; +} diff --git a/hosts/poweredge/fileshares.nix b/hosts/poweredge/fileshares.nix new file mode 100644 index 0000000..faf0f83 --- /dev/null +++ b/hosts/poweredge/fileshares.nix @@ -0,0 +1,68 @@ +{ + # Configure services + services._fileShares = { + enable = true; + smb.openFirewall = true; + nfs.openFirewall = true; + }; + # Shares + services._fileShares.shares = { + WinBackups = { + path = "/media/ingens/backups/windows"; + smb.enable = true; + }; + pictures = { + path = "/media/ingens/pictures"; + nfs.enable = true; + }; + tapes = { + path = "/media/ingens/tapes"; + nfs.enable = true; + smb.enable = true; + }; + backups = { + path = "/media/ingens/backups"; + nfs.enable = true; + }; + games = { + path = "/media/ingens/games"; + nfs.enable = true; + }; + documents = { + path = "/media/ingens/documents"; + nfs.enable = true; + smb.enable = true; + }; + }; + + # retro shares + containers.retronas = { + autoStart = true; + bindMounts = { + "/media/ingens/games" = { + hostPath = "/media/ingens/games"; + isReadOnly = false; + }; + }; + + config = { config, pkgs, ... }: { + imports = [ ../../nixos/services/fileshares.nix ]; # Get fileshares module + + services._fileShares = { + enable = true; + smb = { + port = 1445; + enableLegacyNT1 = true; # purpose of this container + openFirewall = true; + }; + }; + services._fileShares.shares = { + PS2 = { + path = "/media/ingens/games/ps2"; + smb.enable = true; + smb.allowGuests = true; + }; + }; + }; + }; +} diff --git a/hosts/poweredge/gitea.nix b/hosts/poweredge/gitea.nix new file mode 100644 index 0000000..4c800df --- /dev/null +++ b/hosts/poweredge/gitea.nix @@ -0,0 +1,41 @@ +{ + containers.gitea = { + autoStart = true; + privateNetwork = true; + hostBridge = "br-lan0"; + localMacAddress = "02:00:00:00:00:03"; + + # TODO make a mountpoint for git repositories + + config = { lib, pkgs, config, ... }: { + # Network + networking.interfaces.eth0.useDHCP = true; + networking.firewall.allowedTCPPorts = [ 80 22 ]; # Caddy + ssh + + # Gitea + services.gitea = { + enable = true; + #user = "git"; # So ssh cloning uses git@gitea + settings = { + repository = { + ENABLE_PUSH_CREATE_USER = true; + ENABLE_PUSH_CREATE_ORG = true; + }; + }; + }; + + # SSH for repositories + services.openssh.enable = true; + + # Reverse proxy + services.caddy = { + enable = true; + virtualHosts.":80".extraConfig = '' + reverse_proxy localhost:3000 + ''; + }; + + system.stateVersion = "25.11"; + }; + }; +} diff --git a/hosts/poweredge/hardware-configuration.nix b/hosts/poweredge/hardware-configuration.nix new file mode 100644 index 0000000..0fcc098 --- /dev/null +++ b/hosts/poweredge/hardware-configuration.nix @@ -0,0 +1,50 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "megaraid_sas" "usbhid" "usb_storage" "sd_mod" "sr_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "zpool/root"; + fsType = "zfs"; + options = [ "zfsutil" ]; + }; + + fileSystems."/nix" = + { device = "zpool/nix"; + fsType = "zfs"; + options = [ "zfsutil" ]; + }; + + fileSystems."/var" = + { device = "zpool/var"; + fsType = "zfs"; + options = [ "zfsutil" ]; + }; + + fileSystems."/home" = + { device = "zpool/home"; + fsType = "zfs"; + options = [ "zfsutil" ]; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/D083-98C0"; + fsType = "vfat"; + options = [ "fmask=0022" "dmask=0022" ]; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/poweredge/immich.nix b/hosts/poweredge/immich.nix new file mode 100644 index 0000000..ff0275c --- /dev/null +++ b/hosts/poweredge/immich.nix @@ -0,0 +1,89 @@ +{ pkgs, ... }: let + onnxruntimeCuda = pkgs.onnxruntime.override { cudaSupport = true; }; +in { + containers.immich = { + autoStart = true; + privateNetwork = true; + hostBridge = "br-lan0"; + localMacAddress = "02:00:00:00:00:01"; + + # Host path + bindMounts = { + "/var/lib/immich" = { + hostPath = "/media/ingens/immich"; + isReadOnly = false; + }; + }; + + # GPU + allowedDevices = [ + { node = "/dev/nvidia0"; modifier = "rw"; } + { node = "/dev/nvidiactl"; modifier = "rw"; } + { node = "/dev/nvidia-uvm"; modifier = "rw"; } + { node = "/dev/nvidia-uvm-tools"; modifier = "rw"; } + { node = "/dev/nvidia-modeset"; modifier = "rw"; } + ]; + + bindMounts = { + # NVENC/NVDEC - video transcoding + "/dev/nvidia0" = { hostPath = "/dev/nvidia0"; isReadOnly = false; }; + "/dev/nvidiactl" = { hostPath = "/dev/nvidiactl"; isReadOnly = false; }; + # CUDA - required for ML inference + "/dev/nvidia-uvm" = { hostPath = "/dev/nvidia-uvm"; isReadOnly = false; }; + "/dev/nvidia-uvm-tools" = { hostPath = "/dev/nvidia-uvm-tools"; isReadOnly = false; }; + # Modeset - needed by some driver paths + "/dev/nvidia-modeset" = { hostPath = "/dev/nvidia-modeset"; isReadOnly = false; }; + }; + + config = { lib, config, ... }: { + imports = [ ./nvidia.nix ]; + + # Network + networking.interfaces.eth0.useDHCP = true; + networking.firewall.allowedTCPPorts = [ 80 2283 ]; # Caddy + immich + + # Immich + services.immich = { + enable = true; + host = "0.0.0.0"; + package = pkgs.unstable.immich; + accelerationDevices = [ + "/dev/nvidia0" + "/dev/nvidiactl" + "/dev/nvidia-uvm" + "/dev/nvidia-uvm-tools" + "/dev/nvidia-modeset" + ]; + + # Tell immich-server to use NVENC for transcoding + environment = { + NVIDIA_VISIBLE_DEVICES = "all"; + NVIDIA_DRIVER_CAPABILITIES = "compute,video,utility"; + }; + + # Enable the ML microservice with CUDA + # FIXME Disabled since the ML service w/ CUDA uses almost all the vram on my gpu + machine-learning.enable = false; + }; + environment.systemPackages = with pkgs.unstable; [ immich immich-cli ]; + + # TODO IPP is missing a lot of features right now. Check back later + ## Immich public proxy + #services.immich-public-proxy = { + # enable = true; + # immichUrl = "http://localhost:2283"; + # package = pkgs.unstable.immich-public-proxy; + #}; + + # Reverse proxy + services.caddy = { + enable = true; + virtualHosts.":80".extraConfig = '' + reverse_proxy localhost:2283 + ''; + }; + + system.stateVersion = "25.11"; + }; + }; +} diff --git a/hosts/poweredge/jellyfin.nix b/hosts/poweredge/jellyfin.nix new file mode 100644 index 0000000..761c3ae --- /dev/null +++ b/hosts/poweredge/jellyfin.nix @@ -0,0 +1,91 @@ +{ + containers.jellyfin = { + autoStart = true; + privateNetwork = true; + hostBridge = "br-lan0"; + localMacAddress = "02:00:00:00:00:02"; + bindMounts = { + "/media" = { + hostPath = "/media/ingens/media"; + isReadOnly = true; + }; + }; + + # GPU + allowedDevices = [ + { node = "/dev/nvidia0"; modifier = "rw"; } + { node = "/dev/nvidiactl"; modifier = "rw"; } + { node = "/dev/nvidia-uvm"; modifier = "rw"; } + { node = "/dev/nvidia-uvm-tools"; modifier = "rw"; } + { node = "/dev/nvidia-modeset"; modifier = "rw"; } + ]; + + bindMounts = { + # NVENC/NVDEC - video transcoding + "/dev/nvidia0" = { hostPath = "/dev/nvidia0"; isReadOnly = false; }; + "/dev/nvidiactl" = { hostPath = "/dev/nvidiactl"; isReadOnly = false; }; + # CUDA - required for ML inference + "/dev/nvidia-uvm" = { hostPath = "/dev/nvidia-uvm"; isReadOnly = false; }; + "/dev/nvidia-uvm-tools" = { hostPath = "/dev/nvidia-uvm-tools"; isReadOnly = false; }; + # Modeset - needed by some driver paths + "/dev/nvidia-modeset" = { hostPath = "/dev/nvidia-modeset"; isReadOnly = false; }; + }; + + config = { lib, config, pkgs, ... }: { + imports = [ ./nvidia.nix ]; + + # Network + networking.interfaces.eth0.useDHCP = true; + networking.firewall.allowedTCPPorts = [ 80 ]; # Caddy + + # Jellyfin + services.jellyfin = { + enable = true; + openFirewall = true; + + hardwareAcceleration = { + enable = true; + type = "nvenc"; + device = "/dev/nvidia0"; # Required by the module's assertion, unused in encoding.xml for nvenc + }; + + forceEncodingConfig = true; # Override encoding.xml + + transcoding = { + enableHardwareEncoding = true; + + hardwareEncodingCodecs = { + hevc = true; # Pascal 4th-gen NVENC supports HEVC 8/10-bit encode + av1 = false; # NOT supported on Pascal — do not enable + }; + + hardwareDecodingCodecs = { + h264 = true; + hevc = true; + hevc10bit = true; + vp8 = true; + vp9 = true; + mpeg2 = true; + vc1 = true; + av1 = false; # NOT supported on Pascal NVDEC + hevcRExt10bit = false; # Range Extensions decode is a newer-gen feature, skip on Pascal + hevcRExt12bit = false; + }; + + encodingPreset = "medium"; + enableToneMapping = true; # works via CUDA-based tonemap_cuda filter on Pascal+ + }; + }; + + # Reverse proxy + services.caddy = { + enable = true; + virtualHosts.":80".extraConfig = '' + reverse_proxy localhost:8096 + ''; + }; + + system.stateVersion = "26.05"; + }; + }; +} diff --git a/hosts/poweredge/metrics.nix b/hosts/poweredge/metrics.nix new file mode 100644 index 0000000..edf3da9 --- /dev/null +++ b/hosts/poweredge/metrics.nix @@ -0,0 +1,43 @@ +{ config, inputs, ... }: { + imports = [ inputs.telemetry.nixosModules.collectors ]; + + services.telemetry.collectors = { + enable = true; + logs.lokiUrl = "http://metrics:3100"; # The container + }; + + containers.metrics = { + autoStart = true; + privateNetwork = true; + hostBridge = "br-lan0"; + localMacAddress = "02:00:00:00:00:06"; + ephemeral = true; + + # The module reads whatever path you point secretKeyFile at. + bindMounts = { + "/var/lib/prometheus2" = { hostPath = "/nix/persist/metrics/prometheus2"; isReadOnly = false; }; + "/var/lib/loki" = { hostPath = "/nix/persist/metrics/loki"; isReadOnly = false; }; + "/var/lib/grafana" = { hostPath = "/nix/persist/metrics/grafana"; isReadOnly = false; }; + }; + + config = { ... }: { + imports = [ inputs.telemetry.nixosModules.server ]; + + networking.enableIPv6 = false; + networking.interfaces.eth0.useDHCP = true; + + services.telemetry.server = { + enable = true; + collectorHosts = [ "poweredge" ]; + grafana.generateSecretKey = true; + proxy.enable = true; + }; + + # Pin loki uid+gid + users.users.loki = { uid = 3100; group = "loki"; isSystemUser = true; }; + users.groups.loki.gid = 3100; + + system.stateVersion = "26.05"; + }; + }; +} diff --git a/hosts/poweredge/navidrome.nix b/hosts/poweredge/navidrome.nix new file mode 100644 index 0000000..fa40ed4 --- /dev/null +++ b/hosts/poweredge/navidrome.nix @@ -0,0 +1,51 @@ +{ + containers.navidrome = { + autoStart = true; + privateNetwork = true; + hostBridge = "br-lan0"; + localMacAddress = "02:00:00:00:00:08"; + + bindMounts = { + "/media/music" = { + hostPath = "/media/ingens/media/music"; + isReadOnly = true; + }; + #"/media/podcasts" = { + # hostPath = "/media/ingens/media/podcasts"; + # isReadOnly = true; + #}; + }; + + config = { lib, config, pkgs, ... }: { + # Network + networking.interfaces.eth0.useDHCP = true; + networking.firewall.allowedTCPPorts = [ 80 ]; # Caddy + + # Navidrome + services.navidrome = { + enable = true; + + plugins = with pkgs.navidromePlugins; [ + #audiomuseai + listenbrainz-daily-playlist + #lyrics-plugin + ]; + + settings.MusicFolder = "/media/music/library"; + + # The lyrics plugin bundle is named lyrics-plugin.ndp. + settings.LyricsPriority = ".ttml,.yaml,.yml,.elrc,.srt,lyrics-plugin,embedded,.lrc,.txt"; + }; + + # Reverse proxy + services.caddy = { + enable = true; + virtualHosts.":80".extraConfig = '' + reverse_proxy localhost:4533 + ''; + }; + + system.stateVersion = "26.05"; + }; + }; +} diff --git a/hosts/poweredge/networking.nix b/hosts/poweredge/networking.nix new file mode 100644 index 0000000..8be3f4d --- /dev/null +++ b/hosts/poweredge/networking.nix @@ -0,0 +1,167 @@ +let + hostIp = "192.168.1.10"; +in { pkgs, config, ... }: { + networking = { + # Label lan and wan interfaces + _interfaceLabels = { + enable = true; + interfaces.lan0 = "50:9a:4c:5d:c3:7a"; + interfaces.wan0 = "50:9a:4c:5d:c3:7b"; + }; + # Create bridged lan interface for all containers + bridges.br-lan0.interfaces = [ "lan0" ]; + # Disable dhcp on router interfaces + interfaces = { + veth-router-lan.useDHCP = false; + vb-router-lan0.useDHCP = false; + }; + # Configure network + defaultGateway = "10.255.255.1"; # Read explaination for veth-router-lan below + nameservers = [ "192.168.1.1" ]; # DNS will only be available from this ip address THROUGH the default gateway + # br-lan0 will be the interface used for networking on poweredge host + interfaces.br-lan0.ipv4.addresses = [{ + address = hostIp; + prefixLength = 24; + }]; + }; + + # Secrets + sops.secrets.router-wg0 = { sopsFile = ./resources/secrets/router.yaml; key = "wg0"; }; # Office + sops.secrets.router-wg1 = { sopsFile = ./resources/secrets/router.yaml; key = "wg1"; }; # Remote access + + # Router container + containers.router = { + autoStart = true; + ephemeral = true; + privateNetwork = true; + # Pass wan0 directly into container since it isn't needed elsewhere + interfaces = [ "wan0" ]; + # Setup router lan0 + # NOTE: Host/container communication is not possible through a hostBridge interface + extraVeths.vb-router-lan0.hostBridge = "br-lan0"; + # Setup virtual host-router bridge interface. + # This is the default gateway for host/container communication since + # communication isn't possible through hostBridge interfaces. + # This is essentially equivalent to connecting the host to the + # container with a virtual ethernet cable on a separate interface. + extraVeths.veth-router-lan = { + hostAddress = "10.255.255.2"; + localAddress = "10.255.255.1"; + }; + # Bind secrets to container + bindMounts."/run/secrets/wg0" = { + hostPath = config.sops.secrets.router-wg0.path; + isReadOnly = true; + }; + bindMounts."/run/secrets/wg1" = { + hostPath = config.sops.secrets.router-wg1.path; + isReadOnly = true; + }; + + config = { lib, config, ... }: { + imports = [ + ../../nixos/services/router + ./router-hosts.nix # Contains dhcp config + static leases + overrides + ]; + + networking = { + # Set ip addresses + enableIPv6 = false; + interfaces = { + vb-router-lan0.ipv4.addresses = [{ + address = "192.168.1.1"; + prefixLength = 24; + }]; + wan0.useDHCP = true; + }; + # Setup wireguard + wg-quick.interfaces = { + wg0.configFile = "/run/secrets/wg0"; + wg1.configFile = "/run/secrets/wg1"; + }; + # NAT (port-forwarding) rules + nat.forwardPorts = [ + { sourcePort = 8333; proto = "tcp"; destination = "192.168.1.44:8333"; } # Bitcoin p2p + ]; + firewall.allowedUDPPorts = [ 51820 ]; # Allow wg1 running on router host through w/o NAT + # Additional advanced rules + # TODO add multi NAT feature to router service (this is just a normal nat rule) + nftables = { + enable = true; + tables = { + # NAT/masquerade wg0 allowing vb-router-lan0 clients to access wg0 + wg-nat = { + family = "ip"; + content = '' + chain post { + type nat hook postrouting priority srcnat; policy accept; + iifname "vb-router-lan0" oifname "wg0" masquerade comment "vb-router-lan0 => wg0" + iifname "veth-router-lan" oifname "wg0" masquerade comment "veth-router-lan => wg0" + } + ''; + }; + # Hairpin for wg1 clients to access the host via veth-router-lan since path is broken otherwise + host-hairpin = { + family = "ip"; + content = '' + chain pre { + type nat hook prerouting priority dstnat; policy accept; + iifname "wg1" ip daddr 192.168.1.10 dnat to 10.255.255.2 comment "wg1 => host, redirect via veth" + } + chain post { + type nat hook postrouting priority srcnat; policy accept; + ip daddr 10.255.255.2 masquerade comment "wg1 => host, hairpin masquerade" + } + ''; + }; + }; + }; + }; + + # Setup router + services._router = { + dnsDhcpConfig.enable = true; + routing = { + enable = true; + interfaces = { + lan = [ "vb-router-lan0" "veth-router-lan" ]; + wan = "wan0"; + }; + }; + }; + + services.unbound._blocklists = { + enable = true; + hageziBlocklists = [ "pro" "nsfw" ]; + }; + + + environment.systemPackages = with pkgs; [ + tcpdump + ]; + + system.stateVersion = "25.11"; + }; + }; + + # FIXME the following snippet will cause the router container to fail to start: + # networking.defaultGateway = { + # address = "10.255.255.1"; + # interface = "veth-router-lan"; + # }; + # Journalctl will report: + # poweredge container router: Bring veth-router-lan up + # poweredge container router: RTNETLINK answers: File exists + # poweredge systemd: container@router.service: Control process exited, code=exited, status=2/INVALIDARGUMENT + # So the issue nixos is creating an interface with that same name. + # As a temporary workaround, the following service is deployed (after the container starts): + systemd.services.router-default-route = { + after = [ "container@router.service" ]; + wants = [ "container@router.service" ]; + serviceConfig.Type = "oneshot"; + script = '' + /run/current-system/sw/bin/ip route replace default via 10.255.255.1 dev veth-router-lan + ''; + wantedBy = [ "multi-user.target" ]; + }; +} diff --git a/hosts/poweredge/notification-mailer.nix b/hosts/poweredge/notification-mailer.nix new file mode 100644 index 0000000..d8fddc7 --- /dev/null +++ b/hosts/poweredge/notification-mailer.nix @@ -0,0 +1,27 @@ +{ config, ... }: let + serverEmail = "server-notifications@tjkeller.xyz"; +in { + # Mailer password secret for mail application password + sops.secrets.mailerPassword.sopsFile = ./resources/secrets/mailer-pass.yaml; + + # Enable mta for system event notifications + services.mail._mailer = { + sender = { + host = "mail.tjkeller.xyz"; + user = serverEmail; + from = serverEmail; + passwordFile = config.sops.secrets.mailerPassword.path; + }; + recipient = serverEmail; + }; + + # Enable zed mailer module + services.zfs._zedMailer.enable = true; + + # Enable smartd notifications + services.smartd.notifications.mail = { + enable = true; + sender = serverEmail; + recipient = serverEmail; + }; +} diff --git a/hosts/poweredge/nvidia.nix b/hosts/poweredge/nvidia.nix new file mode 100644 index 0000000..5eecc71 --- /dev/null +++ b/hosts/poweredge/nvidia.nix @@ -0,0 +1,29 @@ +{ lib, config, pkgs, ... }: { + # Configure nixpkgs for nvidia/cuda + nixpkgs.config = { + cudaSupport = true; + allowUnfreePredicate = pkg: + pkgs._cuda.lib.allowUnfreeCudaPredicate pkg + || builtins.elem (lib.getName pkg) [ + "nvidia-x11" + "nvidia-kernel-modules" + ]; + }; + + # NVIDIA + services.xserver.videoDrivers = [ "nvidia" ]; # xserver.videoDrivers does not imply X + hardware.graphics.enable = true; + hardware.nvidia = { + modesetting.enable = true; # Required + nvidiaSettings = false; # Don't need gui + open = false; + package = config.boot.kernelPackages.nvidiaPackages.legacy_580; # Support for P600 + powerManagement.enable = false; # Can cause bugs + powerManagement.finegrained = false; # Only works on turing and newer + }; + + # Packages + environment.systemPackages = with pkgs; [ + config.hardware.nvidia.package # nvidia-smi + ]; +} diff --git a/hosts/poweredge/resources/secrets/ddns-updater-config.yaml b/hosts/poweredge/resources/secrets/ddns-updater-config.yaml new file mode 100644 index 0000000..3be017b --- /dev/null +++ b/hosts/poweredge/resources/secrets/ddns-updater-config.yaml @@ -0,0 +1,16 @@ +ddns-updater-config: ENC[AES256_GCM,data:vJ3z4R6P1gHKfkm6L2mQl68MKDJwpMNmrAOQo+4GkO2NC6EjKTLoSKhFiaGWVjMm7nrVfYRV+U/6b4VJXV4qURWhsm41t3x8zXAtt0viLC6pv+uMtuxadhU2Zxij4U2bSiMn6sSbfHd3uGIym7FnfOIL3LPEanVMuRUk20a0ZgHBdq1BPk6r5V8AoGfsu1XWHTvnO4ggg9oQPtGhurKTXixTD0Rb1Iv43JXLXqK/O3JGD5h4XbDmXB9eTqiBHUgZ0E4F5SE23L5mO0kI0TNNph2lTHXdfB+5,iv:xFry3gzdvvYh127yhYySvp5UHDa8Y+t/bg2+mwJ/HXo=,tag:pH2CE2l2UpNJiLJ+tjVvqQ==,type:str] +sops: + age: + - recipient: age1zfvmt2avdlfz0fvchczplc84u7m8vqausm7zytl9s4x9m9yax4cqy30zpz + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtWitQcVlaTmFVaHIraHlT + VFBDVEtlQUlqckN4eFF3YU95N3ZNU3JQcFNzCnkrR2xmTEtyUHRWQlRnTWZSaGVT + U0wvcGt6R0w4L3dSakVDVWVpTUhWbWMKLS0tIGVKSXVTL1B2L2FlSkQwSDVYd3Fk + WE8rLy81UEU5ZG9SaHRLOHNqOWUzWnMKBFtzJ9frroYk6hoW+1ww/3LpxCEa1Vtr + KNNnHKry8lQQDmalN5ZVYMTVAlTnQQ6QE7DxBukUwWYmizQ+BY8HDg== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-03-31T01:47:37Z" + mac: ENC[AES256_GCM,data:8ozC5JWR/s3nNK+njc7zO32/7ptd//wuWGWZPHXrPV1iVyYndczGgu0ekEyKeRCn/WwGE5pyt32gy0l2Y+k7j7mV6GJguy6qhltani6Mz2Gfy5sRohn5s2rBDTiSYEVAgGTRt56DLxGD36P6xFPm+wHGspjCzNALrPretuN5xFg=,iv:+/mlXEMEO80pDVpFwZmnyywvHR/V9zHkbloF/e/dJ6Q=,tag:O+Ox0xUzERjeB+VftiUNEg==,type:str] + unencrypted_suffix: _unencrypted + version: 3.12.1 diff --git a/hosts/poweredge/resources/secrets/grafana.yaml b/hosts/poweredge/resources/secrets/grafana.yaml new file mode 100644 index 0000000..91b9188 --- /dev/null +++ b/hosts/poweredge/resources/secrets/grafana.yaml @@ -0,0 +1,16 @@ +secret_key: ENC[AES256_GCM,data:9GHuENHGk+VKukRuUJi+fxOX+ZFa5q5t5UiGtxSQOEctu9LOJqvHJerFv3U=,iv:6OJTeWbotDVj/ogg9WC170Q4Kdfd1PXf0hHwXd/YaUQ=,tag:qlnEl2uzDuhwOKp17R76Tg==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBrc0tWWHhtM2Q5UC9weSsr + WDdaOXJjZGVoekJKaXUyUXhsRXMxMjQrYUFnCnBqTGJEMFF6clQ1RXd5NE9CenQ5 + U0swNHdNUUxndnlycGVGM0lpY0dFaVEKLS0tIHVlK2MySUJzaGVXd21iWFFzcEJM + Nmh3V2hIbUhWNUxlOE1idTdWNWZ6alEKWae75mhvfpTNOcvm7x1zf19QkmZqrAf7 + jpkyKDE//d4Rn3h4Ogpl5bdXb9RyOoSEJUG+EDPFyynqdodCJ2ucpw== + -----END AGE ENCRYPTED FILE----- + recipient: age1zfvmt2avdlfz0fvchczplc84u7m8vqausm7zytl9s4x9m9yax4cqy30zpz + lastmodified: "2026-06-18T22:40:22Z" + mac: ENC[AES256_GCM,data:5HoPrQU8Q+SGEH4jQHy1otFXGILqttDpcbv+edNoKI/QFoUE74M4PrGzltlManZstqK3nfWV3HNIcY6GRe8TMP5ANC/8UIXfEDerP1Q0kj6xeyLumMCJ6iCjygF2SzL5YMWqBSsCJvH5O10sWncc2iPnGrQPJ8PksIxkXCe4YYk=,iv:f0WpJwENciWkyDKpGM/PaE2lmXWvNiMAxNpqlCEFhM8=,tag:nQAPTJPYsgRIUkDxktIvmA==,type:str] + unencrypted_suffix: _unencrypted + version: 3.13.1 diff --git a/hosts/poweredge/resources/secrets/mailer-pass.yaml b/hosts/poweredge/resources/secrets/mailer-pass.yaml new file mode 100644 index 0000000..331bd66 --- /dev/null +++ b/hosts/poweredge/resources/secrets/mailer-pass.yaml @@ -0,0 +1,16 @@ +pass: ENC[AES256_GCM,data:RHOvLwbDIb8FZ+dG66e5U43qR0aXlLLZGAnlbRjSl8hxCMEtJ4940nggiaIV75jCaiWyLutay7MrKPKZBHDZwBIqcJYQRWm1zWGkoZi0/bX38vUFWOpI4qku9fIB2qll,iv:bqEnTagxlRqlAmMgFCtXXCSSlODE598yoV4fU0jSYL8=,tag:c/ZiGCDSb8quDoYiIKbMeQ==,type:str] +sops: + age: + - recipient: age1zfvmt2avdlfz0fvchczplc84u7m8vqausm7zytl9s4x9m9yax4cqy30zpz + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBEUXlZaUhSUkNGK2xpVzRp + OEhYMTV6bnpPZC9tdHZWbnZxcUp6WWVLMnhFCmZmckVBckdRS1g0MjJQdE80S2Js + aGlNek1nSmU2aGI4cWVXR0NmbjJwa00KLS0tIDJ3N3BoenQ5ZW02K3BLNWxkWU5y + Ym56YzI5Zk9KeFhzZXJXR3NoOUl0ckEKOLweZrk/Pe6BG48+RrwOxyOy0Zb768aZ + YIxTBv/qSzZei6VqZHiIwTUEMyE7z3CS0dBFws6q4fB4LfIpv6fiYg== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-03-31T01:37:29Z" + mac: ENC[AES256_GCM,data:WIGXvuwB4bcBDfMRrrMQ7faUkxFdreyYiuy6bNPI2pzvvUFTSo/lJTv/DjisSARdYmFHFvdResIXUjg75Sc2I5IrvRxZxnYqx/3z5k/WOFWb8HSKH2H+OUHtLkqWJSCQ9YBuX2tys93mEXgwchPpn4nzVaYBgxZl54F3icX7tsE=,iv:BS9KPGkVaH0G0bAZz6+LR0NDcmqw6khOkih5DyvGyug=,tag:dA9YVL1xEqUqe6hDzOH7XQ==,type:str] + unencrypted_suffix: _unencrypted + version: 3.12.1 diff --git a/hosts/poweredge/resources/secrets/router.yaml b/hosts/poweredge/resources/secrets/router.yaml new file mode 100644 index 0000000..4cd3398 --- /dev/null +++ b/hosts/poweredge/resources/secrets/router.yaml @@ -0,0 +1,17 @@ +wg0: ENC[AES256_GCM,data:hxZrOTMx2lS7dkQPV48jUbHxoNr32KSM/wG0OPY8mcgHX4FsHStdH/CN4qlkH9co90yFKjwqcJ3fHXaSbIhp3oIYTo1R2/8KggHV+az4skb7v4kzZgU5u5V2B57gIRFrPHBBq1UtDkBBpANr7zypeLPuEzvCQaZiexrsCcET7xwhsEYtVc5WlISMHhi6sFzo1AeEVfwFvIUN9geXJwP3JycYRpaNXOVYAbPwer8fYa6mnFZIk+sruCO85QNoWQ2T1wPiC9U7Ki9q+FOaOzJWGdpiG3nQdeYlDgAwoPRNi3c0J6t3CS9xC+qC0y4esOL7ay4S2dDoL9ftChQjhWaGdq5+LeyXAPlATGs5aFtBMwEecQ5OPXTri2D5m/gVLW/TGmUT5ZVPymm/wAX+m4IWK6X3FylWnlEoUh+4cBO+2zjTbXEccRuJTOEZAGIsEg==,iv:ycsGniDPFOvFFGqCgiyCWkCS8AxFV7JbXgUxDPXAFmk=,tag:uXkB8b7S3sW9noTIK4J/Zw==,type:str] +wg1: ENC[AES256_GCM,data:RIoKsBtvJ90mw3+Vs3K9MoVoLiGlO9ef1kom8Hkww5SFc9JcVAvs9JUgYrOoc5ATWTK6LPipXaQibWrbHTeBadZnAcRiHeL3/8FOgr8TkzH0KfDL7fd/AKzvJMf/fRZv6DCrY3LRn0PSwkPePiY7aoSpQRxScoR7mU8EOougUUPFolANZAjssKhFUix9bRO6/reU+B3Mzq30ozmMC+J4tsfYHe2beVS0qkLqTEyzh4hsSF3HCAHSUm0NunQwQlo0y2eYR+4tCXNje5X8PqxTRZpqLEFYaUDigdsmXX8DaVulszPnwGaAPsTMcZEGtO3FtPapVDfial3BrSgXZxTaE+a9t5m/F50aNUS1yxQHKd7lNrfI4Q1pX6ktAyW378mFhdT3fygHogkbjMrm947OdenZlA7jKRrsxQ2hVqP6g6x5/910nH7DVLEBkJ85TQfx5bd0eMQvcc/ox6NuCZZFaXCyry5MHZZa0o0Pnw3BW61J56Pxr2t8sraZFhfsTxTOyiL/L5O+PCd0osCn9SBTl8TAJl+/o8wje/GuFGtFkv54pJ9M1e86LKYt/ksU3HDwTDlblmwhtHILdy+ld2XU52ympCu5b9Ix61OTj4sqFYAfob+Ft5lPcbWqbT43HySW9iDTRbtcZVEXuZItrAlnQiXKe3CjQzPizY9P4KoFliUad8qOyvQ6PFG2ExaUL2vwXkQbk0gaCwfhg5HGg/AR2/y4mcey0gVyXJRm4WTSllNom48gEq/ylZcU9hWASNfkHj5W/MXeKbXMsu1u/6tv51anXEdNQTARIu+8zGSDHwL3wRw9hsiz7Fcg98rOrRZPRSjYniLxm2pkXvIZuS5lUUv6bRnEPv/3mw+HBjomjOVhNxdGa21AEf1QtItlBtWTnZawjY3KJumx4GuZmQQ5cunnlUp2Qu2k2jsNDQqhLEK0/gbgLkhi0Eh8lp9xJdQ0iXCqaALs4CcKM/3n/2THmN1Mjq+hjKNwY/TOZdfnyA9NPwQNB3UO5vd8za2/XfeObNRBs+Vd3hV9o1fyynYtHuhYwe0W6AKwmeotS87Jbl5jDu/r5ckpMNM6E+x89Bz95Y6VTh8zWA==,iv:X53OauqcsQEJou7gt/MuqUQ50VwA6hp5ykQ096HJb4c=,tag:k5v+KQtWj6dxjmp/zjvPKw==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxOFFVRFl2MDhiUVRPdnZJ + b3BSZ0pSaG8vR3o3SGlmVENvN3ZObHU3eUc4CmJrdk8rbXpBMWhTZ2hvdlk0VWo1 + ejdnTDR4bFlUUXc4Smd0NEp6b3crZFUKLS0tIFBsQUdRWjZLSDY1ZlFaRDdLOVhs + MFFGY0NSU3NaK2U0U1NndUIyYm54ZWsKZ6q9j1fNaNSzBA0rbZYyUWt3U2V/7/9/ + FZTKd8mH/uCoxvK8unlVZ9uYNADRh2smp7LwK1AWie/6khAIFqVBeg== + -----END AGE ENCRYPTED FILE----- + recipient: age1zfvmt2avdlfz0fvchczplc84u7m8vqausm7zytl9s4x9m9yax4cqy30zpz + lastmodified: "2026-10-09T21:56:37Z" + mac: ENC[AES256_GCM,data:yLU812vLFtABilSRFy44EI5YrNYypfoCM11QKZglw+RZcCjLZlm2zd53t3RsH2y0w2cEWsGsyECNWM2iES3F4+HqrBZmlVZ27GBSoGmX8+FzJnPkvlcfIG3F6C03AU7BLApjYmR+Lu0m2WdhwwXcCSvwN0HAKRZF0pHogoS/+6A=,iv:tMdCvkRBd6xbTPMuazNsT8tBSS4A2YOeaG0rRAxMwsI=,tag:KewEK3C9xhEh6YbDPi3GoQ==,type:str] + unencrypted_suffix: _unencrypted + version: 3.13.3 diff --git a/hosts/poweredge/resources/secrets/slskd.yaml b/hosts/poweredge/resources/secrets/slskd.yaml new file mode 100644 index 0000000..3f0a43b --- /dev/null +++ b/hosts/poweredge/resources/secrets/slskd.yaml @@ -0,0 +1,16 @@ +env-file: ENC[AES256_GCM,data:HFyQoP9iZMx4ieCk7f36McCTVN+5P+wZ5O+4bztmvIjJkdT4CgzXQDEuDEfDCwPNW25hAR+zV6znW6eO/tDoJndliD0ifl6+xODL9g34nInfocB1+alMjcHFz3Ix9HEMUYkABZ3qxn9DQGagrlRBB0sDMHkW2fRcl2Sd7qY5lhM676jpfF+oh2QTWYn9ZP8aS9FcYB2SaeFox3o=,iv:18IODA/fQBwlJhvNKXuo0kc18w4dEspEz5inusnh1f4=,tag:2jAJr5R5LnKwRAhC5lb5Pg==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2WitIOGhGVUp3N0pTQkds + OUJOQ0hReExNNEhZaXhENURwMGFGN3pBckVjClcvbDY4VUpXeWJXa0lLdWVoazNT + S2JjKzFaZ3lwWkZNbnRpOEpmREtMTm8KLS0tIE9yTXQvVzRvVU1YSGRLbWtQaGRB + REx6K2loY3JsTmFkNzZzN3FDdzhaaWsKRVP71gq5x0qPmWwhsDgTtDwe5Ip6cg78 + pvU/OeUmXEdLJAsXFAaCIKPe5QSMaopgKiB9rfXJFM3mn2bhnHNYBQ== + -----END AGE ENCRYPTED FILE----- + recipient: age1zfvmt2avdlfz0fvchczplc84u7m8vqausm7zytl9s4x9m9yax4cqy30zpz + lastmodified: "2026-10-28T22:22:21Z" + mac: ENC[AES256_GCM,data:lhyXZ2PEZ59C7EfshQ5x09dmLTeAhlEjt5rwpMjdVcicUKioH1GdUD+hjKNAUDCfuBS1Oy/ay0yFGn9TZvMqngbXRgSxx4EY26EssvmfZ6wgp1F8t41+gm0tuQFUkkn51k713O21sTAZS7BfpOyiFCHYD852RbRoENJrgRK6KQk=,iv:Jw2Tw1QwdxY7cTT0UBiVJmJhtp+nNsQttv7G8yHs8Rk=,tag:CwjZpbMi8T4ubNMen0EqYg==,type:str] + unencrypted_suffix: _unencrypted + version: 3.13.3 diff --git a/hosts/poweredge/resources/secrets/vpn-router.yaml b/hosts/poweredge/resources/secrets/vpn-router.yaml new file mode 100644 index 0000000..12c109b --- /dev/null +++ b/hosts/poweredge/resources/secrets/vpn-router.yaml @@ -0,0 +1,17 @@ +ovpn-auth: ENC[AES256_GCM,data:9B/JKqliPVmzAiTX9gCayS2lLGqshFONueMz,iv:Yx+6VIP8W0/N059kqL2kAgdYrS8PT/Zk6WU6Tlfm+Kg=,tag:tUQG1Ry8FHQoCPYFcx7PFA==,type:str] +ovpn-config: ENC[AES256_GCM,data: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,iv:R+LK9n9f87YU5bJMXVyNueE7CuLosFcdXzWReASCV5g=,tag:EXYg43lPkDugSUWJG4KgLw==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByNVd5TUlvczNnd2pzZnJn + eUREOFYrSmVYcGNDQzJqQlJETlk1R3Z1Mkc4Ckl5SFc1Tmdta2RQdkw2eXVTR3FX + TjFNTTlVTTgweHg1b1dNWjVXM2wzVU0KLS0tIDk2SkpDUWlwemVXY3Rveld1dXFV + ZWVTMjVKWVJaU0cvbjdOZTNaVWdlY28KsmuwUmhYdvcJLHIdBVJ6RKnPGlZmhG8q + dzotK3ZTynQPJYGC6n6OD1I3fV6GAYXNaVKafR6ckuJ5n0wbS+jjCg== + -----END AGE ENCRYPTED FILE----- + recipient: age1zfvmt2avdlfz0fvchczplc84u7m8vqausm7zytl9s4x9m9yax4cqy30zpz + lastmodified: "2026-10-28T22:18:45Z" + mac: ENC[AES256_GCM,data:fHLraNMezdvfGcTKf1kFpvWbDb1NM9FgRBYtG81IFl4HGhqvRwekRLty0UeT02IKk4LAdzs0QwSSDVUlo3Sun/1xqXgYWK0DDkPlNfQQ6IO45YJn9ESAmTFqWTKFdPjUNcl8EeUJdelHoYd/9p4dw4FL/2OTO4zb/XM7IsfZ+FU=,iv:Uq4Mpvk0OtkOnb7bk+sEUDxFeWLA5CZL0MJjrxNZ3gw=,tag:Q5zMdI1C5LQQ8HZRdjAHgA==,type:str] + unencrypted_suffix: _unencrypted + version: 3.13.3 diff --git a/hosts/poweredge/router-hosts.nix b/hosts/poweredge/router-hosts.nix new file mode 100644 index 0000000..4e14c01 --- /dev/null +++ b/hosts/poweredge/router-hosts.nix @@ -0,0 +1,48 @@ +let + localDomain = "home.lan"; # TODO RFC8375 .home.arpa + dhcp = { + inherit staticLeases; + defaultGateway = "192.168.1.1"; + localhostIp = "192.168.1.1"; + rangeStart = "192.168.1.65"; + rangeEnd = "192.168.1.250"; + }; + staticLeases = { + # Network + idrac-7N94GK2 = { macAddress = "50:9a:4c:5d:c3:7c"; staticIp = "192.168.1.2"; }; + OpenWrt-Attic = { macAddress = "34:98:b5:60:5e:be"; staticIp = "192.168.1.3"; }; + OpenWrt-Basement = { macAddress = "8c:3b:ad:35:c7:8c"; staticIp = "192.168.1.4"; }; + ArcherC54 = { macAddress = "14:eb:b6:13:f9:e0"; staticIp = "192.168.1.5"; }; + vpn-router = { macAddress = "02:00:00:00:01:09"; staticIp = "192.168.1.9"; }; + # Desktops + optiplex = { macAddress = "e4:54:e8:bc:ba:05"; staticIp = "192.168.1.12"; }; + X230 = { macAddress = "84:3a:4b:60:34:c4"; staticIp = "192.168.1.13"; }; + # Appliances + # TODO add epson printer + p1s = { macAddress = "3c:0f:02:d5:23:64"; staticIp = "192.168.1.39"; }; + gnuslashprinter = { macAddress = "00:23:24:5b:f0:6d"; staticIp = "192.168.1.40"; }; + # Services + immich = { macAddress = "02:00:00:00:00:01"; staticIp = "192.168.1.41"; }; + jellyfin = { macAddress = "02:00:00:00:00:02"; staticIp = "192.168.1.42"; }; + gitea = { macAddress = "02:00:00:00:00:03"; staticIp = "192.168.1.43"; }; + bitcoind = { macAddress = "02:00:00:00:00:04"; staticIp = "192.168.1.44"; }; + filebrowser = { macAddress = "02:00:00:00:00:05"; staticIp = "192.168.1.45"; }; + grafana = { macAddress = "02:00:00:00:00:06"; staticIp = "192.168.1.46"; }; + transmission = { macAddress = "02:00:00:00:01:47"; staticIp = "192.168.1.47"; }; + navidrome = { macAddress = "02:00:00:00:00:08"; staticIp = "192.168.1.48"; }; + slskd = { macAddress = "02:00:00:00:01:51"; staticIp = "192.168.1.51"; }; + }; + localDomainOverrides = { + "router.${localDomain}" = "192.168.1.1"; # FIXME ping router on separate host returns 127.0.0.2 + "poweredge.${localDomain}" = "192.168.1.10"; + }; +in { + imports = [ ../poweredge-pro/dns-overrides.nix ]; # Import dns overrides from poweredge pro for use with tun + services._router.dnsDhcpConfig = { + inherit dhcp; + localResolution = { + inherit localDomain localDomainOverrides; + }; + }; + networking.hosts."192.168.1.1" = [ "router.${localDomain}" "router" ]; +} diff --git a/hosts/poweredge/slskd.nix b/hosts/poweredge/slskd.nix new file mode 100644 index 0000000..542757f --- /dev/null +++ b/hosts/poweredge/slskd.nix @@ -0,0 +1,91 @@ +{ config, ... }: { + # Secrets + sops.secrets.slskd-env = { sopsFile = ./resources/secrets/slskd.yaml; key = "env-file"; }; + + # Container + containers.slskd = let + home = "/var/lib/slskd"; + download-dir = "${home}/complete"; + incomplete-dir = "${home}/incomplete"; + in { + autoStart = true; + privateNetwork = true; + hostBridge = "br-lan0"; + localMacAddress = "02:00:00:00:01:51"; + + # Download dirs, shared with transmission's media tree, plus a + # read-only mount of the whole library for Soulseek sharing + bindMounts = { + "${download-dir}" = { + hostPath = "/media/ingens/media/dls/slskd/complete"; + isReadOnly = false; + }; + "${incomplete-dir}" = { + hostPath = "/media/ingens/media/dls/slskd/incomplete"; + isReadOnly = false; + }; + "/srv" = { + hostPath = "/media/ingens/media/dls/slskd/srv"; + isReadOnly = false; + }; + "/media/ingens/media" = { + hostPath = "/media/ingens/media"; + isReadOnly = true; + }; + }; + + # Bind secrets + bindMounts."/run/secrets/slskd.env" = { + hostPath = config.sops.secrets.slskd-env.path; + isReadOnly = true; + }; + + config = { lib, config, pkgs, ... }: { + # Network + networking = { + enableIPv6 = false; # Prevent ip leaks + firewall.allowedTCPPorts = [ 80 50300 ]; # Web ui + soulseek listen port tcp + firewall.allowedUDPPorts = [ 50300 ]; # soulseek listen port udp + # DHCP (see transmission.nix) + interfaces.eth0.useDHCP = true; + dhcpcd.extraConfig = '' + interface eth0 + static routers=192.168.1.9 + static domain_name_servers=9.9.9.9 1.1.1.1 + ''; + }; + + # slskd + services.slskd = { + enable = true; + environmentFile = "/run/secrets/slskd.env"; + settings = { + directories = { + downloads = download-dir; + incomplete = incomplete-dir; + }; + shares.directories = [ "/srv" ]; + transfers = { + upload.slots = 5; + upload.speed_limit = 0; + download.slots = 5; + download.speed_limit = 0; + }; + flags.no_version_check = true; + }; + }; + + users.users.slskd.uid = 1000; # uid is not set otherwise + + # Reverse proxy + services.caddy = { + enable = true; + virtualHosts.":80".extraConfig = '' + reverse_proxy localhost:5030 + ''; + }; + + system.stateVersion = "26.05"; + }; + }; +} diff --git a/hosts/poweredge/transmission.nix b/hosts/poweredge/transmission.nix new file mode 100644 index 0000000..047a3ab --- /dev/null +++ b/hosts/poweredge/transmission.nix @@ -0,0 +1,75 @@ +{ + # Container + containers.transmission = let + home = "/var/lib/transmission"; + download-dir = "${home}/Downloads"; + incomplete-dir = "${home}/.incomplete"; + in { + autoStart = true; + privateNetwork = true; + hostBridge = "br-lan0"; + localMacAddress = "02:00:00:00:01:47"; + + # Download dirs + bindMounts = { + "${download-dir}" = { + hostPath = "/media/ingens/media/dls/transmission/complete"; + isReadOnly = false; + }; + "${incomplete-dir}" = { + hostPath = "/media/ingens/media/dls/transmission/incomplete"; + isReadOnly = false; + }; + "/media/ingens/media" = { + hostPath = "/media/ingens/media"; + isReadOnly = false; + }; + }; + + config = { lib, ... }: { + # Network + networking = { + enableIPv6 = false; # Prevent ip leaks + firewall.allowedTCPPorts = [ 80 51413 ]; # RPC interface + transmission tcp + firewall.allowedUDPPorts = [ 51413 ]; # transmission udp + # Override dhcp server settings for default route and dns servers with static settings + interfaces.eth0.useDHCP = true; + dhcpcd.extraConfig = '' + interface eth0 + static routers=192.168.1.9 + static domain_name_servers=9.9.9.9 1.1.1.1 + ''; + #defaultGateway = "192.168.1.9"; # Doesn't work, see above + #nameservers = [ "9.9.9.9" "1.1.1.1" ]; # Does work, above prevents using dhcp default nameserver + }; + + # Transmission + services.transmission = { + inherit home; + enable = true; + user = "transmission"; + + settings = { + inherit download-dir incomplete-dir; + downloadDirPermissions = "775"; + }; + }; + + # TODO remove (#258793) + systemd.services.transmission.serviceConfig = { + RootDirectoryStartOnly = lib.mkForce null; + RootDirectory = lib.mkForce null; + }; + + # Reverse proxy + services.caddy = { + enable = true; + virtualHosts.":80".extraConfig = '' + reverse_proxy localhost:9091 + ''; + }; + + system.stateVersion = "26.05"; + }; + }; +} diff --git a/hosts/poweredge/vpn-router.nix b/hosts/poweredge/vpn-router.nix new file mode 100644 index 0000000..ac7ce16 --- /dev/null +++ b/hosts/poweredge/vpn-router.nix @@ -0,0 +1,121 @@ +{ lib, config, pkgs, ... }: { + # Secrets + sops.secrets.vpn-router-ovpn-config = { sopsFile = ./resources/secrets/vpn-router.yaml; key = "ovpn-config"; }; + sops.secrets.vpn-router-ovpn-auth = { sopsFile = ./resources/secrets/vpn-router.yaml; key = "ovpn-auth"; }; + + # Container + containers.vpn-router = { + autoStart = true; + privateNetwork = true; + enableTun = true; # OpenVPN requires + hostBridge = "br-lan0"; + localMacAddress = "02:00:00:00:01:09"; + + # Bind secrets + bindMounts = { + "/run/secrets/ovpn-config.ovpn" = { + hostPath = config.sops.secrets.vpn-router-ovpn-config.path; + isReadOnly = true; + }; + "/run/secrets/ovpn-auth" = { + hostPath = config.sops.secrets.vpn-router-ovpn-auth.path; + isReadOnly = true; + }; + }; + + config = { lib, pkgs, ... }: { + + # Networking + networking = { + enableIPv6 = false; # Prevent ip leaks + interfaces.eth0.useDHCP = true; + }; + + # Router config + # This container acts as a router that clients can connect to via default + # route. All traffic is forwarded over the VPN tunnel instead of WAN. + # This allows multiple containers to share the same VPN connection. + boot.kernel.sysctl."net.ipv4.ip_forward" = 1; # Enable IPv4 forwarding + networking.nat = { + enable = true; + externalInterface = "tun0"; + internalInterfaces = [ "eth0" ]; + # Forward ports over VPN + forwardPorts = [ + { sourcePort = 51413; proto = "tcp"; destination = "192.168.1.47:51413"; } # Transmission TCP + { sourcePort = 51413; proto = "udp"; destination = "192.168.1.47:51413"; } # Transmission UDP + { sourcePort = 50300; proto = "tcp"; destination = "192.168.1.51:50300"; } # Slskd TCP + { sourcePort = 50300; proto = "udp"; destination = "192.168.1.51:50300"; } # Slskd UDP + ]; + }; + + # OpenVPN + services.openvpn.servers.main = { + config = '' + config /run/secrets/ovpn-config.ovpn + auth-user-pass /run/secrets/ovpn-auth + + # The server pushes tun-mtu 1500. A full 1500 byte packet plus + # AES-256-GCM/UDP/IP encapsulation (~52 bytes) is ~1552 on the wire, + # so it has to be IP fragmented to cross a 1500 byte path -- and the + # fragments get dropped upstream, blackholing every full size packet + # while small ones (dns, tcp handshakes) still pass. Clamp the TCP MSS + # so the encapsulated datagram never exceeds this, in both directions. + # Must come after the `config` include above so it wins. + #mssfix 1400 + ''; + autoStart = true; + updateResolvConf = true; + }; + + # VPN "killswitch", split across two chains: + networking.firewall.extraCommands = '' + # Get domain name host and port from ovpn config + SERVER_HOST=$(${pkgs.gawk}/bin/awk '/^remote /{print $2;exit}' /run/secrets/ovpn-config.ovpn) + SERVER_PORT=$(${pkgs.gawk}/bin/awk '/^remote /{print $3;exit}' /run/secrets/ovpn-config.ovpn) + [ -n "$SERVER_PORT" ] || SERVER_PORT=1194 + + # Router's own traffic: only lo, tun0, and established connections + ${pkgs.iptables}/bin/iptables -P OUTPUT DROP + ${pkgs.iptables}/bin/iptables -A OUTPUT -o lo -j ACCEPT + ${pkgs.iptables}/bin/iptables -A OUTPUT -o tun0 -j ACCEPT + ${pkgs.iptables}/bin/iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT + + # Get dns ip from resolv.conf + DNS_IP=$(${pkgs.gawk}/bin/awk '/^nameserver /{ if ($2 !~ /:/) { print $2; exit } }' /etc/resolv.conf) + + # Allow dns + ${pkgs.iptables}/bin/iptables -A OUTPUT -o eth0 -p udp -d "$DNS_IP" --dport 53 -j ACCEPT + ${pkgs.iptables}/bin/iptables -A OUTPUT -o eth0 -p tcp -d "$DNS_IP" --dport 53 -j ACCEPT + + # Resolve server ips from host + SERVER_IPS="" + ATTEMPT=0 + while [ -z "$SERVER_IPS" ] && [ "$ATTEMPT" -lt 10 ]; do + ATTEMPT=$((ATTEMPT + 1)) + SERVER_IPS=$(${pkgs.getent}/bin/getent ahostsv4 "$SERVER_HOST" 2>/dev/null | ${pkgs.gawk}/bin/awk '/STREAM/{print $1}') + [ -n "$SERVER_IPS" ] || sleep 3 + done + + # Die if no ips are resolved + if [ -z "$SERVER_IPS" ]; then + echo "killswitch: could not resolve '$SERVER_HOST' after $ATTEMPT attempts, failing closed with no vpn egress" + exit 1 + fi + + # Allow udp traffic to each vpn server ip (for openvpn udp tunnels only, strictly better than tcp) + for SERVER_IP in $SERVER_IPS; do + echo "killswitch: allowing $SERVER_IP:$SERVER_PORT/udp ($SERVER_HOST)" + ${pkgs.iptables}/bin/iptables -A OUTPUT -p udp -d "$SERVER_IP" --dport "$SERVER_PORT" -j ACCEPT + done + + # Anything forwarded through this router: only allowed to reach tun0 + ${pkgs.iptables}/bin/iptables -P FORWARD DROP + ${pkgs.iptables}/bin/iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT + ${pkgs.iptables}/bin/iptables -A FORWARD -i eth0 -o tun0 -j ACCEPT + ''; + + system.stateVersion = "26.05"; + }; + }; +} diff --git a/hosts/sweetiepc/configuration.nix b/hosts/sweetiepc/configuration.nix new file mode 100644 index 0000000..7bf5fcb --- /dev/null +++ b/hosts/sweetiepc/configuration.nix @@ -0,0 +1,51 @@ +{ config, lib, pkgs, home-manager, ... }: { + #imports = [ ./wg.nix ]; + + # Setup bootloader + boot._loader = { + enable = true; + loader = "grub"; + }; + + # Enable common options + _archetypes = { + profiles = { + desktop = { + enable = true; + home.users.timmy.enable = true; + }; + zfs.enable = true; + btrfs.enable = true; + gnome.enable = true; + }; + collections = { + desktop = { + office.enable = true; + }; + }; + }; + + # Import zfs pools + boot.zfs.extraPools = [ "geminus" "quattuor" ]; + + # Enable user timmy + _users.timmy = { + enable = true; + }; + + # Disable suspend + systemd._suspend.disable = true; + + # Configure home + home-manager.users.timmy = { + fonts.fontconfig = { + subpixelRendering = "rgb"; + hinting = "none"; + }; + }; + + # Without this, "ZFS requires networking.hostId to be set" will be raised + networking.hostId = "fdde503a"; + + system.stateVersion = "26.05"; +} diff --git a/hosts/sweetiepc/hardware-configuration.nix b/hosts/sweetiepc/hardware-configuration.nix new file mode 100644 index 0000000..5ed162c --- /dev/null +++ b/hosts/sweetiepc/hardware-configuration.nix @@ -0,0 +1,38 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "ehci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/91572803-436d-4f43-b41f-dfba2103752e"; + fsType = "btrfs"; + options = [ "subvol=@" ]; + }; + + fileSystems."/home" = + { device = "/dev/disk/by-uuid/91572803-436d-4f43-b41f-dfba2103752e"; + fsType = "btrfs"; + options = [ "subvol=@home" ]; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/F618-D6C2"; + fsType = "vfat"; + options = [ "fmask=0022" "dmask=0022" ]; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/sweetiepc/resources/secrets/wg.yaml b/hosts/sweetiepc/resources/secrets/wg.yaml new file mode 100644 index 0000000..9edaea5 --- /dev/null +++ b/hosts/sweetiepc/resources/secrets/wg.yaml @@ -0,0 +1,16 @@ +wg0: ENC[AES256_GCM,data:xow2iL5l7MqlUeCZ2e9R4ygKlK3+ZP2yIR73aHWiIaO24aF02I88cWajOvs44/CP2tTHJLM6OltN/rKr3+4DLCbhOrngl/uFyWv/Xva4n9ZCWBv0DgtQ0Qbk/Bi6Q+h3Uf7XXlOtsUNvzSXvW4L+EcwsTMQRU5CIpSHcIsyG/IsQ1ypHpzDPM8j3HHtoPp6zaYPpQiELoMIIuIjvnvjTAAEWYMPuiV4OgJy2kiAUFkEwDud3MV/e/D/q861lKSz5qiKWnxE/So9kmA4HaSw9EOi46EcFojat7r3LiludcMify4V+IliVs7LPYf8kaHSOPWdmd8cgDeYP3Np0ydhB2+2xSbRLCgZvJWuxkStbeNjA5sC3tAmA86I+axhjVGRD9NdbpksdDORBMJhx2iWVhBBvM5p/Ya0f5nXHlsLw4MLSCKOZlTf9OM5YlYGw/GA30nJbcOVx1TzK+BJ0cYsz7U4YJWEMHTEPIQ==,iv:TM0Csdn65smwseVzq36IJAcapEZx+yjhRyG3Atz2Jk0=,tag:A6wWrO8PJAPFaI2IFq5Ucw==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlS0pyVGtTekV0MXQ5WHYy + MlRZYnVVaXdKVDlGNlZOekxUWng4NUlWTXlBCnBzbzNwUWtTdExBUXpCNy83YStm + Y0xvTlo5bkczS2xSdUtjenNjQlhDNlkKLS0tIGd6RjlZWGtZNVpXeVNpd0EyTk5h + cWN0b0dXQjNwNFZjdXdiUDZCUDZETkkKJlDzHxpRHbh4+LPEaWjrmiFFGMOL4Hdi + lMhSrn/EmMmf6p82FVpWMfr7fEFc9lCRw1VytKNUc1Le3nIpkM8iJQ== + -----END AGE ENCRYPTED FILE----- + recipient: age1fl4rk54n2xv4vssjkw4nywy93s4yqv69uzq2f64zuwd8fjq5u4cq9wmmsw + lastmodified: "2026-06-22T19:17:43Z" + mac: ENC[AES256_GCM,data:o+p9xd02QZ9VcUwiAMAGExf5FBrDaKCkOen58d1zTzZuiH2Svcmg5xrA+N23XuEi9kVTcqby9fpymgTOlwNZn8JbmMYjLLiykBIWQvOPKNjAGzp2A9KFA1DpIzTegM+xXbnKv+FEZdRagAojkAUftUUzQYAUsmQVDnflzwNsSUI=,iv:s0oM+TgNNUgNZQ99Pb33UCUbhdZJ93Dv1X+GK6oFUwo=,tag:306d418MjlEZnPi6L2qd/g==,type:str] + unencrypted_suffix: _unencrypted + version: 3.13.1 diff --git a/hosts/sweetiepc/wg.nix b/hosts/sweetiepc/wg.nix new file mode 100644 index 0000000..bf459d9 --- /dev/null +++ b/hosts/sweetiepc/wg.nix @@ -0,0 +1,7 @@ +{ config, pkgs, inputs, ... }: { + sops.secrets.wg0 = { sopsFile = ./resources/secrets/wg.yaml; key = "wg0"; }; + + networking.wg-quick.interfaces = { + wg0.configFile = config.sops.secrets.wg0.path; + }; +} |
