diff --git a/AGENTS.md b/AGENTS.md index ba27fd69..c9ec41b4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -53,16 +53,16 @@ treefmt-nix). Enforced via `nix flake check` in `just check`. ## Architecture -- `nix/` — flake-parts with its entrypoint in `nix/flake/`. Hosts live in - `nix/hosts/.nix` and set `flake.nixosConfigurations.`. Hosts - import the wholesale `self.nixosModules.myNixOs` and, where needed, - `self.nixosModules.myHw` collections. Features are opt-in under - `myNixOs.profile.*`, `myNixOs.program.*`, `myNixOs.service.*`, and - `myHw..` (for example, - `myHw.intel.gpu.enable = true`). Disk profiles live in `nix/disko.nix`. - k3s node config is in - `nix/nixos/profiles/k3s.nix` (flannel on the configured transport interface; - startup blocks until that interface has an IP). +- `nix/modules/` — dendritic flake-parts tree loaded wholesale by import-tree. + Shared NixOS files contribute directly to `flake.nixosModules.default` or a + named deferred module. Hosts live in `nix/modules/hosts/nixos//`: + topical sibling files contribute to `flake.nixosModules.`, while + `default.nix` constructs `config.flake.nixosConfigurations.` from the + shared, named, and host deferred modules. Importing a named deferred module + activates it; `myNixOs.*` and `myDisko.*` options only parameterize imported + modules. Disko modules live in `nix/modules/disko/`. k3s node config is in + `nix/modules/nixos/profiles/k3s.nix` (flannel on the configured transport + interface; startup blocks until that interface has an IP). - `k8s/` — `flux/` is the ordered release graph. `flux/system/layers.yaml` defines the Flux Kustomization DAG; `flux/*/*.yaml` hold HelmReleases; `flux/secrets/*.sops.yaml` are first-class Kubernetes Secrets decrypted by diff --git a/README.md b/README.md index 931d1d52..9609943f 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,7 @@ This repository contains NixOS, K8s, and Ansible configurations, along with what . ├── flake.nix # Flake entry point ├── nix/ # NixOS + flake modules -│ ├── hosts/ # NixOS host configurations -│ └── modules/ # NixOS / flake modules +│ └── modules/ # Dendritic flake, NixOS, Disko, and host modules ├── k8s/ # k3s: Flux + in-tree Helm charts │ ├── flux/ # GitOps release graph (Flux Kustomizations/HelmReleases) │ ├── charts/ # In-tree helm charts (see k8s/charts/README.md) diff --git a/flake.nix b/flake.nix index bd57593c..7a03dbc3 100644 --- a/flake.nix +++ b/flake.nix @@ -69,7 +69,7 @@ systems = ["aarch64-darwin" "x86_64-linux"]; imports = [ - (inputs.import-tree ./nix/flake) + (inputs.import-tree ./nix/modules) inputs.files.flakeModules.default inputs.flake-parts.flakeModules.modules inputs.blzrd.flakeModule diff --git a/nix/disko.nix b/nix/disko.nix deleted file mode 100644 index 911d8c10..00000000 --- a/nix/disko.nix +++ /dev/null @@ -1,24 +0,0 @@ -{inputs, ...}: let - myDisko = inputs.import-tree ./disko; -in { - flake.diskoConfigurations = { - btrfs-subvolumes = { - imports = [myDisko]; - myDisko.installDrive = "/dev/nvme0n1"; - myDisko.profile.btrfsSubvolumes.enable = true; - }; - - luks-btrfs-subvolumes = { - imports = [myDisko]; - myDisko.installDrive = "/dev/nvme0n1"; - myDisko.profile.luksBtrfsSubvolumes.enable = true; - }; - - lvm-ext4 = { - imports = [myDisko]; - myDisko.profile.lvmExt4.enable = true; - }; - }; - - flake.nixosModules.myDisko = myDisko; -} diff --git a/nix/disko/default.nix b/nix/disko/default.nix deleted file mode 100644 index bf0a0c7b..00000000 --- a/nix/disko/default.nix +++ /dev/null @@ -1,7 +0,0 @@ -{lib, ...}: { - options.myDisko.installDrive = lib.mkOption { - description = "Disk to install NixOS to."; - default = "/dev/sda"; - type = lib.types.str; - }; -} diff --git a/nix/flake/default.nix b/nix/flake/default.nix deleted file mode 100644 index f88f07d7..00000000 --- a/nix/flake/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - imports = [ - ../deployments.nix - ../devShells.nix - ../disko.nix - ../files/zed.nix - ../hosts/eterna - ../hosts/jubilife - ../hosts/pastoria - ../hosts/snowpoint - ../nixos.nix - ../overlays.nix - ../packages.nix - ../treefmt.nix - ]; -} diff --git a/nix/hosts/eterna/base.nix b/nix/hosts/eterna/base.nix deleted file mode 100644 index be45ebae..00000000 --- a/nix/hosts/eterna/base.nix +++ /dev/null @@ -1,45 +0,0 @@ -{pkgs, ...}: { - environment.sessionVariables.LIBVA_DRIVER_NAME = "iHD"; - - hardware = { - facter.detected.graphics.enable = true; - intel-gpu-tools.enable = true; - - graphics.extraPackages = [ - (pkgs.intel-vaapi-driver.override {enableHybridCodec = true;}) - pkgs.intel-compute-runtime - pkgs.intel-media-driver - ]; - }; - - services = { - k3s.extraFlags = ["--node-label=cute.haus/intel-gpu=true"]; - xserver.videoDrivers = ["modesetting"]; - }; - - myNixOs = { - profile = { - base.enable = true; - backups.enable = true; - btrfs.enable = true; - dataShare.enable = true; - k3s.enable = false; - localeEnUs.enable = true; - swap.enable = true; - wireguardK3s.enable = true; - }; - program = { - lanzaboote.enable = true; - docker.enable = true; - }; - service = { - alloy.enable = true; - caddy.enable = true; - fail2ban.enable = true; - prometheusNode.enable = true; - syncthing.enable = true; - tailscale.enable = true; - }; - users.aly.enable = true; - }; -} diff --git a/nix/hosts/eterna/configuration.nix b/nix/hosts/eterna/configuration.nix deleted file mode 100644 index fd316d0a..00000000 --- a/nix/hosts/eterna/configuration.nix +++ /dev/null @@ -1,180 +0,0 @@ -{ - inputs, - self, - ... -}: [ - self.nixosModules.myNixOs - - { - hardware.facter.reportPath = ./facter.json; - } - - ./base.nix - - inputs.disko.nixosModules.disko - inputs.sops-nix.nixosModules.sops - ( - {config, ...}: { - fileSystems."/mnt/Storage" = { - device = "/dev/disk/by-id/ata-CT2000BX500SSD1_2345E8842829"; - fsType = "btrfs"; - options = ["compress=zstd" "noatime" "nofail"]; - }; - - networking = { - firewall = { - enable = true; - allowedTCPPorts = [2049]; - allowedUDPPorts = [2049]; - }; - - hostName = "eterna"; - }; - - services.nfs.server = { - enable = true; - - exports = '' - /mnt/Storage 100.64.0.0/10(rw,sync,no_subtree_check,no_root_squash,fsid=0) - ''; - }; - - system = { - autoUpgrade.dates = "05:00"; - stateVersion = "25.11"; - }; - - myNixOs = { - profile = { - backups.jobs = { - syncthing-sync = { - paths = ["/home/aly/sync"]; - repository = "rclone:b2:aly-backups/syncthing/sync"; - }; - - syncthing-roms = { - paths = [config.myNixOs.service.syncthing.romsPath]; - repository = "rclone:b2:aly-backups/syncthing/roms"; - }; - }; - - k3s = { - role = "agent"; - serverAddr = "https://pastoria.cute:6443"; - transportInterface = "wg-k3s"; - nodeIP = "10.254.0.4"; - zone = "home"; - ingress = true; - }; - }; - - service.syncthing = { - certFile = config.sops.secrets.syncthingCert.path; - keyFile = config.sops.secrets.syncthingKey.path; - user = "aly"; - }; - - users.aly.password = "$6$JTk2qi27OpA2fOAY$ZgTDg0wbmbwHUD..0xT4xYX.AR5hWQFCMVmn8G88yi3IAY7015AupovTpfy0arkI7nl/IDu5L09bzLKeXGvJC1"; - }; - - sops.secrets = { - syncthingCert = { - sopsFile = "${self}/secrets/syncthing.yaml"; - key = "eterna_cert"; - }; - syncthingKey = { - sopsFile = "${self}/secrets/syncthing.yaml"; - key = "eterna_key"; - }; - }; - } - ) - - # disk layout - { - disko.devices = { - disk = { - vdb = { - type = "disk"; - device = "/dev/sda"; - - content = { - type = "gpt"; - - partitions = { - ESP = { - content = { - format = "vfat"; - - mountOptions = [ - "defaults" - "umask=0077" - ]; - - mountpoint = "/boot"; - type = "filesystem"; - }; - - size = "1024M"; - type = "EF00"; - }; - - luks = { - size = "100%"; - - content = { - type = "luks"; - name = "crypted"; - - content = { - type = "btrfs"; - extraArgs = ["-f"]; - - subvolumes = { - "/root" = { - mountOptions = ["compress=zstd" "noatime"]; - mountpoint = "/"; - }; - - "persist" = { - mountOptions = ["compress=zstd" "noatime"]; - mountpoint = "/persist"; - }; - - "/home" = { - mountOptions = ["compress=zstd" "noatime"]; - mountpoint = "/home"; - }; - - "/home/.snapshots" = { - mountOptions = ["compress=zstd" "noatime"]; - mountpoint = "/home/.snapshots"; - }; - - "/nix" = { - mountOptions = ["compress=zstd" "noatime"]; - mountpoint = "/nix"; - }; - }; - }; - }; - }; - }; - }; - }; - }; - }; - } - - # services - { - services.caddy.email = "alyraffauf@fastmail.com"; - } - - { - nixpkgs = { - overlays = [self.overlays.default]; - config.allowUnfree = true; - }; - } -] diff --git a/nix/hosts/eterna/default.nix b/nix/hosts/eterna/default.nix deleted file mode 100644 index 7358b24e..00000000 --- a/nix/hosts/eterna/default.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ - inputs, - self, - ... -}: { - flake.nixosConfigurations.eterna = inputs.nixpkgs.lib.nixosSystem { - specialArgs = {inherit inputs self;}; - modules = import ./configuration.nix {inherit inputs self;}; - }; -} diff --git a/nix/hosts/jubilife/base.nix b/nix/hosts/jubilife/base.nix deleted file mode 100644 index dfaa1b36..00000000 --- a/nix/hosts/jubilife/base.nix +++ /dev/null @@ -1,51 +0,0 @@ -{pkgs, ...}: { - environment.sessionVariables.LIBVA_DRIVER_NAME = "iHD"; - - hardware = { - facter.detected.graphics.enable = true; - intel-gpu-tools.enable = true; - - graphics.extraPackages = [ - (pkgs.intel-vaapi-driver.override {enableHybridCodec = true;}) - pkgs.intel-compute-runtime - pkgs.intel-media-driver - ]; - }; - - services = { - k3s.extraFlags = ["--node-label=cute.haus/intel-gpu=true"]; - xserver.videoDrivers = ["modesetting"]; - }; - - myNixOs = { - profile = { - arr.enable = true; - b2Mounts.enable = true; - backups.enable = true; - base.enable = true; - btrfs.enable = true; - k3s.enable = true; - localeEnUs.enable = true; - swap.enable = true; - wireguardK3s.enable = true; - }; - program = { - lanzaboote.enable = true; - docker.enable = true; - }; - service = { - alloy.enable = true; - atbbs.enable = true; - caddy.enable = true; - fail2ban.enable = true; - prometheusNode.enable = true; - qbittorrent.enable = true; - syncthing.enable = true; - tailscale.enable = true; - tautulli.enable = true; - }; - users.aly.enable = true; - }; - - myDisko.profile.luksBtrfsSubvolumes.enable = true; -} diff --git a/nix/hosts/jubilife/configuration.nix b/nix/hosts/jubilife/configuration.nix deleted file mode 100644 index 6ec99a44..00000000 --- a/nix/hosts/jubilife/configuration.nix +++ /dev/null @@ -1,401 +0,0 @@ -{ - inputs, - self, - ... -}: let - lib = inputs.nixpkgs.lib; - tnet = "narwhal-snapper.ts.net"; - dataDirectory = "/mnt/Data"; - k3sPodCidr = "10.42.0.0/16"; - exportarrServices = { - bazarr = { - apiKey = "bazarr_api_key"; - port = 9708; - }; - lidarr = { - apiKey = "lidarr_api_key"; - port = 9709; - }; - prowlarr = { - apiKey = "prowlarr_api_key"; - port = 9710; - }; - radarr = { - apiKey = "radarr_api_key"; - port = 9711; - }; - sonarr = { - apiKey = "sonarr_api_key"; - port = 9712; - }; - }; -in [ - self.nixosModules.myNixOs - self.nixosModules.myDisko - - { - hardware.facter.reportPath = ./facter.json; - } - - ./base.nix - - inputs.disko.nixosModules.disko - inputs.sops-nix.nixosModules.sops - ./containers.nix - ( - { - config, - pkgs, - ... - }: { - boot.kernelModules = ["sg"]; - - environment.systemPackages = with pkgs; [ - abcde - age - chezmoi - claude-code - codex - curl - delta - eza - ffmpeg-full - flac - fzf - gh - handbrake - lazygit - mediainfo - mkvtoolnix - opencode - rclone - restic - ripgrep - starship - zoxide - ]; - - fileSystems = { - "/mnt/Data" = { - device = "/dev/disk/by-id/ata-CT4000BX500SSD1_2447E9959972"; - fsType = "btrfs"; - options = ["compress=zstd" "noatime" "nofail"]; - }; - - "/mnt/Media" = { - device = "/dev/disk/by-id/ata-ST14000NM001G-2KJ103_ZL201XNJ-part1"; - fsType = "btrfs"; - options = ["subvol=@media" "compress=zstd" "noatime" "nofail"]; - }; - }; - - networking = { - firewall.allowedTCPPorts = [2342 5143 6881]; - hostName = "jubilife"; - }; - - system.stateVersion = "25.11"; - system.autoUpgrade.dates = "04:15"; - - myDisko = { - installDrive = "/dev/disk/by-id/nvme-PNY_CS2130_1TB_SSD_PNY211821050701050CC"; - }; - - myNixOs = { - profile = { - arr.dataDir = "/mnt/Data"; - - b2Mounts = { - cacheDir = "/mnt/Data/.rclone-cache"; - audioCacheSize = "50G"; - audioReadAhead = "3G"; - videoCacheSize = "300G"; - videoReadAhead = "5G"; - }; - - k3s = { - role = "server"; - clusterInit = true; - transportInterface = "wg-k3s"; - nodeIP = "10.254.0.1"; - zone = "home"; - }; - }; - - service.syncthing = { - certFile = config.sops.secrets.syncthingCert.path; - keyFile = config.sops.secrets.syncthingKey.path; - romsPath = "${dataDirectory}/syncthing/ROMs"; - syncROMs = true; - user = "aly"; - }; - - users.aly.password = "$6$JTk2qi27OpA2fOAY$ZgTDg0wbmbwHUD..0xT4xYX.AR5hWQFCMVmn8G88yi3IAY7015AupovTpfy0arkI7nl/IDu5L09bzLKeXGvJC1"; - }; - - sops.secrets = { - garageNextcloudAccessKey = { - sopsFile = "${self}/secrets/garage.yaml"; - key = "nextcloud_access_key"; - owner = "garage"; - group = "garage"; - }; - garageNextcloudSecretKey = { - sopsFile = "${self}/secrets/garage.yaml"; - key = "nextcloud_secret_key"; - owner = "garage"; - group = "garage"; - }; - garageRpcSecret = { - sopsFile = "${self}/secrets/garage.yaml"; - key = "rpc_secret"; - owner = "garage"; - group = "garage"; - }; - syncthingCert = { - sopsFile = "${self}/secrets/syncthing.yaml"; - key = "jubilife_cert"; - }; - syncthingKey = { - sopsFile = "${self}/secrets/syncthing.yaml"; - key = "jubilife_key"; - }; - }; - - sops.templates = { - garage-config = { - owner = "garage"; - group = "garage"; - mode = "0400"; - content = '' - metadata_dir = "${dataDirectory}/garage/meta" - data_dir = "${dataDirectory}/garage/data" - db_engine = "sqlite" - replication_factor = 1 - rpc_bind_addr = "[::]:3901" - rpc_public_addr = "10.254.0.1:3901" - rpc_secret = "${config.sops.placeholder.garageRpcSecret}" - - [s3_api] - api_bind_addr = "10.254.0.1:3900" - s3_region = "garage" - ''; - }; - - garage-environment = { - owner = "garage"; - group = "garage"; - mode = "0400"; - content = '' - GARAGE_CONFIG_FILE=${config.sops.templates.garage-config.path} - GARAGE_DEFAULT_ACCESS_KEY=${config.sops.placeholder.garageNextcloudAccessKey} - GARAGE_DEFAULT_SECRET_KEY=${config.sops.placeholder.garageNextcloudSecretKey} - GARAGE_DEFAULT_BUCKET=aly-nextcloud - ''; - }; - }; - - users = { - groups.garage = {}; - users.garage = { - isSystemUser = true; - group = "garage"; - }; - }; - - services.garage = { - enable = true; - package = pkgs.garage_2; - environmentFile = config.sops.templates.garage-environment.path; - settings = { - metadata_dir = "${dataDirectory}/garage/meta"; - data_dir = "${dataDirectory}/garage/data"; - }; - }; - - systemd.services.garage = { - after = ["mnt-Data.mount"]; - requires = ["mnt-Data.mount"]; - serviceConfig = { - DynamicUser = false; - User = "garage"; - Group = "garage"; - }; - }; - } - ) - - # prometheus exporters - ( - {config, ...}: { - sops.secrets = - lib.mapAttrs' ( - serviceName: service: { - name = "${serviceName}ApiKey"; - value = { - sopsFile = "${self}/secrets/arr.yaml"; - key = service.apiKey; - }; - } - ) - exportarrServices; - - services.prometheus.exporters = - (lib.mapAttrs' ( - serviceName: service: { - name = "exportarr-${serviceName}"; - value = { - enable = true; - apiKeyFile = config.sops.secrets."${serviceName}ApiKey".path; - inherit (service) port; - url = "https://${serviceName}.${tnet}"; - }; - } - ) - exportarrServices) - // {smartctl.enable = true;}; - } - ) - - # services - ( - {config, ...}: { - myNixOs = { - profile.backups.jobs = { - immich = { - paths = [ - "${dataDirectory}/immich/library" - "${dataDirectory}/immich/profile" - "${dataDirectory}/immich/upload" - "${dataDirectory}/immich/backups" - "${dataDirectory}/immich/postgres" - ]; - }; - - garage.paths = ["${dataDirectory}/garage"]; - nextcloud.paths = ["${dataDirectory}/nextcloud/html"]; - paperless.paths = ["${dataDirectory}/paperless"]; - - plex = { - exclude = ["${dataDirectory}/plex/Library/Application Support/Plex Media Server/Plug-in Support/Databases"]; - paths = ["${dataDirectory}/plex"]; - }; - }; - }; - - networking.firewall = { - allowedTCPPorts = - [6881] - ++ [ - # Plex (hostNetwork): PMS, Companion, HTTPS - 32400 - 8324 - 32443 - ]; - allowedUDPPorts = [ - # Plex (hostNetwork): DLNA + GDM auto-discovery - 1900 - 32410 - 32412 - 32413 - 32414 - ]; - extraInputRules = '' - -s ${k3sPodCidr} -p tcp --dport 3900 -j ACCEPT - -s ${k3sPodCidr} -p tcp --dport 2049 -j ACCEPT - -s ${k3sPodCidr} -p udp --dport 2049 -j ACCEPT - ''; - }; - - services = { - nfs.server = { - enable = true; - exports = '' - /mnt/Data 100.64.0.0/10(rw,sync,no_subtree_check,no_root_squash,fsid=0) ${k3sPodCidr}(rw,sync,no_subtree_check,no_root_squash,fsid=0) - /mnt/Media 100.64.0.0/10(rw,sync,no_subtree_check,no_root_squash,fsid=1) ${k3sPodCidr}(rw,sync,no_subtree_check,no_root_squash,fsid=1) - ''; - }; - - samba = { - enable = true; - openFirewall = true; - - settings = { - global = { - security = "user"; - "map to guest" = "Bad User"; - - # Protocol tuning - "server min protocol" = "SMB3"; - "server max protocol" = "SMB3_11"; - - # Performance options - "socket options" = "TCP_NODELAY IPTOS_LOWDELAY SO_RCVBUF=262144 SO_SNDBUF=262144"; - "use sendfile" = "no"; # Plex compatibility - "aio read size" = "1"; - "aio write size" = "1"; - "min receivefile size" = "131072"; # Bump slightly from 16K to 128K - "max xmit" = "65535"; # Samba's max recommended for best throughput - - # Locking & latency - "strict locking" = "no"; - "oplocks" = "yes"; - "level2 oplocks" = "yes"; - }; - - Data = { - "create mask" = "0755"; - "directory mask" = "0755"; - "force group" = "users"; - "force user" = "aly"; - "guest ok" = "yes"; - "read only" = "no"; - browseable = "yes"; - comment = "Data @ ${config.networking.hostName}"; - path = dataDirectory; - }; - - Media = { - "create mask" = "0755"; - "directory mask" = "0755"; - "force group" = "users"; - "force user" = "aly"; - "guest ok" = "yes"; - "read only" = "no"; - browseable = "yes"; - comment = "Media @ ${config.networking.hostName}"; - path = "/mnt/Media"; - }; - }; - }; - - samba-wsdd = { - enable = true; - openFirewall = true; - }; - - smartd.enable = true; - - snapper.configs.media = { - ALLOW_GROUPS = ["users"]; - FSTYPE = "btrfs"; - SUBVOLUME = "/mnt/Media"; - TIMELINE_CLEANUP = true; - TIMELINE_CREATE = true; - }; - - tuned = { - enable = true; - settings.dynamic_tuning = true; - }; - }; - } - ) - - { - nixpkgs = { - overlays = [self.overlays.default]; - config.allowUnfree = true; - }; - } -] diff --git a/nix/hosts/jubilife/containers.nix b/nix/hosts/jubilife/containers.nix deleted file mode 100644 index fe0db0f4..00000000 --- a/nix/hosts/jubilife/containers.nix +++ /dev/null @@ -1,229 +0,0 @@ -{ - config, - inputs, - pkgs, - ... -}: { - myNixOs.profile.backups.jobs.dizquetv.paths = ["/mnt/Data/dizquetv"]; - - systemd.tmpfiles.rules = [ - "z /mnt/Data 0755 root root - -" - "d /mnt/Data/dizquetv 0755 root root" - "d /mnt/Data/arm/home 0755 1000 1000 - -" - "d /mnt/Data/arm/config 0755 1000 1000 - -" - "d /mnt/Data/arm 0755 1000 1000 - -" - "d /mnt/Data/jellyfin 0700 1000 1000 - -" - "d /mnt/Data/plex 0755 1000 1000 - -" - "d /mnt/Data/garage 0750 garage garage - -" - "d /mnt/Data/garage/meta 0700 garage garage - -" - "d /mnt/Data/garage/data 0700 garage garage - -" - "d /mnt/Data/immich/ml-cache 0755 root root - -" - "d /mnt/Data/immich/postgres 0700 999 999 - -" - "d /mnt/Data/nextcloud/html 0750 33 33 - -" - "d /mnt/Data/paperless 0750 1000 1000 - -" - "d /mnt/Data/paperless/data 0750 1000 1000 - -" - "d /mnt/Data/paperless/consume 0750 1000 1000 - -" - "d /mnt/Data/paperless/media 0750 1000 1000 - -" - ]; - - sops.secrets = { - immichDbPassword = { - sopsFile = "${inputs.self}/k8s/flux/secrets/immich-env.sops.yaml"; - key = "data/DB_PASSWORD"; - }; - - immichConfigBase64 = { - sopsFile = "${inputs.self}/k8s/flux/secrets/immich-config.sops.yaml"; - key = "data/config.json"; - restartUnits = [ - "docker-immich.service" - ]; - }; - }; - - sops.templates = { - immich-postgres-environment.content = "POSTGRES_PASSWORD=${config.sops.placeholder.immichDbPassword}"; - immich-server-environment.content = "DB_PASSWORD=${config.sops.placeholder.immichDbPassword}"; - }; - - virtualisation.oci-containers.containers = { - dizquetv = { - image = "vexorian/dizquetv:latest@sha256:98a7bc11dc5d16732c06c779ac7fd843dc4254853203f2d9dd9293b099743ca1"; - ports = ["0.0.0.0:8000:8000"]; - volumes = [ - "/mnt/Data/dizquetv:/home/node/app/.dizquetv" - "/etc/localtime:/etc/localtime:ro" - ]; - }; - - plex = { - image = "docker.io/plexinc/pms-docker:1.43.3.10861-07dfddaeb@sha256:5bc1d13f48da6366f46aaf2a3ce1a6292897eadc1f8efcbbd7321d30e94f2ed4"; - devices = ["/dev/dri:/dev/dri"]; - - environment = { - ADVERTISE_IP = "https://plex.cute.haus:443"; - PLEX_GID = "1000"; - PLEX_UID = "1000"; - TZ = "America/New_York"; - }; - - extraOptions = [ - "--group-add=44" - "--memory=4g" - "--network=host" - ]; - - volumes = [ - "/mnt/Data/plex:/config" - "/mnt/Media:/mnt/Media:ro" - "/etc/localtime:/etc/localtime:ro" - "/mnt/Backblaze:/mnt/Backblaze:ro,rslave" - "${inputs.audnexus}:/config/Library/Application Support/Plex Media Server/Plug-ins/Audnexus.bundle:ro" - "${inputs.hama}:/config/Library/Application Support/Plex Media Server/Plug-ins/Hama.bundle:ro" - "${inputs.absolute}/Scanners:/config/Library/Application Support/Plex Media Server/Scanners:ro" - ]; - }; - - slingshot = { - image = "ghcr.io/alyraffauf/slingshot:latest@sha256:24d0777f1beedb946c4b2a06410a55cea75ff883430cc7629a18336207f212f7"; - - environment = { - SLINGSHOT_CACHE_DIR = "/cache"; - SLINGSHOT_IDENTITY_CACHE_DISK_DB = "2"; - SLINGSHOT_IDENTITY_CACHE_MEMORY_MB = "64"; - SLINGSHOT_JETSTREAM = "wss://jetstream1.us-east.bsky.network/subscribe"; - SLINGSHOT_RECORD_CACHE_DISK_DB = "4"; - SLINGSHOT_RECORD_CACHE_MEMORY_MB = "256"; - }; - - extraOptions = [ - "--cpus=2" - "--memory=2g" - "--tmpfs=/cache:rw,size=8g,uid=65532,gid=65532" - "--ulimit=nofile=8192:8192" - ]; - - ports = ["10.254.0.1:8765:8080"]; - }; - - immich-postgres = { - image = "ghcr.io/immich-app/postgres:17-vectorchord0.4.3-pgvector0.8.0@sha256:0baf4cde9b54d8d7dc6a6ad8d8c43c3c6b884f82e1c2a023d571414820e39336"; - networks = ["immich"]; - - environment = { - PGDATA = "/var/lib/postgresql/data/pgdata"; - POSTGRES_DB = "immich"; - POSTGRES_INITDB_ARGS = "--data-checksums"; - POSTGRES_USER = "immich"; - }; - - environmentFiles = [config.sops.templates.immich-postgres-environment.path]; - - extraOptions = [ - "--memory=3g" - "--shm-size=128m" - ]; - - volumes = ["/mnt/Data/immich/postgres:/var/lib/postgresql/data"]; - }; - - immich-machine-learning = { - image = "ghcr.io/immich-app/immich-machine-learning:v3.1.0-openvino@sha256:627dfaf9339037be132209784883f7be13c1deb6be799454797bf6f231331f5b"; - devices = ["/dev/dri:/dev/dri"]; - networks = ["immich"]; - environment.MACHINE_LEARNING_CACHE_FOLDER = "/cache"; - extraOptions = [ - "--memory=4g" - ]; - volumes = ["/mnt/Data/immich/ml-cache:/cache"]; - }; - - immich-valkey = { - image = "valkey/valkey:9-alpine@sha256:ee91f7a174ac4d6a6b0685b3a60e321f0a9dbbb691f9b0e285be2ba1d1be8328"; - networks = ["immich"]; - cmd = ["valkey-server" "--maxmemory" "1gb" "--maxmemory-policy" "volatile-lru"]; - }; - - immich = { - image = "ghcr.io/immich-app/immich-server:v3.1.0@sha256:b434cb9287eea1471c9974845914d4dd328c9c2d652e446ed4930f99944f0ceb"; - dependsOn = [ - "immich-postgres" - "immich-machine-learning" - "immich-valkey" - ]; - networks = ["immich"]; - environment = { - DB_DATABASE_NAME = "immich"; - DB_HOSTNAME = "immich-postgres"; - DB_PORT = "5432"; - DB_USERNAME = "immich"; - IMMICH_CONFIG_FILE = "/etc/immich/config.json"; - IMMICH_MACHINE_LEARNING_URL = "http://immich-machine-learning:3003"; - REDIS_DBINDEX = "4"; - REDIS_HOSTNAME = "immich-valkey"; - TZ = "America/New_York"; - }; - environmentFiles = [config.sops.templates.immich-server-environment.path]; - extraOptions = [ - "--memory=4g" - "--ulimit=nofile=8192:8192" - ]; - ports = ["10.254.0.1:2283:2283"]; - volumes = [ - "/mnt/Data/immich:/data" - "/run/immich/config.json:/etc/immich/config.json:ro" - ]; - }; - }; - - systemd.services = { - docker-network-immich = { - after = ["docker.service"]; - requires = ["docker.service"]; - - before = [ - "docker-immich-postgres.service" - "docker-immich-machine-learning.service" - "docker-immich-valkey.service" - "docker-immich.service" - ]; - - requiredBy = [ - "docker-immich-postgres.service" - "docker-immich-machine-learning.service" - "docker-immich-valkey.service" - "docker-immich.service" - ]; - - path = [pkgs.docker]; - script = "docker network inspect immich >/dev/null 2>&1 || docker network create immich"; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - }; - }; - - docker-dizquetv.unitConfig.RequiresMountsFor = ["/mnt/Data"]; - - docker-plex.unitConfig.RequiresMountsFor = [ - "/mnt/Data" - "/mnt/Media" - ]; - - docker-immich = { - preStart = '' - ${pkgs.coreutils}/bin/base64 --decode \ - < "${config.sops.secrets.immichConfigBase64.path}" \ - > "$RUNTIME_DIRECTORY/config.json" - ''; - serviceConfig = { - RuntimeDirectory = "immich"; - RuntimeDirectoryMode = "0700"; - }; - unitConfig.RequiresMountsFor = ["/mnt/Data"]; - }; - - docker-immich-machine-learning.unitConfig.RequiresMountsFor = ["/mnt/Data"]; - docker-immich-postgres.unitConfig.RequiresMountsFor = ["/mnt/Data"]; - }; -} diff --git a/nix/hosts/jubilife/default.nix b/nix/hosts/jubilife/default.nix deleted file mode 100644 index 02dae80b..00000000 --- a/nix/hosts/jubilife/default.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ - inputs, - self, - ... -}: { - flake.nixosConfigurations.jubilife = inputs.nixpkgs.lib.nixosSystem { - specialArgs = {inherit inputs self;}; - modules = import ./configuration.nix {inherit inputs self;}; - }; -} diff --git a/nix/hosts/pastoria/configuration.nix b/nix/hosts/pastoria/configuration.nix deleted file mode 100644 index 08b48949..00000000 --- a/nix/hosts/pastoria/configuration.nix +++ /dev/null @@ -1,86 +0,0 @@ -{ - inputs, - self, - ... -}: [ - self.nixosModules.myNixOs - self.nixosModules.myDisko - - { - hardware.facter.reportPath = ./facter.json; - } - - { - myNixOs = { - profile = { - backups.enable = true; - base.enable = true; - k3s.enable = true; - localeEnUs.enable = true; - swap.enable = true; - wireguardK3s.enable = true; - }; - - program.docker.enable = true; - - service = { - alloy.enable = true; - fail2ban.enable = true; - prometheusNode.enable = true; - tailscale.enable = true; - }; - }; - - myDisko.profile.lvmExt4.enable = true; - } - - inputs.disko.nixosModules.disko - inputs.sops-nix.nixosModules.sops - ({pkgs, ...}: { - boot.loader.grub = { - efiSupport = true; - efiInstallAsRemovable = true; - }; - - networking = { - firewall.allowedTCPPorts = [23]; - hostName = "pastoria"; - }; - - system = { - stateVersion = "26.05"; - autoUpgrade.dates = "01:45"; - }; - - myDisko.installDrive = "/dev/sda"; - - systemd.services.atbbs-telnet = { - description = "TCP proxy for atbbs telnet"; - wantedBy = ["multi-user.target"]; - after = ["network.target"]; - serviceConfig = { - ExecStart = "${pkgs.socat}/bin/socat TCP-LISTEN:23,fork,reuseaddr TCP:jubilife:2323"; - Restart = "always"; - }; - }; - - myNixOs.profile = { - k3s = { - role = "server"; - serverAddr = "https://snowpoint.cute:6443"; - transportInterface = "wg-k3s"; - nodeIP = "10.254.0.2"; - zone = "cloud"; - ingress = true; - }; - swap.size = 4096; - }; - }) - - { - nixpkgs = { - overlays = [self.overlays.default]; - config.allowUnfree = true; - }; - } -] diff --git a/nix/hosts/pastoria/default.nix b/nix/hosts/pastoria/default.nix deleted file mode 100644 index b526a02a..00000000 --- a/nix/hosts/pastoria/default.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ - inputs, - self, - ... -}: { - flake.nixosConfigurations.pastoria = inputs.nixpkgs.lib.nixosSystem { - specialArgs = {inherit inputs self;}; - modules = import ./configuration.nix {inherit inputs self;}; - }; -} diff --git a/nix/hosts/snowpoint/configuration.nix b/nix/hosts/snowpoint/configuration.nix deleted file mode 100644 index 39f1c58e..00000000 --- a/nix/hosts/snowpoint/configuration.nix +++ /dev/null @@ -1,96 +0,0 @@ -{ - inputs, - self, - ... -}: [ - self.nixosModules.myNixOs - self.nixosModules.myDisko - - { - hardware.facter.reportPath = ./facter.json; - } - - { - myNixOs = { - profile = { - backups.enable = true; - base.enable = true; - dataShare.enable = true; - k3s.enable = true; - localeEnUs.enable = true; - mediaShare.enable = true; - observability.enable = true; - swap.enable = true; - wireguardK3s.enable = true; - }; - service = { - alloy.enable = true; - cachefilesd.enable = true; - fail2ban.enable = true; - prometheusNode.enable = true; - syncthing.enable = true; - tailscale.enable = true; - }; - users.aly.enable = true; - }; - myDisko.profile.lvmExt4.enable = true; - } - - inputs.disko.nixosModules.disko - inputs.sops-nix.nixosModules.sops - ({ - config, - self, - ... - }: { - boot.loader.grub = { - efiSupport = true; - efiInstallAsRemovable = true; - }; - - networking.hostName = "snowpoint"; - system = { - stateVersion = "25.11"; - autoUpgrade.dates = "03:30"; - }; - - sops.secrets = { - syncthingCert = { - sopsFile = "${self}/secrets/syncthing.yaml"; - key = "snowpoint_cert"; - }; - syncthingKey = { - sopsFile = "${self}/secrets/syncthing.yaml"; - key = "snowpoint_key"; - }; - }; - - services.qemuGuest.enable = true; - myDisko.installDrive = "/dev/vda"; - - myNixOs = { - profile.k3s = { - role = "server"; - serverAddr = "https://pastoria.cute:6443"; - transportInterface = "wg-k3s"; - nodeIP = "10.254.0.3"; - zone = "cloud"; - ingress = true; - }; - service.syncthing = { - certFile = config.sops.secrets.syncthingCert.path; - keyFile = config.sops.secrets.syncthingKey.path; - syncROMs = false; - user = "aly"; - }; - users.aly.password = "$6$JTk2qi27OpA2fOAY$ZgTDg0wbmbwHUD..0xT4xYX.AR5hWQFCMVmn8G88yi3IAY7015AupovTpfy0arkI7nl/IDu5L09bzLKeXGvJC1"; - }; - }) - - { - nixpkgs = { - overlays = [self.overlays.default]; - config.allowUnfree = true; - }; - } -] diff --git a/nix/hosts/snowpoint/default.nix b/nix/hosts/snowpoint/default.nix deleted file mode 100644 index 297d9548..00000000 --- a/nix/hosts/snowpoint/default.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ - inputs, - self, - ... -}: { - flake.nixosConfigurations.snowpoint = inputs.nixpkgs.lib.nixosSystem { - specialArgs = {inherit inputs self;}; - modules = import ./configuration.nix {inherit inputs self;}; - }; -} diff --git a/nix/deployments.nix b/nix/modules/deployments.nix similarity index 100% rename from nix/deployments.nix rename to nix/modules/deployments.nix diff --git a/nix/devShells.nix b/nix/modules/devShells.nix similarity index 100% rename from nix/devShells.nix rename to nix/modules/devShells.nix diff --git a/nix/disko/btrfs-subvolumes.nix b/nix/modules/disko/btrfs-subvolumes.nix similarity index 89% rename from nix/disko/btrfs-subvolumes.nix rename to nix/modules/disko/btrfs-subvolumes.nix index 963acc64..c183669f 100644 --- a/nix/disko/btrfs-subvolumes.nix +++ b/nix/modules/disko/btrfs-subvolumes.nix @@ -1,11 +1,5 @@ -{ - config, - lib, - ... -}: { - options.myDisko.profile.btrfsSubvolumes.enable = lib.mkEnableOption "the btrfs subvolume disk layout"; - - config = lib.mkIf config.myDisko.profile.btrfsSubvolumes.enable { +_: { + flake.nixosModules.btrfsSubvolumes = {config, ...}: { assertions = [ { assertion = config.myDisko.installDrive != ""; diff --git a/nix/modules/disko/configurations.nix b/nix/modules/disko/configurations.nix new file mode 100644 index 00000000..2d2169e7 --- /dev/null +++ b/nix/modules/disko/configurations.nix @@ -0,0 +1,26 @@ +{self, ...}: { + flake.diskoConfigurations = { + btrfs-subvolumes = { + imports = [ + self.nixosModules.disko + self.nixosModules.btrfsSubvolumes + ]; + myDisko.installDrive = "/dev/nvme0n1"; + }; + + luks-btrfs-subvolumes = { + imports = [ + self.nixosModules.disko + self.nixosModules.luksBtrfsSubvolumes + ]; + myDisko.installDrive = "/dev/nvme0n1"; + }; + + lvm-ext4 = { + imports = [ + self.nixosModules.disko + self.nixosModules.lvmExt4 + ]; + }; + }; +} diff --git a/nix/modules/disko/default.nix b/nix/modules/disko/default.nix new file mode 100644 index 00000000..71c027ea --- /dev/null +++ b/nix/modules/disko/default.nix @@ -0,0 +1,9 @@ +_: { + flake.nixosModules.disko = {lib, ...}: { + options.myDisko.installDrive = lib.mkOption { + description = "Disk to install NixOS to."; + default = "/dev/sda"; + type = lib.types.str; + }; + }; +} diff --git a/nix/disko/luks-btrfs-subvolumes.nix b/nix/modules/disko/luks-btrfs-subvolumes.nix similarity index 91% rename from nix/disko/luks-btrfs-subvolumes.nix rename to nix/modules/disko/luks-btrfs-subvolumes.nix index 27a762e0..96388593 100644 --- a/nix/disko/luks-btrfs-subvolumes.nix +++ b/nix/modules/disko/luks-btrfs-subvolumes.nix @@ -1,11 +1,5 @@ -{ - config, - lib, - ... -}: { - options.myDisko.profile.luksBtrfsSubvolumes.enable = lib.mkEnableOption "the encrypted btrfs subvolume disk layout"; - - config = lib.mkIf config.myDisko.profile.luksBtrfsSubvolumes.enable { +_: { + flake.nixosModules.luksBtrfsSubvolumes = {config, ...}: { assertions = [ { assertion = config.myDisko.installDrive != ""; diff --git a/nix/disko/lvm-ext4.nix b/nix/modules/disko/lvm-ext4.nix similarity index 88% rename from nix/disko/lvm-ext4.nix rename to nix/modules/disko/lvm-ext4.nix index a22795bf..6beeb002 100644 --- a/nix/disko/lvm-ext4.nix +++ b/nix/modules/disko/lvm-ext4.nix @@ -1,11 +1,5 @@ -{ - config, - lib, - ... -}: { - options.myDisko.profile.lvmExt4.enable = lib.mkEnableOption "the LVM ext4 disk layout"; - - config = lib.mkIf config.myDisko.profile.lvmExt4.enable { +_: { + flake.nixosModules.lvmExt4 = {config, ...}: { assertions = [ { assertion = config.myDisko.installDrive != ""; diff --git a/nix/files/zed.nix b/nix/modules/files/zed.nix similarity index 100% rename from nix/files/zed.nix rename to nix/modules/files/zed.nix diff --git a/nix/modules/hosts/nixos/eterna/auto-upgrade.nix b/nix/modules/hosts/nixos/eterna/auto-upgrade.nix new file mode 100644 index 00000000..ba1279f2 --- /dev/null +++ b/nix/modules/hosts/nixos/eterna/auto-upgrade.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.eterna = { + system.autoUpgrade.dates = "05:00"; + }; +} diff --git a/nix/modules/hosts/nixos/eterna/backups.nix b/nix/modules/hosts/nixos/eterna/backups.nix new file mode 100644 index 00000000..02106ea1 --- /dev/null +++ b/nix/modules/hosts/nixos/eterna/backups.nix @@ -0,0 +1,14 @@ +_: { + flake.nixosModules.eterna = {config, ...}: { + myNixOs.profile.backups.jobs = { + syncthing-sync = { + paths = ["/home/aly/sync"]; + repository = "rclone:b2:aly-backups/syncthing/sync"; + }; + syncthing-roms = { + paths = [config.myNixOs.service.syncthing.romsPath]; + repository = "rclone:b2:aly-backups/syncthing/roms"; + }; + }; + }; +} diff --git a/nix/modules/hosts/nixos/eterna/caddy.nix b/nix/modules/hosts/nixos/eterna/caddy.nix new file mode 100644 index 00000000..e3787184 --- /dev/null +++ b/nix/modules/hosts/nixos/eterna/caddy.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.eterna = { + services.caddy.email = "alyraffauf@fastmail.com"; + }; +} diff --git a/nix/modules/hosts/nixos/eterna/default.nix b/nix/modules/hosts/nixos/eterna/default.nix new file mode 100644 index 00000000..a4213567 --- /dev/null +++ b/nix/modules/hosts/nixos/eterna/default.nix @@ -0,0 +1,31 @@ +{ + inputs, + self, + ... +}: { + config.flake.nixosConfigurations.eterna = inputs.nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + specialArgs = {inherit inputs self;}; + modules = [ + inputs.disko.nixosModules.disko + inputs.sops-nix.nixosModules.sops + self.nixosModules.default + self.nixosModules.eterna + self.nixosModules.intelGpu + self.nixosModules.backups + self.nixosModules.btrfs + self.nixosModules.dataShare + self.nixosModules.swap + self.nixosModules.wireguardK3s + self.nixosModules.lanzaboote + self.nixosModules.docker + self.nixosModules.alloy + self.nixosModules.caddy + self.nixosModules.fail2ban + self.nixosModules.prometheusNode + self.nixosModules.syncthing + self.nixosModules.tailscale + self.nixosModules.aly + ]; + }; +} diff --git a/nix/modules/hosts/nixos/eterna/disko.nix b/nix/modules/hosts/nixos/eterna/disko.nix new file mode 100644 index 00000000..58b1a62f --- /dev/null +++ b/nix/modules/hosts/nixos/eterna/disko.nix @@ -0,0 +1,56 @@ +_: { + flake.nixosModules.eterna = { + disko.devices.disk.vdb = { + type = "disk"; + device = "/dev/sda"; + content = { + type = "gpt"; + partitions = { + ESP = { + size = "1024M"; + type = "EF00"; + content = { + format = "vfat"; + mountOptions = ["defaults" "umask=0077"]; + mountpoint = "/boot"; + type = "filesystem"; + }; + }; + luks = { + size = "100%"; + content = { + type = "luks"; + name = "crypted"; + content = { + type = "btrfs"; + extraArgs = ["-f"]; + subvolumes = { + "/root" = { + mountOptions = ["compress=zstd" "noatime"]; + mountpoint = "/"; + }; + persist = { + mountOptions = ["compress=zstd" "noatime"]; + mountpoint = "/persist"; + }; + "/home" = { + mountOptions = ["compress=zstd" "noatime"]; + mountpoint = "/home"; + }; + "/home/.snapshots" = { + mountOptions = ["compress=zstd" "noatime"]; + mountpoint = "/home/.snapshots"; + }; + "/nix" = { + mountOptions = ["compress=zstd" "noatime"]; + mountpoint = "/nix"; + }; + }; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/nix/hosts/eterna/facter.json b/nix/modules/hosts/nixos/eterna/facter.json similarity index 100% rename from nix/hosts/eterna/facter.json rename to nix/modules/hosts/nixos/eterna/facter.json diff --git a/nix/modules/hosts/nixos/eterna/facter.nix b/nix/modules/hosts/nixos/eterna/facter.nix new file mode 100644 index 00000000..b68b4b53 --- /dev/null +++ b/nix/modules/hosts/nixos/eterna/facter.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.eterna = {self, ...}: { + hardware.facter.reportPath = self + "/nix/modules/hosts/nixos/eterna/facter.json"; + }; +} diff --git a/nix/modules/hosts/nixos/eterna/hostname.nix b/nix/modules/hosts/nixos/eterna/hostname.nix new file mode 100644 index 00000000..c4232d49 --- /dev/null +++ b/nix/modules/hosts/nixos/eterna/hostname.nix @@ -0,0 +1,6 @@ +_: { + flake.nixosModules.eterna = { + networking.hostName = "eterna"; + system.stateVersion = "25.11"; + }; +} diff --git a/nix/modules/hosts/nixos/eterna/nfs.nix b/nix/modules/hosts/nixos/eterna/nfs.nix new file mode 100644 index 00000000..b6f250e1 --- /dev/null +++ b/nix/modules/hosts/nixos/eterna/nfs.nix @@ -0,0 +1,15 @@ +_: { + flake.nixosModules.eterna = { + services.nfs.server = { + enable = true; + exports = '' + /mnt/Storage 100.64.0.0/10(rw,sync,no_subtree_check,no_root_squash,fsid=0) + ''; + }; + networking.firewall = { + enable = true; + allowedTCPPorts = [2049]; + allowedUDPPorts = [2049]; + }; + }; +} diff --git a/nix/modules/hosts/nixos/eterna/storage.nix b/nix/modules/hosts/nixos/eterna/storage.nix new file mode 100644 index 00000000..dbd489e3 --- /dev/null +++ b/nix/modules/hosts/nixos/eterna/storage.nix @@ -0,0 +1,9 @@ +_: { + flake.nixosModules.eterna = { + fileSystems."/mnt/Storage" = { + device = "/dev/disk/by-id/ata-CT2000BX500SSD1_2345E8842829"; + fsType = "btrfs"; + options = ["compress=zstd" "noatime" "nofail"]; + }; + }; +} diff --git a/nix/modules/hosts/nixos/eterna/syncthing.nix b/nix/modules/hosts/nixos/eterna/syncthing.nix new file mode 100644 index 00000000..54c0d72f --- /dev/null +++ b/nix/modules/hosts/nixos/eterna/syncthing.nix @@ -0,0 +1,26 @@ +_: { + flake.nixosModules.eterna = { + config, + self, + ... + }: { + myNixOs = { + service.syncthing = { + certFile = config.sops.secrets.syncthingCert.path; + keyFile = config.sops.secrets.syncthingKey.path; + user = "aly"; + }; + users.aly.password = "$6$JTk2qi27OpA2fOAY$ZgTDg0wbmbwHUD..0xT4xYX.AR5hWQFCMVmn8G88yi3IAY7015AupovTpfy0arkI7nl/IDu5L09bzLKeXGvJC1"; + }; + sops.secrets = { + syncthingCert = { + sopsFile = "${self}/secrets/syncthing.yaml"; + key = "eterna_cert"; + }; + syncthingKey = { + sopsFile = "${self}/secrets/syncthing.yaml"; + key = "eterna_key"; + }; + }; + }; +} diff --git a/nix/modules/hosts/nixos/jubilife/auto-upgrade.nix b/nix/modules/hosts/nixos/jubilife/auto-upgrade.nix new file mode 100644 index 00000000..cdeaa774 --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/auto-upgrade.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.jubilife = { + system.autoUpgrade.dates = "04:15"; + }; +} diff --git a/nix/modules/hosts/nixos/jubilife/backups.nix b/nix/modules/hosts/nixos/jubilife/backups.nix new file mode 100644 index 00000000..7c250564 --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/backups.nix @@ -0,0 +1,22 @@ +_: { + flake.nixosModules.jubilife = { + myNixOs.profile.backups.jobs = let + dataDirectory = "/mnt/Data"; + in { + immich.paths = [ + "${dataDirectory}/immich/library" + "${dataDirectory}/immich/profile" + "${dataDirectory}/immich/upload" + "${dataDirectory}/immich/backups" + "${dataDirectory}/immich/postgres" + ]; + garage.paths = ["${dataDirectory}/garage"]; + nextcloud.paths = ["${dataDirectory}/nextcloud/html"]; + paperless.paths = ["${dataDirectory}/paperless"]; + plex = { + exclude = ["${dataDirectory}/plex/Library/Application Support/Plex Media Server/Plug-in Support/Databases"]; + paths = ["${dataDirectory}/plex"]; + }; + }; + }; +} diff --git a/nix/modules/hosts/nixos/jubilife/containers.nix b/nix/modules/hosts/nixos/jubilife/containers.nix new file mode 100644 index 00000000..28bfb7f6 --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/containers.nix @@ -0,0 +1,231 @@ +_: { + flake.nixosModules.jubilife = { + config, + inputs, + pkgs, + ... + }: { + myNixOs.profile.backups.jobs.dizquetv.paths = ["/mnt/Data/dizquetv"]; + + systemd.tmpfiles.rules = [ + "z /mnt/Data 0755 root root - -" + "d /mnt/Data/dizquetv 0755 root root" + "d /mnt/Data/arm/home 0755 1000 1000 - -" + "d /mnt/Data/arm/config 0755 1000 1000 - -" + "d /mnt/Data/arm 0755 1000 1000 - -" + "d /mnt/Data/jellyfin 0700 1000 1000 - -" + "d /mnt/Data/plex 0755 1000 1000 - -" + "d /mnt/Data/garage 0750 garage garage - -" + "d /mnt/Data/garage/meta 0700 garage garage - -" + "d /mnt/Data/garage/data 0700 garage garage - -" + "d /mnt/Data/immich/ml-cache 0755 root root - -" + "d /mnt/Data/immich/postgres 0700 999 999 - -" + "d /mnt/Data/nextcloud/html 0750 33 33 - -" + "d /mnt/Data/paperless 0750 1000 1000 - -" + "d /mnt/Data/paperless/data 0750 1000 1000 - -" + "d /mnt/Data/paperless/consume 0750 1000 1000 - -" + "d /mnt/Data/paperless/media 0750 1000 1000 - -" + ]; + + sops.secrets = { + immichDbPassword = { + sopsFile = "${inputs.self}/k8s/flux/secrets/immich-env.sops.yaml"; + key = "data/DB_PASSWORD"; + }; + + immichConfigBase64 = { + sopsFile = "${inputs.self}/k8s/flux/secrets/immich-config.sops.yaml"; + key = "data/config.json"; + restartUnits = [ + "docker-immich.service" + ]; + }; + }; + + sops.templates = { + immich-postgres-environment.content = "POSTGRES_PASSWORD=${config.sops.placeholder.immichDbPassword}"; + immich-server-environment.content = "DB_PASSWORD=${config.sops.placeholder.immichDbPassword}"; + }; + + virtualisation.oci-containers.containers = { + dizquetv = { + image = "vexorian/dizquetv:latest@sha256:98a7bc11dc5d16732c06c779ac7fd843dc4254853203f2d9dd9293b099743ca1"; + ports = ["0.0.0.0:8000:8000"]; + volumes = [ + "/mnt/Data/dizquetv:/home/node/app/.dizquetv" + "/etc/localtime:/etc/localtime:ro" + ]; + }; + + plex = { + image = "docker.io/plexinc/pms-docker:1.43.3.10861-07dfddaeb@sha256:5bc1d13f48da6366f46aaf2a3ce1a6292897eadc1f8efcbbd7321d30e94f2ed4"; + devices = ["/dev/dri:/dev/dri"]; + + environment = { + ADVERTISE_IP = "https://plex.cute.haus:443"; + PLEX_GID = "1000"; + PLEX_UID = "1000"; + TZ = "America/New_York"; + }; + + extraOptions = [ + "--group-add=44" + "--memory=4g" + "--network=host" + ]; + + volumes = [ + "/mnt/Data/plex:/config" + "/mnt/Media:/mnt/Media:ro" + "/etc/localtime:/etc/localtime:ro" + "/mnt/Backblaze:/mnt/Backblaze:ro,rslave" + "${inputs.audnexus}:/config/Library/Application Support/Plex Media Server/Plug-ins/Audnexus.bundle:ro" + "${inputs.hama}:/config/Library/Application Support/Plex Media Server/Plug-ins/Hama.bundle:ro" + "${inputs.absolute}/Scanners:/config/Library/Application Support/Plex Media Server/Scanners:ro" + ]; + }; + + slingshot = { + image = "ghcr.io/alyraffauf/slingshot:latest@sha256:24d0777f1beedb946c4b2a06410a55cea75ff883430cc7629a18336207f212f7"; + + environment = { + SLINGSHOT_CACHE_DIR = "/cache"; + SLINGSHOT_IDENTITY_CACHE_DISK_DB = "2"; + SLINGSHOT_IDENTITY_CACHE_MEMORY_MB = "64"; + SLINGSHOT_JETSTREAM = "wss://jetstream1.us-east.bsky.network/subscribe"; + SLINGSHOT_RECORD_CACHE_DISK_DB = "4"; + SLINGSHOT_RECORD_CACHE_MEMORY_MB = "256"; + }; + + extraOptions = [ + "--cpus=2" + "--memory=2g" + "--tmpfs=/cache:rw,size=8g,uid=65532,gid=65532" + "--ulimit=nofile=8192:8192" + ]; + + ports = ["10.254.0.1:8765:8080"]; + }; + + immich-postgres = { + image = "ghcr.io/immich-app/postgres:17-vectorchord0.4.3-pgvector0.8.0@sha256:0baf4cde9b54d8d7dc6a6ad8d8c43c3c6b884f82e1c2a023d571414820e39336"; + networks = ["immich"]; + + environment = { + PGDATA = "/var/lib/postgresql/data/pgdata"; + POSTGRES_DB = "immich"; + POSTGRES_INITDB_ARGS = "--data-checksums"; + POSTGRES_USER = "immich"; + }; + + environmentFiles = [config.sops.templates.immich-postgres-environment.path]; + + extraOptions = [ + "--memory=3g" + "--shm-size=128m" + ]; + + volumes = ["/mnt/Data/immich/postgres:/var/lib/postgresql/data"]; + }; + + immich-machine-learning = { + image = "ghcr.io/immich-app/immich-machine-learning:v3.1.0-openvino@sha256:627dfaf9339037be132209784883f7be13c1deb6be799454797bf6f231331f5b"; + devices = ["/dev/dri:/dev/dri"]; + networks = ["immich"]; + environment.MACHINE_LEARNING_CACHE_FOLDER = "/cache"; + extraOptions = [ + "--memory=4g" + ]; + volumes = ["/mnt/Data/immich/ml-cache:/cache"]; + }; + + immich-valkey = { + image = "valkey/valkey:9-alpine@sha256:ee91f7a174ac4d6a6b0685b3a60e321f0a9dbbb691f9b0e285be2ba1d1be8328"; + networks = ["immich"]; + cmd = ["valkey-server" "--maxmemory" "1gb" "--maxmemory-policy" "volatile-lru"]; + }; + + immich = { + image = "ghcr.io/immich-app/immich-server:v3.1.0@sha256:b434cb9287eea1471c9974845914d4dd328c9c2d652e446ed4930f99944f0ceb"; + dependsOn = [ + "immich-postgres" + "immich-machine-learning" + "immich-valkey" + ]; + networks = ["immich"]; + environment = { + DB_DATABASE_NAME = "immich"; + DB_HOSTNAME = "immich-postgres"; + DB_PORT = "5432"; + DB_USERNAME = "immich"; + IMMICH_CONFIG_FILE = "/etc/immich/config.json"; + IMMICH_MACHINE_LEARNING_URL = "http://immich-machine-learning:3003"; + REDIS_DBINDEX = "4"; + REDIS_HOSTNAME = "immich-valkey"; + TZ = "America/New_York"; + }; + environmentFiles = [config.sops.templates.immich-server-environment.path]; + extraOptions = [ + "--memory=4g" + "--ulimit=nofile=8192:8192" + ]; + ports = ["10.254.0.1:2283:2283"]; + volumes = [ + "/mnt/Data/immich:/data" + "/run/immich/config.json:/etc/immich/config.json:ro" + ]; + }; + }; + + systemd.services = { + docker-network-immich = { + after = ["docker.service"]; + requires = ["docker.service"]; + + before = [ + "docker-immich-postgres.service" + "docker-immich-machine-learning.service" + "docker-immich-valkey.service" + "docker-immich.service" + ]; + + requiredBy = [ + "docker-immich-postgres.service" + "docker-immich-machine-learning.service" + "docker-immich-valkey.service" + "docker-immich.service" + ]; + + path = [pkgs.docker]; + script = "docker network inspect immich >/dev/null 2>&1 || docker network create immich"; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + }; + + docker-dizquetv.unitConfig.RequiresMountsFor = ["/mnt/Data"]; + + docker-plex.unitConfig.RequiresMountsFor = [ + "/mnt/Data" + "/mnt/Media" + ]; + + docker-immich = { + preStart = '' + ${pkgs.coreutils}/bin/base64 --decode \ + < "${config.sops.secrets.immichConfigBase64.path}" \ + > "$RUNTIME_DIRECTORY/config.json" + ''; + serviceConfig = { + RuntimeDirectory = "immich"; + RuntimeDirectoryMode = "0700"; + }; + unitConfig.RequiresMountsFor = ["/mnt/Data"]; + }; + + docker-immich-machine-learning.unitConfig.RequiresMountsFor = ["/mnt/Data"]; + docker-immich-postgres.unitConfig.RequiresMountsFor = ["/mnt/Data"]; + }; + }; +} diff --git a/nix/modules/hosts/nixos/jubilife/default.nix b/nix/modules/hosts/nixos/jubilife/default.nix new file mode 100644 index 00000000..0102f4db --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/default.nix @@ -0,0 +1,38 @@ +{ + inputs, + self, + ... +}: { + config.flake.nixosConfigurations.jubilife = inputs.nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + specialArgs = {inherit inputs self;}; + modules = [ + inputs.disko.nixosModules.disko + inputs.sops-nix.nixosModules.sops + self.nixosModules.default + self.nixosModules.jubilife + self.nixosModules.intelGpu + self.nixosModules.disko + self.nixosModules.luksBtrfsSubvolumes + self.nixosModules.arr + self.nixosModules.b2Mounts + self.nixosModules.backups + self.nixosModules.btrfs + self.nixosModules.k3s + self.nixosModules.swap + self.nixosModules.wireguardK3s + self.nixosModules.lanzaboote + self.nixosModules.docker + self.nixosModules.alloy + self.nixosModules.atbbs + self.nixosModules.caddy + self.nixosModules.fail2ban + self.nixosModules.tautulli + self.nixosModules.prometheusNode + self.nixosModules.qbittorrent + self.nixosModules.syncthing + self.nixosModules.tailscale + self.nixosModules.aly + ]; + }; +} diff --git a/nix/modules/hosts/nixos/jubilife/disko.nix b/nix/modules/hosts/nixos/jubilife/disko.nix new file mode 100644 index 00000000..677c9ecc --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/disko.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.jubilife = { + myDisko.installDrive = "/dev/disk/by-id/nvme-PNY_CS2130_1TB_SSD_PNY211821050701050CC"; + }; +} diff --git a/nix/modules/hosts/nixos/jubilife/exporters.nix b/nix/modules/hosts/nixos/jubilife/exporters.nix new file mode 100644 index 00000000..cbe74f44 --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/exporters.nix @@ -0,0 +1,54 @@ +_: { + flake.nixosModules.jubilife = { + config, + lib, + self, + ... + }: let + tailnet = "narwhal-snapper.ts.net"; + exporters = { + bazarr = { + apiKey = "bazarr_api_key"; + port = 9708; + }; + lidarr = { + apiKey = "lidarr_api_key"; + port = 9709; + }; + prowlarr = { + apiKey = "prowlarr_api_key"; + port = 9710; + }; + radarr = { + apiKey = "radarr_api_key"; + port = 9711; + }; + sonarr = { + apiKey = "sonarr_api_key"; + port = 9712; + }; + }; + in { + sops.secrets = + lib.mapAttrs' (serviceName: service: { + name = "${serviceName}ApiKey"; + value = { + sopsFile = "${self}/secrets/arr.yaml"; + key = service.apiKey; + }; + }) + exporters; + services.prometheus.exporters = + (lib.mapAttrs' (serviceName: service: { + name = "exportarr-${serviceName}"; + value = { + enable = true; + apiKeyFile = config.sops.secrets."${serviceName}ApiKey".path; + inherit (service) port; + url = "https://${serviceName}.${tailnet}"; + }; + }) + exporters) + // {smartctl.enable = true;}; + }; +} diff --git a/nix/hosts/jubilife/facter.json b/nix/modules/hosts/nixos/jubilife/facter.json similarity index 100% rename from nix/hosts/jubilife/facter.json rename to nix/modules/hosts/nixos/jubilife/facter.json diff --git a/nix/modules/hosts/nixos/jubilife/facter.nix b/nix/modules/hosts/nixos/jubilife/facter.nix new file mode 100644 index 00000000..ce357a84 --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/facter.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.jubilife = {self, ...}: { + hardware.facter.reportPath = self + "/nix/modules/hosts/nixos/jubilife/facter.json"; + }; +} diff --git a/nix/modules/hosts/nixos/jubilife/firewall.nix b/nix/modules/hosts/nixos/jubilife/firewall.nix new file mode 100644 index 00000000..3574e037 --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/firewall.nix @@ -0,0 +1,13 @@ +_: { + flake.nixosModules.jubilife = { + networking.firewall = { + allowedTCPPorts = [2342 5143 6881 32400 8324 32443]; + allowedUDPPorts = [1900 32410 32412 32413 32414]; + extraInputRules = '' + -s 10.42.0.0/16 -p tcp --dport 3900 -j ACCEPT + -s 10.42.0.0/16 -p tcp --dport 2049 -j ACCEPT + -s 10.42.0.0/16 -p udp --dport 2049 -j ACCEPT + ''; + }; + }; +} diff --git a/nix/modules/hosts/nixos/jubilife/garage.nix b/nix/modules/hosts/nixos/jubilife/garage.nix new file mode 100644 index 00000000..d6c79658 --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/garage.nix @@ -0,0 +1,87 @@ +_: { + flake.nixosModules.jubilife = { + config, + pkgs, + self, + ... + }: let + dataDirectory = "/mnt/Data"; + in { + sops.secrets = { + garageNextcloudAccessKey = { + sopsFile = "${self}/secrets/garage.yaml"; + key = "nextcloud_access_key"; + owner = "garage"; + group = "garage"; + }; + garageNextcloudSecretKey = { + sopsFile = "${self}/secrets/garage.yaml"; + key = "nextcloud_secret_key"; + owner = "garage"; + group = "garage"; + }; + garageRpcSecret = { + sopsFile = "${self}/secrets/garage.yaml"; + key = "rpc_secret"; + owner = "garage"; + group = "garage"; + }; + }; + sops.templates = { + garage-config = { + owner = "garage"; + group = "garage"; + mode = "0400"; + content = '' + metadata_dir = "${dataDirectory}/garage/meta" + data_dir = "${dataDirectory}/garage/data" + db_engine = "sqlite" + replication_factor = 1 + rpc_bind_addr = "[::]:3901" + rpc_public_addr = "10.254.0.1:3901" + rpc_secret = "${config.sops.placeholder.garageRpcSecret}" + + [s3_api] + api_bind_addr = "10.254.0.1:3900" + s3_region = "garage" + ''; + }; + garage-environment = { + owner = "garage"; + group = "garage"; + mode = "0400"; + content = '' + GARAGE_CONFIG_FILE=${config.sops.templates.garage-config.path} + GARAGE_DEFAULT_ACCESS_KEY=${config.sops.placeholder.garageNextcloudAccessKey} + GARAGE_DEFAULT_SECRET_KEY=${config.sops.placeholder.garageNextcloudSecretKey} + GARAGE_DEFAULT_BUCKET=aly-nextcloud + ''; + }; + }; + users = { + groups.garage = {}; + users.garage = { + isSystemUser = true; + group = "garage"; + }; + }; + services.garage = { + enable = true; + package = pkgs.garage_2; + environmentFile = config.sops.templates.garage-environment.path; + settings = { + metadata_dir = "${dataDirectory}/garage/meta"; + data_dir = "${dataDirectory}/garage/data"; + }; + }; + systemd.services.garage = { + after = ["mnt-Data.mount"]; + requires = ["mnt-Data.mount"]; + serviceConfig = { + DynamicUser = false; + User = "garage"; + Group = "garage"; + }; + }; + }; +} diff --git a/nix/modules/hosts/nixos/jubilife/hostname.nix b/nix/modules/hosts/nixos/jubilife/hostname.nix new file mode 100644 index 00000000..f715880e --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/hostname.nix @@ -0,0 +1,6 @@ +_: { + flake.nixosModules.jubilife = { + networking.hostName = "jubilife"; + system.stateVersion = "25.11"; + }; +} diff --git a/nix/modules/hosts/nixos/jubilife/k3s.nix b/nix/modules/hosts/nixos/jubilife/k3s.nix new file mode 100644 index 00000000..184cb092 --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/k3s.nix @@ -0,0 +1,11 @@ +_: { + flake.nixosModules.jubilife = { + myNixOs.profile.k3s = { + role = "server"; + clusterInit = true; + transportInterface = "wg-k3s"; + nodeIP = "10.254.0.1"; + zone = "home"; + }; + }; +} diff --git a/nix/modules/hosts/nixos/jubilife/nfs.nix b/nix/modules/hosts/nixos/jubilife/nfs.nix new file mode 100644 index 00000000..e8ebb215 --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/nfs.nix @@ -0,0 +1,11 @@ +_: { + flake.nixosModules.jubilife = { + services.nfs.server = { + enable = true; + exports = '' + /mnt/Data 100.64.0.0/10(rw,sync,no_subtree_check,no_root_squash,fsid=0) 10.42.0.0/16(rw,sync,no_subtree_check,no_root_squash,fsid=0) + /mnt/Media 100.64.0.0/10(rw,sync,no_subtree_check,no_root_squash,fsid=1) 10.42.0.0/16(rw,sync,no_subtree_check,no_root_squash,fsid=1) + ''; + }; + }; +} diff --git a/nix/modules/hosts/nixos/jubilife/packages.nix b/nix/modules/hosts/nixos/jubilife/packages.nix new file mode 100644 index 00000000..187a7ee1 --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/packages.nix @@ -0,0 +1,28 @@ +_: { + flake.nixosModules.jubilife = {pkgs, ...}: { + environment.systemPackages = with pkgs; [ + abcde + age + chezmoi + claude-code + codex + curl + delta + eza + ffmpeg-full + flac + fzf + gh + handbrake + lazygit + mediainfo + mkvtoolnix + opencode + rclone + restic + ripgrep + starship + zoxide + ]; + }; +} diff --git a/nix/modules/hosts/nixos/jubilife/samba.nix b/nix/modules/hosts/nixos/jubilife/samba.nix new file mode 100644 index 00000000..d7aa8384 --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/samba.nix @@ -0,0 +1,53 @@ +_: { + flake.nixosModules.jubilife = {config, ...}: { + services = { + samba = { + enable = true; + openFirewall = true; + settings = { + global = { + security = "user"; + "map to guest" = "Bad User"; + "server min protocol" = "SMB3"; + "server max protocol" = "SMB3_11"; + "socket options" = "TCP_NODELAY IPTOS_LOWDELAY SO_RCVBUF=262144 SO_SNDBUF=262144"; + "use sendfile" = "no"; + "aio read size" = "1"; + "aio write size" = "1"; + "min receivefile size" = "131072"; + "max xmit" = "65535"; + "strict locking" = "no"; + oplocks = "yes"; + "level2 oplocks" = "yes"; + }; + Data = { + "create mask" = "0755"; + "directory mask" = "0755"; + "force group" = "users"; + "force user" = "aly"; + "guest ok" = "yes"; + "read only" = "no"; + browseable = "yes"; + comment = "Data @ ${config.networking.hostName}"; + path = "/mnt/Data"; + }; + Media = { + "create mask" = "0755"; + "directory mask" = "0755"; + "force group" = "users"; + "force user" = "aly"; + "guest ok" = "yes"; + "read only" = "no"; + browseable = "yes"; + comment = "Media @ ${config.networking.hostName}"; + path = "/mnt/Media"; + }; + }; + }; + samba-wsdd = { + enable = true; + openFirewall = true; + }; + }; + }; +} diff --git a/nix/modules/hosts/nixos/jubilife/scsi.nix b/nix/modules/hosts/nixos/jubilife/scsi.nix new file mode 100644 index 00000000..54400163 --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/scsi.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.jubilife = { + boot.kernelModules = ["sg"]; + }; +} diff --git a/nix/modules/hosts/nixos/jubilife/smartd.nix b/nix/modules/hosts/nixos/jubilife/smartd.nix new file mode 100644 index 00000000..3021a0a0 --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/smartd.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.jubilife = { + services.smartd.enable = true; + }; +} diff --git a/nix/modules/hosts/nixos/jubilife/snapper.nix b/nix/modules/hosts/nixos/jubilife/snapper.nix new file mode 100644 index 00000000..331def70 --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/snapper.nix @@ -0,0 +1,11 @@ +_: { + flake.nixosModules.jubilife = { + services.snapper.configs.media = { + ALLOW_GROUPS = ["users"]; + FSTYPE = "btrfs"; + SUBVOLUME = "/mnt/Media"; + TIMELINE_CLEANUP = true; + TIMELINE_CREATE = true; + }; + }; +} diff --git a/nix/modules/hosts/nixos/jubilife/storage.nix b/nix/modules/hosts/nixos/jubilife/storage.nix new file mode 100644 index 00000000..5de44dad --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/storage.nix @@ -0,0 +1,26 @@ +_: { + flake.nixosModules.jubilife = { + fileSystems = { + "/mnt/Data" = { + device = "/dev/disk/by-id/ata-CT4000BX500SSD1_2447E9959972"; + fsType = "btrfs"; + options = ["compress=zstd" "noatime" "nofail"]; + }; + "/mnt/Media" = { + device = "/dev/disk/by-id/ata-ST14000NM001G-2KJ103_ZL201XNJ-part1"; + fsType = "btrfs"; + options = ["subvol=@media" "compress=zstd" "noatime" "nofail"]; + }; + }; + myNixOs = { + profile.arr.dataDir = "/mnt/Data"; + profile.b2Mounts = { + cacheDir = "/mnt/Data/.rclone-cache"; + audioCacheSize = "50G"; + audioReadAhead = "3G"; + videoCacheSize = "300G"; + videoReadAhead = "5G"; + }; + }; + }; +} diff --git a/nix/modules/hosts/nixos/jubilife/syncthing.nix b/nix/modules/hosts/nixos/jubilife/syncthing.nix new file mode 100644 index 00000000..467d57df --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/syncthing.nix @@ -0,0 +1,28 @@ +_: { + flake.nixosModules.jubilife = { + config, + self, + ... + }: { + myNixOs = { + service.syncthing = { + certFile = config.sops.secrets.syncthingCert.path; + keyFile = config.sops.secrets.syncthingKey.path; + romsPath = "/mnt/Data/syncthing/ROMs"; + syncROMs = true; + user = "aly"; + }; + users.aly.password = "$6$JTk2qi27OpA2fOAY$ZgTDg0wbmbwHUD..0xT4xYX.AR5hWQFCMVmn8G88yi3IAY7015AupovTpfy0arkI7nl/IDu5L09bzLKeXGvJC1"; + }; + sops.secrets = { + syncthingCert = { + sopsFile = "${self}/secrets/syncthing.yaml"; + key = "jubilife_cert"; + }; + syncthingKey = { + sopsFile = "${self}/secrets/syncthing.yaml"; + key = "jubilife_key"; + }; + }; + }; +} diff --git a/nix/modules/hosts/nixos/jubilife/tuned.nix b/nix/modules/hosts/nixos/jubilife/tuned.nix new file mode 100644 index 00000000..87695acc --- /dev/null +++ b/nix/modules/hosts/nixos/jubilife/tuned.nix @@ -0,0 +1,8 @@ +_: { + flake.nixosModules.jubilife = { + services.tuned = { + enable = true; + settings.dynamic_tuning = true; + }; + }; +} diff --git a/nix/modules/hosts/nixos/pastoria/atbbs.nix b/nix/modules/hosts/nixos/pastoria/atbbs.nix new file mode 100644 index 00000000..b712bf2e --- /dev/null +++ b/nix/modules/hosts/nixos/pastoria/atbbs.nix @@ -0,0 +1,15 @@ +_: { + flake.nixosModules.pastoria = {pkgs, ...}: { + networking.firewall.allowedTCPPorts = [23]; + + systemd.services.atbbs-telnet = { + description = "TCP proxy for atbbs telnet"; + wantedBy = ["multi-user.target"]; + after = ["network.target"]; + serviceConfig = { + ExecStart = "${pkgs.socat}/bin/socat TCP-LISTEN:23,fork,reuseaddr TCP:jubilife:2323"; + Restart = "always"; + }; + }; + }; +} diff --git a/nix/modules/hosts/nixos/pastoria/auto-upgrade.nix b/nix/modules/hosts/nixos/pastoria/auto-upgrade.nix new file mode 100644 index 00000000..c4a11fd6 --- /dev/null +++ b/nix/modules/hosts/nixos/pastoria/auto-upgrade.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.pastoria = { + system.autoUpgrade.dates = "01:45"; + }; +} diff --git a/nix/modules/hosts/nixos/pastoria/boot.nix b/nix/modules/hosts/nixos/pastoria/boot.nix new file mode 100644 index 00000000..798bf40f --- /dev/null +++ b/nix/modules/hosts/nixos/pastoria/boot.nix @@ -0,0 +1,8 @@ +_: { + flake.nixosModules.pastoria = { + boot.loader.grub = { + efiSupport = true; + efiInstallAsRemovable = true; + }; + }; +} diff --git a/nix/modules/hosts/nixos/pastoria/default.nix b/nix/modules/hosts/nixos/pastoria/default.nix new file mode 100644 index 00000000..5d675f88 --- /dev/null +++ b/nix/modules/hosts/nixos/pastoria/default.nix @@ -0,0 +1,27 @@ +{ + inputs, + self, + ... +}: { + config.flake.nixosConfigurations.pastoria = inputs.nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + specialArgs = {inherit inputs self;}; + modules = [ + inputs.disko.nixosModules.disko + inputs.sops-nix.nixosModules.sops + self.nixosModules.default + self.nixosModules.pastoria + self.nixosModules.disko + self.nixosModules.lvmExt4 + self.nixosModules.backups + self.nixosModules.k3s + self.nixosModules.swap + self.nixosModules.wireguardK3s + self.nixosModules.docker + self.nixosModules.alloy + self.nixosModules.fail2ban + self.nixosModules.prometheusNode + self.nixosModules.tailscale + ]; + }; +} diff --git a/nix/modules/hosts/nixos/pastoria/disko.nix b/nix/modules/hosts/nixos/pastoria/disko.nix new file mode 100644 index 00000000..0a6a800b --- /dev/null +++ b/nix/modules/hosts/nixos/pastoria/disko.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.pastoria = { + myDisko.installDrive = "/dev/sda"; + }; +} diff --git a/nix/hosts/pastoria/facter.json b/nix/modules/hosts/nixos/pastoria/facter.json similarity index 100% rename from nix/hosts/pastoria/facter.json rename to nix/modules/hosts/nixos/pastoria/facter.json diff --git a/nix/modules/hosts/nixos/pastoria/facter.nix b/nix/modules/hosts/nixos/pastoria/facter.nix new file mode 100644 index 00000000..da7664c3 --- /dev/null +++ b/nix/modules/hosts/nixos/pastoria/facter.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.pastoria = {self, ...}: { + hardware.facter.reportPath = self + "/nix/modules/hosts/nixos/pastoria/facter.json"; + }; +} diff --git a/nix/modules/hosts/nixos/pastoria/hostname.nix b/nix/modules/hosts/nixos/pastoria/hostname.nix new file mode 100644 index 00000000..ad0502de --- /dev/null +++ b/nix/modules/hosts/nixos/pastoria/hostname.nix @@ -0,0 +1,6 @@ +_: { + flake.nixosModules.pastoria = { + networking.hostName = "pastoria"; + system.stateVersion = "26.05"; + }; +} diff --git a/nix/modules/hosts/nixos/pastoria/k3s.nix b/nix/modules/hosts/nixos/pastoria/k3s.nix new file mode 100644 index 00000000..575b776c --- /dev/null +++ b/nix/modules/hosts/nixos/pastoria/k3s.nix @@ -0,0 +1,15 @@ +_: { + flake.nixosModules.pastoria = { + myNixOs.profile = { + k3s = { + role = "server"; + serverAddr = "https://snowpoint.cute:6443"; + transportInterface = "wg-k3s"; + nodeIP = "10.254.0.2"; + zone = "cloud"; + ingress = true; + }; + swap.size = 4096; + }; + }; +} diff --git a/nix/modules/hosts/nixos/snowpoint/auto-upgrade.nix b/nix/modules/hosts/nixos/snowpoint/auto-upgrade.nix new file mode 100644 index 00000000..b2fec59a --- /dev/null +++ b/nix/modules/hosts/nixos/snowpoint/auto-upgrade.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.snowpoint = { + system.autoUpgrade.dates = "03:30"; + }; +} diff --git a/nix/modules/hosts/nixos/snowpoint/boot.nix b/nix/modules/hosts/nixos/snowpoint/boot.nix new file mode 100644 index 00000000..71dab561 --- /dev/null +++ b/nix/modules/hosts/nixos/snowpoint/boot.nix @@ -0,0 +1,8 @@ +_: { + flake.nixosModules.snowpoint = { + boot.loader.grub = { + efiSupport = true; + efiInstallAsRemovable = true; + }; + }; +} diff --git a/nix/modules/hosts/nixos/snowpoint/default.nix b/nix/modules/hosts/nixos/snowpoint/default.nix new file mode 100644 index 00000000..2026297a --- /dev/null +++ b/nix/modules/hosts/nixos/snowpoint/default.nix @@ -0,0 +1,33 @@ +{ + inputs, + self, + ... +}: { + config.flake.nixosConfigurations.snowpoint = inputs.nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + specialArgs = {inherit inputs self;}; + modules = [ + inputs.disko.nixosModules.disko + inputs.sops-nix.nixosModules.sops + self.nixosModules.default + self.nixosModules.snowpoint + self.nixosModules.disko + self.nixosModules.lvmExt4 + self.nixosModules.backups + self.nixosModules.dataShare + self.nixosModules.k3s + self.nixosModules.mediaShare + self.nixosModules.observability + self.nixosModules.swap + self.nixosModules.wireguardK3s + self.nixosModules.alloy + self.nixosModules.cachefilesd + self.nixosModules.caddy + self.nixosModules.fail2ban + self.nixosModules.prometheusNode + self.nixosModules.syncthing + self.nixosModules.tailscale + self.nixosModules.aly + ]; + }; +} diff --git a/nix/modules/hosts/nixos/snowpoint/disko.nix b/nix/modules/hosts/nixos/snowpoint/disko.nix new file mode 100644 index 00000000..b14afde2 --- /dev/null +++ b/nix/modules/hosts/nixos/snowpoint/disko.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.snowpoint = { + myDisko.installDrive = "/dev/vda"; + }; +} diff --git a/nix/hosts/snowpoint/facter.json b/nix/modules/hosts/nixos/snowpoint/facter.json similarity index 100% rename from nix/hosts/snowpoint/facter.json rename to nix/modules/hosts/nixos/snowpoint/facter.json diff --git a/nix/modules/hosts/nixos/snowpoint/facter.nix b/nix/modules/hosts/nixos/snowpoint/facter.nix new file mode 100644 index 00000000..25ef1e89 --- /dev/null +++ b/nix/modules/hosts/nixos/snowpoint/facter.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.snowpoint = {self, ...}: { + hardware.facter.reportPath = self + "/nix/modules/hosts/nixos/snowpoint/facter.json"; + }; +} diff --git a/nix/modules/hosts/nixos/snowpoint/hardware.nix b/nix/modules/hosts/nixos/snowpoint/hardware.nix new file mode 100644 index 00000000..dad1aa7d --- /dev/null +++ b/nix/modules/hosts/nixos/snowpoint/hardware.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.snowpoint = { + services.qemuGuest.enable = true; + }; +} diff --git a/nix/modules/hosts/nixos/snowpoint/hostname.nix b/nix/modules/hosts/nixos/snowpoint/hostname.nix new file mode 100644 index 00000000..fbc649e1 --- /dev/null +++ b/nix/modules/hosts/nixos/snowpoint/hostname.nix @@ -0,0 +1,6 @@ +_: { + flake.nixosModules.snowpoint = { + networking.hostName = "snowpoint"; + system.stateVersion = "25.11"; + }; +} diff --git a/nix/modules/hosts/nixos/snowpoint/k3s.nix b/nix/modules/hosts/nixos/snowpoint/k3s.nix new file mode 100644 index 00000000..760d0bc0 --- /dev/null +++ b/nix/modules/hosts/nixos/snowpoint/k3s.nix @@ -0,0 +1,12 @@ +_: { + flake.nixosModules.snowpoint = { + myNixOs.profile.k3s = { + role = "server"; + serverAddr = "https://pastoria.cute:6443"; + transportInterface = "wg-k3s"; + nodeIP = "10.254.0.3"; + zone = "cloud"; + ingress = true; + }; + }; +} diff --git a/nix/modules/hosts/nixos/snowpoint/syncthing.nix b/nix/modules/hosts/nixos/snowpoint/syncthing.nix new file mode 100644 index 00000000..786aa1db --- /dev/null +++ b/nix/modules/hosts/nixos/snowpoint/syncthing.nix @@ -0,0 +1,27 @@ +_: { + flake.nixosModules.snowpoint = { + config, + self, + ... + }: { + sops.secrets = { + syncthingCert = { + sopsFile = "${self}/secrets/syncthing.yaml"; + key = "snowpoint_cert"; + }; + syncthingKey = { + sopsFile = "${self}/secrets/syncthing.yaml"; + key = "snowpoint_key"; + }; + }; + myNixOs = { + service.syncthing = { + certFile = config.sops.secrets.syncthingCert.path; + keyFile = config.sops.secrets.syncthingKey.path; + syncROMs = false; + user = "aly"; + }; + users.aly.password = "$6$JTk2qi27OpA2fOAY$ZgTDg0wbmbwHUD..0xT4xYX.AR5hWQFCMVmn8G88yi3IAY7015AupovTpfy0arkI7nl/IDu5L09bzLKeXGvJC1"; + }; + }; +} diff --git a/nix/modules/nixos/documentation.nix b/nix/modules/nixos/documentation.nix new file mode 100644 index 00000000..82d4c9cc --- /dev/null +++ b/nix/modules/nixos/documentation.nix @@ -0,0 +1,8 @@ +_: { + flake.nixosModules.default = { + documentation = { + enable = false; + nixos.enable = false; + }; + }; +} diff --git a/nix/modules/nixos/hardware/firmware.nix b/nix/modules/nixos/hardware/firmware.nix new file mode 100644 index 00000000..6ab248e2 --- /dev/null +++ b/nix/modules/nixos/hardware/firmware.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.default = { + hardware.enableAllFirmware = true; + }; +} diff --git a/nix/modules/nixos/hardware/intel-gpu.nix b/nix/modules/nixos/hardware/intel-gpu.nix new file mode 100644 index 00000000..b35c4d14 --- /dev/null +++ b/nix/modules/nixos/hardware/intel-gpu.nix @@ -0,0 +1,20 @@ +_: { + flake.nixosModules.intelGpu = {pkgs, ...}: { + environment.sessionVariables.LIBVA_DRIVER_NAME = "iHD"; + + hardware = { + facter.detected.graphics.enable = true; + intel-gpu-tools.enable = true; + graphics.extraPackages = [ + (pkgs.intel-vaapi-driver.override {enableHybridCodec = true;}) + pkgs.intel-compute-runtime + pkgs.intel-media-driver + ]; + }; + + services = { + k3s.extraFlags = ["--node-label=cute.haus/intel-gpu=true"]; + xserver.videoDrivers = ["modesetting"]; + }; + }; +} diff --git a/nix/modules/nixos/known-hosts.nix b/nix/modules/nixos/known-hosts.nix new file mode 100644 index 00000000..0ee6aa97 --- /dev/null +++ b/nix/modules/nixos/known-hosts.nix @@ -0,0 +1,31 @@ +_: { + flake.nixosModules.default = { + lib, + self, + ... + }: let + tnet = "narwhal-snapper.ts.net"; + rootKeyFiles = lib.filterAttrs ( + fileName: fileType: + fileType + == "regular" + && lib.hasPrefix "root_" fileName + && lib.hasSuffix ".pub" fileName + ) (builtins.readDir "${self}/keys"); + aliases = { + eterna = ["eterna.cute" "mauville" "mauville.local" "mauville.${tnet}"]; + jubilife = ["jubilife.cute" "lilycove" "lilycove.local" "lilycove.${tnet}"]; + pastoria = ["pastoria.cute"]; + snowpoint = ["snowpoint.cute" "dewford" "dewford.local" "dewford.${tnet}"]; + }; + in { + programs.ssh.knownHosts = lib.mapAttrs' (fileName: _fileType: let + hostName = lib.removeSuffix ".pub" (lib.removePrefix "root_" fileName); + in + lib.nameValuePair hostName { + hostNames = [hostName "${hostName}.local" "${hostName}.${tnet}"] ++ (aliases.${hostName} or []); + publicKeyFile = "${self}/keys/${fileName}"; + }) + rootKeyFiles; + }; +} diff --git a/nix/nixos/locale-en-us.nix b/nix/modules/nixos/locale.nix similarity index 77% rename from nix/nixos/locale-en-us.nix rename to nix/modules/nixos/locale.nix index df45f316..76b6ef35 100644 --- a/nix/nixos/locale-en-us.nix +++ b/nix/modules/nixos/locale.nix @@ -1,11 +1,5 @@ -{ - config, - lib, - ... -}: { - options.myNixOs.profile.localeEnUs.enable = lib.mkEnableOption "US English locale"; - - config = lib.mkIf config.myNixOs.profile.localeEnUs.enable { +_: { + flake.nixosModules.default = {lib, ...}: { i18n = { defaultLocale = lib.mkDefault "en_US.UTF-8"; diff --git a/nix/modules/nixos/nixpkgs.nix b/nix/modules/nixos/nixpkgs.nix new file mode 100644 index 00000000..484fe4d5 --- /dev/null +++ b/nix/modules/nixos/nixpkgs.nix @@ -0,0 +1,8 @@ +_: { + flake.nixosModules.default = {self, ...}: { + nixpkgs = { + config.allowUnfree = true; + overlays = [self.overlays.default]; + }; + }; +} diff --git a/nix/nixos/base/packages.nix b/nix/modules/nixos/packages.nix similarity index 66% rename from nix/nixos/base/packages.nix rename to nix/modules/nixos/packages.nix index 4c86c9b6..6006132a 100644 --- a/nix/nixos/base/packages.nix +++ b/nix/modules/nixos/packages.nix @@ -1,10 +1,5 @@ -{ - config, - lib, - pkgs, - ... -}: { - config = lib.mkIf config.myNixOs.profile.base.enable { +_: { + flake.nixosModules.default = {pkgs, ...}: { environment.systemPackages = with pkgs; [ (inxi.override {withRecommends = true;}) helix diff --git a/nix/nixos/base/performance.nix b/nix/modules/nixos/performance.nix similarity index 87% rename from nix/nixos/base/performance.nix rename to nix/modules/nixos/performance.nix index 9643263f..45f646e9 100644 --- a/nix/nixos/base/performance.nix +++ b/nix/modules/nixos/performance.nix @@ -1,9 +1,5 @@ -{ - config, - lib, - ... -}: { - config = lib.mkIf config.myNixOs.profile.base.enable { +_: { + flake.nixosModules.default = {lib, ...}: { boot.kernel.sysctl = { "fs.file-max" = lib.mkDefault 2097152; "fs.inotify.max_user_instances" = lib.mkOverride 100 8192; diff --git a/nix/modules/nixos/profiles/arr.nix b/nix/modules/nixos/profiles/arr.nix new file mode 100644 index 00000000..e2742e19 --- /dev/null +++ b/nix/modules/nixos/profiles/arr.nix @@ -0,0 +1,67 @@ +_: { + flake.nixosModules.arr = { + config, + lib, + pkgs, + ... + }: let + cfg = config.myNixOs.profile.arr; + arrServices = { + bazarr.dataDir = "${cfg.dataDir}/bazarr"; + lidarr = { + dataDir = "${cfg.dataDir}/lidarr/.config/Lidarr"; + createDataDir = true; + }; + prowlarr = {}; + radarr = { + dataDir = "${cfg.dataDir}/radarr/.config/Radarr/"; + createDataDir = true; + }; + sonarr = { + dataDir = "${cfg.dataDir}/sonarr/.config/NzbDrone/"; + createDataDir = true; + }; + }; + + enabledServices = + lib.mapAttrs ( + _: service: + { + enable = true; + openFirewall = true; + } + // lib.optionalAttrs (service ? dataDir) {inherit (service) dataDir;} + ) + arrServices; + + backupJobs = + lib.mapAttrs (serviceName: _: { + backupCleanupCommand = "${pkgs.systemd}/bin/systemctl start ${serviceName}"; + backupPrepareCommand = "${pkgs.systemd}/bin/systemctl stop ${serviceName}"; + paths = [config.services.${serviceName}.dataDir]; + }) + arrServices; + + dataDirectoryServices = lib.filterAttrs (_: service: service.createDataDir or false) arrServices; + in { + options.myNixOs.profile.arr = { + dataDir = lib.mkOption { + type = lib.types.str; + default = "/var/lib"; + description = "The directory where *arr stores its data files."; + }; + }; + + config = { + services = enabledServices; + + systemd.tmpfiles.rules = + lib.mapAttrsToList ( + serviceName: service: "d ${service.dataDir} 0755 ${serviceName} ${serviceName}" + ) + dataDirectoryServices; + + myNixOs.profile.backups.jobs = backupJobs; + }; + }; +} diff --git a/nix/modules/nixos/profiles/b2-mounts.nix b/nix/modules/nixos/profiles/b2-mounts.nix new file mode 100644 index 00000000..fb6d6d5d --- /dev/null +++ b/nix/modules/nixos/profiles/b2-mounts.nix @@ -0,0 +1,104 @@ +_: { + flake.nixosModules.b2Mounts = { + config, + lib, + pkgs, + self, + ... + }: let + cfg = config.myNixOs.profile.b2Mounts; + + b2Options = [ + "allow_other" + "args2env" + "cache-dir=${cfg.cacheDir}" + "config=${config.sops.secrets.b2-mount-rclone.path}" + "dir-cache-time=1h" + "nodev" + "nofail" + "vfs-cache-mode=full" + "vfs-write-back=10s" + "x-systemd.after=network-online.target" + "x-systemd.automount" + ]; + + b2ProfileOptions = { + audio = [ + "buffer-size=128M" + "vfs-cache-max-age=168h" + "vfs-cache-max-size=${cfg.audioCacheSize}" + "vfs-read-ahead=${cfg.audioReadAhead}" + ]; + + video = [ + "buffer-size=512M" + "vfs-cache-max-age=336h" + "vfs-cache-max-size=${cfg.videoCacheSize}" + "vfs-read-ahead=${cfg.videoReadAhead}" + ]; + }; + + mkB2Mount = name: remote: profile: { + "/mnt/Backblaze/${name}" = { + device = "b2:${remote}"; + fsType = "rclone"; + options = b2Options ++ b2ProfileOptions.${profile}; + }; + }; + + allShares = { + Anime = mkB2Mount "Anime" "aly-anime" "video"; + Audiobooks = mkB2Mount "Audiobooks" "aly-audiobooks" "audio"; + Movies = mkB2Mount "Movies" "aly-movies" "video"; + Music = mkB2Mount "Music" "aly-music" "audio"; + Shows = mkB2Mount "Shows" "aly-shows" "video"; + }; + in { + options.myNixOs.profile.b2Mounts = { + cacheDir = lib.mkOption { + description = "Directory for rclone VFS cache."; + example = "/mnt/Data/.rclone-cache"; + type = lib.types.str; + }; + + audioCacheSize = lib.mkOption { + default = "15G"; + type = lib.types.str; + }; + videoCacheSize = lib.mkOption { + default = "50G"; + type = lib.types.str; + }; + audioReadAhead = lib.mkOption { + default = "1G"; + type = lib.types.str; + }; + videoReadAhead = lib.mkOption { + default = "3G"; + type = lib.types.str; + }; + + shares = lib.mkOption { + description = "Which B2 shares to mount."; + default = ["Anime" "Audiobooks" "Movies" "Music" "Shows"]; + type = lib.types.listOf (lib.types.enum ["Anime" "Audiobooks" "Movies" "Music" "Shows"]); + }; + }; + + config = { + sops.secrets.b2-mount-rclone = { + sopsFile = "${self}/secrets/b2.yaml"; + key = "rclone_config"; + }; + + environment.systemPackages = [pkgs.rclone]; + + fileSystems = builtins.foldl' (a: b: a // b) {} (builtins.attrValues (builtins.intersectAttrs (builtins.listToAttrs (map (s: { + name = s; + value = null; + }) + cfg.shares)) + allShares)); + }; + }; +} diff --git a/nix/modules/nixos/profiles/backups.nix b/nix/modules/nixos/profiles/backups.nix new file mode 100644 index 00000000..068bb101 --- /dev/null +++ b/nix/modules/nixos/profiles/backups.nix @@ -0,0 +1,99 @@ +_: { + flake.nixosModules.backups = { + config, + lib, + self, + ... + }: let + backupDestination = "rclone:b2:aly-backups/${config.networking.hostName}"; + mkRepo = service: "${backupDestination}/${service}"; + + restic = { + extraBackupArgs = [ + "--cleanup-cache" + "--compression max" + "--no-scan" + ]; + + inhibitsSleep = true; + initialize = true; + passwordFile = config.sops.secrets.restic-passwd.path; + + pruneOpts = [ + "--keep-daily 7" + "--keep-weekly 4" + "--keep-monthly 3" + ]; + + rcloneConfigFile = config.sops.secrets.rclone-b2.path; + + timerConfig = { + OnCalendar = "daily"; + Persistent = true; + RandomizedDelaySec = "3h"; + }; + }; + in { + options.myNixOs.profile.backups = { + jobs = lib.mkOption { + description = "Restic backup jobs rendered with the shared defaults."; + default = {}; + + type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { + options = { + paths = lib.mkOption { + type = lib.types.listOf lib.types.path; + description = "Paths to back up."; + }; + + repository = lib.mkOption { + type = lib.types.str; + default = mkRepo name; + description = "Restic repository URL."; + }; + + backupPrepareCommand = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + }; + + backupCleanupCommand = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + }; + + exclude = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = []; + }; + }; + })); + }; + }; + + config = { + sops.secrets = { + restic-passwd = { + sopsFile = "${self}/secrets/restic.yaml"; + key = "PASSWORD"; + }; + + rclone-b2 = { + sopsFile = "${self}/secrets/b2.yaml"; + key = "rclone_config"; + }; + }; + + services.restic.backups = let + mkRestic = _: job: + restic + // { + inherit (job) paths repository exclude; + backupPrepareCommand = lib.mkIf (job.backupPrepareCommand != null) job.backupPrepareCommand; + backupCleanupCommand = lib.mkIf (job.backupCleanupCommand != null) job.backupCleanupCommand; + }; + in + lib.mapAttrs mkRestic config.myNixOs.profile.backups.jobs; + }; + }; +} diff --git a/nix/modules/nixos/profiles/btrfs.nix b/nix/modules/nixos/profiles/btrfs.nix new file mode 100644 index 00000000..1bcbd48f --- /dev/null +++ b/nix/modules/nixos/profiles/btrfs.nix @@ -0,0 +1,77 @@ +_: { + flake.nixosModules.btrfs = { + config, + lib, + pkgs, + ... + }: let + btrfsFSDevices = let + isDeviceInList = list: device: builtins.any (e: e.device == device) list; + uniqueDeviceList = lib.foldl' (acc: e: + if isDeviceInList acc e.device + then acc + else acc ++ [e]) []; + in + uniqueDeviceList ( + lib.mapAttrsToList (_: fs: {inherit (fs) mountPoint device;}) + (lib.filterAttrs (_: fs: fs.fsType == "btrfs") config.fileSystems) + ); + + beesdConfig = lib.listToAttrs (map (fs: { + name = lib.strings.sanitizeDerivationName (baseNameOf fs.device); + value = { + hashTableSizeMB = 2048; + spec = fs.device; + verbosity = "info"; + extraOptions = ["--loadavg-target" "1.0" "--thread-factor" "0.50"]; + }; + }) + btrfsFSDevices); + + hasHomeSubvolume = + lib.hasAttr "/home" config.fileSystems + && config.fileSystems."/home".fsType == "btrfs"; + in { + options.myNixOs.profile.btrfs = { + deduplicate = lib.mkEnableOption "deduplicate btrfs filesystems"; + }; + + config = { + boot.supportedFilesystems = ["btrfs"]; + environment.systemPackages = lib.optionals config.services.xserver.enable [pkgs.snapper-gui]; + + services = lib.mkIf (btrfsFSDevices != []) { + beesd.filesystems = lib.mkIf config.myNixOs.profile.btrfs.deduplicate beesdConfig; + btrfs.autoScrub.enable = true; + + snapper = { + configs.home = lib.mkIf hasHomeSubvolume { + ALLOW_GROUPS = ["users"]; + FSTYPE = "btrfs"; + SUBVOLUME = "/home"; + TIMELINE_CLEANUP = true; + TIMELINE_CREATE = true; + }; + + filters = '' + -.bash_profile + -.bashrc + -.cache + -.config + -.librewolf + -.local + -.mozilla + -.nix-profile + -.pki + -.share + -.snapshots + -.thunderbird + -.zshrc + ''; + + persistentTimer = true; + }; + }; + }; + }; +} diff --git a/nix/nixos/profiles/data-share.nix b/nix/modules/nixos/profiles/data-share.nix similarity index 80% rename from nix/nixos/profiles/data-share.nix rename to nix/modules/nixos/profiles/data-share.nix index 3416b259..b2146d2e 100644 --- a/nix/nixos/profiles/data-share.nix +++ b/nix/modules/nixos/profiles/data-share.nix @@ -1,12 +1,9 @@ -{ - config, - lib, - pkgs, - ... -}: { - options.myNixOs.profile.dataShare.enable = lib.mkEnableOption "NFS data share"; - - config = lib.mkIf config.myNixOs.profile.dataShare.enable { +_: { + flake.nixosModules.dataShare = { + config, + pkgs, + ... + }: { assertions = [ { assertion = config.services.tailscale.enable; diff --git a/nix/modules/nixos/profiles/k3s.nix b/nix/modules/nixos/profiles/k3s.nix new file mode 100644 index 00000000..a7eee5c5 --- /dev/null +++ b/nix/modules/nixos/profiles/k3s.nix @@ -0,0 +1,173 @@ +_: { + flake.nixosModules.k3s = { + config, + lib, + pkgs, + self, + ... + }: let + cfg = config.myNixOs.profile.k3s; + transportService = + if cfg.transportInterface == "wg-k3s" + then "wireguard-wg-k3s.service" + else "tailscaled.service"; + in { + options.myNixOs.profile.k3s = { + role = lib.mkOption { + type = lib.types.enum ["server" "agent"]; + default = "server"; + }; + + clusterInit = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Whether this node initializes the cluster's etcd. Exactly one node + in the cluster should set this. Other servers join via `serverAddr`. + ''; + }; + + serverAddr = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "https://solaceon:6443"; + }; + + transportInterface = lib.mkOption { + type = lib.types.str; + default = "tailscale0"; + description = "Network interface used for k3s node and Flannel traffic."; + }; + + nodeIP = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = "Address k3s advertises for the Kubernetes node."; + }; + + tlsSans = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ + "snowpoint" + "pastoria" + "jubilife" + "snowpoint.cute" + "pastoria.cute" + "jubilife.cute" + ]; + }; + + zone = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "cloud"; + }; + + ingress = lib.mkEnableOption "cute.haus/ingress=true node label"; + }; + + config = { + sops.secrets.k3s = { + sopsFile = "${self}/secrets/k3s.yaml"; + key = "TOKEN"; + }; + + # systemd-oomd fights kubelet's eviction manager + systemd.oomd.enable = lib.mkForce false; + + networking.firewall = { + allowedTCPPorts = lib.mkIf cfg.ingress [80 443 2222]; + + # Let a pod reach kubelet:10250 on its own host. Same-node traffic to + # the node's Tailscale IP is delivered locally and arrives via cni0, so + # metrics-server can't scrape the node it runs on without this. + trustedInterfaces = ["cni0"]; + }; + + services = { + k3s = { + enable = true; + inherit (cfg) role clusterInit; + serverAddr = lib.mkIf (cfg.serverAddr != null) cfg.serverAddr; + tokenFile = config.sops.secrets.k3s.path; + extraFlags = + [ + "--flannel-iface=${cfg.transportInterface}" + # Keep image storage below Longhorn's 75% disk-use ceiling. + "--kubelet-arg=image-gc-high-threshold=70" + "--kubelet-arg=image-gc-low-threshold=65" + ] + ++ lib.optionals (cfg.nodeIP != null) ["--node-ip=${cfg.nodeIP}"] + ++ lib.optionals (cfg.role == "server") ( + [ + "--service-node-port-range=8000-32767" + "--disable=traefik" + "--disable=servicelb" + ] + ++ lib.optionals (cfg.nodeIP != null) ["--advertise-address=${cfg.nodeIP}"] + ++ map (san: "--tls-san=${san}") cfg.tlsSans + ) + ++ lib.optionals cfg.clusterInit ["--write-kubeconfig-mode=644"] + ++ lib.optionals (cfg.zone != null) ["--node-label=topology.kubernetes.io/zone=${cfg.zone}"] + ++ lib.optionals cfg.ingress ["--node-label=cute.haus/ingress=true"]; + }; + + openiscsi = { + enable = true; + name = "iqn.2026-05.haus.cute:${config.networking.hostName}"; + }; + }; + + environment.systemPackages = with pkgs; [ + kubernetes-helm + nfs-utils + ]; + + systemd = { + # Longhorn instance-manager looks for binaries in /usr/local/bin + tmpfiles.rules = [ + "L+ /usr/local/bin - - - - /run/current-system/sw/bin/" + ]; + + services = { + # Block k3s startup until its transport interface has an IP. This + # prevents Flannel and etcd peer setup from racing at cold boot. + k3s = { + after = [transportService]; + wants = [transportService]; + serviceConfig.ExecStartPre = pkgs.writeShellScript "wait-k3s-transport" '' + until ${pkgs.iproute2}/bin/ip -4 addr show ${cfg.transportInterface} | grep -q inet; do + ${pkgs.coreutils}/bin/sleep 1 + done + ''; + }; + + # Cleanly log out iSCSI sessions at shutdown so reboots don't hang + # waiting for udev scsi_id timeouts against dead longhorn devices. + iscsi-logout = { + description = "Log out iSCSI sessions cleanly at shutdown"; + after = ["iscsid.service"]; + before = ["k3s.service"]; + requires = ["iscsid.service"]; + wantedBy = ["multi-user.target"]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${pkgs.coreutils}/bin/true"; + ExecStop = "-${pkgs.openiscsi}/bin/iscsiadm -m node -u"; + TimeoutStopSec = "30s"; + }; + }; + }; + }; + myNixOs.profile.backups.jobs.k3s = lib.mkIf (config.services.k3s.role == "server") { + backupPrepareCommand = "${config.services.k3s.package}/bin/k3s etcd-snapshot save"; + paths = [ + "/var/lib/rancher/k3s/server/db/snapshots" + "/var/lib/rancher/k3s/server/cred" + "/var/lib/rancher/k3s/server/tls" + ]; + }; + }; + }; +} diff --git a/nix/nixos/profiles/media-share.nix b/nix/modules/nixos/profiles/media-share.nix similarity index 80% rename from nix/nixos/profiles/media-share.nix rename to nix/modules/nixos/profiles/media-share.nix index 2acb3f16..45427a1c 100644 --- a/nix/nixos/profiles/media-share.nix +++ b/nix/modules/nixos/profiles/media-share.nix @@ -1,12 +1,9 @@ -{ - config, - lib, - pkgs, - ... -}: { - options.myNixOs.profile.mediaShare.enable = lib.mkEnableOption "NFS media share"; - - config = lib.mkIf config.myNixOs.profile.mediaShare.enable { +_: { + flake.nixosModules.mediaShare = { + config, + pkgs, + ... + }: { assertions = [ { assertion = config.services.tailscale.enable; diff --git a/nix/nixos/profiles/observability.nix b/nix/modules/nixos/profiles/observability.nix similarity index 54% rename from nix/nixos/profiles/observability.nix rename to nix/modules/nixos/profiles/observability.nix index 0b2b1d60..15a9d777 100644 --- a/nix/nixos/profiles/observability.nix +++ b/nix/modules/nixos/profiles/observability.nix @@ -1,158 +1,148 @@ -{ - config, - lib, - pkgs, - ... -}: let - cfg = config.myNixOs.profile.observability; - tailnet = "narwhal-snapper.ts.net"; - kubernetesOperationsDashboard = builtins.toJSON { - annotations.list = []; - editable = true; - panels = [ - { - datasource = "Kubernetes Prometheus"; - fieldConfig.defaults.unit = "short"; - gridPos = { - h = 8; - w = 8; - x = 0; - y = 0; - }; - targets = [ - { - expr = "sum(gotk_reconcile_condition{type=\"Ready\",status=\"True\"})"; - refId = "A"; - } - ]; - title = "Flux resources ready"; - type = "stat"; - } - { - datasource = "Kubernetes Prometheus"; - fieldConfig.defaults.unit = "short"; - gridPos = { - h = 8; - w = 8; - x = 8; - y = 0; - }; - targets = [ - { - expr = "sum(gotk_reconcile_condition{type=\"Ready\",status=\"False\"})"; - refId = "A"; - } - ]; - title = "Flux reconciliation failures"; - type = "stat"; - } - { - datasource = "Kubernetes Prometheus"; - fieldConfig.defaults.unit = "short"; - gridPos = { - h = 8; - w = 8; - x = 16; - y = 0; - }; - targets = [ - { - expr = "sum(increase(kube_pod_container_status_restarts_total[1h]))"; - refId = "A"; - } - ]; - title = "Container restarts (1h)"; - type = "stat"; - } - { - datasource = "Kubernetes Prometheus"; - fieldConfig.defaults.unit = "short"; - gridPos = { - h = 8; - w = 8; - x = 0; - y = 8; - }; - targets = [ - { - expr = "sum(kube_pod_status_ready{condition=\"true\"})"; - refId = "A"; - } - ]; - title = "Ready pods"; - type = "stat"; - } - { - datasource = "Kubernetes Prometheus"; - fieldConfig.defaults.unit = "short"; - gridPos = { - h = 8; - w = 8; - x = 8; - y = 8; - }; - targets = [ - { - expr = "sum(kube_persistentvolumeclaim_status_phase{phase=\"Pending\"})"; - refId = "A"; - } - ]; - title = "Pending PVCs"; - type = "stat"; - } - { - datasource = "Kubernetes Prometheus"; - fieldConfig.defaults.unit = "percent"; - gridPos = { - h = 8; - w = 8; - x = 16; - y = 8; - }; - targets = [ - { - expr = "sum(kube_pod_container_resource_requests{resource=\"cpu\"}) / sum(kube_node_status_allocatable{resource=\"cpu\"})"; - refId = "A"; - } - ]; - title = "Requested node CPU"; - type = "gauge"; - } - { - datasource = "Loki"; - gridPos = { - h = 10; - w = 24; - x = 0; - y = 16; - }; - targets = [ - { - expr = "{job=\"kubernetes-pods\"} |~ \"(?i)error\""; - refId = "A"; - } - ]; - title = "Recent Kubernetes error logs"; - type = "logs"; - } - ]; - refresh = "30s"; - schemaVersion = 39; - tags = ["kubernetes" "operations"]; - templating.list = []; - time = { - from = "now-6h"; - to = "now"; +_: { + flake.nixosModules.observability = {pkgs, ...}: let + tailnet = "narwhal-snapper.ts.net"; + kubernetesOperationsDashboard = builtins.toJSON { + annotations.list = []; + editable = true; + panels = [ + { + datasource = "Kubernetes Prometheus"; + fieldConfig.defaults.unit = "short"; + gridPos = { + h = 8; + w = 8; + x = 0; + y = 0; + }; + targets = [ + { + expr = "sum(gotk_reconcile_condition{type=\"Ready\",status=\"True\"})"; + refId = "A"; + } + ]; + title = "Flux resources ready"; + type = "stat"; + } + { + datasource = "Kubernetes Prometheus"; + fieldConfig.defaults.unit = "short"; + gridPos = { + h = 8; + w = 8; + x = 8; + y = 0; + }; + targets = [ + { + expr = "sum(gotk_reconcile_condition{type=\"Ready\",status=\"False\"})"; + refId = "A"; + } + ]; + title = "Flux reconciliation failures"; + type = "stat"; + } + { + datasource = "Kubernetes Prometheus"; + fieldConfig.defaults.unit = "short"; + gridPos = { + h = 8; + w = 8; + x = 16; + y = 0; + }; + targets = [ + { + expr = "sum(increase(kube_pod_container_status_restarts_total[1h]))"; + refId = "A"; + } + ]; + title = "Container restarts (1h)"; + type = "stat"; + } + { + datasource = "Kubernetes Prometheus"; + fieldConfig.defaults.unit = "short"; + gridPos = { + h = 8; + w = 8; + x = 0; + y = 8; + }; + targets = [ + { + expr = "sum(kube_pod_status_ready{condition=\"true\"})"; + refId = "A"; + } + ]; + title = "Ready pods"; + type = "stat"; + } + { + datasource = "Kubernetes Prometheus"; + fieldConfig.defaults.unit = "short"; + gridPos = { + h = 8; + w = 8; + x = 8; + y = 8; + }; + targets = [ + { + expr = "sum(kube_persistentvolumeclaim_status_phase{phase=\"Pending\"})"; + refId = "A"; + } + ]; + title = "Pending PVCs"; + type = "stat"; + } + { + datasource = "Kubernetes Prometheus"; + fieldConfig.defaults.unit = "percent"; + gridPos = { + h = 8; + w = 8; + x = 16; + y = 8; + }; + targets = [ + { + expr = "sum(kube_pod_container_resource_requests{resource=\"cpu\"}) / sum(kube_node_status_allocatable{resource=\"cpu\"})"; + refId = "A"; + } + ]; + title = "Requested node CPU"; + type = "gauge"; + } + { + datasource = "Loki"; + gridPos = { + h = 10; + w = 24; + x = 0; + y = 16; + }; + targets = [ + { + expr = "{job=\"kubernetes-pods\"} |~ \"(?i)error\""; + refId = "A"; + } + ]; + title = "Recent Kubernetes error logs"; + type = "logs"; + } + ]; + refresh = "30s"; + schemaVersion = 39; + tags = ["kubernetes" "operations"]; + templating.list = []; + time = { + from = "now-6h"; + to = "now"; + }; + title = "Kubernetes Operations"; + uid = "kubernetes-operations"; }; - title = "Kubernetes Operations"; - uid = "kubernetes-operations"; - }; -in { - options.myNixOs.profile.observability.enable = lib.mkEnableOption "the Grafana, Prometheus, and Loki observability stack"; - - config = lib.mkIf cfg.enable { - myNixOs.service.caddy.enable = true; - + in { services = { caddy.virtualHosts = { "grafana.${tailnet}".extraConfig = '' diff --git a/nix/modules/nixos/profiles/swap.nix b/nix/modules/nixos/profiles/swap.nix new file mode 100644 index 00000000..452055a3 --- /dev/null +++ b/nix/modules/nixos/profiles/swap.nix @@ -0,0 +1,26 @@ +_: { + flake.nixosModules.swap = { + config, + lib, + ... + }: { + options.myNixOs.profile.swap = { + size = lib.mkOption { + default = 8192; + description = "Swap size in megabytes."; + type = lib.types.int; + }; + }; + + config = { + swapDevices = [ + { + device = "/.swap"; + priority = 0; + randomEncryption.enable = true; + inherit (config.myNixOs.profile.swap) size; + } + ]; + }; + }; +} diff --git a/nix/nixos/profiles/wireguard-k3s.nix b/nix/modules/nixos/profiles/wireguard-k3s.nix similarity index 54% rename from nix/nixos/profiles/wireguard-k3s.nix rename to nix/modules/nixos/profiles/wireguard-k3s.nix index fb65bd4f..48e846ee 100644 --- a/nix/nixos/profiles/wireguard-k3s.nix +++ b/nix/modules/nixos/profiles/wireguard-k3s.nix @@ -1,42 +1,39 @@ -{ - config, - lib, - self, - ... -}: let - cfg = config.myNixOs.profile.wireguardK3s; - nodes = { - jubilife = { - address = "10.254.0.1"; - homeEndpoint = "192.168.1.138:51820"; - listenPort = 51820; - publicKey = "6gZ8YuQXYq1cQKOWisgjeEwOX2KLYZNnGY6vIW5wvGU="; - }; - pastoria = { - address = "10.254.0.2"; - listenPort = 51820; - endpoint = "51.81.87.134:51820"; - publicKey = "5bEvmgY36NiZalRwEy9h0oZJqsJvPC+zmaD78GOLuUo="; - }; - snowpoint = { - address = "10.254.0.3"; - listenPort = 51820; - endpoint = "152.53.90.225:51820"; - publicKey = "t1mErjV5oE4ucLtRt2UHiPShkPluxp+uM2+pRoswVS8="; - }; - eterna = { - address = "10.254.0.4"; - homeEndpoint = "192.168.1.248:51821"; - listenPort = 51821; - publicKey = "jZV8JNiEx+mZ6BzYFAxqUPy1a78AZkdgTAt7VBClhGE="; +_: { + flake.nixosModules.wireguardK3s = { + config, + lib, + self, + ... + }: let + nodes = { + jubilife = { + address = "10.254.0.1"; + homeEndpoint = "192.168.1.138:51820"; + listenPort = 51820; + publicKey = "6gZ8YuQXYq1cQKOWisgjeEwOX2KLYZNnGY6vIW5wvGU="; + }; + pastoria = { + address = "10.254.0.2"; + listenPort = 51820; + endpoint = "51.81.87.134:51820"; + publicKey = "5bEvmgY36NiZalRwEy9h0oZJqsJvPC+zmaD78GOLuUo="; + }; + snowpoint = { + address = "10.254.0.3"; + listenPort = 51820; + endpoint = "152.53.90.225:51820"; + publicKey = "t1mErjV5oE4ucLtRt2UHiPShkPluxp+uM2+pRoswVS8="; + }; + eterna = { + address = "10.254.0.4"; + homeEndpoint = "192.168.1.248:51821"; + listenPort = 51821; + publicKey = "jZV8JNiEx+mZ6BzYFAxqUPy1a78AZkdgTAt7VBClhGE="; + }; }; - }; - node = nodes.${config.networking.hostName}; - isHomeNode = node ? homeEndpoint; -in { - options.myNixOs.profile.wireguardK3s.enable = lib.mkEnableOption "the dedicated k3s WireGuard mesh"; - - config = lib.mkIf cfg.enable { + node = nodes.${config.networking.hostName}; + isHomeNode = node ? homeEndpoint; + in { sops.secrets.wireguard-k3s-private = { sopsFile = "${self}/secrets/wireguard-k3s.yaml"; key = config.networking.hostName; diff --git a/nix/modules/nixos/programs/direnv.nix b/nix/modules/nixos/programs/direnv.nix new file mode 100644 index 00000000..8067c0c5 --- /dev/null +++ b/nix/modules/nixos/programs/direnv.nix @@ -0,0 +1,9 @@ +_: { + flake.nixosModules.default = { + programs.direnv = { + enable = true; + nix-direnv.enable = true; + silent = true; + }; + }; +} diff --git a/nix/modules/nixos/programs/docker.nix b/nix/modules/nixos/programs/docker.nix new file mode 100644 index 00000000..77cbf997 --- /dev/null +++ b/nix/modules/nixos/programs/docker.nix @@ -0,0 +1,10 @@ +_: { + flake.nixosModules.docker = { + virtualisation.oci-containers.backend = "docker"; + + virtualisation.docker = { + enable = true; + autoPrune.enable = true; + }; + }; +} diff --git a/nix/modules/nixos/programs/fish.nix b/nix/modules/nixos/programs/fish.nix new file mode 100644 index 00000000..1e32ac62 --- /dev/null +++ b/nix/modules/nixos/programs/fish.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.default = { + programs.fish.enable = true; + }; +} diff --git a/nix/modules/nixos/programs/git.nix b/nix/modules/nixos/programs/git.nix new file mode 100644 index 00000000..c3a98a1d --- /dev/null +++ b/nix/modules/nixos/programs/git.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.default = { + programs.git.enable = true; + }; +} diff --git a/nix/modules/nixos/programs/htop.nix b/nix/modules/nixos/programs/htop.nix new file mode 100644 index 00000000..370f796c --- /dev/null +++ b/nix/modules/nixos/programs/htop.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.default = { + programs.htop.enable = true; + }; +} diff --git a/nix/nixos/programs/lanzaboote.md b/nix/modules/nixos/programs/lanzaboote.md similarity index 100% rename from nix/nixos/programs/lanzaboote.md rename to nix/modules/nixos/programs/lanzaboote.md diff --git a/nix/nixos/programs/lanzaboote.nix b/nix/modules/nixos/programs/lanzaboote.nix similarity index 59% rename from nix/nixos/programs/lanzaboote.nix rename to nix/modules/nixos/programs/lanzaboote.nix index 41d240c4..ae134fbb 100644 --- a/nix/nixos/programs/lanzaboote.nix +++ b/nix/modules/nixos/programs/lanzaboote.nix @@ -1,15 +1,12 @@ -{ - config, - inputs, - lib, - pkgs, - ... -}: { - imports = [inputs.lanzaboote.nixosModules.lanzaboote]; +_: { + flake.nixosModules.lanzaboote = { + inputs, + lib, + pkgs, + ... + }: { + imports = [inputs.lanzaboote.nixosModules.lanzaboote]; - options.myNixOs.program.lanzaboote.enable = lib.mkEnableOption "Lanzaboote secure boot"; - - config = lib.mkIf config.myNixOs.program.lanzaboote.enable { boot = { initrd.systemd.enable = true; diff --git a/nix/modules/nixos/programs/nh.nix b/nix/modules/nixos/programs/nh.nix new file mode 100644 index 00000000..60f0025b --- /dev/null +++ b/nix/modules/nixos/programs/nh.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.default = { + programs.nh.enable = true; + }; +} diff --git a/nix/modules/nixos/programs/nix.nix b/nix/modules/nixos/programs/nix.nix new file mode 100644 index 00000000..290e962f --- /dev/null +++ b/nix/modules/nixos/programs/nix.nix @@ -0,0 +1,94 @@ +_: { + flake.nixosModules.default = { + config, + lib, + ... + }: let + buildMachines = [ + { + hostName = "jubilife"; + maxJobs = 12; + protocol = "ssh-ng"; + speedFactor = 5; + sshKey = "/etc/ssh/ssh_host_ed25519_key"; + sshUser = "nixbuild"; + supportedFeatures = ["nixos-test" "benchmark" "big-parallel" "kvm"]; + systems = ["x86_64-linux"]; + } + ]; + + isBuildMachine = lib.elem config.networking.hostName (lib.map (m: m.hostName) buildMachines); + in { + config = lib.mkMerge [ + { + nix = { + buildMachines = lib.mkIf config.services.tailscale.enable ( + lib.filter (m: m.hostName != config.networking.hostName) buildMachines + ); + + distributedBuilds = true; + + gc = { + automatic = true; + + options = + if isBuildMachine + then "--delete-older-than 20d" + else "--delete-older-than 3d"; + + persistent = true; + randomizedDelaySec = "60min"; + }; + + extraOptions = '' + min-free = ${toString (1 * 1024 * 1024 * 1024)} + max-free = ${toString (5 * 1024 * 1024 * 1024)} + ''; + + optimise = { + automatic = true; + persistent = true; + randomizedDelaySec = "60min"; + }; + + settings = { + builders-use-substitutes = true; + + experimental-features = [ + "fetch-closure" + "flakes" + "nix-command" + ]; + + substituters = [ + "https://cache.nixos.org/" + "https://cutehaus.cachix.org" + ]; + + trusted-public-keys = [ + "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" + "cutehaus.cachix.org-1:KiifTsseQBitoaHH8rkDUDwzyz9akLeOM+K+e2eK8dA=" + ]; + + trusted-users = ["aly" "@admin" "@wheel" "nixbuild"]; + }; + }; + + programs.nix-ld.enable = true; + + users.users.nixbuild = lib.mkIf isBuildMachine { + uid = 1999; + isNormalUser = true; + createHome = false; + group = "nixbuild"; + }; + + users.groups.nixbuild = lib.mkIf isBuildMachine {}; + } + + (lib.mkIf isBuildMachine { + mySshKeys.authorizedUsers.nixbuild = ["aly" "root"]; + }) + ]; + }; +} diff --git a/nix/nixos/programs/podman.nix b/nix/modules/nixos/programs/podman.nix similarity index 56% rename from nix/nixos/programs/podman.nix rename to nix/modules/nixos/programs/podman.nix index d2ba1c83..43841dca 100644 --- a/nix/nixos/programs/podman.nix +++ b/nix/modules/nixos/programs/podman.nix @@ -1,11 +1,5 @@ -{ - config, - lib, - ... -}: { - options.myNixOs.program.podman.enable = lib.mkEnableOption "podman container runtime"; - - config = lib.mkIf config.myNixOs.program.podman.enable { +_: { + flake.nixosModules.podman = { virtualisation.oci-containers.backend = "podman"; virtualisation.podman = { diff --git a/nix/modules/nixos/programs/sudo.nix b/nix/modules/nixos/programs/sudo.nix new file mode 100644 index 00000000..7325bb10 --- /dev/null +++ b/nix/modules/nixos/programs/sudo.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.default = { + security.sudo-rs.enable = true; + }; +} diff --git a/nix/nixos/programs/systemd-boot.nix b/nix/modules/nixos/programs/systemd-boot.nix similarity index 61% rename from nix/nixos/programs/systemd-boot.nix rename to nix/modules/nixos/programs/systemd-boot.nix index 2eff54f9..3a85c3b4 100644 --- a/nix/nixos/programs/systemd-boot.nix +++ b/nix/modules/nixos/programs/systemd-boot.nix @@ -1,11 +1,5 @@ -{ - config, - lib, - ... -}: { - options.myNixOs.program.systemdBoot.enable = lib.mkEnableOption "systemd-boot"; - - config = lib.mkIf config.myNixOs.program.systemdBoot.enable { +_: { + flake.nixosModules.systemdBoot = {lib, ...}: { boot = { initrd.systemd.enable = lib.mkDefault true; diff --git a/nix/modules/nixos/repository.nix b/nix/modules/nixos/repository.nix new file mode 100644 index 00000000..9131f5df --- /dev/null +++ b/nix/modules/nixos/repository.nix @@ -0,0 +1,6 @@ +_: { + flake.nixosModules.default = {self, ...}: { + environment.etc."nixos".source = self; + system.configurationRevision = self.rev or self.dirtyRev or null; + }; +} diff --git a/nix/modules/nixos/services/alloy.nix b/nix/modules/nixos/services/alloy.nix new file mode 100644 index 00000000..eef8ab2c --- /dev/null +++ b/nix/modules/nixos/services/alloy.nix @@ -0,0 +1,51 @@ +_: { + flake.nixosModules.alloy = { + config, + lib, + ... + }: { + options.myNixOs.service.alloy = { + lokiUrl = lib.mkOption { + description = "Loki URL to report to"; + default = "https://loki.narwhal-snapper.ts.net/loki/api/v1/push"; + type = lib.types.str; + }; + }; + + config = { + services.alloy.enable = true; + + environment.etc."alloy/config.alloy".text = '' + loki.write "default" { + endpoint { + url = "${config.myNixOs.service.alloy.lokiUrl}" + } + } + + loki.relabel "journal" { + forward_to = [] + + rule { + source_labels = ["__journal__systemd_unit"] + target_label = "unit" + } + + rule { + source_labels = ["__journal__systemd_user_unit"] + target_label = "user_unit" + } + } + + loki.source.journal "read" { + forward_to = [loki.write.default.receiver] + relabel_rules = loki.relabel.journal.rules + max_age = "12h" + labels = { + job = "systemd-journal", + host = "${config.networking.hostName}", + } + } + ''; + }; + }; +} diff --git a/nix/modules/nixos/services/atbbs.nix b/nix/modules/nixos/services/atbbs.nix new file mode 100644 index 00000000..c0a88376 --- /dev/null +++ b/nix/modules/nixos/services/atbbs.nix @@ -0,0 +1,43 @@ +_: { + flake.nixosModules.atbbs = { + config, + lib, + ... + }: { + options.myNixOs.service.atbbs = { + port = lib.mkOption { + description = "Port to listen on."; + default = 8582; + type = lib.types.int; + }; + + telnetPort = lib.mkOption { + description = "Port to listen on for telnet."; + default = 2323; + type = lib.types.int; + }; + }; + + config = { + networking.firewall.allowedTCPPorts = [ + config.myNixOs.service.atbbs.port + config.myNixOs.service.atbbs.telnetPort + ]; + + virtualisation.oci-containers.containers = { + atbbs = { + extraOptions = ["--pull=always"]; + image = "ghcr.io/alyraffauf/atbbs"; + environment.PUBLIC_URL = "https://atbbs.xyz"; + ports = ["0.0.0.0:${toString config.myNixOs.service.atbbs.port}:80"]; + }; + + atbbs-telnet = { + extraOptions = ["--pull=always"]; + image = "ghcr.io/alyraffauf/atbbs-telnet"; + ports = ["0.0.0.0:${toString config.myNixOs.service.atbbs.telnetPort}:2323"]; + }; + }; + }; + }; +} diff --git a/nix/modules/nixos/services/auto-upgrade.nix b/nix/modules/nixos/services/auto-upgrade.nix new file mode 100644 index 00000000..412b8ffa --- /dev/null +++ b/nix/modules/nixos/services/auto-upgrade.nix @@ -0,0 +1,37 @@ +_: { + flake.nixosModules.default = { + config, + lib, + ... + }: { + options.myNixOs.profile.base.flakeUrl = lib.mkOption { + type = lib.types.str; + default = "github:alyraffauf/infra"; + description = "Default flake URL for this NixOS configuration."; + }; + + config = { + environment.variables = { + FLAKE = config.myNixOs.profile.base.flakeUrl; + NH_FLAKE = config.myNixOs.profile.base.flakeUrl; + }; + + system.autoUpgrade = { + enable = true; + allowReboot = true; + dates = lib.mkDefault "02:00"; + flags = ["--accept-flake-config"]; + flake = config.myNixOs.profile.base.flakeUrl; + operation = lib.mkDefault "switch"; + persistent = true; + randomizedDelaySec = lib.mkDefault "0"; + runGarbageCollection = true; + + rebootWindow = { + lower = "02:00"; + upper = "06:00"; + }; + }; + }; + }; +} diff --git a/nix/modules/nixos/services/cachefilesd.nix b/nix/modules/nixos/services/cachefilesd.nix new file mode 100644 index 00000000..20bc7203 --- /dev/null +++ b/nix/modules/nixos/services/cachefilesd.nix @@ -0,0 +1,13 @@ +_: { + flake.nixosModules.cachefilesd = { + services.cachefilesd = { + enable = true; + + extraConfig = '' + brun 20% + bcull 10% + bstop 5% + ''; + }; + }; +} diff --git a/nix/nixos/services/caddy.nix b/nix/modules/nixos/services/caddy.nix similarity index 79% rename from nix/nixos/services/caddy.nix rename to nix/modules/nixos/services/caddy.nix index 38e599fd..253bf68e 100644 --- a/nix/nixos/services/caddy.nix +++ b/nix/modules/nixos/services/caddy.nix @@ -1,13 +1,10 @@ -{ - config, - lib, - pkgs, - self, - ... -}: { - options.myNixOs.service.caddy.enable = lib.mkEnableOption "Caddy web server"; - - config = lib.mkIf config.myNixOs.service.caddy.enable { +_: { + flake.nixosModules.caddy = { + config, + pkgs, + self, + ... + }: { sops.secrets.tailscaleCaddyAuth = { sopsFile = "${self}/secrets/tailscale.yaml"; key = "caddy_auth_env"; diff --git a/nix/nixos/services/fail2ban.nix b/nix/modules/nixos/services/fail2ban.nix similarity index 95% rename from nix/nixos/services/fail2ban.nix rename to nix/modules/nixos/services/fail2ban.nix index e7cd063d..ce5bb06b 100644 --- a/nix/nixos/services/fail2ban.nix +++ b/nix/modules/nixos/services/fail2ban.nix @@ -1,11 +1,5 @@ -{ - config, - lib, - ... -}: { - options.myNixOs.service.fail2ban.enable = lib.mkEnableOption "fail2ban"; - - config = lib.mkIf config.myNixOs.service.fail2ban.enable { +_: { + flake.nixosModules.fail2ban = {config, ...}: { environment.etc = { "fail2ban/filter.d/forgejo.conf".text = '' [Definition] diff --git a/nix/modules/nixos/services/forgejo-runner.nix b/nix/modules/nixos/services/forgejo-runner.nix new file mode 100644 index 00000000..27416f34 --- /dev/null +++ b/nix/modules/nixos/services/forgejo-runner.nix @@ -0,0 +1,77 @@ +_: { + flake.nixosModules.forgejoRunner = { + config, + lib, + pkgs, + self, + ... + }: { + options.myNixOs.service.forgejoRunner = { + nativeRunners = lib.mkOption { + type = lib.types.int; + default = 1; + description = "How many native NixOS runners to run."; + }; + + dockerContainers = lib.mkOption { + type = lib.types.int; + default = 1; + description = "How many docker containers to run."; + }; + }; + config = { + assertions = [ + { + assertion = config.services.tailscale.enable; + message = "We contact Forĝejo over tailscale, but services.tailscale.enable != true."; + } + ]; + + sops.secrets.act-runner = { + sopsFile = "${self}/secrets/act-runner.yaml"; + key = "TOKEN"; + }; + + services.gitea-actions-runner = let + arch = lib.replaceStrings ["-"] ["_"] pkgs.stdenv.hostPlatform.system; + in { + instances = let + tokenFile = config.sops.secrets.act-runner.path; + in { + alycodes-containers = { + inherit tokenFile; + enable = true; + labels = lib.optional (arch == "aarch64_linux") "ubuntu-24.04-arm:docker://gitea/runner-images:ubuntu-latest" ++ lib.optional (arch == "x86_64_linux") "ubuntu-latest:docker://gitea/runner-images:ubuntu-latest"; + name = "${arch}-${config.networking.hostName}-alycodes-containers"; + + settings = { + container.network = "host"; + runner.capacity = config.myNixOs.service.forgejoRunner.dockerContainers; + }; + + url = "https://git.aly.codes"; + }; + + alycodes-nixos = { + inherit tokenFile; + enable = true; + + hostPackages = with pkgs; + [bash cachix coreutils curl gawk gitMinimal gnused jq nodejs wget] + ++ [config.nix.package]; + + labels = ["nixos-${arch}:host"]; + name = "${arch}-${config.networking.hostName}-alycodes-nixos"; + + settings = { + container.network = "host"; + runner.capacity = config.myNixOs.service.forgejoRunner.nativeRunners; + }; + + url = "https://git.aly.codes"; + }; + }; + }; + }; + }; +} diff --git a/nix/modules/nixos/services/fstrim.nix b/nix/modules/nixos/services/fstrim.nix new file mode 100644 index 00000000..a590af52 --- /dev/null +++ b/nix/modules/nixos/services/fstrim.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.default = { + services.fstrim.enable = true; + }; +} diff --git a/nix/modules/nixos/services/journald.nix b/nix/modules/nixos/services/journald.nix new file mode 100644 index 00000000..eb165aae --- /dev/null +++ b/nix/modules/nixos/services/journald.nix @@ -0,0 +1,11 @@ +_: { + flake.nixosModules.default = { + services.journald = { + storage = "persistent"; + extraConfig = '' + SystemMaxUse=500M + MaxRetentionSec=1week + ''; + }; + }; +} diff --git a/nix/modules/nixos/services/networkmanager.nix b/nix/modules/nixos/services/networkmanager.nix new file mode 100644 index 00000000..76bdbcd2 --- /dev/null +++ b/nix/modules/nixos/services/networkmanager.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.default = { + networking.networkmanager.enable = true; + }; +} diff --git a/nix/nixos/base/openssh.nix b/nix/modules/nixos/services/openssh.nix similarity index 69% rename from nix/nixos/base/openssh.nix rename to nix/modules/nixos/services/openssh.nix index bcaf28c2..6a83bf7a 100644 --- a/nix/nixos/base/openssh.nix +++ b/nix/modules/nixos/services/openssh.nix @@ -1,9 +1,5 @@ -{ - config, - lib, - ... -}: { - config = lib.mkIf config.myNixOs.profile.base.enable { +_: { + flake.nixosModules.default = { services.openssh = { enable = true; openFirewall = true; diff --git a/nix/modules/nixos/services/plex.nix b/nix/modules/nixos/services/plex.nix new file mode 100644 index 00000000..1ba815a4 --- /dev/null +++ b/nix/modules/nixos/services/plex.nix @@ -0,0 +1,67 @@ +_: { + flake.nixosModules = { + plex = { + config, + inputs, + lib, + pkgs, + ... + }: { + options.myNixOs.service.plex.dataDir = lib.mkOption { + description = "Data directory to use."; + default = "/var/lib"; + type = lib.types.str; + }; + + config = { + services.plex = { + enable = true; + dataDir = "${config.myNixOs.service.plex.dataDir}/plex"; + extraPlugins = [ + (builtins.path { + name = "Audnexus.bundle"; + path = inputs.audnexus; + }) + (builtins.path { + name = "Hama.bundle"; + path = inputs.hama; + }) + ]; + extraScanners = [ + (builtins.path { + name = "Absolute-Series-Scanner"; + path = inputs.absolute; + }) + ]; + openFirewall = true; + }; + + systemd.services.plex.serviceConfig.TimeoutStopSec = 15; + + myNixOs.profile.backups.jobs.plex = { + backupCleanupCommand = "${pkgs.systemd}/bin/systemctl start plex"; + backupPrepareCommand = "${pkgs.systemd}/bin/systemctl stop plex"; + exclude = ["${config.services.plex.dataDir}/Plex Media Server/Plug-in Support/Databases"]; + paths = [config.services.plex.dataDir]; + }; + }; + }; + + tautulli = { + config, + pkgs, + ... + }: { + services.tautulli = { + enable = true; + openFirewall = true; + }; + + myNixOs.profile.backups.jobs.tautulli = { + backupCleanupCommand = "${pkgs.systemd}/bin/systemctl start tautulli"; + backupPrepareCommand = "${pkgs.systemd}/bin/systemctl stop tautulli"; + paths = [config.services.tautulli.dataDir]; + }; + }; + }; +} diff --git a/nix/nixos/services/prometheusNode.nix b/nix/modules/nixos/services/prometheus-node.nix similarity index 59% rename from nix/nixos/services/prometheusNode.nix rename to nix/modules/nixos/services/prometheus-node.nix index 2b493118..dc8e55f3 100644 --- a/nix/nixos/services/prometheusNode.nix +++ b/nix/modules/nixos/services/prometheus-node.nix @@ -1,11 +1,5 @@ -{ - config, - lib, - ... -}: { - options.myNixOs.service.prometheusNode.enable = lib.mkEnableOption "Prometheus node exporter"; - - config = lib.mkIf config.myNixOs.service.prometheusNode.enable { +_: { + flake.nixosModules.prometheusNode = { services.prometheus.exporters.node = { enable = true; enabledCollectors = ["systemd"]; diff --git a/nix/modules/nixos/services/qbittorrent.nix b/nix/modules/nixos/services/qbittorrent.nix new file mode 100644 index 00000000..fde525a9 --- /dev/null +++ b/nix/modules/nixos/services/qbittorrent.nix @@ -0,0 +1,21 @@ +_: { + flake.nixosModules.qbittorrent = { + config, + pkgs, + ... + }: { + services.qbittorrent = { + enable = true; + profileDir = "/var/lib/qbittorrent"; + }; + + myNixOs.profile.backups.jobs.qbittorrent = let + stop = service: "${pkgs.systemd}/bin/systemctl stop ${service}"; + start = service: "${pkgs.systemd}/bin/systemctl start ${service}"; + in { + backupCleanupCommand = start "qbittorrent"; + backupPrepareCommand = stop "qbittorrent"; + paths = [config.services.qbittorrent.profileDir]; + }; + }; +} diff --git a/nix/modules/nixos/services/syncthing.nix b/nix/modules/nixos/services/syncthing.nix new file mode 100644 index 00000000..2cd9d6b0 --- /dev/null +++ b/nix/modules/nixos/services/syncthing.nix @@ -0,0 +1,134 @@ +_: { + flake.nixosModules.syncthing = { + config, + lib, + ... + }: { + options.myNixOs.service.syncthing = { + certFile = lib.mkOption { + description = "Path to the certificate file."; + type = lib.types.path; + }; + + keyFile = lib.mkOption { + description = "Path to the key file."; + type = lib.types.path; + }; + + romsPath = lib.mkOption { + default = "/home/${config.myNixOs.service.syncthing.user}/roms"; + description = "Path to the ROM folder."; + type = lib.types.path; + }; + + syncROMs = lib.mkEnableOption "Whether to sync ROMs."; + + user = lib.mkOption { + description = "User to run Syncthing as."; + type = lib.types.str; + }; + }; + + config = { + systemd.services.syncthing.environment.STNODEFAULTFOLDER = "true"; + + services = { + caddy.virtualHosts = + lib.mkIf + (config.services.caddy.enable && config.services.tailscale.enable) + { + "syncthing-${config.networking.hostName}.narwhal-snapper.ts.net" = { + extraConfig = '' + bind tailscale/syncthing-${config.networking.hostName} + reverse_proxy localhost:8384 { + header_up Host localhost + } + ''; + }; + }; + + syncthing = let + cfg = config.myNixOs.service.syncthing; + + devices = { + "allyx" = {id = "XTEVJX2-DBEFN4X-UCG43YR-V4FOQYU-DMM2WH4-AMCC5FS-42UB3DM-KUDVHQL";}; + "eterna" = {id = "ZAD2MVO-I2OQII4-C3T756B-BEBQMM6-Q4ILH2H-5CR3TMI-DR4VBFD-GLRVOQK";}; + "fallarbor" = {id = "P4URLH4-YWLMO6J-W62ET7H-TQAO3Y6-T2FAYOY-C2VTI65-VQXHVGG-NQ76PAZ";}; + "fortree" = {id = "S6PVA3I-EKOCGIU-GFX7AE6-FXM45OW-JTYN5LJ-UZ4LADZ-NNAJGDD-KST2VAG";}; + "groudon" = {id = "VOEAEAG-NP5Z3BM-DK5FO75-6G4NKSJ-3EUNFSV-VIR4KDH-OM6ZN7L-OOQKCQJ";}; + "jubilife" = {id = "52MTCMC-PKEWSAU-HADMTZU-DY5EKFO-B323P7V-OBXLNTQ-EJY7F7Y-EUWFBQX";}; + "kyogre" = {id = "SBQNUXS-H4XDJ3E-RBHJPT5-45WDJJA-2U43M4P-23XGUJ7-E3CNNKZ-BXSGIA3";}; + "oreburgh" = {id = "RFVF6DA-CQJLXTP-RKMYEB3-D2KMWJH-3Z2CIAN-PNYOXI6-FIDBFWG-JJA57AX";}; + "pacifidlog" = {id = "6EBVXYI-HZW4LQI-T6L3TTI-DZEBXJM-RP3DW7N-BCAG6FC-G2654DN-XJFSLQD";}; + "petalburg" = {id = "O75EK2H-YBXPM5D-PBYV7XB-DJKFL3E-OFZBB7H-MLCD2UT-NXQRMDG-BTZZQQH";}; + "rp5" = {id = "5AKCXRS-XU7BBSS-RDPSSLG-4BDOZ4K-OXLFQZX-HJSM53W-4GLSOAC-RZ7APA7";}; + "rpclassic" = {id = "EDNFUWI-UFYEOPI-QPJIEWF-NXVEGZ6-2J7IXW7-X22L27F-VU6JKSB-CH6GDAO";}; + "rustboro" = {id = "NY53BFH-CPVCXGH-MI5AT7E-WBK7TXS-5NQDSCW-J5BALLV-EGS2VJL-CMED2AH";}; + "slateport" = {id = "MDJFDUG-UJAXQXI-AMEF2AR-PBMD5QK-Z5ZG6AA-RCJCU3M-GZHQQEA-X2JGOAK";}; + "snowpoint" = {id = "TFSZWZB-EDIFV2P-333APP2-T655TM4-2XGA7QA-P22Z36W-3RNGX2C-DLETAQ7";}; + "sootopolis" = {id = "7QGSZ2D-CGMLPWD-OCFCBXP-7746W7F-COFV52F-Q2PMCAS-GV5DCSV-6NIXDQJ";}; + "thor" = {id = "B33X5WA-S6P4XEE-VURE4PB-WKMXHLP-6AG55LZ-QIG6ZJG-GDGXWAD-EDVIRAF";}; + "verdanturf" = {id = "CQ7A2KW-2JRZHEO-NF6NZLY-C2OX4SO-EPKQRMV-7YBSSFA-FJ2CW2P-NOIKPQB";}; + }; + + folders = lib.mkMerge [ + { + "sync" = { + devices = ["allyx" "eterna" "fallarbor" "fortree" "groudon" "jubilife" "kyogre" "oreburgh" "pacifidlog" "petalburg" "rustboro" "slateport" "snowpoint" "sootopolis" "verdanturf"]; + id = "default"; + path = "~/sync"; + versioning = { + params.cleanoutDays = "5"; + type = "trashcan"; + }; + }; + + "screenshots" = { + devices = ["fallarbor" "oreburgh" "jubilife" "pacifidlog" "petalburg" "rustboro" "slateport" "snowpoint" "sootopolis" "verdanturf"]; + id = "screenshots"; + path = "~/pics/screenshots"; + versioning = { + params.cleanoutDays = "5"; + type = "trashcan"; + }; + }; + + "roms" = { + devices = ["jubilife" "oreburgh" "pacifidlog" "petalburg" "rp5" "rpclassic" "rustboro" "sootopolis" "thor"]; + id = "emudeck"; + versioning = { + params.cleanoutDays = "3"; + type = "trashcan"; + }; + }; + } + { + "roms" = { + enable = cfg.syncROMs; + path = cfg.romsPath; + }; + } + ]; + in { + enable = true; + cert = cfg.certFile; + configDir = "${config.services.syncthing.dataDir}/.syncthing"; + dataDir = "/home/${cfg.user}"; + key = cfg.keyFile; + openDefaultPorts = true; + inherit (cfg) user; + + settings = { + options = { + localAnnounceEnabled = true; + relaysEnabled = true; + urAccepted = -1; + }; + + inherit devices folders; + }; + }; + }; + }; + }; +} diff --git a/nix/modules/nixos/services/tailscale.nix b/nix/modules/nixos/services/tailscale.nix new file mode 100644 index 00000000..36693848 --- /dev/null +++ b/nix/modules/nixos/services/tailscale.nix @@ -0,0 +1,69 @@ +_: { + flake.nixosModules.tailscale = { + config, + lib, + self, + ... + }: { + options.myNixOs.service.tailscale = { + authKeyFile = lib.mkOption { + description = "Key file to use for authentication"; + default = config.sops.secrets.tailscaleAuthKey.path or null; + type = lib.types.nullOr lib.types.path; + }; + + operator = lib.mkOption { + description = "Tailscale operator name"; + default = null; + type = lib.types.nullOr lib.types.str; + }; + }; + config = { + sops.secrets.tailscaleAuthKey = { + sopsFile = "${self}/secrets/tailscale.yaml"; + key = "auth_key"; + }; + + assertions = [ + { + assertion = config.myNixOs.service.tailscale.authKeyFile != null; + message = "config.myNixOs.service.tailscale.authKeyFile cannot be null."; + } + ]; + + networking.firewall = { + allowedUDPPorts = [config.services.tailscale.port]; + trustedInterfaces = [config.services.tailscale.interfaceName]; + }; + + services = { + # When caddy is also enabled, expose a tailnet-hostname vhost that + # proxies the local syncthing UI through /syncthing/. + caddy = lib.mkIf config.services.caddy.enable { + virtualHosts."${config.networking.hostName}.narwhal-snapper.ts.net".extraConfig = lib.concatLines (lib.optional config.services.syncthing.enable '' + redir /syncthing /syncthing/ + handle_path /syncthing/* { + reverse_proxy localhost:8384 { + header_up Host localhost + } + } + ''); + }; + + tailscale = { + enable = true; + authKeyFile = config.myNixOs.service.tailscale.authKeyFile; + + extraUpFlags = + ["--ssh"] + ++ lib.optional (config.myNixOs.service.tailscale.operator != null) + "--operator ${config.myNixOs.service.tailscale.operator}"; + + openFirewall = true; + permitCertUid = lib.mkIf config.services.caddy.enable "caddy"; + useRoutingFeatures = "both"; + }; + }; + }; + }; +} diff --git a/nix/modules/nixos/services/timesyncd.nix b/nix/modules/nixos/services/timesyncd.nix new file mode 100644 index 00000000..ad2097af --- /dev/null +++ b/nix/modules/nixos/services/timesyncd.nix @@ -0,0 +1,5 @@ +_: { + flake.nixosModules.default = { + services.timesyncd.enable = true; + }; +} diff --git a/nix/modules/nixos/ssh-keys.nix b/nix/modules/nixos/ssh-keys.nix new file mode 100644 index 00000000..45ec05be --- /dev/null +++ b/nix/modules/nixos/ssh-keys.nix @@ -0,0 +1,40 @@ +_: { + flake.nixosModules.default = { + config, + lib, + self, + ... + }: let + keyFiles = builtins.attrNames (builtins.readDir "${self}/keys"); + filesFor = keys: builtins.concatMap (key: config.mySshKeys.keys.${key} or []) keys; + in { + options.mySshKeys = { + keys = lib.mkOption { + type = lib.types.attrsOf (lib.types.listOf lib.types.path); + description = "Cached SSH key file paths, read once to avoid repeated filesystem scans."; + default = { + aly = lib.map (file: "${self}/keys/${file}") (lib.filter (file: lib.hasPrefix "aly_" file) keyFiles); + root = lib.map (file: "${self}/keys/${file}") (lib.filter (file: lib.hasPrefix "root_" file) keyFiles); + }; + }; + + authorizedUsers = lib.mkOption { + type = lib.types.attrsOf (lib.types.listOf lib.types.str); + default = {}; + }; + }; + + config = lib.mkMerge [ + { + mySshKeys.authorizedUsers.root = lib.mkDefault ["aly"]; + users.users.root.openssh.authorizedKeys.keyFiles = filesFor (config.mySshKeys.authorizedUsers.root or []); + } + (lib.mkIf (config.mySshKeys.authorizedUsers ? aly) { + users.users.aly.openssh.authorizedKeys.keyFiles = filesFor config.mySshKeys.authorizedUsers.aly; + }) + (lib.mkIf (config.mySshKeys.authorizedUsers ? nixbuild) { + users.users.nixbuild.openssh.authorizedKeys.keyFiles = filesFor config.mySshKeys.authorizedUsers.nixbuild; + }) + ]; + }; +} diff --git a/nix/modules/nixos/systemd.nix b/nix/modules/nixos/systemd.nix new file mode 100644 index 00000000..cf200eff --- /dev/null +++ b/nix/modules/nixos/systemd.nix @@ -0,0 +1,8 @@ +_: { + flake.nixosModules.default = { + systemd = { + coredump.enable = false; + enableEmergencyMode = false; + }; + }; +} diff --git a/nix/modules/nixos/users/aly.nix b/nix/modules/nixos/users/aly.nix new file mode 100644 index 00000000..a199d8b0 --- /dev/null +++ b/nix/modules/nixos/users/aly.nix @@ -0,0 +1,41 @@ +_: { + flake.nixosModules.aly = { + config, + lib, + ... + }: { + options.myNixOs.users.aly = { + password = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = "Hashed password for aly."; + }; + }; + + config = { + mySshKeys.authorizedUsers.aly = ["aly"]; + + users.users.aly = { + description = "Aly Raffauf"; + + extraGroups = [ + "cdrom" + "dialout" + "docker" + "libvirtd" + "lp" + "networkmanager" + "plugdev" + "scanner" + "transmission" + "video" + "wheel" + ]; + + hashedPassword = config.myNixOs.users.aly.password; + isNormalUser = true; + uid = 1000; + }; + }; + }; +} diff --git a/nix/nixos/base/users.nix b/nix/modules/nixos/users/defaults.nix similarity index 59% rename from nix/nixos/base/users.nix rename to nix/modules/nixos/users/defaults.nix index 169a0fa8..dc49aec1 100644 --- a/nix/nixos/base/users.nix +++ b/nix/modules/nixos/users/defaults.nix @@ -1,10 +1,5 @@ -{ - config, - lib, - pkgs, - ... -}: { - config = lib.mkIf config.myNixOs.profile.base.enable { +_: { + flake.nixosModules.default = {pkgs, ...}: { mySshKeys.authorizedUsers.root = ["aly"]; users = { diff --git a/nix/nixos/base/zram.nix b/nix/modules/nixos/zram.nix similarity index 53% rename from nix/nixos/base/zram.nix rename to nix/modules/nixos/zram.nix index 90b701b7..99348595 100644 --- a/nix/nixos/base/zram.nix +++ b/nix/modules/nixos/zram.nix @@ -1,9 +1,5 @@ -{ - config, - lib, - ... -}: { - config = lib.mkIf config.myNixOs.profile.base.enable { +_: { + flake.nixosModules.default = { zramSwap = { enable = true; algorithm = "zstd"; diff --git a/nix/overlays.nix b/nix/modules/overlays.nix similarity index 100% rename from nix/overlays.nix rename to nix/modules/overlays.nix diff --git a/nix/packages.nix b/nix/modules/packages.nix similarity index 100% rename from nix/packages.nix rename to nix/modules/packages.nix diff --git a/nix/treefmt.nix b/nix/modules/treefmt.nix similarity index 100% rename from nix/treefmt.nix rename to nix/modules/treefmt.nix diff --git a/nix/nixos.nix b/nix/nixos.nix deleted file mode 100644 index 390a4709..00000000 --- a/nix/nixos.nix +++ /dev/null @@ -1,5 +0,0 @@ -{inputs, ...}: { - flake.nixosModules = { - myNixOs = inputs.import-tree ./nixos; - }; -} diff --git a/nix/nixos/base/auto-upgrade.nix b/nix/nixos/base/auto-upgrade.nix deleted file mode 100644 index 8031d7f3..00000000 --- a/nix/nixos/base/auto-upgrade.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ - config, - lib, - ... -}: { - options.myNixOs.profile.base.flakeUrl = lib.mkOption { - type = lib.types.str; - default = "github:alyraffauf/infra"; - description = "Default flake URL for this NixOS configuration."; - }; - - config = lib.mkIf config.myNixOs.profile.base.enable { - environment.variables = { - FLAKE = config.myNixOs.profile.base.flakeUrl; - NH_FLAKE = config.myNixOs.profile.base.flakeUrl; - }; - - system.autoUpgrade = { - enable = true; - allowReboot = true; - dates = lib.mkDefault "02:00"; - flags = ["--accept-flake-config"]; - flake = config.myNixOs.profile.base.flakeUrl; - operation = lib.mkDefault "switch"; - persistent = true; - randomizedDelaySec = lib.mkDefault "0"; - runGarbageCollection = true; - - rebootWindow = { - lower = "02:00"; - upper = "06:00"; - }; - }; - }; -} diff --git a/nix/nixos/base/default.nix b/nix/nixos/base/default.nix deleted file mode 100644 index 58836030..00000000 --- a/nix/nixos/base/default.nix +++ /dev/null @@ -1,42 +0,0 @@ -{ - config, - lib, - self, - ... -}: { - options.myNixOs.profile.base.enable = lib.mkEnableOption "base system configuration"; - - config = lib.mkIf config.myNixOs.profile.base.enable { - documentation = { - enable = false; - nixos.enable = false; - }; - - environment.etc."nixos".source = self; - - hardware.enableAllFirmware = true; - networking.networkmanager.enable = true; - security.sudo-rs.enable = true; - - services = { - fstrim.enable = true; - - journald = { - storage = "persistent"; - extraConfig = '' - SystemMaxUse=500M - MaxRetentionSec=1week - ''; - }; - - timesyncd.enable = true; - }; - - system.configurationRevision = self.rev or self.dirtyRev or null; - - systemd = { - coredump.enable = false; - enableEmergencyMode = false; - }; - }; -} diff --git a/nix/nixos/base/known-hosts.nix b/nix/nixos/base/known-hosts.nix deleted file mode 100644 index 4b8c3559..00000000 --- a/nix/nixos/base/known-hosts.nix +++ /dev/null @@ -1,32 +0,0 @@ -{ - config, - lib, - self, - ... -}: let - tnet = "narwhal-snapper.ts.net"; - rootKeyFiles = lib.filterAttrs ( - fileName: fileType: - fileType - == "regular" - && lib.hasPrefix "root_" fileName - && lib.hasSuffix ".pub" fileName - ) (builtins.readDir "${self}/keys"); - aliases = { - eterna = ["eterna.cute" "mauville" "mauville.local" "mauville.${tnet}"]; - jubilife = ["jubilife.cute" "lilycove" "lilycove.local" "lilycove.${tnet}"]; - pastoria = ["pastoria.cute"]; - snowpoint = ["snowpoint.cute" "dewford" "dewford.local" "dewford.${tnet}"]; - }; -in { - config = lib.mkIf config.myNixOs.profile.base.enable { - programs.ssh.knownHosts = lib.mapAttrs' (fileName: _fileType: let - hostName = lib.removeSuffix ".pub" (lib.removePrefix "root_" fileName); - in - lib.nameValuePair hostName { - hostNames = [hostName "${hostName}.local" "${hostName}.${tnet}"] ++ (aliases.${hostName} or []); - publicKeyFile = "${self}/keys/${fileName}"; - }) - rootKeyFiles; - }; -} diff --git a/nix/nixos/base/nix.nix b/nix/nixos/base/nix.nix deleted file mode 100644 index 98004b30..00000000 --- a/nix/nixos/base/nix.nix +++ /dev/null @@ -1,92 +0,0 @@ -{ - config, - lib, - ... -}: let - buildMachines = [ - { - hostName = "jubilife"; - maxJobs = 12; - protocol = "ssh-ng"; - speedFactor = 5; - sshKey = "/etc/ssh/ssh_host_ed25519_key"; - sshUser = "nixbuild"; - supportedFeatures = ["nixos-test" "benchmark" "big-parallel" "kvm"]; - systems = ["x86_64-linux"]; - } - ]; - - isBuildMachine = lib.elem config.networking.hostName (lib.map (m: m.hostName) buildMachines); -in { - config = lib.mkIf config.myNixOs.profile.base.enable (lib.mkMerge [ - { - nix = { - buildMachines = lib.mkIf config.services.tailscale.enable ( - lib.filter (m: m.hostName != config.networking.hostName) buildMachines - ); - - distributedBuilds = true; - - gc = { - automatic = true; - - options = - if isBuildMachine - then "--delete-older-than 20d" - else "--delete-older-than 3d"; - - persistent = true; - randomizedDelaySec = "60min"; - }; - - extraOptions = '' - min-free = ${toString (1 * 1024 * 1024 * 1024)} - max-free = ${toString (5 * 1024 * 1024 * 1024)} - ''; - - optimise = { - automatic = true; - persistent = true; - randomizedDelaySec = "60min"; - }; - - settings = { - builders-use-substitutes = true; - - experimental-features = [ - "fetch-closure" - "flakes" - "nix-command" - ]; - - substituters = [ - "https://cache.nixos.org/" - "https://cutehaus.cachix.org" - ]; - - trusted-public-keys = [ - "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" - "cutehaus.cachix.org-1:KiifTsseQBitoaHH8rkDUDwzyz9akLeOM+K+e2eK8dA=" - ]; - - trusted-users = ["aly" "@admin" "@wheel" "nixbuild"]; - }; - }; - - programs.nix-ld.enable = true; - - users.users.nixbuild = lib.mkIf isBuildMachine { - uid = 1999; - isNormalUser = true; - createHome = false; - group = "nixbuild"; - }; - - users.groups.nixbuild = lib.mkIf isBuildMachine {}; - } - - (lib.mkIf isBuildMachine { - mySshKeys.authorizedUsers.nixbuild = ["aly" "root"]; - }) - ]); -} diff --git a/nix/nixos/base/programs.nix b/nix/nixos/base/programs.nix deleted file mode 100644 index 51e5d403..00000000 --- a/nix/nixos/base/programs.nix +++ /dev/null @@ -1,20 +0,0 @@ -{ - config, - lib, - ... -}: { - config = lib.mkIf config.myNixOs.profile.base.enable { - programs = { - direnv = { - enable = true; - nix-direnv.enable = true; - silent = true; - }; - - fish.enable = true; - git.enable = true; - htop.enable = true; - nh.enable = true; - }; - }; -} diff --git a/nix/nixos/base/ssh-keys.nix b/nix/nixos/base/ssh-keys.nix deleted file mode 100644 index 4d9f52f9..00000000 --- a/nix/nixos/base/ssh-keys.nix +++ /dev/null @@ -1,38 +0,0 @@ -{ - config, - lib, - self, - ... -}: let - keyFiles = builtins.attrNames (builtins.readDir "${self}/keys"); - filesFor = keys: builtins.concatMap (key: config.mySshKeys.keys.${key} or []) keys; -in { - options.mySshKeys = { - keys = lib.mkOption { - type = lib.types.attrsOf (lib.types.listOf lib.types.path); - description = "Cached SSH key file paths, read once to avoid repeated filesystem scans."; - default = { - aly = lib.map (file: "${self}/keys/${file}") (lib.filter (file: lib.hasPrefix "aly_" file) keyFiles); - root = lib.map (file: "${self}/keys/${file}") (lib.filter (file: lib.hasPrefix "root_" file) keyFiles); - }; - }; - - authorizedUsers = lib.mkOption { - type = lib.types.attrsOf (lib.types.listOf lib.types.str); - default = {}; - }; - }; - - config = lib.mkIf config.myNixOs.profile.base.enable (lib.mkMerge [ - { - mySshKeys.authorizedUsers.root = lib.mkDefault ["aly"]; - users.users.root.openssh.authorizedKeys.keyFiles = filesFor (config.mySshKeys.authorizedUsers.root or []); - } - (lib.mkIf (config.mySshKeys.authorizedUsers ? aly) { - users.users.aly.openssh.authorizedKeys.keyFiles = filesFor config.mySshKeys.authorizedUsers.aly; - }) - (lib.mkIf (config.mySshKeys.authorizedUsers ? nixbuild) { - users.users.nixbuild.openssh.authorizedKeys.keyFiles = filesFor config.mySshKeys.authorizedUsers.nixbuild; - }) - ]); -} diff --git a/nix/nixos/profiles/arr/default.nix b/nix/nixos/profiles/arr/default.nix deleted file mode 100644 index ea8de786..00000000 --- a/nix/nixos/profiles/arr/default.nix +++ /dev/null @@ -1,70 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: let - cfg = config.myNixOs.profile.arr; - arrServices = { - bazarr.dataDir = "${cfg.dataDir}/bazarr"; - lidarr = { - dataDir = "${cfg.dataDir}/lidarr/.config/Lidarr"; - createDataDir = true; - }; - prowlarr = {}; - radarr = { - dataDir = "${cfg.dataDir}/radarr/.config/Radarr/"; - createDataDir = true; - }; - sonarr = { - dataDir = "${cfg.dataDir}/sonarr/.config/NzbDrone/"; - createDataDir = true; - }; - }; - - enabledServices = - lib.mapAttrs ( - _: service: - { - enable = true; - openFirewall = true; - } - // lib.optionalAttrs (service ? dataDir) {inherit (service) dataDir;} - ) - arrServices; - - backupJobs = - lib.mapAttrs (serviceName: _: { - backupCleanupCommand = "${pkgs.systemd}/bin/systemctl start ${serviceName}"; - backupPrepareCommand = "${pkgs.systemd}/bin/systemctl stop ${serviceName}"; - paths = [config.services.${serviceName}.dataDir]; - }) - arrServices; - - dataDirectoryServices = lib.filterAttrs (_: service: service.createDataDir or false) arrServices; -in { - options.myNixOs.profile.arr = { - enable = lib.mkEnableOption "*arr services"; - - dataDir = lib.mkOption { - type = lib.types.str; - default = "/var/lib"; - description = "The directory where *arr stores its data files."; - }; - }; - - config = lib.mkMerge [ - (lib.mkIf cfg.enable { - services = enabledServices; - - systemd.tmpfiles.rules = - lib.mapAttrsToList ( - serviceName: service: "d ${service.dataDir} 0755 ${serviceName} ${serviceName}" - ) - dataDirectoryServices; - }) - (lib.mkIf (cfg.enable && config.myNixOs.profile.backups.enable) { - myNixOs.profile.backups.jobs = backupJobs; - }) - ]; -} diff --git a/nix/nixos/profiles/b2-mounts.nix b/nix/nixos/profiles/b2-mounts.nix deleted file mode 100644 index a2a161e9..00000000 --- a/nix/nixos/profiles/b2-mounts.nix +++ /dev/null @@ -1,104 +0,0 @@ -{ - config, - lib, - pkgs, - self, - ... -}: let - cfg = config.myNixOs.profile.b2Mounts; - - b2Options = [ - "allow_other" - "args2env" - "cache-dir=${cfg.cacheDir}" - "config=${config.sops.secrets.b2-mount-rclone.path}" - "dir-cache-time=1h" - "nodev" - "nofail" - "vfs-cache-mode=full" - "vfs-write-back=10s" - "x-systemd.after=network-online.target" - "x-systemd.automount" - ]; - - b2ProfileOptions = { - audio = [ - "buffer-size=128M" - "vfs-cache-max-age=168h" - "vfs-cache-max-size=${cfg.audioCacheSize}" - "vfs-read-ahead=${cfg.audioReadAhead}" - ]; - - video = [ - "buffer-size=512M" - "vfs-cache-max-age=336h" - "vfs-cache-max-size=${cfg.videoCacheSize}" - "vfs-read-ahead=${cfg.videoReadAhead}" - ]; - }; - - mkB2Mount = name: remote: profile: { - "/mnt/Backblaze/${name}" = { - device = "b2:${remote}"; - fsType = "rclone"; - options = b2Options ++ b2ProfileOptions.${profile}; - }; - }; - - allShares = { - Anime = mkB2Mount "Anime" "aly-anime" "video"; - Audiobooks = mkB2Mount "Audiobooks" "aly-audiobooks" "audio"; - Movies = mkB2Mount "Movies" "aly-movies" "video"; - Music = mkB2Mount "Music" "aly-music" "audio"; - Shows = mkB2Mount "Shows" "aly-shows" "video"; - }; -in { - options.myNixOs.profile.b2Mounts = { - enable = lib.mkEnableOption "Backblaze B2 mounts"; - - cacheDir = lib.mkOption { - description = "Directory for rclone VFS cache."; - example = "/mnt/Data/.rclone-cache"; - type = lib.types.str; - }; - - audioCacheSize = lib.mkOption { - default = "15G"; - type = lib.types.str; - }; - videoCacheSize = lib.mkOption { - default = "50G"; - type = lib.types.str; - }; - audioReadAhead = lib.mkOption { - default = "1G"; - type = lib.types.str; - }; - videoReadAhead = lib.mkOption { - default = "3G"; - type = lib.types.str; - }; - - shares = lib.mkOption { - description = "Which B2 shares to mount."; - default = ["Anime" "Audiobooks" "Movies" "Music" "Shows"]; - type = lib.types.listOf (lib.types.enum ["Anime" "Audiobooks" "Movies" "Music" "Shows"]); - }; - }; - - config = lib.mkIf config.myNixOs.profile.b2Mounts.enable { - sops.secrets.b2-mount-rclone = { - sopsFile = "${self}/secrets/b2.yaml"; - key = "rclone_config"; - }; - - environment.systemPackages = [pkgs.rclone]; - - fileSystems = builtins.foldl' (a: b: a // b) {} (builtins.attrValues (builtins.intersectAttrs (builtins.listToAttrs (map (s: { - name = s; - value = null; - }) - cfg.shares)) - allShares)); - }; -} diff --git a/nix/nixos/profiles/backups.nix b/nix/nixos/profiles/backups.nix deleted file mode 100644 index 9b625a65..00000000 --- a/nix/nixos/profiles/backups.nix +++ /dev/null @@ -1,99 +0,0 @@ -{ - config, - lib, - self, - ... -}: let - backupDestination = "rclone:b2:aly-backups/${config.networking.hostName}"; - mkRepo = service: "${backupDestination}/${service}"; - - restic = { - extraBackupArgs = [ - "--cleanup-cache" - "--compression max" - "--no-scan" - ]; - - inhibitsSleep = true; - initialize = true; - passwordFile = config.sops.secrets.restic-passwd.path; - - pruneOpts = [ - "--keep-daily 7" - "--keep-weekly 4" - "--keep-monthly 3" - ]; - - rcloneConfigFile = config.sops.secrets.rclone-b2.path; - - timerConfig = { - OnCalendar = "daily"; - Persistent = true; - RandomizedDelaySec = "3h"; - }; - }; -in { - options.myNixOs.profile.backups = { - enable = lib.mkEnableOption "restic backups"; - - jobs = lib.mkOption { - description = "Restic backup jobs rendered with the shared defaults."; - default = {}; - - type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { - options = { - paths = lib.mkOption { - type = lib.types.listOf lib.types.path; - description = "Paths to back up."; - }; - - repository = lib.mkOption { - type = lib.types.str; - default = mkRepo name; - description = "Restic repository URL."; - }; - - backupPrepareCommand = lib.mkOption { - type = lib.types.nullOr lib.types.str; - default = null; - }; - - backupCleanupCommand = lib.mkOption { - type = lib.types.nullOr lib.types.str; - default = null; - }; - - exclude = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = []; - }; - }; - })); - }; - }; - - config = lib.mkIf config.myNixOs.profile.backups.enable { - sops.secrets = { - restic-passwd = { - sopsFile = "${self}/secrets/restic.yaml"; - key = "PASSWORD"; - }; - - rclone-b2 = { - sopsFile = "${self}/secrets/b2.yaml"; - key = "rclone_config"; - }; - }; - - services.restic.backups = let - mkRestic = _: job: - restic - // { - inherit (job) paths repository exclude; - backupPrepareCommand = lib.mkIf (job.backupPrepareCommand != null) job.backupPrepareCommand; - backupCleanupCommand = lib.mkIf (job.backupCleanupCommand != null) job.backupCleanupCommand; - }; - in - lib.mapAttrs mkRestic config.myNixOs.profile.backups.jobs; - }; -} diff --git a/nix/nixos/profiles/btrfs.nix b/nix/nixos/profiles/btrfs.nix deleted file mode 100644 index f74b3e95..00000000 --- a/nix/nixos/profiles/btrfs.nix +++ /dev/null @@ -1,76 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: let - btrfsFSDevices = let - isDeviceInList = list: device: builtins.any (e: e.device == device) list; - uniqueDeviceList = lib.foldl' (acc: e: - if isDeviceInList acc e.device - then acc - else acc ++ [e]) []; - in - uniqueDeviceList ( - lib.mapAttrsToList (_: fs: {inherit (fs) mountPoint device;}) - (lib.filterAttrs (_: fs: fs.fsType == "btrfs") config.fileSystems) - ); - - beesdConfig = lib.listToAttrs (map (fs: { - name = lib.strings.sanitizeDerivationName (baseNameOf fs.device); - value = { - hashTableSizeMB = 2048; - spec = fs.device; - verbosity = "info"; - extraOptions = ["--loadavg-target" "1.0" "--thread-factor" "0.50"]; - }; - }) - btrfsFSDevices); - - hasHomeSubvolume = - lib.hasAttr "/home" config.fileSystems - && config.fileSystems."/home".fsType == "btrfs"; -in { - options.myNixOs.profile.btrfs = { - enable = lib.mkEnableOption "btrfs filesystem configuration"; - deduplicate = lib.mkEnableOption "deduplicate btrfs filesystems"; - }; - - config = lib.mkIf config.myNixOs.profile.btrfs.enable { - boot.supportedFilesystems = ["btrfs"]; - environment.systemPackages = lib.optionals config.services.xserver.enable [pkgs.snapper-gui]; - - services = lib.mkIf (btrfsFSDevices != []) { - beesd.filesystems = lib.mkIf config.myNixOs.profile.btrfs.deduplicate beesdConfig; - btrfs.autoScrub.enable = true; - - snapper = { - configs.home = lib.mkIf hasHomeSubvolume { - ALLOW_GROUPS = ["users"]; - FSTYPE = "btrfs"; - SUBVOLUME = "/home"; - TIMELINE_CLEANUP = true; - TIMELINE_CREATE = true; - }; - - filters = '' - -.bash_profile - -.bashrc - -.cache - -.config - -.librewolf - -.local - -.mozilla - -.nix-profile - -.pki - -.share - -.snapshots - -.thunderbird - -.zshrc - ''; - - persistentTimer = true; - }; - }; - }; -} diff --git a/nix/nixos/profiles/k3s.nix b/nix/nixos/profiles/k3s.nix deleted file mode 100644 index 0511ab70..00000000 --- a/nix/nixos/profiles/k3s.nix +++ /dev/null @@ -1,173 +0,0 @@ -{ - config, - lib, - pkgs, - self, - ... -}: let - cfg = config.myNixOs.profile.k3s; - transportService = - if cfg.transportInterface == "wg-k3s" - then "wireguard-wg-k3s.service" - else "tailscaled.service"; -in { - options.myNixOs.profile.k3s = { - enable = lib.mkEnableOption "k3s cluster node"; - - role = lib.mkOption { - type = lib.types.enum ["server" "agent"]; - default = "server"; - }; - - clusterInit = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Whether this node initializes the cluster's etcd. Exactly one node - in the cluster should set this. Other servers join via `serverAddr`. - ''; - }; - - serverAddr = lib.mkOption { - type = lib.types.nullOr lib.types.str; - default = null; - example = "https://solaceon:6443"; - }; - - transportInterface = lib.mkOption { - type = lib.types.str; - default = "tailscale0"; - description = "Network interface used for k3s node and Flannel traffic."; - }; - - nodeIP = lib.mkOption { - type = lib.types.nullOr lib.types.str; - default = null; - description = "Address k3s advertises for the Kubernetes node."; - }; - - tlsSans = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = [ - "snowpoint" - "pastoria" - "jubilife" - "snowpoint.cute" - "pastoria.cute" - "jubilife.cute" - ]; - }; - - zone = lib.mkOption { - type = lib.types.nullOr lib.types.str; - default = null; - example = "cloud"; - }; - - ingress = lib.mkEnableOption "cute.haus/ingress=true node label"; - }; - - config = lib.mkIf cfg.enable { - sops.secrets.k3s = { - sopsFile = "${self}/secrets/k3s.yaml"; - key = "TOKEN"; - }; - - # systemd-oomd fights kubelet's eviction manager - systemd.oomd.enable = lib.mkForce false; - - networking.firewall = { - allowedTCPPorts = lib.mkIf cfg.ingress [80 443 2222]; - - # Let a pod reach kubelet:10250 on its own host. Same-node traffic to - # the node's Tailscale IP is delivered locally and arrives via cni0, so - # metrics-server can't scrape the node it runs on without this. - trustedInterfaces = ["cni0"]; - }; - - services = { - k3s = { - enable = true; - inherit (cfg) role clusterInit; - serverAddr = lib.mkIf (cfg.serverAddr != null) cfg.serverAddr; - tokenFile = config.sops.secrets.k3s.path; - extraFlags = - [ - "--flannel-iface=${cfg.transportInterface}" - # Keep image storage below Longhorn's 75% disk-use ceiling. - "--kubelet-arg=image-gc-high-threshold=70" - "--kubelet-arg=image-gc-low-threshold=65" - ] - ++ lib.optionals (cfg.nodeIP != null) ["--node-ip=${cfg.nodeIP}"] - ++ lib.optionals (cfg.role == "server") ( - [ - "--service-node-port-range=8000-32767" - "--disable=traefik" - "--disable=servicelb" - ] - ++ lib.optionals (cfg.nodeIP != null) ["--advertise-address=${cfg.nodeIP}"] - ++ map (san: "--tls-san=${san}") cfg.tlsSans - ) - ++ lib.optionals cfg.clusterInit ["--write-kubeconfig-mode=644"] - ++ lib.optionals (cfg.zone != null) ["--node-label=topology.kubernetes.io/zone=${cfg.zone}"] - ++ lib.optionals cfg.ingress ["--node-label=cute.haus/ingress=true"]; - }; - - openiscsi = { - enable = true; - name = "iqn.2026-05.haus.cute:${config.networking.hostName}"; - }; - }; - - environment.systemPackages = with pkgs; [ - kubernetes-helm - nfs-utils - ]; - - systemd = { - # Longhorn instance-manager looks for binaries in /usr/local/bin - tmpfiles.rules = [ - "L+ /usr/local/bin - - - - /run/current-system/sw/bin/" - ]; - - services = { - # Block k3s startup until its transport interface has an IP. This - # prevents Flannel and etcd peer setup from racing at cold boot. - k3s = { - after = [transportService]; - wants = [transportService]; - serviceConfig.ExecStartPre = pkgs.writeShellScript "wait-k3s-transport" '' - until ${pkgs.iproute2}/bin/ip -4 addr show ${cfg.transportInterface} | grep -q inet; do - ${pkgs.coreutils}/bin/sleep 1 - done - ''; - }; - - # Cleanly log out iSCSI sessions at shutdown so reboots don't hang - # waiting for udev scsi_id timeouts against dead longhorn devices. - iscsi-logout = { - description = "Log out iSCSI sessions cleanly at shutdown"; - after = ["iscsid.service"]; - before = ["k3s.service"]; - requires = ["iscsid.service"]; - wantedBy = ["multi-user.target"]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - ExecStart = "${pkgs.coreutils}/bin/true"; - ExecStop = "-${pkgs.openiscsi}/bin/iscsiadm -m node -u"; - TimeoutStopSec = "30s"; - }; - }; - }; - }; - myNixOs.profile.backups.jobs.k3s = lib.mkIf (cfg.enable && config.myNixOs.profile.backups.enable && config.services.k3s.role == "server") { - backupPrepareCommand = "${config.services.k3s.package}/bin/k3s etcd-snapshot save"; - paths = [ - "/var/lib/rancher/k3s/server/db/snapshots" - "/var/lib/rancher/k3s/server/cred" - "/var/lib/rancher/k3s/server/tls" - ]; - }; - }; -} diff --git a/nix/nixos/profiles/swap.nix b/nix/nixos/profiles/swap.nix deleted file mode 100644 index fe59b0fd..00000000 --- a/nix/nixos/profiles/swap.nix +++ /dev/null @@ -1,26 +0,0 @@ -{ - config, - lib, - ... -}: { - options.myNixOs.profile.swap = { - enable = lib.mkEnableOption "encrypted swap"; - - size = lib.mkOption { - default = 8192; - description = "Swap size in megabytes."; - type = lib.types.int; - }; - }; - - config = lib.mkIf config.myNixOs.profile.swap.enable { - swapDevices = [ - { - device = "/.swap"; - priority = 0; - randomEncryption.enable = true; - inherit (config.myNixOs.profile.swap) size; - } - ]; - }; -} diff --git a/nix/nixos/programs/docker.nix b/nix/nixos/programs/docker.nix deleted file mode 100644 index f0868376..00000000 --- a/nix/nixos/programs/docker.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - config, - lib, - ... -}: { - options.myNixOs.program.docker.enable = lib.mkEnableOption "Docker container runtime"; - - config = lib.mkIf config.myNixOs.program.docker.enable { - virtualisation.oci-containers.backend = "docker"; - - virtualisation.docker = { - enable = true; - autoPrune.enable = true; - }; - }; -} diff --git a/nix/nixos/services/alloy.nix b/nix/nixos/services/alloy.nix deleted file mode 100644 index ec5b625a..00000000 --- a/nix/nixos/services/alloy.nix +++ /dev/null @@ -1,51 +0,0 @@ -{ - config, - lib, - ... -}: { - options.myNixOs.service.alloy = { - enable = lib.mkEnableOption "Grafana Alloy"; - - lokiUrl = lib.mkOption { - description = "Loki URL to report to"; - default = "https://loki.narwhal-snapper.ts.net/loki/api/v1/push"; - type = lib.types.str; - }; - }; - - config = lib.mkIf config.myNixOs.service.alloy.enable { - services.alloy.enable = true; - - environment.etc."alloy/config.alloy".text = '' - loki.write "default" { - endpoint { - url = "${config.myNixOs.service.alloy.lokiUrl}" - } - } - - loki.relabel "journal" { - forward_to = [] - - rule { - source_labels = ["__journal__systemd_unit"] - target_label = "unit" - } - - rule { - source_labels = ["__journal__systemd_user_unit"] - target_label = "user_unit" - } - } - - loki.source.journal "read" { - forward_to = [loki.write.default.receiver] - relabel_rules = loki.relabel.journal.rules - max_age = "12h" - labels = { - job = "systemd-journal", - host = "${config.networking.hostName}", - } - } - ''; - }; -} diff --git a/nix/nixos/services/atbbs.nix b/nix/nixos/services/atbbs.nix deleted file mode 100644 index 1cd0ad00..00000000 --- a/nix/nixos/services/atbbs.nix +++ /dev/null @@ -1,43 +0,0 @@ -{ - config, - lib, - ... -}: { - options.myNixOs.service.atbbs = { - enable = lib.mkEnableOption "ATBBS services"; - - port = lib.mkOption { - description = "Port to listen on."; - default = 8582; - type = lib.types.int; - }; - - telnetPort = lib.mkOption { - description = "Port to listen on for telnet."; - default = 2323; - type = lib.types.int; - }; - }; - - config = lib.mkIf config.myNixOs.service.atbbs.enable { - networking.firewall.allowedTCPPorts = [ - config.myNixOs.service.atbbs.port - config.myNixOs.service.atbbs.telnetPort - ]; - - virtualisation.oci-containers.containers = { - atbbs = { - extraOptions = ["--pull=always"]; - image = "ghcr.io/alyraffauf/atbbs"; - environment.PUBLIC_URL = "https://atbbs.xyz"; - ports = ["0.0.0.0:${toString config.myNixOs.service.atbbs.port}:80"]; - }; - - atbbs-telnet = { - extraOptions = ["--pull=always"]; - image = "ghcr.io/alyraffauf/atbbs-telnet"; - ports = ["0.0.0.0:${toString config.myNixOs.service.atbbs.telnetPort}:2323"]; - }; - }; - }; -} diff --git a/nix/nixos/services/cachefilesd.nix b/nix/nixos/services/cachefilesd.nix deleted file mode 100644 index dc82122b..00000000 --- a/nix/nixos/services/cachefilesd.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ - config, - lib, - ... -}: { - options.myNixOs.service.cachefilesd.enable = lib.mkEnableOption "cachefilesd"; - - config = lib.mkIf config.myNixOs.service.cachefilesd.enable { - services.cachefilesd = { - enable = true; - - extraConfig = '' - brun 20% - bcull 10% - bstop 5% - ''; - }; - }; -} diff --git a/nix/nixos/services/forgejo-runner.nix b/nix/nixos/services/forgejo-runner.nix deleted file mode 100644 index b94a0a4c..00000000 --- a/nix/nixos/services/forgejo-runner.nix +++ /dev/null @@ -1,77 +0,0 @@ -{ - config, - lib, - pkgs, - self, - ... -}: { - options.myNixOs.service.forgejoRunner = { - enable = lib.mkEnableOption "Forgejo Actions runners"; - - nativeRunners = lib.mkOption { - type = lib.types.int; - default = 1; - description = "How many native NixOS runners to run."; - }; - - dockerContainers = lib.mkOption { - type = lib.types.int; - default = 1; - description = "How many docker containers to run."; - }; - }; - config = lib.mkIf config.myNixOs.service.forgejoRunner.enable { - assertions = [ - { - assertion = config.services.tailscale.enable; - message = "We contact Forĝejo over tailscale, but services.tailscale.enable != true."; - } - ]; - - sops.secrets.act-runner = { - sopsFile = "${self}/secrets/act-runner.yaml"; - key = "TOKEN"; - }; - - services.gitea-actions-runner = let - arch = lib.replaceStrings ["-"] ["_"] pkgs.stdenv.hostPlatform.system; - in { - instances = let - tokenFile = config.sops.secrets.act-runner.path; - in { - alycodes-containers = { - inherit tokenFile; - enable = true; - labels = lib.optional (arch == "aarch64_linux") "ubuntu-24.04-arm:docker://gitea/runner-images:ubuntu-latest" ++ lib.optional (arch == "x86_64_linux") "ubuntu-latest:docker://gitea/runner-images:ubuntu-latest"; - name = "${arch}-${config.networking.hostName}-alycodes-containers"; - - settings = { - container.network = "host"; - runner.capacity = config.myNixOs.service.forgejoRunner.dockerContainers; - }; - - url = "https://git.aly.codes"; - }; - - alycodes-nixos = { - inherit tokenFile; - enable = true; - - hostPackages = with pkgs; - [bash cachix coreutils curl gawk gitMinimal gnused jq nodejs wget] - ++ [config.nix.package]; - - labels = ["nixos-${arch}:host"]; - name = "${arch}-${config.networking.hostName}-alycodes-nixos"; - - settings = { - container.network = "host"; - runner.capacity = config.myNixOs.service.forgejoRunner.nativeRunners; - }; - - url = "https://git.aly.codes"; - }; - }; - }; - }; -} diff --git a/nix/nixos/services/plex.nix b/nix/nixos/services/plex.nix deleted file mode 100644 index 388cfffb..00000000 --- a/nix/nixos/services/plex.nix +++ /dev/null @@ -1,79 +0,0 @@ -{ - config, - inputs, - lib, - pkgs, - ... -}: { - options.myNixOs.service = { - plex = { - enable = lib.mkEnableOption "Plex media server"; - dataDir = lib.mkOption { - description = "Data directory to use."; - default = "/var/lib"; - type = lib.types.str; - }; - }; - - tautulli.enable = lib.mkEnableOption "Tautulli"; - }; - - config = lib.mkMerge [ - (lib.mkIf config.myNixOs.service.plex.enable { - services.plex = { - enable = true; - dataDir = "${config.myNixOs.service.plex.dataDir}/plex"; - - extraPlugins = [ - (builtins.path { - name = "Audnexus.bundle"; - path = inputs.audnexus; - }) - (builtins.path { - name = "Hama.bundle"; - path = inputs.hama; - }) - ]; - - extraScanners = [ - (builtins.path { - name = "Absolute-Series-Scanner"; - path = inputs.absolute; - }) - ]; - - openFirewall = true; - }; - - systemd.services.plex.serviceConfig.TimeoutStopSec = 15; - }) - - (lib.mkIf config.myNixOs.service.tautulli.enable { - services.tautulli = { - enable = true; - openFirewall = true; - }; - }) - - (lib.mkIf config.myNixOs.profile.backups.enable { - myNixOs.profile.backups.jobs = lib.mkMerge [ - (lib.mkIf config.myNixOs.service.plex.enable { - plex = { - backupCleanupCommand = "${pkgs.systemd}/bin/systemctl start plex"; - backupPrepareCommand = "${pkgs.systemd}/bin/systemctl stop plex"; - exclude = ["${config.services.plex.dataDir}/Plex Media Server/Plug-in Support/Databases"]; - paths = [config.services.plex.dataDir]; - }; - }) - - (lib.mkIf config.myNixOs.service.tautulli.enable { - tautulli = { - backupCleanupCommand = "${pkgs.systemd}/bin/systemctl start tautulli"; - backupPrepareCommand = "${pkgs.systemd}/bin/systemctl stop tautulli"; - paths = [config.services.tautulli.dataDir]; - }; - }) - ]; - }) - ]; -} diff --git a/nix/nixos/services/qbittorrent.nix b/nix/nixos/services/qbittorrent.nix deleted file mode 100644 index 8e9fe434..00000000 --- a/nix/nixos/services/qbittorrent.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: { - options.myNixOs.service.qbittorrent.enable = lib.mkEnableOption "qBittorrent"; - - config = lib.mkMerge [ - (lib.mkIf config.myNixOs.service.qbittorrent.enable { - services.qbittorrent = { - enable = true; - profileDir = "/var/lib/qbittorrent"; - }; - }) - - (lib.mkIf (config.myNixOs.service.qbittorrent.enable && config.myNixOs.profile.backups.enable) (let - stop = service: "${pkgs.systemd}/bin/systemctl stop ${service}"; - start = service: "${pkgs.systemd}/bin/systemctl start ${service}"; - in { - myNixOs.profile.backups.jobs.qbittorrent = { - backupCleanupCommand = start "qbittorrent"; - backupPrepareCommand = stop "qbittorrent"; - paths = [config.services.qbittorrent.profileDir]; - }; - })) - ]; -} diff --git a/nix/nixos/services/syncthing.nix b/nix/nixos/services/syncthing.nix deleted file mode 100644 index bcef8800..00000000 --- a/nix/nixos/services/syncthing.nix +++ /dev/null @@ -1,134 +0,0 @@ -{ - config, - lib, - ... -}: { - options.myNixOs.service.syncthing = { - enable = lib.mkEnableOption "Syncthing file syncing service"; - - certFile = lib.mkOption { - description = "Path to the certificate file."; - type = lib.types.path; - }; - - keyFile = lib.mkOption { - description = "Path to the key file."; - type = lib.types.path; - }; - - romsPath = lib.mkOption { - default = "/home/${config.myNixOs.service.syncthing.user}/roms"; - description = "Path to the ROM folder."; - type = lib.types.path; - }; - - syncROMs = lib.mkEnableOption "Whether to sync ROMs."; - - user = lib.mkOption { - description = "User to run Syncthing as."; - type = lib.types.str; - }; - }; - - config = lib.mkIf config.myNixOs.service.syncthing.enable { - systemd.services.syncthing.environment.STNODEFAULTFOLDER = "true"; - - services = { - caddy.virtualHosts = - lib.mkIf - (config.services.caddy.enable && config.services.tailscale.enable) - { - "syncthing-${config.networking.hostName}.narwhal-snapper.ts.net" = { - extraConfig = '' - bind tailscale/syncthing-${config.networking.hostName} - reverse_proxy localhost:8384 { - header_up Host localhost - } - ''; - }; - }; - - syncthing = let - cfg = config.myNixOs.service.syncthing; - - devices = { - "allyx" = {id = "XTEVJX2-DBEFN4X-UCG43YR-V4FOQYU-DMM2WH4-AMCC5FS-42UB3DM-KUDVHQL";}; - "eterna" = {id = "ZAD2MVO-I2OQII4-C3T756B-BEBQMM6-Q4ILH2H-5CR3TMI-DR4VBFD-GLRVOQK";}; - "fallarbor" = {id = "P4URLH4-YWLMO6J-W62ET7H-TQAO3Y6-T2FAYOY-C2VTI65-VQXHVGG-NQ76PAZ";}; - "fortree" = {id = "S6PVA3I-EKOCGIU-GFX7AE6-FXM45OW-JTYN5LJ-UZ4LADZ-NNAJGDD-KST2VAG";}; - "groudon" = {id = "VOEAEAG-NP5Z3BM-DK5FO75-6G4NKSJ-3EUNFSV-VIR4KDH-OM6ZN7L-OOQKCQJ";}; - "jubilife" = {id = "52MTCMC-PKEWSAU-HADMTZU-DY5EKFO-B323P7V-OBXLNTQ-EJY7F7Y-EUWFBQX";}; - "kyogre" = {id = "SBQNUXS-H4XDJ3E-RBHJPT5-45WDJJA-2U43M4P-23XGUJ7-E3CNNKZ-BXSGIA3";}; - "oreburgh" = {id = "RFVF6DA-CQJLXTP-RKMYEB3-D2KMWJH-3Z2CIAN-PNYOXI6-FIDBFWG-JJA57AX";}; - "pacifidlog" = {id = "6EBVXYI-HZW4LQI-T6L3TTI-DZEBXJM-RP3DW7N-BCAG6FC-G2654DN-XJFSLQD";}; - "petalburg" = {id = "O75EK2H-YBXPM5D-PBYV7XB-DJKFL3E-OFZBB7H-MLCD2UT-NXQRMDG-BTZZQQH";}; - "rp5" = {id = "5AKCXRS-XU7BBSS-RDPSSLG-4BDOZ4K-OXLFQZX-HJSM53W-4GLSOAC-RZ7APA7";}; - "rpclassic" = {id = "EDNFUWI-UFYEOPI-QPJIEWF-NXVEGZ6-2J7IXW7-X22L27F-VU6JKSB-CH6GDAO";}; - "rustboro" = {id = "NY53BFH-CPVCXGH-MI5AT7E-WBK7TXS-5NQDSCW-J5BALLV-EGS2VJL-CMED2AH";}; - "slateport" = {id = "MDJFDUG-UJAXQXI-AMEF2AR-PBMD5QK-Z5ZG6AA-RCJCU3M-GZHQQEA-X2JGOAK";}; - "snowpoint" = {id = "TFSZWZB-EDIFV2P-333APP2-T655TM4-2XGA7QA-P22Z36W-3RNGX2C-DLETAQ7";}; - "sootopolis" = {id = "7QGSZ2D-CGMLPWD-OCFCBXP-7746W7F-COFV52F-Q2PMCAS-GV5DCSV-6NIXDQJ";}; - "thor" = {id = "B33X5WA-S6P4XEE-VURE4PB-WKMXHLP-6AG55LZ-QIG6ZJG-GDGXWAD-EDVIRAF";}; - "verdanturf" = {id = "CQ7A2KW-2JRZHEO-NF6NZLY-C2OX4SO-EPKQRMV-7YBSSFA-FJ2CW2P-NOIKPQB";}; - }; - - folders = lib.mkMerge [ - { - "sync" = { - devices = ["allyx" "eterna" "fallarbor" "fortree" "groudon" "jubilife" "kyogre" "oreburgh" "pacifidlog" "petalburg" "rustboro" "slateport" "snowpoint" "sootopolis" "verdanturf"]; - id = "default"; - path = "~/sync"; - versioning = { - params.cleanoutDays = "5"; - type = "trashcan"; - }; - }; - - "screenshots" = { - devices = ["fallarbor" "oreburgh" "jubilife" "pacifidlog" "petalburg" "rustboro" "slateport" "snowpoint" "sootopolis" "verdanturf"]; - id = "screenshots"; - path = "~/pics/screenshots"; - versioning = { - params.cleanoutDays = "5"; - type = "trashcan"; - }; - }; - - "roms" = { - devices = ["jubilife" "oreburgh" "pacifidlog" "petalburg" "rp5" "rpclassic" "rustboro" "sootopolis" "thor"]; - id = "emudeck"; - versioning = { - params.cleanoutDays = "3"; - type = "trashcan"; - }; - }; - } - { - "roms" = { - enable = cfg.syncROMs; - path = cfg.romsPath; - }; - } - ]; - in { - enable = true; - cert = cfg.certFile; - configDir = "${config.services.syncthing.dataDir}/.syncthing"; - dataDir = "/home/${cfg.user}"; - key = cfg.keyFile; - openDefaultPorts = true; - inherit (cfg) user; - - settings = { - options = { - localAnnounceEnabled = true; - relaysEnabled = true; - urAccepted = -1; - }; - - inherit devices folders; - }; - }; - }; - }; -} diff --git a/nix/nixos/services/tailscale.nix b/nix/nixos/services/tailscale.nix deleted file mode 100644 index f38ba4ce..00000000 --- a/nix/nixos/services/tailscale.nix +++ /dev/null @@ -1,69 +0,0 @@ -{ - config, - lib, - self, - ... -}: { - options.myNixOs.service.tailscale = { - enable = lib.mkEnableOption "Tailscale"; - - authKeyFile = lib.mkOption { - description = "Key file to use for authentication"; - default = config.sops.secrets.tailscaleAuthKey.path or null; - type = lib.types.nullOr lib.types.path; - }; - - operator = lib.mkOption { - description = "Tailscale operator name"; - default = null; - type = lib.types.nullOr lib.types.str; - }; - }; - config = lib.mkIf config.myNixOs.service.tailscale.enable { - sops.secrets.tailscaleAuthKey = { - sopsFile = "${self}/secrets/tailscale.yaml"; - key = "auth_key"; - }; - - assertions = [ - { - assertion = config.myNixOs.service.tailscale.authKeyFile != null; - message = "config.myNixOs.service.tailscale.authKeyFile cannot be null."; - } - ]; - - networking.firewall = { - allowedUDPPorts = [config.services.tailscale.port]; - trustedInterfaces = [config.services.tailscale.interfaceName]; - }; - - services = { - # When caddy is also enabled, expose a tailnet-hostname vhost that - # proxies the local syncthing UI through /syncthing/. - caddy = lib.mkIf config.services.caddy.enable { - virtualHosts."${config.networking.hostName}.narwhal-snapper.ts.net".extraConfig = lib.concatLines (lib.optional config.services.syncthing.enable '' - redir /syncthing /syncthing/ - handle_path /syncthing/* { - reverse_proxy localhost:8384 { - header_up Host localhost - } - } - ''); - }; - - tailscale = { - enable = true; - authKeyFile = config.myNixOs.service.tailscale.authKeyFile; - - extraUpFlags = - ["--ssh"] - ++ lib.optional (config.myNixOs.service.tailscale.operator != null) - "--operator ${config.myNixOs.service.tailscale.operator}"; - - openFirewall = true; - permitCertUid = lib.mkIf config.services.caddy.enable "caddy"; - useRoutingFeatures = "both"; - }; - }; - }; -} diff --git a/nix/nixos/users/aly.nix b/nix/nixos/users/aly.nix deleted file mode 100644 index 9790da64..00000000 --- a/nix/nixos/users/aly.nix +++ /dev/null @@ -1,41 +0,0 @@ -{ - config, - lib, - ... -}: { - options.myNixOs.users.aly = { - enable = lib.mkEnableOption "the aly user"; - - password = lib.mkOption { - type = lib.types.nullOr lib.types.str; - default = null; - description = "Hashed password for aly."; - }; - }; - - config = lib.mkIf config.myNixOs.users.aly.enable { - mySshKeys.authorizedUsers.aly = ["aly"]; - - users.users.aly = { - description = "Aly Raffauf"; - - extraGroups = [ - "cdrom" - "dialout" - "docker" - "libvirtd" - "lp" - "networkmanager" - "plugdev" - "scanner" - "transmission" - "video" - "wheel" - ]; - - hashedPassword = config.myNixOs.users.aly.password; - isNormalUser = true; - uid = 1000; - }; - }; -} diff --git a/renovate.json b/renovate.json index c1825f74..dfe636b0 100644 --- a/renovate.json +++ b/renovate.json @@ -49,7 +49,9 @@ { "description": "Direct OCI containers on NixOS hosts", "customType": "regex", - "managerFilePatterns": ["/^nix/hosts/.*/containers\\.nix$/"], + "managerFilePatterns": [ + "/^nix/modules/hosts/nixos/.*/containers\\.nix$/" + ], "matchStrings": [ "image = \\\"(?[^\\s\\\"]+):(?[^@\\\"]+)@(?sha256:[a-f0-9]{64})\\\"" ], diff --git a/scripts/update-caddy-tailscale.ts b/scripts/update-caddy-tailscale.ts index 165cbc7a..158a763e 100755 --- a/scripts/update-caddy-tailscale.ts +++ b/scripts/update-caddy-tailscale.ts @@ -10,7 +10,7 @@ import { $ } from "bun"; -const CADDY_FILE = "nix/nixos/services/caddy.nix"; +const CADDY_FILE = "nix/modules/nixos/services/caddy.nix"; const GITHUB_REPO = "tailscale/caddy-tailscale"; const NIX_BUILD_TARGET = ".#nixosConfigurations.jubilife.config.services.caddy.package";