summaryrefslogtreecommitdiffstats
path: root/hosts/poweredge-pro
diff options
context:
space:
mode:
Diffstat (limited to 'hosts/poweredge-pro')
-rw-r--r--hosts/poweredge-pro/cgit.nix105
-rw-r--r--hosts/poweredge-pro/configuration.nix62
-rw-r--r--hosts/poweredge-pro/dhcp-hosts.nix29
-rw-r--r--hosts/poweredge-pro/dns-overrides.nix12
-rw-r--r--hosts/poweredge-pro/dns.nix57
-rw-r--r--hosts/poweredge-pro/embedtube.nix43
-rw-r--r--hosts/poweredge-pro/filebrowser.nix55
-rw-r--r--hosts/poweredge-pro/fileshares.nix92
-rw-r--r--hosts/poweredge-pro/hardware-configuration.nix50
-rw-r--r--hosts/poweredge-pro/key.nix23
-rw-r--r--hosts/poweredge-pro/networking.nix32
-rw-r--r--hosts/poweredge-pro/resources/openssh/zfsbackup/truenas-10.0.0.9-rsa.pub1
-rw-r--r--hosts/poweredge-pro/resources/secrets/embedtube.yaml16
-rw-r--r--hosts/poweredge-pro/resources/secrets/initial-pass.yaml17
-rw-r--r--hosts/poweredge-pro/resources/secrets/zfs-key.yaml16
-rw-r--r--hosts/poweredge-pro/searxng.nix179
16 files changed, 789 insertions, 0 deletions
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";
+ };
+ };
+}