From 032072374b0f390dc21aa51a11bc4e4a33d5a346 Mon Sep 17 00:00:00 2001 From: plasmagoat Date: Thu, 17 Jul 2025 00:35:44 +0200 Subject: [PATCH] moved mail --- flake.lock | 121 ++++++++++++++++++ flake.nix | 6 + hive.nix | 12 +- machines/auth/authelia.nix | 98 ++++++++++---- machines/auth/bootstrap/default.nix | 39 ------ machines/auth/bootstrap/group-configs.nix | 14 +- machines/auth/bootstrap/lldap-bootstrap.nix | 1 + machines/auth/bootstrap/service-accounts.nix | 51 ++++++++ machines/auth/bootstrap/user-configs.nix | 49 ++++--- machines/mail/definition.nix | 19 +++ machines/mail/mailserver.nix | 37 ++++++ machines/modules/journal-log.nix | 4 +- machines/monitor/gatus.nix | 44 ++++++- machines/monitor/grafana.nix | 8 +- machines/monitor/influxdb.nix | 6 +- machines/monitor/prometheus.nix | 8 +- machines/monitor/promtail.nix | 6 +- nixos/README.md | 3 +- nixos/configuration.nix | 45 ++++--- nixos/hosts/dns/dnsmasq.nix | 1 + nixos/hosts/mail/host.nix | 14 -- nixos/hosts/mail/mailserver.nix | 39 ------ nixos/hosts/mail/networking.nix | 8 -- nixos/hosts/mail/sops.nix | 8 -- nixos/hosts/media/nixarr.nix | 8 +- .../traefik/configuration/auth/routers.nix | 15 +-- .../traefik/configuration/auth/services.nix | 2 +- .../traefik/configuration/infra/routers.nix | 4 +- .../configuration/media-center/routers.nix | 46 +++++-- .../configuration/media-center/services.nix | 7 +- .../traefik/configuration/middlewares.nix | 21 +-- .../configuration/monitoring/routers.nix | 6 +- nixos/hosts/traefik/host.nix | 1 - nixos/hosts/traefik/oauth2proxy.nix | 76 ----------- secrets/secrets.yaml | 8 +- 35 files changed, 511 insertions(+), 324 deletions(-) delete mode 100644 machines/auth/bootstrap/default.nix create mode 100644 machines/auth/bootstrap/service-accounts.nix create mode 100644 machines/mail/definition.nix create mode 100644 machines/mail/mailserver.nix delete mode 100644 nixos/hosts/mail/host.nix delete mode 100644 nixos/hosts/mail/mailserver.nix delete mode 100644 nixos/hosts/mail/networking.nix delete mode 100644 nixos/hosts/mail/sops.nix delete mode 100644 nixos/hosts/traefik/oauth2proxy.nix diff --git a/flake.lock b/flake.lock index 662767e..3d6d35c 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,21 @@ { "nodes": { + "blobs": { + "flake": false, + "locked": { + "lastModified": 1604995301, + "narHash": "sha256-wcLzgLec6SGJA8fx1OEN1yV/Py5b+U5iyYpksUY/yLw=", + "owner": "simple-nixos-mailserver", + "repo": "blobs", + "rev": "2cccdf1ca48316f2cfd1c9a0017e8de5a7156265", + "type": "gitlab" + }, + "original": { + "owner": "simple-nixos-mailserver", + "repo": "blobs", + "type": "gitlab" + } + }, "colmena": { "inputs": { "flake-compat": "flake-compat", @@ -38,6 +54,22 @@ "type": "github" } }, + "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1747046372, + "narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-utils": { "locked": { "lastModified": 1659877975, @@ -53,6 +85,54 @@ "type": "github" } }, + "git-hooks": { + "inputs": { + "flake-compat": [ + "simple-nixos-mailserver", + "flake-compat" + ], + "gitignore": "gitignore", + "nixpkgs": [ + "simple-nixos-mailserver", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1750779888, + "narHash": "sha256-wibppH3g/E2lxU43ZQHC5yA/7kIKLGxVEnsnVK1BtRg=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "16ec914f6fb6f599ce988427d9d94efddf25fe6d", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "simple-nixos-mailserver", + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, "nix-github-actions": { "inputs": { "nixpkgs": [ @@ -90,6 +170,22 @@ "type": "github" } }, + "nixpkgs-25_05": { + "locked": { + "lastModified": 1751741127, + "narHash": "sha256-t75Shs76NgxjZSgvvZZ9qOmz5zuBE8buUaYD28BMTxg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "29e290002bfff26af1db6f64d070698019460302", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, "nixpkgs_2": { "locked": { "lastModified": 1752624097, @@ -109,9 +205,34 @@ "inputs": { "colmena": "colmena", "nixpkgs": "nixpkgs_2", + "simple-nixos-mailserver": "simple-nixos-mailserver", "sops-nix": "sops-nix" } }, + "simple-nixos-mailserver": { + "inputs": { + "blobs": "blobs", + "flake-compat": "flake-compat_2", + "git-hooks": "git-hooks", + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-25_05": "nixpkgs-25_05" + }, + "locked": { + "lastModified": 1752060039, + "narHash": "sha256-MqcbN/PgfXOv8S4q6GcmlORd6kJZ3UlFNhzCvLOEe4I=", + "owner": "simple-nixos-mailserver", + "repo": "nixos-mailserver", + "rev": "80d21ed7a1ab8007597f7cd9adc26ebc98b9611f", + "type": "gitlab" + }, + "original": { + "owner": "simple-nixos-mailserver", + "repo": "nixos-mailserver", + "type": "gitlab" + } + }, "sops-nix": { "inputs": { "nixpkgs": [ diff --git a/flake.nix b/flake.nix index 9e03ab2..9f15ca5 100644 --- a/flake.nix +++ b/flake.nix @@ -8,6 +8,11 @@ url = "github:Mic92/sops-nix"; inputs.nixpkgs.follows = "nixpkgs"; }; + + simple-nixos-mailserver = { + url = "gitlab:simple-nixos-mailserver/nixos-mailserver"; + inputs.nixpkgs.follows = "nixpkgs"; + }; # home-manager = { # url = "home-manager"; # inputs.nixpkgs.follows = "nixpkgs"; @@ -22,6 +27,7 @@ sops-nix, # home-manager, colmena, + simple-nixos-mailserver, ... } @ inputs: let overlays = [ diff --git a/hive.nix b/hive.nix index f0b993a..05f8896 100644 --- a/hive.nix +++ b/hive.nix @@ -2,6 +2,7 @@ inputs @ { self, nixpkgs, sops-nix, + simple-nixos-mailserver, # home-manager, overlays, ... @@ -14,11 +15,8 @@ inputs @ { }; defaults = { - pkgs, lib, name, - nodes, - meta, config, ... }: { @@ -50,4 +48,12 @@ inputs @ { imports = [./machines/${name}/definition.nix]; deployment.tags = ["zitadel" "sso" "ldap"]; }; + + mail = {name, ...}: { + imports = [ + ./machines/${name}/definition.nix + simple-nixos-mailserver.nixosModule + ]; + deployment.tags = ["mail"]; + }; } diff --git a/machines/auth/authelia.nix b/machines/auth/authelia.nix index 023fa5c..dc57c96 100644 --- a/machines/auth/authelia.nix +++ b/machines/auth/authelia.nix @@ -14,21 +14,91 @@ in { enable = true; settings = { theme = "auto"; + server = { + buffers = { + read = 16384; + write = 16384; + }; + }; authentication_backend.ldap = { + implementation = "lldap"; address = "ldap://localhost:3890"; base_dn = "dc=procopius,dc=dk"; - users_filter = "(&({username_attribute}={input})(objectClass=person))"; - groups_filter = "(member={dn})"; user = "uid=authelia,ou=people,dc=procopius,dc=dk"; }; + definitions = { + network = { + internal = [ + "192.168.1.0/24" + ]; + }; + }; access_control = { default_policy = "deny"; # We want this rule to be low priority so it doesn't override the others rules = lib.mkAfter [ { - domain = "*.procopius.dk"; + domain = [ + "proxmox.procopius.dk" + "traefik.procopius.dk" + "prometheus.procopius.dk" + "alertmanager.procopius.dk" + ]; + policy = "one_factor"; + subject = [ + ["group:server-admin"] + ]; + } + # bypass /api and /ping + { + domain = ["*.procopius.dk"]; + policy = "bypass"; + resources = [ + "^/api$" + "^/api/" + "^/ping$" + ]; + } + # media + { + domain = [ + "sonarr.procopius.dk" + "radarr.procopius.dk" + "readarr.procopius.dk" + "lidarr.procopius.dk" + "bazarr.procopius.dk" + "prowlarr.procopius.dk" + ]; + policy = "one_factor"; + subject = [ + ["group:media-admin"] + ]; + } + # authenticated + { + domain = [ + "gatus.procopius.dk" + ]; policy = "one_factor"; } + # bypass auth internally + # { + # domain = [ + # "gatus.procopius.dk" + # "prometheus.procopius.dk" + # "alertmanager.procopius.dk" + # "sonarr.procopius.dk" + # "radarr.procopius.dk" + # "readarr.procopius.dk" + # "lidarr.procopius.dk" + # "bazarr.procopius.dk" + # "prowlarr.procopius.dk" + # ]; + # policy = "bypass"; + # networks = [ + # "internal" + # ]; + # } ]; }; storage.postgres = { @@ -58,8 +128,8 @@ in { }; notifier.smtp = { address = "smtp://mail.procopius.dk"; - username = "admin@procopius.dk"; - sender = "auth@procopius.dk"; + username = "authelia@procopius.dk"; + sender = "authelia@procopius.dk"; }; log.level = "info"; # identity_providers.oidc = { @@ -97,24 +167,9 @@ in { environmentVariables = with config.sops; { AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE = secrets."authelia/lldap_authelia_password".path; - AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE = secrets."authelia/smtp_authelia_password".path; + AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE = secrets.smtp-password_authelia.path; }; }; - # caddy = { - # virtualHosts."auth.procopius.cc".extraConfig = '' - # reverse_proxy :9091 - # ''; - # # A Caddy snippet that can be imported to enable Authelia in front of a service - # # Taken from https://www.authelia.com/integration/proxies/caddy/#subdomain - # extraConfig = '' - # (auth) { - # forward_auth :9091 { - # uri /api/authz/forward-auth - # copy_headers Remote-User Remote-Groups Remote-Email Remote-Name - # } - # } - # ''; - # }; }; # Give Authelia access to the Redis socket @@ -142,7 +197,6 @@ in { "authelia/storage_encryption_key".owner = authelia; # The password for the `authelia` LLDAP user "authelia/lldap_authelia_password".owner = authelia; - "authelia/smtp_authelia_password".owner = authelia; smtp-password_authelia = { owner = authelia; key = "service_accounts/authelia/password"; diff --git a/machines/auth/bootstrap/default.nix b/machines/auth/bootstrap/default.nix deleted file mode 100644 index b93965a..0000000 --- a/machines/auth/bootstrap/default.nix +++ /dev/null @@ -1,39 +0,0 @@ -{ - pkgs, - config, - ... -}: { - systemd.services.lldap-bootstrap = { - description = "Bootstraps LLDAP users"; - requires = ["lldap.service"]; - serviceConfig = { - DynamicUser = true; - Type = "oneshot"; - ProtectSystem = "strict"; - ProtectHome = true; - PrivateUsers = true; - PrivateTmp = true; - LoadCredential = "inadyn.conf:${config.sops.templates."inadyn.conf".path}"; - CacheDirectory = "inadyn"; - ExecStart = '' - export LLDAP_URL=http://localhost:8080 - export LLDAP_ADMIN_USERNAME=admin - export LLDAP_ADMIN_PASSWORD=changeme - export USER_CONFIGS_DIR="$(realpath ./configs/user)" - export GROUP_CONFIGS_DIR="$(realpath ./configs/group)" - export USER_SCHEMAS_DIR="$(realpath ./configs/user-schema)" - export GROUP_SCHEMAS_DIR="$(realpath ./configs/group-schema)" - export LLDAP_SET_PASSWORD_PATH="$(realpath ./lldap_set_password)" - export DO_CLEANUP=false - ./bootstrap.sh - - ${pkgs.inadyn}/bin/inadyn \ - --foreground \ - --syslog \ - --once \ - --cache-dir ''${CACHE_DIRECTORY} \ - --config ''${CREDENTIALS_DIRECTORY}/inadyn.conf - ''; - }; - }; -} diff --git a/machines/auth/bootstrap/group-configs.nix b/machines/auth/bootstrap/group-configs.nix index 16d144e..b33bbd0 100644 --- a/machines/auth/bootstrap/group-configs.nix +++ b/machines/auth/bootstrap/group-configs.nix @@ -1,12 +1,24 @@ -{config, ...}: { +{ sops.templates."default-groups.json" = { content = '' + { + "name": "mail" + } { "name": "git-user" } { "name": "git-admin" } + { + "name": "media-user" + } + { + "name": "media-admin" + } + { + "name": "server-admin" + } ''; path = "/bootstrap/group-configs/default-groups.json"; owner = "lldap"; diff --git a/machines/auth/bootstrap/lldap-bootstrap.nix b/machines/auth/bootstrap/lldap-bootstrap.nix index a8cbbfb..e7265b7 100644 --- a/machines/auth/bootstrap/lldap-bootstrap.nix +++ b/machines/auth/bootstrap/lldap-bootstrap.nix @@ -7,6 +7,7 @@ cfg = config.services.lldapBootstrap; in { imports = [ + ./service-accounts.nix ./user-configs.nix ./group-configs.nix ]; diff --git a/machines/auth/bootstrap/service-accounts.nix b/machines/auth/bootstrap/service-accounts.nix new file mode 100644 index 0000000..09a552e --- /dev/null +++ b/machines/auth/bootstrap/service-accounts.nix @@ -0,0 +1,51 @@ +{config, ...}: { + sops.secrets."service_accounts/authelia/password" = {}; + sops.secrets."service_accounts/forgejo/password" = {}; + sops.secrets."service_accounts/jellyfin/password" = {}; + sops.secrets."service_accounts/mail/password" = {}; + sops.templates."service-accounts.json" = { + content = '' + { + "id": "authelia", + "email": "authelia@procopius.dk", + "password": "${config.sops.placeholder."service_accounts/authelia/password"}", + "displayName": "Authelia", + "groups": [ + "lldap_password_manager", + "mail" + ] + } + { + "id": "forgejo", + "email": "forgejo@procopius.dk", + "password": "${config.sops.placeholder."service_accounts/forgejo/password"}", + "displayName": "Forgejo", + "groups": [ + "lldap_password_manager", + "mail" + ] + } + { + "id": "jellyfin", + "email": "jellyfin@procopius.dk", + "password": "${config.sops.placeholder."service_accounts/jellyfin/password"}", + "displayName": "Jellyfin", + "groups": [ + "lldap_password_manager" + ] + } + { + "id": "mail", + "email": "mail@procopius.dk", + "password": "${config.sops.placeholder."service_accounts/mail/password"}", + "displayName": "NixOS Mailserver", + "groups": [ + "lldap_password_manager", + "mail" + ] + } + ''; + path = "/bootstrap/user-configs/service-accounts.json"; + owner = "lldap"; + }; +} diff --git a/machines/auth/bootstrap/user-configs.nix b/machines/auth/bootstrap/user-configs.nix index d5c714e..726ec45 100644 --- a/machines/auth/bootstrap/user-configs.nix +++ b/machines/auth/bootstrap/user-configs.nix @@ -1,28 +1,47 @@ -{config, ...}: { - sops.secrets."service_accounts/authelia/password" = {}; - sops.secrets."service_accounts/forgejo/password" = {}; - sops.templates."service-accounts.json" = { +{ + sops.templates."user-configs.json" = { content = '' { - "id": "authelia", - "email": "authelia@procopius.dk", - "password": "${config.sops.placeholder."service_accounts/authelia/password"}", - "displayName": "Authelia", + "id": "plasmagoat", + "email": "david.mikael@proton.me", + "displayName": "David", "groups": [ - "lldap_password_manager" + "media-user", + "media-admin", + "git-user", + "git-admin", + "server-admin" ] } { - "id": "forgejo", - "email": "forgejo@procopius.dk", - "password": "${config.sops.placeholder."service_accounts/forgejo/password"}", - "displayName": "Forgejo", + "id": "kurisudanoda", + "email": "iluvmizuki@gmail.com", + "displayName": "Noda", "groups": [ - "lldap_password_manager" + "media-user", + "git-user" + ] + } + { + "id": "dannydannydanny", + "email": "powerhouseplayer@gmail.com", + "displayName": "Danny", + "groups": [ + "media-user", + "git-user" + ] + } + { + "id": "stocksking", + "email": "ethanstocks9@gmail.com", + "displayName": "Ethan", + "groups": [ + "media-user", + "git-user" ] } ''; - path = "/bootstrap/user-configs/service-accounts.json"; + path = "/bootstrap/user-configs/user-configs.json"; owner = "lldap"; }; } diff --git a/machines/mail/definition.nix b/machines/mail/definition.nix new file mode 100644 index 0000000..97607b0 --- /dev/null +++ b/machines/mail/definition.nix @@ -0,0 +1,19 @@ +{ + imports = [ + ./mailserver.nix + ]; + + networking = { + interfaces.eth0.ipv4.addresses = [ + { + address = "192.168.1.25"; + prefixLength = 24; + } + ]; + nameservers = ["192.168.1.53"]; + defaultGateway = "192.168.1.1"; + }; + deployment.targetHost = "192.168.1.25"; + + system.stateVersion = "25.05"; +} diff --git a/machines/mail/mailserver.nix b/machines/mail/mailserver.nix new file mode 100644 index 0000000..5b0563a --- /dev/null +++ b/machines/mail/mailserver.nix @@ -0,0 +1,37 @@ +{config, ...}: { + sops.secrets."service_accounts/mail/password" = {}; + mailserver = { + enable = true; + stateVersion = 3; + fqdn = "mail.procopius.dk"; + domains = ["procopius.dk"]; + localDnsResolver = false; + ldap = { + enable = true; + uris = [ + "ldap://auth.lab:3890" + ]; + bind = { + dn = "cn=mail,ou=people,dc=procopius,dc=dk"; + passwordFile = config.sops.secrets."service_accounts/mail/password".path; + }; + postfix = { + filter = "(&(objectClass=person)(memberOf=cn=mail,ou=groups,dc=procopius,dc=dk)(|(mail=%s)(mail-alias=%s)))"; # Will require MR!351 for aliases to work properly + mailAttribute = "mail"; + }; + + dovecot = { + userFilter = "(&(objectClass=person)(memberOf=cn=mail,ou=groups,dc=procopius,dc=dk)(mail=%u))"; + passFilter = "(&(objectClass=person)(memberOf=cn=mail,ou=groups,dc=procopius,dc=dk)(mail=%u))"; + }; + + searchBase = "ou=people,dc=procopius,dc=dk"; + }; + + # Use Let's Encrypt certificates. Note that this needs to set up a stripped + # down nginx and opens port 80. + certificateScheme = "acme-nginx"; + }; + security.acme.acceptTerms = true; + security.acme.defaults.email = "david.mikael@proton.me"; +} diff --git a/machines/modules/journal-log.nix b/machines/modules/journal-log.nix index 260cb73..712feeb 100644 --- a/machines/modules/journal-log.nix +++ b/machines/modules/journal-log.nix @@ -1,7 +1,7 @@ { lib, config, - nodes, + # nodes, # name, # meta, ... @@ -21,7 +21,7 @@ in { }; clientUrl = mkOption { - type = types.string; + type = types.str; default = "http://monitor.lab:3100/loki/api/v1/push"; }; diff --git a/machines/monitor/gatus.nix b/machines/monitor/gatus.nix index c646ecf..b2d2381 100644 --- a/machines/monitor/gatus.nix +++ b/machines/monitor/gatus.nix @@ -18,11 +18,51 @@ } { name = "sonarr"; - url = "https://sonarr.procopius.dk/health"; + url = "https://sonarr.procopius.dk/ping"; interval = "5m"; conditions = [ "[STATUS] == 200" - "[BODY] == Healthy" + "[BODY].status == OK" + "[RESPONSE_TIME] < 300" + ]; + } + { + name = "radarr"; + url = "https://radarr.procopius.dk/ping"; + interval = "5m"; + conditions = [ + "[STATUS] == 200" + "[BODY].status == OK" + "[RESPONSE_TIME] < 300" + ]; + } + { + name = "lidarr"; + url = "https://lidarr.procopius.dk/ping"; + interval = "5m"; + conditions = [ + "[STATUS] == 200" + "[BODY].status == OK" + "[RESPONSE_TIME] < 300" + ]; + } + { + name = "readarr"; + url = "https://readarr.procopius.dk/ping"; + interval = "5m"; + conditions = [ + "[STATUS] == 200" + "[BODY].status == OK" + "[RESPONSE_TIME] < 300" + ]; + } + { + name = "prowlarr"; + url = "https://prowlarr.procopius.dk/ping"; + interval = "5m"; + conditions = [ + "[STATUS] == 200" + "[BODY].status == OK" "[RESPONSE_TIME] < 300" ]; } diff --git a/machines/monitor/grafana.nix b/machines/monitor/grafana.nix index 6fa50df..abf7800 100644 --- a/machines/monitor/grafana.nix +++ b/machines/monitor/grafana.nix @@ -1,10 +1,4 @@ -{ - config, - pkgs, - modulesPath, - lib, - ... -}: { +{config, ...}: { # Add grafana user to the inlfuxdb2 group (for secret) users.users.grafana.extraGroups = ["influxdb2"]; services.grafana.enable = true; diff --git a/machines/monitor/influxdb.nix b/machines/monitor/influxdb.nix index 3f6d584..04e5b7d 100644 --- a/machines/monitor/influxdb.nix +++ b/machines/monitor/influxdb.nix @@ -1,8 +1,4 @@ -{ - config, - pkgs, - ... -}: let +{config, ...}: let influxdbPassword = config.sops.secrets."influxdb/password".path; influxdbToken = config.sops.secrets."influxdb/token".path; in { diff --git a/machines/monitor/prometheus.nix b/machines/monitor/prometheus.nix index d480e6c..2bdb765 100644 --- a/machines/monitor/prometheus.nix +++ b/machines/monitor/prometheus.nix @@ -1,10 +1,4 @@ -{ - config, - pkgs, - modulesPath, - lib, - ... -}: let +{pkgs, ...}: let monitor_hostname = "monitor.lab"; traefik_hostname = "traefik.lab"; sandbox_hostname = "sandbox.lab"; diff --git a/machines/monitor/promtail.nix b/machines/monitor/promtail.nix index 37a5611..78471e2 100644 --- a/machines/monitor/promtail.nix +++ b/machines/monitor/promtail.nix @@ -1,8 +1,4 @@ -{ - config, - pkgs, - ... -}: let +{config, ...}: let promtail_port = 9080; in { networking.firewall.allowedTCPPorts = [promtail_port]; diff --git a/nixos/README.md b/nixos/README.md index 24d74ca..3c98a20 100644 --- a/nixos/README.md +++ b/nixos/README.md @@ -1,4 +1,4 @@ -nixos-rebuild switch --flake .#traefik --target-host root@192.168.1.171 --verbose +nixos-rebuild switch --flake .#traefik --target-host root@traefik.lab --verbose nixos-rebuild switch --flake .#proxmox --target-host root@192.168.1.205 --verbose nixos-rebuild switch --flake .#sandbox --target-host root@sandbox.lab --verbose nixos-rebuild switch --flake .#monitoring --target-host root@monitor.lab --verbose @@ -6,6 +6,7 @@ nixos-rebuild switch --flake .#forgejo --target-host root@forgejo.lab --verbose nixos-rebuild switch --flake .#dns --target-host root@192.168.1.140 --verbose nixos-rebuild switch --flake .#keycloak --target-host root@keycloak.lab --verbose nixos-rebuild switch --flake .#mail --target-host root@mail.lab --verbose +nixos-rebuild switch --flake .#media --target-host root@media.lab --verbose nixos-rebuild switch --flake .#runner01 --target-host root@forgejo-runner-01.lab --verbose diff --git a/nixos/configuration.nix b/nixos/configuration.nix index d629197..8d386d1 100644 --- a/nixos/configuration.nix +++ b/nixos/configuration.nix @@ -1,6 +1,10 @@ -{ config, pkgs, modulesPath, lib, ... }: - { + config, + pkgs, + modulesPath, + lib, + ... +}: { ######################################################################## # IMPORTS & PROFILE # @@ -30,9 +34,8 @@ services.qemuGuest.enable = lib.mkDefault true; # GRUB on the “boot drive” - # Both live and template should install a bootloader on /dev/disk/by-label/nixos. boot.loader.grub.enable = lib.mkDefault true; - boot.loader.grub.devices = [ "nodev" ]; + boot.loader.grub.devices = ["nodev"]; # Grow the root partition on first boot boot.growPartition = lib.mkDefault true; @@ -53,16 +56,16 @@ # Root’s SSH authorized_keys (copy your own keys here) # Both live & template will install these, so you can ssh in. users.users.root.openssh.authorizedKeys.keys = [ - # ← Replace these with your actual public keys - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCeg/n/vst9KME8byhxX2FhA+FZNQ60W38kkNt45eNzK5zFqBYuwo1nDXVanJSh9unRvB13b+ygpZhrb4sHvkETGWiEioc49MiWr8czEhu6Wpo0vv5MAJkiYvGZUYPdUW52jUzWcYdw8PukG2rowrxL5G0CmsqLwHMPU2FyeCe5aByFI/JZb8R80LoEacgjUiipJcoLWUVgG2koMomHClqGu+16kB8nL5Ja3Kc9lgLfDK7L0A5R8JXhCjrlEsmXbxZmwDKuxvjDAZdE9Sl1VZmMDfWkyrRlenrt01eR3t3Fec6ziRm5ZJk9e2Iu1DPoz+PoHH9aZGVwmlvvnr/gMF3OILxcqb0qx+AYlCCnb6D6pJ9zufhZkKcPRS1Q187F6fz+v2oD1xLZWFHJ92+7ItM0WmbDOHOC29s5EA6wNm3iXZCq86OI3n6T34njDtPqh6Z7Pk2sdK4GBwnFj4KwEWXvdKZKSX1qb2EVlEBE9QI4Gf3eg4SiBu2cAFt3nOSzs8c= asol\\dbs@ALPHA-DBS-P14sG2" - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+U3DWOrklcA8n8wdbLBGyli5LsJI3dpL2Zod8mx8eOdC4H127ZT1hzuk2uSmkic4c73BykPyQv8rcqwaRGW94xdMRanKmHYxnbHXo5FBiGrCkNlNNZuahthAGO49c6sUhJMq0eLhYOoFWjtf15sr5Zu7Ug2YTUL3HXB1o9PZ3c9sqYHo2rC/Il1x2j3jNAMKST/qUZYySvdfNJEeQhMbQcdoKJsShcE3oGRL6DFBoV/mjJAJ+wuDhGLDnqi79nQjYfbYja1xKcrKX+D3MfkFxFl6ZIzomR1t75AnZ+09oaWcv1J7ehZ3h9PpDBFNXvzyLwDBMNS+UYcH6SyFjkUbF David@NZXT" - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICUP7m8jZJiclZGfSje8CeBYFhX10SrdtjYziuChmj1X plasmagoat@macbook-air" + # ← Replace these with your actual public keys + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCeg/n/vst9KME8byhxX2FhA+FZNQ60W38kkNt45eNzK5zFqBYuwo1nDXVanJSh9unRvB13b+ygpZhrb4sHvkETGWiEioc49MiWr8czEhu6Wpo0vv5MAJkiYvGZUYPdUW52jUzWcYdw8PukG2rowrxL5G0CmsqLwHMPU2FyeCe5aByFI/JZb8R80LoEacgjUiipJcoLWUVgG2koMomHClqGu+16kB8nL5Ja3Kc9lgLfDK7L0A5R8JXhCjrlEsmXbxZmwDKuxvjDAZdE9Sl1VZmMDfWkyrRlenrt01eR3t3Fec6ziRm5ZJk9e2Iu1DPoz+PoHH9aZGVwmlvvnr/gMF3OILxcqb0qx+AYlCCnb6D6pJ9zufhZkKcPRS1Q187F6fz+v2oD1xLZWFHJ92+7ItM0WmbDOHOC29s5EA6wNm3iXZCq86OI3n6T34njDtPqh6Z7Pk2sdK4GBwnFj4KwEWXvdKZKSX1qb2EVlEBE9QI4Gf3eg4SiBu2cAFt3nOSzs8c= asol\\dbs@ALPHA-DBS-P14sG2" + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+U3DWOrklcA8n8wdbLBGyli5LsJI3dpL2Zod8mx8eOdC4H127ZT1hzuk2uSmkic4c73BykPyQv8rcqwaRGW94xdMRanKmHYxnbHXo5FBiGrCkNlNNZuahthAGO49c6sUhJMq0eLhYOoFWjtf15sr5Zu7Ug2YTUL3HXB1o9PZ3c9sqYHo2rC/Il1x2j3jNAMKST/qUZYySvdfNJEeQhMbQcdoKJsShcE3oGRL6DFBoV/mjJAJ+wuDhGLDnqi79nQjYfbYja1xKcrKX+D3MfkFxFl6ZIzomR1t75AnZ+09oaWcv1J7ehZ3h9PpDBFNXvzyLwDBMNS+UYcH6SyFjkUbF David@NZXT" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICUP7m8jZJiclZGfSje8CeBYFhX10SrdtjYziuChmj1X plasmagoat@macbook-air" ]; # Default filesystem on fileSystems."/" = lib.mkDefault { device = "/dev/disk/by-label/nixos"; - autoResize = true; # grow on first boot + autoResize = true; # grow on first boot fsType = "ext4"; }; @@ -72,23 +75,23 @@ # Default set of packages environment.systemPackages = with pkgs; [ - vim # emergencies - git # pulling flakes, code - curl # downloading things - python3 # for Ansible if needed on live VM + vim # emergencies + git # pulling flakes, code + curl # downloading things + python3 # for Ansible if needed on live VM ]; # Nix settings (cache, experimental, gc) - nix.settings.trusted-users = [ "root" "@wheel" ]; - nix.settings.experimental-features = [ "nix-command" "flakes" ]; + nix.settings.trusted-users = ["root" "@wheel"]; + nix.settings.experimental-features = ["nix-command" "flakes"]; nix.extraOptions = '' - experimental-features = nix-command flakes - keep-outputs = true - keep-derivations = true + experimental-features = nix-command flakes + keep-outputs = true + keep-derivations = true ''; nix.gc.automatic = true; - nix.gc.dates = "weekly"; - nix.gc.options = "--delete-older-than 7d"; + nix.gc.dates = "weekly"; + nix.gc.options = "--delete-older-than 7d"; # mDNS with avahi to enable .local dns services.avahi = { @@ -104,7 +107,7 @@ ipv6 = false; }; - networking.firewall.allowedUDPPorts = [ 5353 ]; + networking.firewall.allowedUDPPorts = [5353]; # State version (set to match the Nixpkgs you’re using) system.stateVersion = lib.mkDefault "25.05"; diff --git a/nixos/hosts/dns/dnsmasq.nix b/nixos/hosts/dns/dnsmasq.nix index 5cecdf1..9adfe80 100644 --- a/nixos/hosts/dns/dnsmasq.nix +++ b/nixos/hosts/dns/dnsmasq.nix @@ -30,6 +30,7 @@ # Static IPs "/dns.lab/192.168.1.53" "/traefik.lab/192.168.1.80" + "/mail.lab/192.168.1.25" # "/proxmox-01.lab/192.168.1.205" # "/nas-01.lab/192.168.1.226" diff --git a/nixos/hosts/mail/host.nix b/nixos/hosts/mail/host.nix deleted file mode 100644 index 8793fa3..0000000 --- a/nixos/hosts/mail/host.nix +++ /dev/null @@ -1,14 +0,0 @@ -{ - config, - pkgs, - modulesPath, - lib, - ... -}: { - imports = [ - ../../templates/base.nix - ./networking.nix - ./sops.nix - ./mailserver.nix - ]; -} diff --git a/nixos/hosts/mail/mailserver.nix b/nixos/hosts/mail/mailserver.nix deleted file mode 100644 index 348ea96..0000000 --- a/nixos/hosts/mail/mailserver.nix +++ /dev/null @@ -1,39 +0,0 @@ -{ - config, - pkgs, - ... -}: { - imports = [ - (builtins.fetchTarball { - # Pick a release version you are interested in and set its hash, e.g. - url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/nixos-25.05/nixos-mailserver-nixos-25.05.tar.gz"; - # To get the sha256 of the nixos-mailserver tarball, we can use the nix-prefetch-url command: - # release="nixos-25.05"; nix-prefetch-url "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/${release}/nixos-mailserver-${release}.tar.gz" --unpack - sha256 = "0jpp086m839dz6xh6kw5r8iq0cm4nd691zixzy6z11c4z2vf8v85"; - }) - ]; - - mailserver = { - enable = true; - fqdn = "mail.procopius.dk"; - domains = ["procopius.dk"]; - - # A list of all login accounts. To create the password hashes, use - # nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt' - loginAccounts = { - "admin@procopius.dk" = { - hashedPasswordFile = config.sops.secrets.mailserver-admin-pass.path; - aliases = [ - "@procopius.dk" - "postmaster@procopius.dk" - ]; - }; - }; - - # Use Let's Encrypt certificates. Note that this needs to set up a stripped - # down nginx and opens port 80. - certificateScheme = "acme-nginx"; - }; - security.acme.acceptTerms = true; - security.acme.defaults.email = "david.mikael@proton.me"; -} diff --git a/nixos/hosts/mail/networking.nix b/nixos/hosts/mail/networking.nix deleted file mode 100644 index 06a895c..0000000 --- a/nixos/hosts/mail/networking.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: { - networking.hostName = "mail"; -} diff --git a/nixos/hosts/mail/sops.nix b/nixos/hosts/mail/sops.nix deleted file mode 100644 index b532a76..0000000 --- a/nixos/hosts/mail/sops.nix +++ /dev/null @@ -1,8 +0,0 @@ -{...}: let - mailserverSops = ../../secrets/mailserver/secrets.yml; -in { - sops.secrets.mailserver-admin-pass = { - sopsFile = mailserverSops; - mode = "0440"; - }; -} diff --git a/nixos/hosts/media/nixarr.nix b/nixos/hosts/media/nixarr.nix index 715dc8f..9e54790 100644 --- a/nixos/hosts/media/nixarr.nix +++ b/nixos/hosts/media/nixarr.nix @@ -1,7 +1,9 @@ {config, ...}: { - services.sonarr.settings = { - auth.method = "External"; - }; + services.sonarr.settings.auth.method = "External"; + services.radarr.settings.auth.method = "External"; + services.lidarr.settings.auth.method = "External"; + services.readarr.settings.auth.method = "External"; + services.prowlarr.settings.auth.method = "External"; nixarr = { enable = true; diff --git a/nixos/hosts/traefik/configuration/auth/routers.nix b/nixos/hosts/traefik/configuration/auth/routers.nix index 5ed6407..4b8f879 100644 --- a/nixos/hosts/traefik/configuration/auth/routers.nix +++ b/nixos/hosts/traefik/configuration/auth/routers.nix @@ -13,19 +13,10 @@ tls.certResolver = "letsencrypt"; }; - oauth2proxy = { - rule = "Host(`radarr.procopius.dk`) && PathPrefix(`/oauth2/`)"; - service = "oauth2proxy"; + lldap = { + rule = "Host(`lldap.procopius.dk`)"; + service = "lldap"; entryPoints = ["websecure"]; - middlewares = ["auth-headers"]; - tls.certResolver = "letsencrypt"; - }; - - oauth2route = { - rule = "Host(`oauth.procopius.dk`)"; - service = "oauth2proxy"; - entryPoints = ["websecure"]; - middlewares = ["auth-headers"]; tls.certResolver = "letsencrypt"; }; } diff --git a/nixos/hosts/traefik/configuration/auth/services.nix b/nixos/hosts/traefik/configuration/auth/services.nix index 52a40a8..d5e0efc 100644 --- a/nixos/hosts/traefik/configuration/auth/services.nix +++ b/nixos/hosts/traefik/configuration/auth/services.nix @@ -1,6 +1,6 @@ { keycloak.loadBalancer.servers = [{url = "http://keycloak.lab:8080";}]; - oauth2proxy.loadBalancer.servers = [{url = "http://localhost:4180";}]; authelia.loadBalancer.servers = [{url = "http://auth.lab:9091";}]; + lldap.loadBalancer.servers = [{url = "http://auth.lab:17170";}]; } diff --git a/nixos/hosts/traefik/configuration/infra/routers.nix b/nixos/hosts/traefik/configuration/infra/routers.nix index 5667d22..67ed719 100644 --- a/nixos/hosts/traefik/configuration/infra/routers.nix +++ b/nixos/hosts/traefik/configuration/infra/routers.nix @@ -3,7 +3,7 @@ rule = "Host(`traefik.procopius.dk`)"; service = "traefik"; entryPoints = ["websecure"]; - middlewares = ["oauth-auth"]; + middlewares = ["authelia"]; tls.certResolver = "letsencrypt"; }; @@ -25,7 +25,7 @@ rule = "Host(`proxmox.procopius.dk`)"; service = "proxmox"; entryPoints = ["websecure"]; - middlewares = ["oauth-auth"]; + middlewares = ["authelia"]; tls.certResolver = "letsencrypt"; }; nas = { diff --git a/nixos/hosts/traefik/configuration/media-center/routers.nix b/nixos/hosts/traefik/configuration/media-center/routers.nix index b30e50e..95eec8a 100644 --- a/nixos/hosts/traefik/configuration/media-center/routers.nix +++ b/nixos/hosts/traefik/configuration/media-center/routers.nix @@ -6,14 +6,18 @@ tls.certResolver = "letsencrypt"; }; + jellyseerr = { + rule = "Host(`jellyseerr.procopius.dk`)"; + service = "jellyseerr"; + entryPoints = ["websecure"]; + tls.certResolver = "letsencrypt"; + }; + radarr = { rule = "Host(`radarr.procopius.dk`)"; service = "radarr"; entryPoints = ["websecure"]; - middlewares = [ - "oauth-auth" - "restrict-admin" - ]; + middlewares = ["authelia"]; tls.certResolver = "letsencrypt"; }; @@ -21,15 +25,39 @@ rule = "Host(`sonarr.procopius.dk`)"; service = "sonarr"; entryPoints = ["websecure"]; - middlewares = ["oauth-auth"]; + middlewares = ["authelia"]; tls.certResolver = "letsencrypt"; }; - jellyseerr = { - rule = "Host(`jellyseerr.procopius.dk`)"; - service = "jellyseerr"; + prowlarr = { + rule = "Host(`prowlarr.procopius.dk`)"; + service = "prowlarr"; entryPoints = ["websecure"]; - # middlewares = ["oauth-auth"]; + middlewares = ["authelia"]; + tls.certResolver = "letsencrypt"; + }; + + bazarr = { + rule = "Host(`bazarr.procopius.dk`)"; + service = "bazarr"; + entryPoints = ["websecure"]; + middlewares = ["authelia"]; + tls.certResolver = "letsencrypt"; + }; + + lidarr = { + rule = "Host(`lidarr.procopius.dk`)"; + service = "lidarr"; + entryPoints = ["websecure"]; + middlewares = ["authelia"]; + tls.certResolver = "letsencrypt"; + }; + + readarr = { + rule = "Host(`readarr.procopius.dk`)"; + service = "readarr"; + entryPoints = ["websecure"]; + middlewares = ["authelia"]; tls.certResolver = "letsencrypt"; }; } diff --git a/nixos/hosts/traefik/configuration/media-center/services.nix b/nixos/hosts/traefik/configuration/media-center/services.nix index 2fa3a71..136b502 100644 --- a/nixos/hosts/traefik/configuration/media-center/services.nix +++ b/nixos/hosts/traefik/configuration/media-center/services.nix @@ -1,6 +1,11 @@ { jellyfin.loadBalancer.servers = [{url = "http://media.lab:8096";}]; + jellyseerr.loadBalancer.servers = [{url = "http://media.lab:5055";}]; + radarr.loadBalancer.servers = [{url = "http://media.lab:7878";}]; sonarr.loadBalancer.servers = [{url = "http://media.lab:8989";}]; - jellyseerr.loadBalancer.servers = [{url = "http://media.lab:5055";}]; + readarr.loadBalancer.servers = [{url = "http://media.lab:8787";}]; + lidarr.loadBalancer.servers = [{url = "http://media.lab:8686";}]; + bazarr.loadBalancer.servers = [{url = "http://media.lab:6767";}]; + prowlarr.loadBalancer.servers = [{url = "http://media.lab:9696";}]; } diff --git a/nixos/hosts/traefik/configuration/middlewares.nix b/nixos/hosts/traefik/configuration/middlewares.nix index 42bba66..d8c81c7 100644 --- a/nixos/hosts/traefik/configuration/middlewares.nix +++ b/nixos/hosts/traefik/configuration/middlewares.nix @@ -19,25 +19,16 @@ in { }; }; - oauth-auth = { + authelia = { forwardAuth = { - address = "http://localhost:4180/"; + address = "http://auth.lab:9091/api/authz/forward-auth"; trustForwardHeader = true; authResponseHeaders = [ - "Authorization" - "X-Auth-Request-Access-Token" - "X-Auth-Request-User" - "X-Auth-Request-Email" - "X-Auth-Request-Preferred-Username" # Recommended - "X-Auth-Request-Access-Token" # If you want to pass the token - "X-Auth-Request-Groups" # If you configured a mapper in Keycloak to emit groups + "Remote-User" + "Remote-Groups" + "Remote-Email" + "Remote-Name" ]; }; }; - - restrict-admin = { - forwardAuth = { - address = "http://localhost:4180/oauth2/auth?allowed_groups=role:admin"; - }; - }; } diff --git a/nixos/hosts/traefik/configuration/monitoring/routers.nix b/nixos/hosts/traefik/configuration/monitoring/routers.nix index 8f30959..1cb88c7 100644 --- a/nixos/hosts/traefik/configuration/monitoring/routers.nix +++ b/nixos/hosts/traefik/configuration/monitoring/routers.nix @@ -3,7 +3,7 @@ rule = "Host(`prometheus.procopius.dk`)"; service = "prometheus"; entryPoints = ["websecure"]; - middlewares = ["oauth-auth"]; + middlewares = ["authelia"]; tls.certResolver = "letsencrypt"; }; grafana = { @@ -16,14 +16,14 @@ rule = "Host(`alertmanager.procopius.dk`)"; service = "alertmanager"; entryPoints = ["websecure"]; - middlewares = ["oauth-auth"]; + middlewares = ["authelia"]; tls.certResolver = "letsencrypt"; }; gatus = { rule = "Host(`gatus.procopius.dk`)"; service = "gatus"; entryPoints = ["websecure"]; - middlewares = ["oauth-auth"]; + middlewares = ["authelia"]; tls.certResolver = "letsencrypt"; }; umami = { diff --git a/nixos/hosts/traefik/host.nix b/nixos/hosts/traefik/host.nix index 4570d3c..2af4433 100644 --- a/nixos/hosts/traefik/host.nix +++ b/nixos/hosts/traefik/host.nix @@ -11,6 +11,5 @@ ./traefik.nix ./promtail.nix ./sops.nix - ./oauth2proxy.nix ]; } diff --git a/nixos/hosts/traefik/oauth2proxy.nix b/nixos/hosts/traefik/oauth2proxy.nix deleted file mode 100644 index 2250877..0000000 --- a/nixos/hosts/traefik/oauth2proxy.nix +++ /dev/null @@ -1,76 +0,0 @@ -# /etc/nixos/configuration.nix -{ - config, - lib, - pkgs, - ... -}: let - oauth2ProxyKeyFile = config.sops.secrets."oauth2-proxy-env".path; -in { - services.oauth2-proxy = { - enable = true; - package = pkgs.oauth2-proxy; - - keyFile = oauth2ProxyKeyFile; - - provider = "keycloak-oidc"; # Use "oidc" for standard OIDC providers like Keycloak - oidcIssuerUrl = "https://keycloak.procopius.dk/realms/homelab"; - clientID = "oauth2-proxy"; # Matches the client ID in Keycloak - - # Public URL for oauth2-proxy itself, where Keycloak redirects back to - redirectURL = "https://oauth.procopius.dk/oauth2/callback"; - upstream = ["static://202"]; - extraConfig = { - code-challenge-method = "S256"; - # email-domain = "*"; - auth-logging = true; - request-logging = true; - whitelist-domain = ".procopius.dk"; - pass-host-header = true; - skip-provider-button = true; - }; - - # Cookie configuration - cookie = { - name = "_oauth2_proxy_homelab"; - domain = ".procopius.dk"; - secure = true; - httpOnly = true; - expire = "24h"; - refresh = "1h"; - }; - - # Listen address for oauth2-proxy internally. Traefik will forward to this. - httpAddress = "http://127.0.0.1:4180"; # Ensure this port is not blocked by your firewall internally - - # Reverse proxy settings for headers - reverseProxy = true; # Set to true because it's behind Traefik - - # Headers to set for the upstream applications after successful authentication - setXauthrequest = true; # Set X-Auth-Request-User, X-Auth-Request-Email etc. - passBasicAuth = true; # Pass HTTP Basic Auth headers - passHostHeader = true; # Pass the original Host header to the upstream - - # Authorization rules for who can access - # You can restrict by email domain (allows everyone from that domain) - email.domains = ["*"]; # Allows any authenticated user from Keycloak - # Or restrict by specific email addresses (if you want tighter control): - # email.addresses = allowedOauth2ProxyEmails; - - # Logging - requestLogging = true; - - # Optional: If you use specific scopes for Keycloak (e.g., if you want groups claim) - # scope = "openid profile email"; - # If you specifically added a 'groups' claim in Keycloak: - scope = "openid profile email"; - - # You can add extra command-line flags here if needed, e.g., for debug logging - # extraConfig = { - # - # }; - }; - - # Expose the internal port for oauth2-proxy if needed for debugging or direct access (less common) - networking.firewall.allowedTCPPorts = [4180]; -} diff --git a/secrets/secrets.yaml b/secrets/secrets.yaml index 3919e1e..6a8d487 100644 --- a/secrets/secrets.yaml +++ b/secrets/secrets.yaml @@ -21,6 +21,10 @@ service_accounts: password: ENC[AES256_GCM,data:r4Qy09FOhUgD48SHSkWKtrlrMptvXYdScCL8h7gjJNs=,iv:IzsDdV4o35hnS/F2S713cJ5pQ+PGiaVTmTWe6YXgfYc=,tag:OisvmY7QI2Ph7R3g3Xy/Ww==,type:str] forgejo: password: ENC[AES256_GCM,data:HLEoGjx++9fkiJQoLWQvAjgg58mIs1vk1hvUJvr6TiA=,iv:mPIx9cSlHEK+0wLs1/1bjYcsxgdwgLReUoI5JrA4E1k=,tag:TdyznTIGiAFFq8D3Irb0rA==,type:str] + jellyfin: + password: ENC[AES256_GCM,data:PpUHEhNfnR1eg7DmnO7tyNciNE4Tsx/Y4uL92gqiods=,iv:DNKQfymvgEu/iEW8t79m0ZmKTU0Ffasu+gp2KOIAK3o=,tag:lGKw5dbXqImDJNVX6p8kLg==,type:str] + mail: + password: ENC[AES256_GCM,data:6lfziq1zXlFxCAFWv5co3MkBgwaWixjHHX9riQXCbe0=,iv:/t4CnW3bKUDxfpE/qGf1LPs0ciivRMkfgJ1nMseruy4=,tag:TWApzLsm2HV+JMaZLG/Kig==,type:str] sops: age: - recipient: age1n20y9kmdh324m3tkclvhmyuc7c8hk4w84zsal725adahwl8nzq0s04aq4y @@ -32,7 +36,7 @@ sops: QzNYRk5ERmR4aGtLQ3dwQ1lPeDZyaEkKJMLXqv6tBBql7VVnWDIwAh24SfQ2O6Ca CEOQTGEonbqr5doWqTsXUXrdQAS0amL45UdT6ITFtfNAjaHwCMfhZg== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-07-16T00:07:58Z" - mac: ENC[AES256_GCM,data:kKSjCmLGbr7WaLb+Z1KZL/bjBszNgCCAb67CENaKKpFbqbCk3o5QFok/kVTs3k3JwKmODqbTe0ebP6uMENN/t85+1n4ofnMq5ire/NqCyoE1EJFDmG9xyys24CB+NJJZ2trdxm5CYutme7FfG4bQY0/2OgflmjiZeBsMZcxRxtI=,iv:md6qX+WlFFgMFbDs8MTTKXEOPWKFoVYAUMehWvGF5wk=,tag:Y3AelrfrsBMIJ0wYzFYtLQ==,type:str] + lastmodified: "2025-07-16T15:33:06Z" + mac: ENC[AES256_GCM,data:nZm7N8qfANzHadtW+3eTJljpmYejJdKGFO44iw40CnwlGgb454us9LZbQIAYkNiS7UkivoWa5BqvgLcpObHNAn3tVi+ha0jySIrAmp43y5ilmg76fvL4znel4Nk7eRiGoF3t3xiCR39/3l7PPffx2RJ6PerEyGBpiUZ6mBcWoTE=,iv:UmhSynpMdTnY0R6jwDJts13b0rKsaRFlCizdM2oargE=,tag:Q2xh/QXFOQYqqkxKs7nujA==,type:str] unencrypted_suffix: _unencrypted version: 3.10.2