From 630f9b0074173c011dc79e2b2fa0a8157924cc99 Mon Sep 17 00:00:00 2001 From: Jay Looney Date: Tue, 28 Oct 2025 16:11:45 -0500 Subject: [PATCH] even more backups of things --- README.md | 4 + flake.bak | 70 ++++++++++++ flake.lock | 88 +++++++++----- flake.nix | 13 ++- hosts/lithium/configuration.nix | 2 +- hosts/lithium/default.nix | 7 ++ hosts/lithium/microvms/default.nix | 18 +++ hosts/lithium/microvms/palworld/default.nix | 107 ++++++++++++++++++ hosts/lithium/microvms/valheim.nix | 50 ++++++++ hosts/lithium/private-config.nix | 8 ++ hosts/lithium/secrets/common.yaml | 31 ++--- hosts/lithium/services/README.md | 11 ++ hosts/lithium/services/acme-dns.nix | 65 +++++++++++ hosts/lithium/services/audiobookshelf.nix | 20 ++++ hosts/lithium/services/caddy.nix | 46 +++++--- hosts/lithium/services/calibre-web.nix | 27 +++-- hosts/lithium/services/forgejo.nix | 8 +- .../services/forgejo/actions-runner.nix | 0 hosts/lithium/services/forgejo/default.nix | 0 hosts/lithium/services/forgejo/forgejo.nix | 0 hosts/lithium/services/game_servers.nix | 42 +++++++ hosts/lithium/services/grafana.nix | 24 ---- hosts/lithium/services/home-assistant.nix | 7 ++ hosts/lithium/services/immich.nix | 65 ++++++----- hosts/lithium/services/kanidm.nix | 103 ++++++++++++++--- hosts/lithium/services/miniflux/default.nix | 60 +++++++--- hosts/lithium/services/monitoring/README.md | 14 +++ hosts/lithium/services/monitoring/grafana.nix | 6 +- .../monitoring/loki-local-config.yaml | 4 + hosts/lithium/services/monitoring/loki.nix | 15 +++ .../services/monitoring/prometheus.nix | 39 ++++--- hosts/lithium/services/old-kanidm.nix | 79 +++++++++++++ hosts/lithium/services/palworld/default.nix | 4 +- hosts/lithium/services/smartd.nix | 25 ++-- hosts/lithium/services/uptime-kuma.nix | 4 +- hosts/lithium/sops.nix | 12 +- hosts/titanium/default.nix | 6 +- lib/default.nix | 1 + localnotes.md | 37 ++++++ localsecrets.yaml | 24 ++++ modules/nixos/desktop.nix | 3 +- pkgs/mv7-udev-rules/package.nix | 38 +++++++ secrets/global.yaml | 36 ++++++ secrets/temp.yaml | 56 +++++++++ users/jay/default.nix | 16 +++ users/jay/home.nix | 68 +++++++++++ 46 files changed, 1166 insertions(+), 197 deletions(-) create mode 100644 flake.bak create mode 100644 hosts/lithium/microvms/default.nix create mode 100644 hosts/lithium/microvms/palworld/default.nix create mode 100644 hosts/lithium/microvms/valheim.nix create mode 100644 hosts/lithium/private-config.nix create mode 100644 hosts/lithium/services/README.md create mode 100644 hosts/lithium/services/acme-dns.nix create mode 100644 hosts/lithium/services/audiobookshelf.nix create mode 100644 hosts/lithium/services/forgejo/actions-runner.nix create mode 100644 hosts/lithium/services/forgejo/default.nix create mode 100644 hosts/lithium/services/forgejo/forgejo.nix create mode 100644 hosts/lithium/services/game_servers.nix delete mode 100644 hosts/lithium/services/grafana.nix create mode 100644 hosts/lithium/services/home-assistant.nix create mode 100644 hosts/lithium/services/monitoring/README.md create mode 100644 hosts/lithium/services/monitoring/loki-local-config.yaml create mode 100644 hosts/lithium/services/monitoring/loki.nix create mode 100644 hosts/lithium/services/old-kanidm.nix create mode 100644 localnotes.md create mode 100644 localsecrets.yaml create mode 100644 pkgs/mv7-udev-rules/package.nix create mode 100644 secrets/global.yaml create mode 100644 secrets/temp.yaml create mode 100644 users/jay/default.nix create mode 100644 users/jay/home.nix diff --git a/README.md b/README.md index 3544565..89d5ab2 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,10 @@ nix-shell -p sops --run "sops secrets/example.yaml" ``` +## Configuring and Accessing Secrets + +I need to rip out agecrypt and go pure SOPS. + ## References - [@shazow](https://github.com/shazow/) and https://github.com/shazow/nixfiles/ diff --git a/flake.bak b/flake.bak new file mode 100644 index 0000000..6f3318a --- /dev/null +++ b/flake.bak @@ -0,0 +1,70 @@ +{ + description = "Configuration for NixOS"; + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + nixos-hardware.url = "github:nixos/nixos-hardware"; + home-manager.url = "github:nix-community/home-manager"; + home-manager.inputs.nixpkgs.follows = "nixpkgs"; + sops-nix.url = "github:Mic92/sops-nix"; + sops-nix.inputs.nixpkgs.follows = "nixpkgs"; + + # flake-parts.url = "github:hercules-ci/flake-parts"; + }; + # https://nix.dev/tutorials/nix-language.html#named-attribute-set-argument + outputs = inputs@{self, nixpkgs, nixos-hardware, home-manager, sops-nix, ...}: + let + lib = import ./lib { inherit (nixpkgs) lib; }; + in + { + # NOTE: Run `nix flake show` to see what this flake has to offer. + # TODO: Enable automated formatting with numtide/treefmt-nix + # `nixos-rebuild switch --flake .#` + nixosConfigurations = { + neon = nixpkgs.lib.nixosSystem { + specialArgs = { inherit inputs; }; + system = "x86_64-linux"; + modules = [ + ./hosts/neon + ]; + }; + #lithium = nixpkgs.lib.nixosSystem { + #specialArgs = { inherit inputs; }; + #system = "x86_64-linux"; + #modules = [ + #./hosts/lithium + #]; + #}; + lithium = lib.mkSystem { + users = [ + { name = "jml"; } + ]; + }; + }; + homeConfigurations = { + "jml" = home-manager.lib.homeManagerConfiguration { + modules = [ + ./users/jml/home.nix + ]; + }; + }; + # TODO: Implement a dev shell for working on this repository. + # Personally I'm using hx, nil, and git-agecrypt + # The only thing totally necessary which isn't captured by the flake inputs + # is git-agecrypt so that should be included here or somehow in the flake. + devShells.x86_64-linux.default = pkgs.mkShell { + buildInputs = with pkgs; [ + nixpkgs-fmt + sops + age + git-agecrypt + ]; + shellHook = '' + echo "ready to rock" + ''; + }; + # `nix run .#name` and `nix build .#name` + # packages = {}; + # `home-manager switch` + # homeConfigurations = {}; + }; +} diff --git a/flake.lock b/flake.lock index 9064650..d40ebb3 100644 --- a/flake.lock +++ b/flake.lock @@ -22,11 +22,11 @@ ] }, "locked": { - "lastModified": 1757508292, - "narHash": "sha256-7lVWL5bC6xBIMWWDal41LlGAG+9u2zUorqo3QCUL4p4=", + "lastModified": 1758287904, + "narHash": "sha256-IGmaEf3Do8o5Cwp1kXBN1wQmZwQN3NLfq5t4nHtVtcU=", "owner": "nix-community", "repo": "disko", - "rev": "146f45bee02b8bd88812cfce6ffc0f933788875a", + "rev": "67ff9807dd148e704baadbd4fd783b54282ca627", "type": "github" }, "original": { @@ -119,11 +119,11 @@ ] }, "locked": { - "lastModified": 1749499854, - "narHash": "sha256-V1BgwiX8NjbRreU6LC2EzmuqFSQAHhoSeNlYJyZ40NE=", + "lastModified": 1759337100, + "narHash": "sha256-CcT3QvZ74NGfM+lSOILcCEeU+SnqXRvl1XCRHenZ0Us=", "owner": "nix-community", "repo": "home-manager", - "rev": "1df816c407d3a5090c8496c9b00170af7891f021", + "rev": "004753ae6b04c4b18aa07192c1106800aaacf6c3", "type": "github" }, "original": { @@ -167,11 +167,11 @@ "spectrum": "spectrum" }, "locked": { - "lastModified": 1750358184, - "narHash": "sha256-17EYMeY5v8KRk9HW6Z4dExY8Wg4y/zM2eM2wbbx+vMs=", + "lastModified": 1758113222, + "narHash": "sha256-Q5i/qaj6v6F4N1Q5gI/4aL0IEEUE/LjQuwcA8L5IOMc=", "owner": "astro", "repo": "microvm.nix", - "rev": "fd9f5dba1ffee5ad6f29394b2a9e4c66c1ce77dc", + "rev": "b9206e245c07c0782beff58e1e94bb48b2531d15", "type": "github" }, "original": { @@ -182,11 +182,11 @@ }, "nixos-hardware": { "locked": { - "lastModified": 1749195551, - "narHash": "sha256-W5GKQHgunda/OP9sbKENBZhMBDNu2QahoIPwnsF6CeM=", + "lastModified": 1759261527, + "narHash": "sha256-wPd5oGvBBpUEzMF0kWnXge0WITNsITx/aGI9qLHgJ4g=", "owner": "nixos", "repo": "nixos-hardware", - "rev": "4602f7e1d3f197b3cb540d5accf5669121629628", + "rev": "e087756cf4abbe1a34f3544c480fc1034d68742f", "type": "github" }, "original": { @@ -195,18 +195,37 @@ "type": "github" } }, + "nixos-secrets": { + "inputs": { + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1759474546, + "narHash": "sha256-ZOlrxrAb5x5yM13P16sZowXb8AbEH02cZxets6SmkkA=", + "ref": "refs/heads/main", + "rev": "b28dde5afb05bf107905eff5c38908463fde5c59", + "shallow": true, + "type": "git", + "url": "ssh://forgejo@git.garage.systems/jml/nixos-secrets.git" + }, + "original": { + "shallow": true, + "type": "git", + "url": "ssh://forgejo@git.garage.systems/jml/nixos-secrets.git" + } + }, "nixpkgs": { "locked": { - "lastModified": 1749285348, - "narHash": "sha256-frdhQvPbmDYaScPFiCnfdh3B/Vh81Uuoo0w5TkWmmjU=", - "owner": "nixos", + "lastModified": 1757967192, + "narHash": "sha256-/aA9A/OBmnuOMgwfzdsXRusqzUpd8rQnQY8jtrHK+To=", + "owner": "NixOS", "repo": "nixpkgs", - "rev": "3e3afe5174c561dee0df6f2c2b2236990146329f", + "rev": "0d7c15863b251a7a50265e57c1dca1a7add2e291", "type": "github" }, "original": { - "owner": "nixos", - "ref": "nixos-unstable", + "owner": "NixOS", + "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" } @@ -227,6 +246,22 @@ "type": "github" } }, + "nixpkgs_2": { + "locked": { + "lastModified": 1759381078, + "narHash": "sha256-gTrEEp5gEspIcCOx9PD8kMaF1iEmfBcTbO0Jag2QhQs=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "7df7ff7d8e00218376575f0acdcc5d66741351ee", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, "pre-commit-hooks-nix": { "inputs": { "flake-compat": [ @@ -261,7 +296,8 @@ "lanzaboote": "lanzaboote", "microvm": "microvm", "nixos-hardware": "nixos-hardware", - "nixpkgs": "nixpkgs", + "nixos-secrets": "nixos-secrets", + "nixpkgs": "nixpkgs_2", "sops-nix": "sops-nix" } }, @@ -293,11 +329,11 @@ ] }, "locked": { - "lastModified": 1747603214, - "narHash": "sha256-lAblXm0VwifYCJ/ILPXJwlz0qNY07DDYdLD+9H+Wc8o=", + "lastModified": 1759188042, + "narHash": "sha256-f9QC2KKiNReZDG2yyKAtDZh0rSK2Xp1wkPzKbHeQVRU=", "owner": "Mic92", "repo": "sops-nix", - "rev": "8d215e1c981be3aa37e47aeabd4e61bb069548fd", + "rev": "9fcfabe085281dd793589bdc770a2e577a3caa5d", "type": "github" }, "original": { @@ -309,11 +345,11 @@ "spectrum": { "flake": false, "locked": { - "lastModified": 1746869549, - "narHash": "sha256-BKZ/yZO/qeLKh9YqVkKB6wJiDQJAZNN5rk5NsMImsWs=", + "lastModified": 1754675037, + "narHash": "sha256-afS08F7lfMUBR4qrBxinN1kuxu+DoHQ5TPNVp9VS/OA=", "ref": "refs/heads/main", - "rev": "d927e78530892ec8ed389e8fae5f38abee00ad87", - "revCount": 862, + "rev": "586577f3015397afacd83bc185454f4cc3c8028f", + "revCount": 955, "type": "git", "url": "https://spectrum-os.org/git/spectrum" }, diff --git a/flake.nix b/flake.nix index d6b35f8..682f169 100644 --- a/flake.nix +++ b/flake.nix @@ -13,9 +13,12 @@ disko.inputs.nixpkgs.follows = "nixpkgs"; microvm.url = "github:astro/microvm.nix"; microvm.inputs.nixpkgs.follows = "nixpkgs"; + nixos-secrets.url = "git+ssh://forgejo@git.garage.systems/jml/nixos-secrets.git?shallow=1"; + #nixos-secrets.flake = false; # TODO: Why does flake need to be false? + #nixos-secrets.inputs.nixpkgs.follows = "nixpkgs"; }; # https://nix.dev/tutorials/nix-language.html#named-attribute-set-argument - outputs = inputs@{self, nixpkgs, nixos-hardware, home-manager, sops-nix, lanzaboote, disko, microvm, ...}: + outputs = inputs@{self, nixpkgs, nixos-hardware, home-manager, sops-nix, lanzaboote, disko, microvm, nixos-secrets, ...}: let mkSystem = (import ./lib { inherit nixpkgs home-manager inputs; @@ -31,8 +34,12 @@ }; lithium = mkSystem { hostname = "lithium"; - # extraModules = [ inputs.sops-nix.nixosModules.sops ]; - extraModules = [ microvm.nixosModules.host ]; + #specialArgs = {inherit inputs;}; + extraModules = [ + inputs.sops-nix.nixosModules.sops + inputs.nixos-secrets.nixosModules.private-config + ]; + #extraModules = [ microvm.nixosModules.host ]; users = [ "jml" "breakglass" diff --git a/hosts/lithium/configuration.nix b/hosts/lithium/configuration.nix index 80cd057..ab3a8d6 100644 --- a/hosts/lithium/configuration.nix +++ b/hosts/lithium/configuration.nix @@ -1,6 +1,6 @@ { config, pkgs, lib, ... }: { - sops.defaultSopsFile = ./secrets/common.yaml; + #sops.defaultSopsFile = ./secrets/common.yaml; networking.hostName = "lithium"; networking.domain = lib.mkForce config.vars.domain; environment.systemPackages = with pkgs; [ diff --git a/hosts/lithium/default.nix b/hosts/lithium/default.nix index 8834b37..8eb2f37 100644 --- a/hosts/lithium/default.nix +++ b/hosts/lithium/default.nix @@ -16,6 +16,7 @@ ./hardware.nix ./configuration.nix ./semi-secret-vars.nix + ./services/caddy.nix ./services/tailscale.nix ./services/kanidm.nix @@ -25,12 +26,18 @@ ./services/miniflux ./services/forgejo.nix + ./services/immich.nix + + ./services/calibre-web.nix + # Monitoring ./services/monitoring + ./services/smartd.nix # Game Servers ./services/palworld + # TODO: Add Karakeep with yt-dlp + https://news.ycombinator.com/item?id=45595084 # Services running in virtual machines #./microvms diff --git a/hosts/lithium/microvms/default.nix b/hosts/lithium/microvms/default.nix new file mode 100644 index 0000000..3467e4c --- /dev/null +++ b/hosts/lithium/microvms/default.nix @@ -0,0 +1,18 @@ +{ config, pkgs, lib, ... }: +{ + microvm.autostart = [ + "palworld-server" + ]; + + microvm = { + interfaces = [ + { type = "user"; id = "main-net"; } + { type = "macvtap"; id = "vm-palworld"; } + ]; + + # Interface Name on the Host + # Ethernet Address of MicroVM's interface. + # Locally administered have one of 2/6/A/E in the second nibble. + #interfaces = [{type = "tap";id = "vm-palworld";mac = "02:00:00:00:00:01";}]; + }; +} diff --git a/hosts/lithium/microvms/palworld/default.nix b/hosts/lithium/microvms/palworld/default.nix new file mode 100644 index 0000000..f20e293 --- /dev/null +++ b/hosts/lithium/microvms/palworld/default.nix @@ -0,0 +1,107 @@ +{ config, pkgs, lib, ... }: +{ + # Host Firewall + networking.firewall.allowedUDPPorts = [ 8211 ]; + #networking.nat = { + #enable = true; + #enableIPv6 = true; + #externalInterface = "eth0"; + #internalInterfaces = [ "microvm" ]; + #}; + + microvm.vms.palworld-server = { + # Basic Requirements + # https://docs.palworldgame.com/getting-started/requirements + #hypervisor = "qemu"; + vcpu = 4; + memory = 16348; + + # Networking + interfaces = [{ type = "user"; id = "main-net"; }]; + + # Interface Name on the Host + # Ethernet Address of MicroVM's interface. + # Locally administered have one of 2/6/A/E in the second nibble. + #interfaces = [{type = "tap";id = "vm-palworld";mac = "02:00:00:00:00:01";}]; + #forwardPorts = [ + #{ proto = "udp"; from = "host"; host.port = 8211; guest.port = 8211; } + # Optional: If you need RCON or other ports, add them here + # { proto = "tcp"; from = "host"; host.port = 25575; guest.port = 25575; } + #]; + + # Persistent Data + sharedDirectories = [ + { + source = "/var/lib/palworld-data"; + target = "/var/lib/palworld-server"; + readonly = false; + } + ]; + + # VM NixOS Configuration + config = { + imports = [ pkgs.nixosModules.notDetected ]; + + networking.hostName = "palworld-vm"; + time.timeZone = "America/Chicago"; + + environment.systemPackages = with pkgs; [ + steamcmd + #glibc + #gnumake + #cff + ]; + + # Pre-VM-Start + binScripts.tap-up = lib.mkAfter '' + ${lib.getExe' pkgs.iproute2 "ip"} link set dev 'vm-ixp-as11201p' master 'ixp-peering' + ''; + + # Service Definition + systemd.services.palworld-dedicated = { + description = "Palworld Dedicated Server"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + Type = "simple"; + User = "palworld"; + Group = "palworld"; + # Working Directory points to where steamcmd installs the server + WorkingDirectory = "/var/lib/palworld-server/Pal/Binaries/Win64"; + ExecStart = '' + ${pkgs.steam-run}/bin/steam-run ${pkgs.bash}/bin/bash -c '\ + ${pkgs.steamcmd}/bin/steamcmd \ + +force_install_dur /var/lib/palworld-server \ + +login anonymous \ + +app_update 2394010 validate \ + +quit \ + && \ + ./PalServer.sh -userperfthreads -NoAsyncLoadingThread -UseNvidiaServers -nosteamclient \ + -Players=8 -Port=8211 -queryport=27015 -PublicPort=8211 -PublicIP=\"\" -RCONEnabled=False + ' + ''; + Restart = "on-failure"; + RestartSec = "5s"; + LimitNPROC = 10000; + LimitNOFILE = 100000; + }; + }; + + # User and Group Configuration + users.users.palworld = { + isSystem = true; + group = "palworld"; + createHome = false; + }; + users.groups.palworld = {}; + + # Firewall Configuration + networking.firewall.allowedUDPPorts = [ 8211 ]; + + # Ensure correct permissions for shared directory + systemd.tmpfiles.rules = [ + "d /var/lib/palworld-server 0755 palworld palworld -" + ]; + }; + }; +} diff --git a/hosts/lithium/microvms/valheim.nix b/hosts/lithium/microvms/valheim.nix new file mode 100644 index 0000000..e4a2f89 --- /dev/null +++ b/hosts/lithium/microvms/valheim.nix @@ -0,0 +1,50 @@ +{ config, lib, pkgs, ... }: +{ + microvm.vms.valheim = { + autoStart = true; + memorySize = 4096; + vcpu = 2; + + forwardPorts = [ + { from = "host"; hostPort = 2456; guestPort = 2456; proto = "udp"; } + { from = "host"; hostPort = 2457; guestPort = 2457; proto = "udp"; } + ]; + + # NOTE: For games with large save files, choose a path in "/tank" for + # storage. + sharedDirectories = [ + { + hostPath = "/srv/game-data-valheim"; + guestPath = "/data"; + tag = "valheim-data"; + readOnly = false; + } + ]; + + packages = [ pkgs.steamcmd pkgs.steam-run ]; + + users.users.valheim = { + isNormalUser = true; + home = "/home/valheim"; + extraGroups = [ "wheel" ]; + }; + + systemd.services.valheim = { + description = "Valheim Dedicated Server"; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + workingDirectory = "/data"; + ExecStart = '' + ${pkgs.steam-run}/bin/steam-run ./valheim_server.x86_64 \ + -name "Valheim NixOS" \ + -port 2456 \ + -world "FlatEarth" \ + -password "secret" \ + -public 1 + ''; + Restart = "always"; + User = "valheim"; + }; + }; + }; +} diff --git a/hosts/lithium/private-config.nix b/hosts/lithium/private-config.nix new file mode 100644 index 0000000..da79603 --- /dev/null +++ b/hosts/lithium/private-config.nix @@ -0,0 +1,8 @@ +{ inputs, ... }: +# let secretsPath = builtins.toString inputs.nixos-secrets; in +{ + #imports = [ inputs.nixos-secrets.nixosModules.private-config ]; + + # Enables a whole littany of private settings. + private-config.enable = true; +} diff --git a/hosts/lithium/secrets/common.yaml b/hosts/lithium/secrets/common.yaml index 341bc36..e02b06c 100644 --- a/hosts/lithium/secrets/common.yaml +++ b/hosts/lithium/secrets/common.yaml @@ -1,27 +1,30 @@ kanidm: - admin-password: ENC[AES256_GCM,data:wNE9qWAjfp8tf29sn1Q6GYrbw8g=,iv:uzg971jGIVyEkEbcOm2W8dy4wVgWiL+4Ph/f/bnieI0=,tag:/yY1okvnJLYGw2OLBd2Zdg==,type:str] - idm-admin-password: ENC[AES256_GCM,data:jIWaXUgHjhp0bP/DrF1m+plzcvE=,iv:nNpIkg9FTbCncih1/pAk4o7teuk7Gf/nPXyrnpFx4no=,tag:WhhsjtEdyS3Zw4F7uF9APg==,type:str] + admin-password: ENC[AES256_GCM,data:Hvmo6YG2ZCoYdQOBOyPiS2XAm6I=,iv:qKu5vlT0HEqK3Mx3zgAA0OUA+B63rEXnq/P059mrweI=,tag:K+iTc8R30ClP8egzIEtXKA==,type:str] + idm-admin-password: ENC[AES256_GCM,data:Dvz2o6gY/G3igJFhaIQ4gj/OG/8=,iv:hDE+y8SKqRU8tNxnd7q4CE3GfOHOkMcODpqc43KiPfc=,tag:fU8AyFokVUhERUvi6W6bYw==,type:str] +forgejo-admin-password: ENC[AES256_GCM,data:d7a2pzSpaeZ0CQ==,iv:XB6Y41egclWzmyZe3g2Z9U1NcCilw3VTZNlym94h3IU=,tag:vR6jrXiBciPXzUmvxHzQNw==,type:str] +miniflux: + oauth2_client_secret: ENC[AES256_GCM,data:tZk6Ru5MQk+VJ/ulZNtKirL2lfLmOeVKsDbJfLly1SBwXC6HdjBx+yAFCc7YVX+2,iv:GIIMhV/sIALjoUZsMMXAJl968owAlULJ1JLpShqa3RM=,tag:c2i+LvGJKQm82fsUEHF/BA==,type:str] sops: age: - recipient: age1mv8xtvkuuw3hphq5ytaekz7p8a4kht79uajyhy534uy9e5472fhqj5zpxu enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB5cFlReGMxV1R3QW1Vd1RU - WTgzNm5tbGhld3RMTGpMU1M2eVdoU0hmZGtNCmZLSTNOMk9IMDh6K2svRmRveGw3 - dlFUZ2lzTDBJWnBSTEhVTmVDOHVTdW8KLS0tIDhLWVZWSVJYM2x4YTlZWWZZZVNh - T2drb0p6TjZrZldpU0VUd0xmcVJUSk0KMjX3vr/74/HU7fmulefUHiNzwX8LcAes - ob3fabhMk9lmbuQk21rpoWbz3PNTfCQH63q+h7gLJTCCW2ISTvh/KQ== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4WUlyeStvZ28xVmV4VlNK + d1J1Z0twaTFzSEFENit0S210eTJFYTR1c1FRCnQvcFRCMUtFMkJxUDlRUTNxcTlK + dE5aM3U4Y0xvRE5jZlhrbjVtVk5rOHMKLS0tIHZISVlVcW9yT3hWcUtsVmN5TmRv + bXk5aSs4Wk9nM1p5d3FVSFBFKzVYZVEKYP2KQZIYm+zuI6OTfy85cEhj3gJWoKNu + jxd8vxwSbDmsXQK+mT8MsA9s+A9AhzGcZQ0rIQM/yKWFKSXt4kJ9rg== -----END AGE ENCRYPTED FILE----- - recipient: age148yre4vaxp6lm59rft24te46szawqyguf8znkrtpq7ud8tpteauqxkwyjl enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpK3VvNUhHNmJUQVZlREJl - c1oyZWx4ekNEM0VqL3NKanNmSmZtQXNpcWdVCmpWcklLVnhWUisvcGZzV1NHN3p4 - bW4wL09wL01XaHpveGdmbU4rbEp5NmsKLS0tIElhQVRmS05xUmJIZlI0S1dyWGhV - OGtKdHVwbWY2akJTQkF4YzlnNWQzNU0K81PyJ1tOvwOohNu9iUkS8vE7UXFRnJab - 8OLHtzX7FrkIH8rO2D5vEL9gPmxUtNKc9Ad3sndQls/yfg4wJAYedA== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHQk1kYjU1bXZ0aUc3cGVQ + N1hwclNpRkJWQlVhaU9EOEFNRkRQMmhLakNjCjAwbE1UYkxxbzNxQjV5Y1I0TU0r + cmZBUTZsTzMxZmFZZUxnRmw3T205aDAKLS0tIGdJTHBHVmk4TmlBQ1RHYkJ3aWw3 + bktSejFIdS8wS2R4RHRFMEwwb2pBN1kK8EoLo1E/DiFmpCf/v0kGLPcqIB1qZDd1 + Uf7ccMFqvQH8wGVuyqqwiZ2SconvK7hHC5U9qgi6bZa/t4aW8eeU/g== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-06-07T02:02:46Z" - mac: ENC[AES256_GCM,data:7mWOon8Hs2oU40l1dx4tVE8yXgcKoxfUAzY8zbtTzXqCOhzTzhY4OZAZiu4RiUSIOm7dMdQbH9zSx0j+5e2k9QflfJDDM3rWfunTa7L8Bm8k9b/WjS0Fnb7OV0InO6tLxQwkTamMcc7ORrKxwHB5PwuXD+efeWNXveHo5GYgF+M=,iv:seh2Pzt+AmmxyD5hwh3VkLQTDMq0Gh9mV6J3QrtxcmM=,tag:jpXn2fht8wArB2KD/ZmbyA==,type:str] + lastmodified: "2025-10-03T06:48:03Z" + mac: ENC[AES256_GCM,data:tglsrKi8Ydifc08LLA/KHzqWI3u9+Tn9kkERI3XKp/vSy4a90T2fU9f/lcyYbOXXuOOCL364wYq7ETmsTzOmb5Eo2Wtcu9Hsn820rLXuxNu7kyz9os/0eL/IThrPQtKov4/IdzoGQCqZvd9kcxTN1UPlRnd9aiHwsKmoFFFNZlE=,iv:y9+JQRXZf/6GabaQ1nQk3dL7qKMQxyzvIsXU2yVmlZo=,tag:klmWeIP068BpsSi8u/tE4A==,type:str] unencrypted_suffix: _unencrypted version: 3.10.2 diff --git a/hosts/lithium/services/README.md b/hosts/lithium/services/README.md new file mode 100644 index 0000000..0bf9c37 --- /dev/null +++ b/hosts/lithium/services/README.md @@ -0,0 +1,11 @@ +# hosts/lithium/services + +The idea is that each `*.nix` or each `./*/default.nix` file would contain all +necessary details for a service to bring itself up and be running. + +One thing I have overlooked thus far is nothing tests for the existence of a +reverse proxy and bails out if one isn't available. Practically if caddy isn't +running, most of these services should also not run, or at the very least, the +blocks pertaining to setting up reverse proxy details don't need to run. + +There's a way of doing that with things like lib.mkDefault and so forth. diff --git a/hosts/lithium/services/acme-dns.nix b/hosts/lithium/services/acme-dns.nix new file mode 100644 index 0000000..9377497 --- /dev/null +++ b/hosts/lithium/services/acme-dns.nix @@ -0,0 +1,65 @@ +{ config, ... }: +let + homelabDomain = inputs.nixos-secrets.homelabDomain; + certDir = config.security.acme.certs."${homelabDomain}".directory; +in +{ + sops.secrets."cloudflare/dns_api_token" = { + mode = "0440"; + group = config.services.caddy.group; + restartUnits = [ "caddy.service" "ddclient.service" ]; + }; + + + # TODO: Consider defining reverse proxy all in one location. + # All the ports and domains would be visible in one place. + security.acme = { + acceptTerms = true; + defaults = { + # NOTE: Uncomment the following line for testing, comment for production. + server = "https://acme-staging-v02.api.letsencrypt.org/directory"; + dnsProvider = "cloudflare"; + dnsResolver = "1.1.1.1:53"; + dnsPropagationCheck = true; + credentialFiles = { + CLOUDFLARE_DNS_API_TOKEN_FILE = config.sops.secrets."cloudflare/dns_api_token".path; + }; + group = config.services.caddy.group; + #reloadServices = [ "caddy" ]; + email = "admin+acme@${homelabDomain}"; # NOTE: This email is /dev/null; + #keyType = "ec384"; + }; + }; + + services.ddclient = { + enable = true; + protocol = "cloudflare"; + usev4 = "webv4, webv4=https://cloudflare.com/cdn-cgi/trace, web-skip='ip='"; + username = "token"; + #secretsFile = config.sops.secrets."cloudflare/dns_api_token".path; + passwordFile = config.sops.secrets."cloudflare/dns_api_token".path; + zone = homelabDomain; + domains = [ + homelabDomain + "*.${homelabDomain}" + "id.${homelabDomain}" + "status.${homelabDomain}" + "grafana.${homelabDomain}" + "feeds.${homelabDomain}" + "git.${homelabDomain}" + "tv.${homelabDomain}" + "demo.${homelabDomain}" # Testing to see if the DNS record is set. + ]; + }; + + # NOTE: Issue a single cert /w subdomain wildcard + # At the expense of individual service security, some public details about + # attack surface remain slightly more private in https://crt.sh/ + security.acme.certs."${homelabDomain}" = { + #group = config.services.caddy.group; + domain = "${homelabDomain}"; + extraDomainNames = [ "*.${homelabDomain}" ]; + }; + # Nginx useACMEHost provides the DNS-01 challenge. + # security.acme.certs."${homelabDomain}".directory +} diff --git a/hosts/lithium/services/audiobookshelf.nix b/hosts/lithium/services/audiobookshelf.nix new file mode 100644 index 0000000..92cf710 --- /dev/null +++ b/hosts/lithium/services/audiobookshelf.nix @@ -0,0 +1,20 @@ +{ inputs, config, pkgs, lib, ... }: +let + homelabDomain = inputs.nixos-secrets.homelabDomain; + svcDomain = "audiobooks.${homelabDomain}"; + svcPort = config.services.audiobookshelf.port; # Prevent a Conflict +in +{ + services.caddy.virtualHosts."${svcDomain}".extraConfig = '' + reverse_proxy :${svcPort} + ''; + + services.audiobookshelf = { + enable = true; + openFirewall = true; + port = 8000; + + # NOTE: Path to AudioBookShelf config & metadata inside of `/var/lib` + dataDir = "audiobookshelf"; + }; +} diff --git a/hosts/lithium/services/caddy.nix b/hosts/lithium/services/caddy.nix index 86a39cf..862c7ce 100644 --- a/hosts/lithium/services/caddy.nix +++ b/hosts/lithium/services/caddy.nix @@ -1,13 +1,22 @@ -{ config, pkgs, ... }: +{ inputs, config, pkgs, lib, ... }: +let + homelabDomain = inputs.nixos-secrets.homelabDomain; + certDir = config.security.acme.certs."${homelabDomain}".directory; +in { - sops.secrets.caddy_env = { - sopsFile = ../secrets/caddy.env; - format = "dotenv"; + services.nginx.enable = lib.mkForce false; + + sops.secrets.cloudflare_env = { mode = "0440"; - owner = config.services.caddy.user; + sopsFile = "${inputs.nixos-secrets}/lithium/cloudflare.env"; + format = "dotenv"; group = config.services.caddy.group; restartUnits = [ "caddy.service" ]; }; + + # TODO: Revert to using Caddy DNS for the whole thing. + # TODO: Add another cloudflare DDNS provider. + # TODO: Add Metrics with Prometheus & Grafana services.caddy = { enable = true; package = pkgs.caddy.withPlugins { @@ -16,26 +25,33 @@ "github.com/mholt/caddy-dynamicdns@v0.0.0-20250430031602-b846b9e8fb83" "github.com/caddy-dns/cloudflare@v0.2.1" ]; - - # NOTE: Built on 6/4/2025 - hash = "sha256-swskhAr7yFJX+qy0FR54nqJarTOojwhV2Mbk7+fyS0I="; + # NOTE: Built on 9/30/2025 + hash = "sha256-xuwNkxZop+RnzFtM9DEwah95nPSyx8KgM+Eu4EJ9kqI="; }; # NOTE: Use Staging CA while testing, check `systemctl status caddy` # to see if everything is working. # acmeCA = "https://acme-staging-v02.api.letsencrypt.org/directory"; - - # TODO: Add Metrics with Prometheus & Grafana - environmentFile = config.sops.secrets.caddy_env.path; + + environmentFile = config.sops.secrets.cloudflare_env.path; + # NOTE: DNS provider settings + # https://caddy.community/t/how-to-use-dns-provider-modules-in-caddy-2/8148 globalConfig = '' - # acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN} + #acme_dns cloudflare {$CLOUDFLARE_DNS_API_TOKEN} dynamic_dns { - provider cloudflare {env.CLOUDFLARE_API_TOKEN} + provider cloudflare {$CLOUDFLARE_DNS_API_TOKEN} + check_interval 30m + ttl 5m domains { - ${config.networking.domain} @ + ${homelabDomain} @ } dynamic_domains } ''; + }; - networking.firewall.allowedTCPPorts = [ 80 443 ]; + networking.firewall = { + allowedTCPPorts = [ 80 443 ]; + allowedUDPPorts = [ 443 ]; + }; + } diff --git a/hosts/lithium/services/calibre-web.nix b/hosts/lithium/services/calibre-web.nix index 44f8baf..38cafb5 100644 --- a/hosts/lithium/services/calibre-web.nix +++ b/hosts/lithium/services/calibre-web.nix @@ -1,11 +1,13 @@ { inputs, config, pkgs, lib, ... }: let homelabDomain = inputs.nixos-secrets.homelabDomain; - certDir = config.security.acme.certs."${homelabDomain}".directory; + #certDir = config.security.acme.certs."${homelabDomain}".directory; svcDomain = "books.${homelabDomain}"; svcHttpPort = config.services.calibre-web.listen.port; web_data_dir = "calibre-web"; + # TODO: I want the actual media stored in the tank. library_path = "/tank/media/library/books"; + #library_path = "/var/lib/calibre-library"; in { # TODO: This isn't the right place for this, but we need to guarantee that a @@ -14,19 +16,25 @@ in users.groups.media = {}; services.caddy.virtualHosts."${svcDomain}".extraConfig = '' - reverse_proxy :${toString svcHttpPort} - encode { - zstd - gzip - minimum_length 1024 - } + reverse_proxy localhost:8883 ''; + # reverse_proxy :${toString svcHttpPort} + # encode { + # zstd + # gzip + # minimum_length 1024 + # } + # ''; + + # NOTE: Needs some manual setup in Web-UI and I ecountered issues connecting even with firewall enabled. + # The following command is what I used to forward the port: + # ssh -f -N -L localhost:8883:localhost:8883 jml@lithium services.calibre-web = { enable = true; - listen.port = 8083; + listen.port = 8883; # NOTE: Don't need to open calibre-web port, it's served by reverse_proxy - openFirewall = false; + openFirewall = true; # TODO: Temporarily opened to allow configuration from inside my network. user = "calibre-web"; group = "calibre-web"; @@ -38,6 +46,7 @@ in options = { enableBookUploading = true; enableBookConversion = true; + # NOTE: If I don't already have an extant calibreLibrary, I need to leave this null or the app won't launch. calibreLibrary = library_path; }; }; diff --git a/hosts/lithium/services/forgejo.nix b/hosts/lithium/services/forgejo.nix index 3cec1fa..2f6377f 100644 --- a/hosts/lithium/services/forgejo.nix +++ b/hosts/lithium/services/forgejo.nix @@ -41,6 +41,7 @@ in server = { DOMAIN = svcDomain; ROOT_URL = "https://${svcDomain}"; + HTTP_PORT = 3000; }; # NOTE: Actions support is based on: https://github.com/nektos/act #actions = { @@ -49,6 +50,7 @@ in #}; actions.ENABLED = false; # NOTE: Registration is handled with kanidm. + # Registration button link is at /user/sign_up service = { REGISTER_EMAIL_CONFIRM = false; DISABLE_REGISTRATION = false; @@ -87,13 +89,15 @@ in services.kanidm.provision.systems.oauth2.forgejo = { displayName = "forgejo"; # TODO: Get this from Forgejo - originUrl = "https://git.${homelabDomain}/user/oauth2/${homelabDomain}/callback"; + # originUrl = "https://git.${homelabDomain}/user/oauth2/${homelabDomain}/callback"; + originUrl = "${config.services.forgejo.settings.server.ROOT_URL}/user/oauth2/kanidm/callback"; originLanding = "https://git.${homelabDomain}/"; #basicSecretFile = "TODO!SETME"; scopeMaps."git.users" = [ "openid" "email" "profile" + "groups" ]; # WARNING: PKCE is currently not supported by gitea/forgejo, # see https://github.com/go-gitea/gitea/issues/21376 @@ -137,5 +141,5 @@ in # TODO: Consider automatically creating admin account and password... # https://wiki.nixos.org/wiki/Forgejo#Ensure_users # Might be necessary to generate a token for kanidm - #sops.secrets.forgejo-admin-password.owner = "forgejo"; + sops.secrets."forgejo/admin-password".owner = "forgejo"; } diff --git a/hosts/lithium/services/forgejo/actions-runner.nix b/hosts/lithium/services/forgejo/actions-runner.nix new file mode 100644 index 0000000..e69de29 diff --git a/hosts/lithium/services/forgejo/default.nix b/hosts/lithium/services/forgejo/default.nix new file mode 100644 index 0000000..e69de29 diff --git a/hosts/lithium/services/forgejo/forgejo.nix b/hosts/lithium/services/forgejo/forgejo.nix new file mode 100644 index 0000000..e69de29 diff --git a/hosts/lithium/services/game_servers.nix b/hosts/lithium/services/game_servers.nix new file mode 100644 index 0000000..0cc2929 --- /dev/null +++ b/hosts/lithium/services/game_servers.nix @@ -0,0 +1,42 @@ +{ pkgs, ... }: +{ + # TODO + # systemd.services..serviceConfig.{MemoryMax,CPUQuota} + systemd.services.valheim-server = { + description = "Valheim dedicated server"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + }; + + serviceConfig = { + Type = "simple"; + User = "valheim"; + Group = "valheim"; + ExecStart = "${pkgs.steamcmd}/bin/steamcmd +login anonymous +force_install_dir /home/valheim/server +app_update 896660 validate +exit && /home/valheim/server/valheim_server.x86_64"; + }; + + users.users.valheim = { + isSystemUser = true; + group = "valheim"; + home = "/home/valheim"; + }; + users.groups.valheim = {}; + + networking.firewall = { + allowedTCPPorts = [ 7777 2456 ]; + allowedUDPPorts = [ 7777 2457 ]; + }; + + services.restic.backups.gameservers = { + user = "root"; + # TODO: Pick a real backup directory. + repository = "/backup/gameservers"; + paths = [ + "/var/lib/terraria" + "/home/valheim/server" + ]; + timeConfig = { + OnCalendar = "daily"; + }; + }; +} diff --git a/hosts/lithium/services/grafana.nix b/hosts/lithium/services/grafana.nix deleted file mode 100644 index 0dddf2b..0000000 --- a/hosts/lithium/services/grafana.nix +++ /dev/null @@ -1,24 +0,0 @@ -{ config, pkgs, ... }: -let - svcDomain = "grafana.${config.networking.domain}"; - svcPort = config.services.grafana.settings.server.http_port; -in -{ - services.caddy.virtualHosts."${svcDomain}".extraConfig = '' - reverse_proxy :${svcPort} - ''; - - services.grafana = { - enable = true; - settings = { - server = { - http_addr = "127.0.0.1"; - http_port = 3000; - enforce_domain = true; - enable_gzip = true; - domain = svcDomain; - }; - analytics.reporting_enabled = false; # NOTE: Disable Telemetry - }; - }; -} diff --git a/hosts/lithium/services/home-assistant.nix b/hosts/lithium/services/home-assistant.nix new file mode 100644 index 0000000..ba87895 --- /dev/null +++ b/hosts/lithium/services/home-assistant.nix @@ -0,0 +1,7 @@ +{ config, pkgs, ... }: +{ + services.home-assistant = { + enable = true; + openFirewall = true; + }; +} diff --git a/hosts/lithium/services/immich.nix b/hosts/lithium/services/immich.nix index 1c71665..6226ade 100644 --- a/hosts/lithium/services/immich.nix +++ b/hosts/lithium/services/immich.nix @@ -4,29 +4,47 @@ let svcDomain = "photos.${homelabDomain}"; photoStorageDir = "/tank/shares/photos"; svcPort = config.services.immich.port; + # https://docs.immich.app/install/config-file/ + jsonSettings = { + server.externalDomain = "https://${svcDomain}"; + oauth = { + enabled = true; + issuerUrl = "https://"; # TODO: the kanidm url? + clientId = "immich"; + clientSecret = config.sops.placeholder."immich/oauth2_client_secret"; + scope = "openid email profile"; + signingAlgorithm = "ES256"; + storageLabelClaim = "email"; + buttonText = "Login with Kanidm"; + autoLaunch = true; + mobileOverrideEnabled = true; + mobileRedirectUri = "https://${svcDomain}/api/oauth/mobile-redirect/"; + }; + }; in { # NOTE: The following repo contains a highly mature immich setup on nixos. # https://github.com/xinyangli/nixos-config/blob/a8b5bea68caea573801ccfdb8ceacb7a8f2b0190/machines/agate/services/immich.nix services.caddy.virtualHosts."${svcDomain}".extraConfig = '' - reverse_proxy :${svcPort} + reverse_proxy :${toString svcPort} ''; # NOTE: Primarily to contain DB_PASSWORD to make it possible to backup and restore the DB. - sops.secrets.immich_env = { - sopsFile = ../../secrets/immich.env; - format = "dotenv"; + # sops.secrets.immich_env = { + # sopsFile = ../../secrets/immich.env; + # format = "dotenv"; + # mode = "0440"; + # owner = "immich"; + # group = "immich"; + # restartUnits = [ "immich.service" ]; + # }; + sops.secrets."immich/oauth2_client_secret" = { }; + sops.templates."immich.json" = { mode = "0440"; - owner = "immich"; - group = "immich"; - restartUnits = [ "immich.service" ]; - }; - sops.secrets."immich/oauth2_client_secret" = { - owner = "immich"; - group = "kanidm"; - mode = "0440"; - restartUnits = [ "immich.service" "kanidm.service" ]; + owner = config.services.immich.user; + group = config.services.immich.group; + content = builtins.toJSON jsonSettings; }; users.users.immich = { @@ -45,27 +63,12 @@ in enable = true; openFirewall = true; port = 2283; # default - secretsFile = config.sops.secrets."immich_secrets.env".path; + #secretsFile = config.sops.secrets.immich_env.path; # TODO: Build this directory with permissions for the immich user. mediaLocation = "/tank/shares/photos"; - - # https://docs.immich.app/install/config-file/ - settings = { - # TODO: Setup OAuth with Kanidm - oauth = { - enabled = true; - issuerUrl = "https://"; # TODO: the kanidm url? - clientId = "immich"; - clientSecret = config.sops.placeholder."immich/oauth2_client_secret"; - scope = "openid email profile"; - signingAlgorithm = "ES256"; - storageLabelClaim = "email"; - buttonText = "Login with Kanidm"; - autoLaunch = true; - mobileOverrideEnabled = true; - mobileRedirectUri = "https://${svcDomain}/api/oauth/mobile-redirect/"; - }; + environment = { + IMMICH_CONFIG_FILE = config.sops.templates."immich.json".path; }; }; diff --git a/hosts/lithium/services/kanidm.nix b/hosts/lithium/services/kanidm.nix index 066652f..a302749 100644 --- a/hosts/lithium/services/kanidm.nix +++ b/hosts/lithium/services/kanidm.nix @@ -1,33 +1,91 @@ -{ config, pkgs, lib, ... }: +{ inputs, config, pkgs, lib, ... }: let - svcDomain = "id.${config.networking.domain}"; - caddyCertsRoot = "${config.services.caddy.dataDir}/.local/share/caddy/certificates"; - caddyCertsDir = "${caddyCertsRoot}/acme-v02.api.letsencrypt.org-directory"; - certsDir = "/var/lib/kanidm/certs"; + homelabDomain = inputs.nixos-secrets.homelabDomain; + svcDomain = "id.${homelabDomain}"; + kanidmCertDir = "/var/lib/kanidm/certs"; + caddyCertStore = "${config.services.caddy.dataDir}/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/${svcDomain}"; + #kcertloc = "${caddyCertsStore}/${svcDomain}/"; + certRenewalScript = pkgs.writeShellScript "copy-kanidm-cert-hook" '' + set -Eeuo pipefail + mkdir -p ${kanidmCertDir} + cp ${caddyCertStore}/${svcDomain}.crt ${kanidmCertDir}/cert.pem + cp ${caddyCertStore}/${svcDomain}.key ${kanidmCertDir}/key.pem + + chown kanidm:kanidm ${kanidmCertDir}/*.pem + + ${pkgs.systemd}/bin/systemctl restart kanidm.service + ''; + kanidmCertCopier = "kanidm-cert-copier"; in { + # NOTE: Domains are serious when they are the root of identity/authnz. + # Recommendation from Kanidm docs for "Maximum" security is to maintain + # Both `example.com` and `id.example-auth.com`, the latter for idm infra exclusively. + # I consider that to be untenable and even more risky. + # The next recommendation is to follow a pattern like so + # id.example.com + # australia.id.example.com + # id-test.example.com + # australia.id-test.example.com + + # Example of yoinking certs from caddy: # https://github.com/marcusramberg/nix-config/blob/e558914dd3705150511c5ef76278fc50bb4604f3/nixos/kanidm.nix#L3 # TODO: If possible, consider specifying the cert location here instead of the following kludge. services.caddy.virtualHosts."${svcDomain}".extraConfig = '' reverse_proxy :8443 { + header_up Host {host} + header_up X-Real-IP {http.request.header.CF-Connecting-IP} transport http { tls_server_name ${svcDomain} } } ''; - # NOTE: Attempted kludge due to caddy generating (and therefore owning the certs) + # NOTE: Cleanup old rules + # systemd.tmpfiles.rules = lib.filter(rule: ! (lib.strings.hasPrefix "C ${kanidmCertDir}" rule)) config.systemd.tmpfiles.rules; systemd.tmpfiles.rules = [ - "d ${certsDir} 0750 kanidm caddy -" - "C ${certsDir}/cert.pem - kanidm - - ${caddyCertsDir}/${svcDomain}/${svcDomain}.crt" - "C ${certsDir}/key.key - kanidm - - ${caddyCertsDir}/${svcDomain}/${svcDomain}.key" + "d ${kanidmCertDir} 0750 kanidm kanidm -" ]; - systemd.services.kanidm = { - after = [ "systemd-tmpfiles-setup.service" ]; - requires = [ "caddy.service" "systemd-tmpfiles-setup.service" ]; + # NOTE: Include automation for copying cert files on renewal. + # systemd.services.caddy.serviceConfig = { + # ExecStartPost = [ + # "${certRenewalScript}/bin/copy-kanidm-cert-hook" + # ]; + # ExecReload = [ + # "${pkgs.caddy}/bin/caddy reload --config ${config.services.caddy.configFile}" + # "${certRenewalScript}/bin/copy-kanidm-cert-hook" + # ]; + # }; + systemd.services.${kanidmCertCopier} = { + description = "Copy Caddy certificates for Kanidm"; + requires = [ "caddy.service" ]; + after = [ "caddy.service" ]; + + serviceConfig = { + Type = "oneshot"; + User = "root"; + ExecStart = "${certRenewalScript}"; + }; }; + # systemd.services.caddy.wantedBy = [ "multi-user.target" ]; + # systemd.services.caddy.wants = [ kanidmCertCopier ]; + systemd.services.caddy.reloadTriggers = [ kanidmCertCopier ]; + systemd.timers.kanidm-cert-copier-daily = { + wantedBy = [ "timers.target" ]; + timerConfig = { + OnBootSec = "5min"; + OnCalendar = "daily"; + Unit = kanidmCertCopier; + }; + }; + + + # systemd.services.kanidm = { + # after = [ kanidmCertCopier ]; + # requires = [ kanidmCertCopier ]; + # }; users.users.kanidm.extraGroups = [ "caddy" ]; @@ -43,21 +101,25 @@ in }; }; + services.kanidm = { - package = pkgs.kanidmWithSecretProvisioning; + package = pkgs.kanidmWithSecretProvisioning_1_7; enableServer = true; serverSettings = { # NOTE: Required to start the server: https://kanidm.github.io/kanidm/stable/server_configuration.html # domain, origin, tls_chain, tls_key domain = svcDomain; origin = "https://${svcDomain}"; - tls_chain = "${certsDir}/cert.pem"; - tls_key = "${certsDir}/key.key"; + tls_chain = "${kanidmCertDir}/cert.pem"; + tls_key = "${kanidmCertDir}/key.pem"; + # tls_chain = "${caddyCertStore}/${svcDomain}.crt"; + # tls_key = "${caddyCertStore}/${svcDomain}.key"; # NOTE: Optional Settings + # TODO: Configure the rest of the binding properly, should be 363 and maybe 8443 ldapbindaddress = "127.0.0.1:3636"; # For Jellyfin LDAP integration. - # trust_x_forwarded_for = true; + #trust_x_forwarded_for = true; }; enableClient = true; @@ -74,6 +136,7 @@ in home_alias = "name"; }; + # TODO: Migrate the secrets from here to `nixos-secrets` # NOTE: There are manual steps required as root to allow a user to set # their own credentials, or to confiugre an account as posix. As-is this # module doesn't support provisioning a complete user /w credentials. @@ -82,7 +145,9 @@ in # https://kanidm.github.io/kanidm/stable/accounts/authentication_and_credentials.html#onboarding-a-new-person--resetting-credentials provision = { enable = true; - autoRemove = false; + autoRemove = true; + acceptInvalidCerts = true; + adminPasswordFile = config.sops.secrets."kanidm/admin-password".path; idmAdminPasswordFile = config.sops.secrets."kanidm/idm-admin-password".path; @@ -98,6 +163,8 @@ in "git.users" "git.admins" "tv.users" + "immich.users" + "miniflux.users" ]; }; }; @@ -107,6 +174,8 @@ in "git.admins" = {}; "tv.users" = {}; "tv.admins" = {}; + "immich.users" = {}; + "miniflux.users" = {}; }; }; }; diff --git a/hosts/lithium/services/miniflux/default.nix b/hosts/lithium/services/miniflux/default.nix index a109874..bd92af4 100644 --- a/hosts/lithium/services/miniflux/default.nix +++ b/hosts/lithium/services/miniflux/default.nix @@ -1,7 +1,8 @@ { config, pkgs, ... }: let - svcDomain = "feeds.${config.networking.domain}"; - svcPort = "8080"; + homelabDomain = config.networking.domain; + svcDomain = "feeds.${homelabDomain}"; + svcPort = "8081"; # Prevent a Conflict in { services.caddy.virtualHosts."${svcDomain}".extraConfig = '' @@ -22,32 +23,57 @@ in group = "miniflux"; restartUnits = [ "miniflux.service" ]; }; - services.kanidm.provision = { - groups = {}; - systems.oauth2.miniflux = { - displayName = "Miniflux Feed Reader"; - originUrl = "https://${fqdn}/callback"; - public = true; # enforces PKCE - preferShortUsername = true; - scopeMaps.pages_users = ["openid" "email" "profile"]; - claimMaps."${permissionsMap}".valuesByGroup.pages_admin = ["admin"]; - }; + sops.secrets."miniflux/oauth2_client_secret" = { + owner = "miniflux"; + group = "kanidm"; + mode = "0440"; + restartUnits = [ "miniflux.service" "kanidm.service" ]; }; + #services.kanidm.provision = { + #groups = {}; + #systems.oauth2.miniflux = { + #displayName = "Miniflux Feed Reader"; + #originUrl = "https://${fqdn}/callback"; + #public = true; # enforces PKCE + #preferShortUsername = true; + #scopeMaps.pages_users = ["openid" "email" "profile"]; + #claimMaps."${permissionsMap}".valuesByGroup.pages_admin = ["admin"]; + #}; + #}; # NOTE: Currently requires some web-interface configuration services.miniflux = { enable = true; adminCredentialsFile = config.sops.secrets.miniflux_env.path; config = { BASE_URL = "https://${svcDomain}"; - CREATE_ADMIN = 0; - DISABLE_LOCAL_AUTH = 1; + #CREATE_ADMIN = 0; + #DISABLE_LOCAL_AUTH = 1; OAUTH2_PROVIDER = "oidc"; - OAUTH2_OIDC_PROVIDER_NAME = "Kanidm"; - OAUTH2_OIDC_DISCOVERY_ENDPOINT = "https://id.${config.networking.domain}"; + OAUTH2_CLIENT_ID = "miniflux"; + OAUTH2_CLIENT_SECRET_FILE = config.sops.secrets."miniflux/oauth2_client_secret".path; OAUTH2_REDIRECT_URL = "https://${svcDomain}/oauth2/oidc/callback"; - OAUTH2_USER_CREATION = 1; + OAUTH2_OIDC_DISCOVERY_ENDPOINT = "https://id.${homelabDomain}/oauth2/openid/miniflux"; + #OAUTH2_USER_CREATION = 1; CLEANUP_FREQUENCY = 48; LISTEN_ADDR = "localhost:${svcPort}"; }; }; + + + services.kanidm.provision.systems.oauth2.miniflux = { + displayName = "miniflux"; + originUrl = "https://${svcDomain}/oauth2/oidc/callback"; + originLanding = "https://${svcDomain}/"; + basicSecretFile = config.sops.secrets."miniflux/oauth2_client_secret".path; + scopeMaps."miniflux.users" = [ + "openid" + "email" + "profile" + "groups" + ]; + # WARNING: PKCE is currently not supported by gitea/forgejo, + # see https://github.com/go-gitea/gitea/issues/21376 + allowInsecureClientDisablePkce = true; + preferShortUsername = true; + }; } diff --git a/hosts/lithium/services/monitoring/README.md b/hosts/lithium/services/monitoring/README.md new file mode 100644 index 0000000..93c1ca8 --- /dev/null +++ b/hosts/lithium/services/monitoring/README.md @@ -0,0 +1,14 @@ +# hosts/lithium/services/monitoring + +This is a Grafana/Prometheus Monitoring Stack. +Why? Basically for the sake of it. + +## Diagram + +```mermaid +```` + +## References + +- https://gist.github.com/rickhull/895b0cb38fdd537c1078a858cf15d63e +- https://xeiaso.net/blog/prometheus-grafana-loki-nixos-2020-11-20/ diff --git a/hosts/lithium/services/monitoring/grafana.nix b/hosts/lithium/services/monitoring/grafana.nix index 7ba0206..afc986e 100644 --- a/hosts/lithium/services/monitoring/grafana.nix +++ b/hosts/lithium/services/monitoring/grafana.nix @@ -1,6 +1,8 @@ -{ config, pkgs, ... }: +{ inputs, config, pkgs, ... }: let - svcDomain = "grafana.${config.networking.domain}"; + homelabDomain = inputs.nixos-secrets.homelabDomain; + #svcDomain = "grafana.${config.networking.domain}"; + svcDomain = "grafana.${homelabDomain}"; svcPort = config.services.grafana.settings.server.http_port; in { diff --git a/hosts/lithium/services/monitoring/loki-local-config.yaml b/hosts/lithium/services/monitoring/loki-local-config.yaml new file mode 100644 index 0000000..919a718 --- /dev/null +++ b/hosts/lithium/services/monitoring/loki-local-config.yaml @@ -0,0 +1,4 @@ +auth_enabled: false + +server: + http_listen_port: 3100 diff --git a/hosts/lithium/services/monitoring/loki.nix b/hosts/lithium/services/monitoring/loki.nix new file mode 100644 index 0000000..448cc37 --- /dev/null +++ b/hosts/lithium/services/monitoring/loki.nix @@ -0,0 +1,15 @@ +{ ... }: +{ + services.loki = { + enable = true; + #configFile = "./loki-local-config.yaml"; + # Nix Object representing the data that might otherwise be in a YAML config + # https://github.com/grafana/loki/blob/main/cmd/loki/loki-local-config.yaml + configuration = { + auth_enabled = false; + server = { + + }; + }; + }; +} diff --git a/hosts/lithium/services/monitoring/prometheus.nix b/hosts/lithium/services/monitoring/prometheus.nix index 51be2ea..84d818c 100644 --- a/hosts/lithium/services/monitoring/prometheus.nix +++ b/hosts/lithium/services/monitoring/prometheus.nix @@ -1,8 +1,8 @@ { config, pkgs, ... }: -#let +let #svcDomain = "status.${config.networking.domain}"; - #svcPort = config.services.prometheus.exporters.node.port; -#in + svcPort = config.services.prometheus.exporters.node.port; +in { #services.caddy.virtualHosts."${svcDomain}".extraConfig = '' #reverse_proxy :${svcPort} @@ -10,20 +10,27 @@ services.prometheus = { enable = true; + port = 9090; #globalConfig.scrape_interval = "10s"; # "1m" - #scrapeConfigs = [ - #{ - #job_name = "node"; - #static_configs = [{ - # targets = [ "localhost:${toString svcPort}" ]; - #}]; - #} - #]; + + exporters = { + # Export data about this host + node = { + enable = true; + enabledCollectors = [ "systemd" ]; + port = 9091; + }; + }; + + # Read data from the export + scrapeConfigs = [ + { + job_name = "node-lithium"; + static_configs = [{ + targets = [ "localhost:${toString svcPort}" ]; + }]; + } + ]; }; - #services.prometheus.exporters.node = { - #enable = true; - #port = 9000; - #enabledCollectors = [ "systemd" ]; - #}; } diff --git a/hosts/lithium/services/old-kanidm.nix b/hosts/lithium/services/old-kanidm.nix new file mode 100644 index 0000000..0bce514 --- /dev/null +++ b/hosts/lithium/services/old-kanidm.nix @@ -0,0 +1,79 @@ +{ config, pkgs, lib, ... }: +let + cfg = config.services.kanidm; + authDomain = "auth.${config.networking.domain}"; + certsDir = config.security.acme.certs."${authDomain}".directory; +in +{ + # TODO: Pull in the appropriate sops-nix secrets and get this baby rolling. + # https://github.com/search?q=language%3ANix+services.kanidm&type=code + services.kanidm = { + # NOTE: Pin a specific kanidm version, we don't want issues from auto-updating. + package = pkgs.kanidm_1_6; + enableServer = true; + + # TODO: Initial kanidm setup. + # I sort of want users to be able to create their own accounts and what I + # don't want is for any of their account information to be leaked here as + # it can be used for remote logins. + # So kanidm accounts aside from the administration will be "impure". + # I vastly prefer people being able to set their own credentials: + # https://kanidm.github.io/kanidm/stable/accounts/authentication_and_credentials.html#onboarding-a-new-person--resetting-credentials + provision = { + enable = true; + autoRemove = false; + # TODO: Add secrets from `sops-nix`. + adminPasswordFile = "TODO!SETME"; + idmAdminPasswordFile = "TODO!SETME"; + + persons = { + # https://kanidm.github.io/kanidm/stable/accounts/authentication_and_credentials.html#resetting-person-account-credentials + # Needs to be a member of idm_people_admins and idm_high_privilege to prevent idm_service_desk from tampering. + zenware = { + displayName = "zenware"; + legalName = "zenware"; + mailAddresses = [ "zenware@${config.networking.domain} "]; + groups = [ + "idm_high_privilege" + "git.users" + "git.admins" + ]; + }; + # TODO: Make an idm_service_desk account. + }; + groups = { + # This group is `git` because it could be forgejo, gitea, etc. + "git.users" = {}; + "git.admins" = {}; + }; + systems.oauth2 = { + forgejo = { + displayName = "forgejo"; + originUrl = "TODO!SETME"; + originLanding = "TODO!SETME"; + basicSecretFile = "TODO!SETME"; + scopeMaps."git.users" = [ + "openid" + "email" + "profile" + ]; + # WARNING: PKCE is currently not supported by gitea/forgejo, + # see https://github.com/go-gitea/gitea/issues/21376 + allowInsecureClientDisablePkce = true; + preferShortUsername = true; + claimMaps.groups = { + joinType = "array"; + valuesByGroup."git.admins" = [ "admin" ]; + }; + }; + }; + }; + + #enableClient = false; + clientSettings = { + uri = "https://${authDomain}"; + verify_hostnames = true; + verify_ca = true; + }; + }; +} diff --git a/hosts/lithium/services/palworld/default.nix b/hosts/lithium/services/palworld/default.nix index e36823d..29a70f7 100644 --- a/hosts/lithium/services/palworld/default.nix +++ b/hosts/lithium/services/palworld/default.nix @@ -34,13 +34,15 @@ in ''; WorkingDirectory = "/home/palworld"; Restart = "always"; - RuntimeMaxSec = "1d"; + RuntimeMaxSec = "1d"; # NOTE: This thing has memory leaks, restart to save our selves. User = "palworld"; }; }; # NOTE: Config is stashed at the following directory. # /home/palworld/.steam/steam/Steamapps/common/PalServer/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini + # TODO: There are benefits to including the meat of the configuration inside the 'nix' file. + # Namely that it will result in actually updating the config when I rebuild. environment.etc."palworld/PalWorldSettings.ini" = { target = "/home/palworld/.steam/steam/Steamapps/common/PalServer/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini"; text = palworldSettings; diff --git a/hosts/lithium/services/smartd.nix b/hosts/lithium/services/smartd.nix index 40bb159..69999db 100644 --- a/hosts/lithium/services/smartd.nix +++ b/hosts/lithium/services/smartd.nix @@ -1,32 +1,39 @@ -{ }: +{ config, ... }: { services.smartd = { enable = true; devices = [ { - device = "ata-CT500MX500SSD1_2206E607D6AA"; + device = "/dev/disk/by-id/ata-CT500MX500SSD1_2206E607D6AA"; } { - device = "ata-CT500MX500SSD1_2206E607D728"; + device = "/dev/disk/by-id/ata-CT500MX500SSD1_2206E607D728"; } { - device = "ata-ST16000NM001G-2KK103_ZL2B73HT"; + device = "/dev/disk/by-id/ata-ST16000NM001G-2KK103_ZL2B73HT"; } { - device = "ata-ST16000NM001G-2KK103_ZL2PSELL"; + device = "/dev/disk/by-id/ata-ST16000NM001G-2KK103_ZL2PSELL"; } { - device = "ata-ST16000NM001G-2KK103_ZL2B4RSM"; + device = "/dev/disk/by-id/ata-ST16000NM001G-2KK103_ZL2B4RSM"; } { - device = "ata-ST16000NM001G-2KK103_ZL23XYMM"; + device = "/dev/disk/by-id/ata-ST16000NM001G-2KK103_ZL23XYMM"; } { - device = "nvme-Samsung_SSD_960_EVO_500GB_S3X4NB0K244331X"; + device = "/dev/disk/by-id/nvme-Samsung_SSD_960_EVO_500GB_S3X4NB0K244331X"; } { - device = "nvme-Samsung_SSD_960_EVO_500GB_S3X4NB0K244303V"; + device = "/dev/disk/by-id/nvme-Samsung_SSD_960_EVO_500GB_S3X4NB0K244303V"; } ]; }; + + services.prometheus.exporters.smartctl = { + enable = config.services.smartd.enable; + openFirewall = config.services.smartd.enable; + # https://github.com/prometheus-community/smartctl_exporter?tab=readme-ov-file#why-is-root-required-cant-i-add-a-user-to-the-disk-group + user = "root"; + }; } diff --git a/hosts/lithium/services/uptime-kuma.nix b/hosts/lithium/services/uptime-kuma.nix index c9669eb..096beb1 100644 --- a/hosts/lithium/services/uptime-kuma.nix +++ b/hosts/lithium/services/uptime-kuma.nix @@ -13,6 +13,8 @@ in enable = true; # NOTE: NixOS Attributes here resolve into these ENV vars: # https://github.com/louislam/uptime-kuma/wiki/Environment-Variables - # settings = {}; + settings = { + PORT = "4000"; + }; }; } diff --git a/hosts/lithium/sops.nix b/hosts/lithium/sops.nix index 23bee33..ce45efa 100644 --- a/hosts/lithium/sops.nix +++ b/hosts/lithium/sops.nix @@ -1,13 +1,15 @@ -{ inputs, config, ... }: +{ inputs, ... }: let secretsPath = builtins.toString inputs.nixos-secrets; in { - imports = [ - inputs.sops-nix.nixosModules.sops - ]; + #imports = [ inputs.sops-nix.nixosModules.sops ]; sops = { - defaultSopsFile = "${secretsPath}/${config.hostname}/secrets.yaml"; + #defaultSopsFile = "${secretsPath}/${config.hostname}/secrets.yaml"; + #defaultSopsFile = "${secretsPath}/global/secrets.yaml"; + # TODO: Make this test the hostname. + #defaultSopsFile = "${secretsPath}/lithium/secrets/common.yaml"; + defaultSopsFile = "${secretsPath}/lithium/secrets.yaml"; }; } diff --git a/hosts/titanium/default.nix b/hosts/titanium/default.nix index 23d9076..bdc3d2f 100644 --- a/hosts/titanium/default.nix +++ b/hosts/titanium/default.nix @@ -7,11 +7,11 @@ ../../modules/nixos/desktop.nix ../../modules/nixos/gaming.nix inputs.nixos-hardware.nixosModules.asus-rog-strix-x570e - #./hardware.nix + ./hardware.nix ./configuration.nix ./nvidia.nix ./secure-boot.nix - inputs.disko.nixosModules.disko - ./disko.nix + #inputs.disko.nixosModules.disko + #./disko.nix ]; } diff --git a/lib/default.nix b/lib/default.nix index 3926ed9..db5a123 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -33,6 +33,7 @@ in nixpkgs.lib.nixosSystem { inherit system; + specialArgs = { inherit inputs hostname; }; modules = [ hostModule ] ++ userModules ++ extraModules diff --git a/localnotes.md b/localnotes.md new file mode 100644 index 0000000..13756cd --- /dev/null +++ b/localnotes.md @@ -0,0 +1,37 @@ + + +Run disko first, then install. + +```bash +sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko -- --mode disko /path/to/disko.nix +sudo nixos-install --root /mnt --no-root-passwd --flake .#titanium +``` + +need to comment out lanzaboote stuff to get it working... :( +then re-enable it after the system is online again. + + +There is clearly some kind of quirk about boot drives. +We're going to try again, and double-check reading through config this time. + +I've already partitioned the drive(s) with disko, but I don't have a reason not to do it again. + +There is some reason why if I import disko into my nixos config it creates a conflict between the name of the drives. + +```bash +/dev/crypt/mapper +# and a full uuid path +``` + +I figured it out, after you have the disk paths and stuff setup with `disko` you no longer need to maintain them in `hardware-configuration.nix` +Which.. is actually quite nice to be honest. + + + +## Some Ideas to consider + +- https://github.com/Sveske-Juice/declarative-jellyfin +- https://docs.clan.lol +- fido2 luks cryptenroll + - https://discourse.nixos.org/t/using-fido2-luks-with-yubikey-pin/15484 +- https://github.com/nix-community/nixhelm/ diff --git a/localsecrets.yaml b/localsecrets.yaml new file mode 100644 index 0000000..ec09dc6 --- /dev/null +++ b/localsecrets.yaml @@ -0,0 +1,24 @@ +cloudflare_api_token: ENC[AES256_GCM,data:IqZ2LkBUyboO9494G3LPFn8prx48SDFluz6u4KDzQfQxTyqiVkORRQ==,iv:5iSnHMFHOEXDxt5/fSQ/83OzG2iU6LQ9OCnah5Qnj1A=,tag:zBQvE9KvW195mLtwjFKWqQ==,type:str] +cloudflare: + api_token: ENC[AES256_GCM,data:ZkiVQeVFHQ==,iv:402yjlUkamfzgAqMQCChR+ui4nsA625GidVIwCOc8bM=,tag:xErz+vXV8en2c3WdHfqUsg==,type:str] + email: ENC[AES256_GCM,data:AnI4i1ar70FvyLzVqiElJTbZ6V12Tw==,iv:VYoK2Q2XmleP2SV9Axy8JPTrPeLjnJBkhaXVuCWGUtA=,tag:uxB9JQJWUwoIQ1QtpbvT8Q==,type:str] +env: + domain_name: ENC[AES256_GCM,data:sGpnauqZ2LSY+Hf34eA=,iv:V1OOAo9zoEAkXDLL2la6DF+FoCj4Lzqg88dbHHSqcXs=,tag:C+0yaNo/TwAtym7NSxNnyA==,type:str] +yubico: + id: ENC[AES256_GCM,data:n80pw3A=,iv:pS/T3JGbVQkmYJ6EnwcdITe9J8knVBJiEn8njxPzAcM=,tag:gwg5pl6ugfBH4qwpcr1cjA==,type:int] + secret_key: ENC[AES256_GCM,data:kax8+XHJwpqFtRdKpkRR5sFhsKawlT7Ru92Umw==,iv:wSs4wdAkHyacKUmIxGfn8KDv1A8yW6E+0eBuXnOzhMA=,tag:Y6Om1OShD6s3dBALseN/qQ==,type:str] +tailscale: + auth_key: ENC[AES256_GCM,data:lIT80TrYfqMa8k6wsxC5BV6sBg6PCw5+AJaUtMhfJuXTIOz48PZKpCFq5z76TenpGpYT1vdqfCGd8Z1UfA==,iv:5LCWydaBX0ap5VScmjSm/QLtkeYy7u0ImVXoaY8URZs=,tag:dZV4s026eS4ME68ET+JxGw==,type:str] +vrising_server_name: ENC[AES256_GCM,data:guRSn4xsGFJ0,iv:spCO2OuFr2JmFL+qboq2dwrpxb7KufxtscZI8/3r9SQ=,tag:qbFV4IIiFmEQW72So6pm7A==,type:str] +valheim_server_name: ENC[AES256_GCM,data:PJV694YqSnOkBw==,iv:yIjgunzkiVdO1pUuAOtKcRI2zhBSb2sfDfM5WrPsVa8=,tag:I18ugPusdBoADlSxYzIYNw==,type:str] +kanidm: + bind_password: ENC[AES256_GCM,data:l9nP,iv:Qtk6hGj+RnLfsNBRp4QHpCo/Oxq+EdVu62xmClPbPNk=,tag:7PRHrMT5kJdtqV2xXZPzZg==,type:int] +tailscale: + auth_key: ENC[AES256_GCM,data:RFno,iv:wG8XyXMQt/BLjp3jW0j509cDmF/V+UqGAFCjJ3twQ3k=,tag:5z1krKBPDWlZGvHleS4rPA==,type:int] +gitea: + secret_key: ENC[AES256_GCM,data:u5EV,iv:UdQaFFC2Rh0aDbqzHdowhTmxrKbOhWEmGmUEjkOUrg4=,tag:MfB6Jbc3IPc8h4VAd4urEg==,type:int] + internal_token: ENC[AES256_GCM,data:K1tX,iv:MhM1IURTet1e919eI9NpitEdfG8WRB33E4GsCmcSDro=,tag:146dEI1/Bj+w5Ul+Sbt9bw==,type:int] + db_password: ENC[AES256_GCM,data:muy+,iv:e0drAD03om5xAmLOUa4IxTFHQ5U1xeK+fgDOhATnMU8=,tag:JVorF+C4+ENhFZ7/0QSwrQ==,type:int] + oauth_client_secret: ENC[AES256_GCM,data:hVM95DQxfS9Af/z+C5AgjpcoHBs=,iv:pq4lXNYXzFIaNUWhmCV5EwD4icjziCWVqpSuIg1FzZQ=,tag:z/lxukCKwgriNLqqeHDFuQ==,type:str] +jellyfin: + oauth_client_secret: ENC[AES256_GCM,data:IQI6FfOga+3bmf+B+/vpGao=,iv:lC/zbax5mgzQBRNIIbeviWBXtMKSegKFJlHdY+bCSyo=,tag:g0BUqfHZrJB2gJUIjLjnuA==,type:str] diff --git a/modules/nixos/desktop.nix b/modules/nixos/desktop.nix index 7251a84..5e4a3c2 100644 --- a/modules/nixos/desktop.nix +++ b/modules/nixos/desktop.nix @@ -5,7 +5,8 @@ xdg-desktop-portal-gtk xdg-desktop-portal-hyprland xwayland - rofi-wayland + #rofi-wayland + rofi waybar hyprpaper kitty # hyprland default term diff --git a/pkgs/mv7-udev-rules/package.nix b/pkgs/mv7-udev-rules/package.nix new file mode 100644 index 0000000..32e03bb --- /dev/null +++ b/pkgs/mv7-udev-rules/package.nix @@ -0,0 +1,38 @@ +{ + lib, + stdenv, + fetchFromGitHub, +}: + +# Based on: +# https://github.com/NixOS/nixpkgs/blob/nixos-25.05/pkgs/by-name/zs/zsa-udev-rules/package.nix + +stdenv.mkDerivation { + pname = "mv7-udev-rules"; + version = "unstable-2025-06-20"; + + src = fetchFromGitHub { + owner = "zenware"; + repo = "mv7-udev-rules"; + rev = "000000000000000000000000000000000"; + hash = "sha256-0000000000000000000000000"; + }; + + # Only copy udev rules + dontConfigure = true; + dontBuild = true; + dontFixup = true; + + installPhase = '' + mkdir -p $out/lib/udev/rules.d + cp dist/linux64/99-mv7-mic.rules $out/lib/udev/rules.d/ + ''; + + meta = with lib; { + description = "udev rules for MV7 devices"; + license = licenses.mit; + maintainers = with maintainers; [ zenware ]; + platforms = platforms.linux; + homepage = "https://github.com/zenware/mv7-udev-rules"; + }; +} diff --git a/secrets/global.yaml b/secrets/global.yaml new file mode 100644 index 0000000..893df2b --- /dev/null +++ b/secrets/global.yaml @@ -0,0 +1,36 @@ +cloudflare_api_token: ENC[AES256_GCM,data:IqZ2LkBUyboO9494G3LPFn8prx48SDFluz6u4KDzQfQxTyqiVkORRQ==,iv:5iSnHMFHOEXDxt5/fSQ/83OzG2iU6LQ9OCnah5Qnj1A=,tag:zBQvE9KvW195mLtwjFKWqQ==,type:str] +kanidm: + bind_password: ENC[AES256_GCM,data:l9nP,iv:Qtk6hGj+RnLfsNBRp4QHpCo/Oxq+EdVu62xmClPbPNk=,tag:7PRHrMT5kJdtqV2xXZPzZg==,type:int] +tailscale: + auth_key: ENC[AES256_GCM,data:RFno,iv:wG8XyXMQt/BLjp3jW0j509cDmF/V+UqGAFCjJ3twQ3k=,tag:5z1krKBPDWlZGvHleS4rPA==,type:int] +gitea: + secret_key: ENC[AES256_GCM,data:u5EV,iv:UdQaFFC2Rh0aDbqzHdowhTmxrKbOhWEmGmUEjkOUrg4=,tag:MfB6Jbc3IPc8h4VAd4urEg==,type:int] + internal_token: ENC[AES256_GCM,data:K1tX,iv:MhM1IURTet1e919eI9NpitEdfG8WRB33E4GsCmcSDro=,tag:146dEI1/Bj+w5Ul+Sbt9bw==,type:int] + db_password: ENC[AES256_GCM,data:muy+,iv:e0drAD03om5xAmLOUa4IxTFHQ5U1xeK+fgDOhATnMU8=,tag:JVorF+C4+ENhFZ7/0QSwrQ==,type:int] + oauth_client_secret: ENC[AES256_GCM,data:hVM95DQxfS9Af/z+C5AgjpcoHBs=,iv:pq4lXNYXzFIaNUWhmCV5EwD4icjziCWVqpSuIg1FzZQ=,tag:z/lxukCKwgriNLqqeHDFuQ==,type:str] +jellyfin: + oauth_client_secret: ENC[AES256_GCM,data:IQI6FfOga+3bmf+B+/vpGao=,iv:lC/zbax5mgzQBRNIIbeviWBXtMKSegKFJlHdY+bCSyo=,tag:g0BUqfHZrJB2gJUIjLjnuA==,type:str] +sops: + age: + - recipient: age1mv8xtvkuuw3hphq5ytaekz7p8a4kht79uajyhy534uy9e5472fhqj5zpxu + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuOTRKeDNjSEdnQ2ZRNnI3 + dzZJc0xJdFFOUk9tWDJRcHZZSXVUMkpRQUc0CjhGWkNYR1daR2VWT2JOQUFZVlJO + ZGswSU5vaDJLWm5INXp5MlVQYjBCUzQKLS0tIDlrZjN6SGFnNDY4TEN6NjlPN01Y + dGRsTVpBMGVaVytpTm55WEIzNVpHTDQK8p9yexr9L7TwBPu/jKZkdDD2GOt9+nkK + 6tcckBjVx/SUIs7U0qbE6DkzCXIWo2Ce5hsk4RE1p91Y4vocaMPxYA== + -----END AGE ENCRYPTED FILE----- + - recipient: age148yre4vaxp6lm59rft24te46szawqyguf8znkrtpq7ud8tpteauqxkwyjl + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyZUI5VFp5R1Z1SU5XSEtt + QndNajRsR0VyOTUrNjljcnlVRW8vRnVid1hjCmhraVA1anFEdUJoa0lMNm5RcjFE + b1o3bzBpRm83VVhWQy94NXNqSjJSekUKLS0tIGNaQno3RzEyYlNPT0RsNzEzaUd6 + c2tIcEx4VGpIVXZzcEJoUTRGRjdSTjAKk4C6PQiAZpunDmNitkrTBq6PqRe53mZB + ehF6fL7DTveVwWq02csekQdi7hXShkoH7EEMw1LrEe6IP7oJbvZ3jw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-06-04T13:43:02Z" + mac: ENC[AES256_GCM,data:Kd+9kPRgwfdJh9rMADopqJyocPg4M3hnvW8LYxV8jcoOGvuK+rBPu0rQF30ZGUq0i7LG7WiqN+m7nDTrl6KcO4WN4IyTqLJ/lheOLiBTpbUv68VEYPEbTEkvTMrfhsaCNk3AUuUI34cle+k9Q0/QgNenVx7yH77VzR3aiYH/hzA=,iv:s6+V8wTYTE6Q28Kyjb2NlyoGRvUaliaeJAn6htQ1Xwo=,tag:ZkO/mKZ/Dk1jit6qgTxzMA==,type:str] + unencrypted_suffix: _unencrypted + version: 3.10.2 diff --git a/secrets/temp.yaml b/secrets/temp.yaml new file mode 100644 index 0000000..d6bf591 --- /dev/null +++ b/secrets/temp.yaml @@ -0,0 +1,56 @@ +#ENC[AES256_GCM,data:dqhy221XOImoFPMsVz3eFipnQZRxDvoXAWRW4gT/UKqmJrsZp/CgmISo/yx7d3Y+Otk2mZHPmi8=,iv:jPJ3jL7heD721vNnGveNUNdOOwJngCFFbaKHxQxwu1w=,tag:EX/SqAJa9H1KMUnJHvwBbw==,type:comment] +#ENC[AES256_GCM,data:2QAMIK1AD8iEVsBl/tEiWAAjjpMzjvnVpoIa8h60KSCEsU8nycqndOPCLq3BOJGK0a5qITm0,iv:HOJ0tFMEY+99aDXdWjiHLXhpssSEMuMhby/n2W/0HqA=,tag:bEZ+IruPQYNj8rJXn3kbvA==,type:comment] +cloudflare: + api_token: ENC[AES256_GCM,data:ZkiVQeVFHQ==,iv:402yjlUkamfzgAqMQCChR+ui4nsA625GidVIwCOc8bM=,tag:xErz+vXV8en2c3WdHfqUsg==,type:str] + email: ENC[AES256_GCM,data:AnI4i1ar70FvyLzVqiElJTbZ6V12Tw==,iv:VYoK2Q2XmleP2SV9Axy8JPTrPeLjnJBkhaXVuCWGUtA=,tag:uxB9JQJWUwoIQ1QtpbvT8Q==,type:str] +#ENC[AES256_GCM,data:qcSPXWftLd3ojT2kQrqsZFuIzRSk7otMj+DA945UYvrut1O6mjYrzKwf/IyHUmlaDFh7kenPXgGDwm5VU9w=,iv:wRGpS4aeMO9tpF4vHE6sKMt1LA9YcLW8+G7VBWwYMOo=,tag:VEDXurG64aT43pi0lKLN1w==,type:comment] +env: + domain_name: ENC[AES256_GCM,data:sGpnauqZ2LSY+Hf34eA=,iv:V1OOAo9zoEAkXDLL2la6DF+FoCj4Lzqg88dbHHSqcXs=,tag:C+0yaNo/TwAtym7NSxNnyA==,type:str] +#ENC[AES256_GCM,data:IYmlxtKW06u6orlQii4IfB45O88ofznUvuuzYt0=,iv:YdDbHxqG/Nd9CF9l/BBMEO28VYnTiKvkdXxTbMJjRG8=,tag:y0rADtZhmdYZjiax9YvJzg==,type:comment] +yubico: + id: ENC[AES256_GCM,data:n80pw3A=,iv:pS/T3JGbVQkmYJ6EnwcdITe9J8knVBJiEn8njxPzAcM=,tag:gwg5pl6ugfBH4qwpcr1cjA==,type:int] + secret_key: ENC[AES256_GCM,data:kax8+XHJwpqFtRdKpkRR5sFhsKawlT7Ru92Umw==,iv:wSs4wdAkHyacKUmIxGfn8KDv1A8yW6E+0eBuXnOzhMA=,tag:Y6Om1OShD6s3dBALseN/qQ==,type:str] +#ENC[AES256_GCM,data:Zwum1QmpeQUb4PIxdqY=,iv:stOFFRpaR+kHIfADKS/o//K1+oQ+Y9ANNp5LbrbgW9c=,tag:hUdnj2menajZhM7yuRs0aQ==,type:comment] +tailscale: + auth_key: ENC[AES256_GCM,data:lIT80TrYfqMa8k6wsxC5BV6sBg6PCw5+AJaUtMhfJuXTIOz48PZKpCFq5z76TenpGpYT1vdqfCGd8Z1UfA==,iv:5LCWydaBX0ap5VScmjSm/QLtkeYy7u0ImVXoaY8URZs=,tag:dZV4s026eS4ME68ET+JxGw==,type:str] +#ENC[AES256_GCM,data:TBtQO7kI+rfcy2XlpYCIAkviKS0=,iv:JjLLJqDMFmHtrqgIH9xVlJ6gbeFT7g74kFL8nZH+nCk=,tag:rUpKWnstKtqbJbGLk9dQfw==,type:comment] +vrising_server_name: ENC[AES256_GCM,data:guRSn4xsGFJ0,iv:spCO2OuFr2JmFL+qboq2dwrpxb7KufxtscZI8/3r9SQ=,tag:qbFV4IIiFmEQW72So6pm7A==,type:str] +valheim_server_name: ENC[AES256_GCM,data:PJV694YqSnOkBw==,iv:yIjgunzkiVdO1pUuAOtKcRI2zhBSb2sfDfM5WrPsVa8=,tag:I18ugPusdBoADlSxYzIYNw==,type:str] +example_key: ENC[AES256_GCM,data:RPKzGyhQVMt53UIrbg==,iv:WdJEIrcLjqwyaEiXAOGoGihp0tgr3P0j+coQThRSAqM=,tag:efPXuh06+ZEyRAY6M8O6Vg==,type:str] +#ENC[AES256_GCM,data:hwNzDeFecGqtr1gCdxQ2Dg==,iv:fvPKS3tH5i+HdJhGxJz7Bf0nM/DZDqGYFy23/CTQq14=,tag:ieLl2TJuIj0mPzAHlZeWKw==,type:comment] +example_array: + - ENC[AES256_GCM,data:Wh1JeEYh5XIXqxCi/kc=,iv:3MH0nBTXkYWSf2FTSJAelSR0jPHhsp0AEPH3bq1v6WM=,tag:pGs/aD013fzjgX1mzFWSeQ==,type:str] + - ENC[AES256_GCM,data:0mIilx8XdDOg5oRxcrA=,iv:Tm6E3M8hi3HqTxO/vFO3GVlZ8IgUKjAliYbHwh4SEqw=,tag:g9u7zaBENVdcloWpj6jxBg==,type:str] +example_number: ENC[AES256_GCM,data:5M+hN39uq5hn7A==,iv:vxWdPRafSZ4LYKgjDK8hrqwb7mMjLDxf7/mcb9Fe4r8=,tag:YmTtnwCcnX+xVs09XFLQfA==,type:float] +example_booleans: + - ENC[AES256_GCM,data:AtfqPA==,iv:/Hsubc6st3Htaidi634RAndd9Rl2Ldetzm+YfZ2Vu0o=,tag:TqC6nn7cAWffzuWk0e2tCw==,type:bool] + - ENC[AES256_GCM,data:nkbswos=,iv:FBM0yr8MdotAWwxyD6aHhYPjINDeJ5Yu3PRQAg6ey/8=,tag:oCgE9qJHRNLDboO80dOjgw==,type:bool] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1mv8xtvkuuw3hphq5ytaekz7p8a4kht79uajyhy534uy9e5472fhqj5zpxu + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB5cGxrQkpqTGJiaGNtenVG + Y2JhVVpDenhuS050SU9hald0RlRRdGpIK3owCkxSNVAzTVNlbmNGSjNZRVlYb3E3 + RVM0ZUVmNkJDRW1NcFpzcjR3QndTaGcKLS0tIElUSCsyQmF1cW52UnVsQlZVT1E0 + OUNLVk1uNWJNbUNRS1d0Q3FIYXFTZGcKRRK5AO8fQ835zNUDoseBAMPEIxlmAxXT + kv82umpkOyAKQe4opDrxdaJQwoT4nYqdr26ZXCEhajNo1sit9j1z/g== + -----END AGE ENCRYPTED FILE----- + - recipient: age148yre4vaxp6lm59rft24te46szawqyguf8znkrtpq7ud8tpteauqxkwyjl + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBmcUVsQU9MNHExd0QyWlZ2 + eVVFd1h4WXJyb0lERFFFbWlqQzFGUFJMT3lJCk1iNXRlVTJjaVBjNjB2LzRIcUdr + dk01QU1hbXZwSk50SXhyWlY3WTM4SEEKLS0tIE95eDEydkExVkU1RUNkVUh0TnU4 + cGpKVCt3dnVOcTYycDNGeVNFWTQvM28KNbvMhnu/kee2lvEqzTeg7708H+HwxSlD + hR4rWnf/lvA66DIFP7RQN0neouC3mD71irlhAYTWV9h3J9/0z/De1A== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-06-02T20:31:13Z" + mac: ENC[AES256_GCM,data:YaTn5x0jBvM9Yjj53IClYX11zIYZlrp95IbljXX3E5GJApTL4Mkigv1sPJXwq4jJ67JCQL3bdmLMyvWDfuLd1deVtG1LXD4NFYxFaeUXWgBfPs2IW3l/JakU6kliluZRwe5hwhCNIb/+7t9948HLq5MDIaLU2PDeASK/wySOYno=,iv:3D4o66NrUlxFagO80LSyei8BsKyb6dYN75eHs/MhOpw=,tag:3oNBSmZwGkv8MJduv4Sr8w==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.9.2 diff --git a/users/jay/default.nix b/users/jay/default.nix new file mode 100644 index 0000000..d91cd38 --- /dev/null +++ b/users/jay/default.nix @@ -0,0 +1,16 @@ +{ pkgs, lib, ... }: +{ + users.users.jay = { + home = + if pkgs.stdenv.isLinux then + lib.mkDefault "/home/jay" + else if pkgs.stdenv.isDarwin then + lib.mkDefault "/Users/jay" + else + abort "Unsupported OS"; + } // lib.optionalAttrs pkgs.stdenv.isLinux { + isNormalUser = true; + extraGroups = [ "networkmanager" "wheel" ]; + # hashedPassword = ""; + }; +} diff --git a/users/jay/home.nix b/users/jay/home.nix new file mode 100644 index 0000000..2b8f6d0 --- /dev/null +++ b/users/jay/home.nix @@ -0,0 +1,68 @@ +{ pkgs, lib, ... }: +{ + # NOTE: This file contains options that resolve under home-manager.users. + home.stateVersion = "25.05"; + + home.sessionVariables = { + EDITOR = "hx"; + }; + home = { + username = "jay"; + homeDirectory = + if pkgs.stdenv.isLinux then + lib.mkDefault "/home/jay" + else if pkgs.stdenv.isDarwin then + lib.mkDefault "/Users/jay" + else + abort "Unsupported OS"; + }; + home.packages = with pkgs; [ ] + # linux only + # TODO: Add a test for linux + desktop environment + ++ (lib.optionals pkgs.stdenv.isLinux [ + tree + cfspeedtest + ripgrep + helix + nil + ]) + # linux + desktop manager + #++ (lib.optionals (pkgs.stdenv.isLinux && osConfig.services.desktopManager.enabled != null) + #[ + # firefox + #]) + # darwin only + ++ (lib.optionals pkgs.stdenv.isDarwin [ + cfspeedtest + ripgrep + ]); + + programs.fish.enable = true; + # TODO: Get that working again. + #users.users.jml.shell = pkgs.fish; + + programs = { + bat.enable = true; + fzf.enable = true; + jq.enable = true; + btop.enable = true; + }; + + programs.git = { + enable = true; + userName = "Jay Looney"; + userEmail = "jay.m.looney@gmail.com"; + aliases = { + ol = "log --oneline"; + }; + ignores = [ "*~" "*.swp" ]; + extraConfig = { + push.default = "simple"; + credential.helper = "cache --timeout=7200"; + init.defaultBranch = "main"; + log.decorate = "full"; + log.date = "iso"; + merge.conflictStyle = "diff3"; + }; + }; +}