diff --git a/dockerImages.nix b/dockerImages.nix new file mode 100644 index 0000000..014a620 --- /dev/null +++ b/dockerImages.nix @@ -0,0 +1,18 @@ +{ + freshrss = { + imageName = "docker.io/freshrss/freshrss"; + imageDigest = "sha256:bca4407f1f3ecb2e02bd57f704593c64f89bbf3fad53f03ebcf4baecb0122de6"; # 1.26.1 + sha256 = "699413e5b0637eb007f77cf7615ff6d372eb01dac8b48d213c8fbf766bef3995"; + }; + + authentik-redis = { + imageName = "docker.io/library/redis"; + imageDigest = "sha256:5c30ac9c59d8fcddc368d0dd98f544b8b5ab3a981c633db59da7eff9d76b97cc"; # 7.4.2-alpine + sha256 = "8a4937f259307fa724fb1a9eac9862b5a9bfba555eba2a43e816cd40104e1692"; + }; + authentik-server = { + imageName = "ghcr.io/goauthentik/server"; + imageDigest = "sha256:7464a70c0d84df0816858106116a3306a80359b4300aa656c3a5ab790a38c229"; # 2024.12.3 + sha256 = "fadbb55b7ae1d84d7322538101e933caa021582e5120828040c3883a18b1b3d5"; + }; +} diff --git a/docs/roles/freshrss.md b/docs/roles/freshrss.md index fce1217..c39a943 100644 --- a/docs/roles/freshrss.md +++ b/docs/roles/freshrss.md @@ -1,22 +1,23 @@ # FreshRSS role ## Notes -- Requires the postgres role to be enabled on the same host. -- By default no SSO is configured. +- Requires the postgres and podman roles to be enabled on the same host. +- Requires you to manually follow the installer + - Set database type to postgres + - Set database host to `host.containers.internal` + - Set database username to `freshrss` + - Set database password to the same value as `postgres/freshrss` + - Set database to `freshrss` + - Set username of the default user to the OIDC identity (username) of the desired admin user. + - Set authentication method to HTTP. ## Options ### `freshrss.domain` The domain used by freshrss. -### `freshrss.adminUser` -The administrator user for freshrss. This users password is controlled by the -`freshrss/admin_pass` secret. - ## Secrets -### `freshrss/db_pass` -The password for the freshrss postgres database. This should be the same as -`postgres/freshrss` on the same host. - -### `freshrss/admin_pass` -The password for the administrator user. +## `freshrss/client_id` +Client id for OIDC. Obtainable from the auth provider. +## `freshrss/client_secret` +Client secret for OIDC. Obtainable from the auth provider. diff --git a/flake.nix b/flake.nix index 3699804..7839199 100644 --- a/flake.nix +++ b/flake.nix @@ -16,6 +16,7 @@ lib = nixpkgs.lib; outputs = self.outputs; + dockerImages = import ./dockerImages.nix; homelabConfig = import ./config.nix; utils = import ./utils.nix { inherit inputs homelabConfig; }; @@ -48,6 +49,7 @@ inputs outputs hosts + dockerImages ; }; nodeSpecialArgs = builtins.mapAttrs (_: cfg: { host = cfg; }) hosts; diff --git a/hosts/cloud.nix b/hosts/cloud.nix index 1459dd6..77c7caf 100644 --- a/hosts/cloud.nix +++ b/hosts/cloud.nix @@ -9,12 +9,12 @@ roles = with roles; [ postgres + podman freshrss ]; config = { freshrss.domain = "rss.${hlConfig.domain}"; - freshrss.adminUser = "kalle"; }; stateVersion = "24.05"; } diff --git a/roles/authentik/default.nix b/roles/authentik/default.nix index 7e5323d..e42abb1 100644 --- a/roles/authentik/default.nix +++ b/roles/authentik/default.nix @@ -26,6 +26,7 @@ lib, config, pkgs, + dockerImages, host, ... }: @@ -115,14 +116,14 @@ podman.containers = { # TODO: Does using system redis make sense here? "authentik-redis" = { - imageMetadata = import ./images/redis.nix; + imageMetadata = dockerImages.authentik-redis; autoStart = true; volumes = [ "/appdata/authentik/redis:/data" ]; }; "authentik-server" = { - imageMetadata = import ./images/server.nix; + imageMetadata = dockerImages.authentik-server; autoStart = true; cmd = [ "server" ]; environment = { diff --git a/roles/authentik/images/redis.nix b/roles/authentik/images/redis.nix deleted file mode 100644 index 04fb921..0000000 --- a/roles/authentik/images/redis.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ - imageName = "docker.io/library/redis"; - imageDigest = "sha256:5c30ac9c59d8fcddc368d0dd98f544b8b5ab3a981c633db59da7eff9d76b97cc"; # 7.4.2-alpine - sha256 = "8a4937f259307fa724fb1a9eac9862b5a9bfba555eba2a43e816cd40104e1692"; -} diff --git a/roles/authentik/images/server.nix b/roles/authentik/images/server.nix deleted file mode 100644 index ff4dbc2..0000000 --- a/roles/authentik/images/server.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ - imageName = "ghcr.io/goauthentik/server"; - imageDigest = "sha256:7464a70c0d84df0816858106116a3306a80359b4300aa656c3a5ab790a38c229"; # 2024.12.3 - sha256 = "fadbb55b7ae1d84d7322538101e933caa021582e5120828040c3883a18b1b3d5"; -} diff --git a/roles/freshrss.nix b/roles/freshrss.nix index e9ccb7d..9ff0318 100644 --- a/roles/freshrss.nix +++ b/roles/freshrss.nix @@ -17,12 +17,18 @@ { name = "${hostname}-freshrss"; rule = "Host(`${config.domain}`)"; - target = "http://${host.ip}:80"; + target = "http://${host.ip}:1342"; } ]; nixosModule = - { lib, config, ... }: + { + lib, + config, + pkgs, + dockerImages, + ... + }: { options.freshrss = { domain = lib.mkOption { @@ -35,18 +41,15 @@ config = let - cfg = config.freshrss; - secrets = config.sops.secrets; + appDir = "/cephfs/appdata/freshrss"; + dataDir = "${appDir}/data"; in { networking.firewall.allowedTCPPorts = [ - 80 # Nginx running freshrss + 1342 # Freshrss ]; sops.secrets = { - "freshrss/db_pass" = { - owner = "freshrss"; - }; "freshrss/client_id" = { owner = "freshrss"; }; @@ -63,43 +66,43 @@ ''; }; + # Set up user to run freshrss + users.users."freshrss" = { + isSystemUser = true; + group = "freshrss"; + }; + users.groups."freshrss" = { }; systemd.tmpfiles.rules = [ - "d '${config.services.freshrss.dataDir}/cache' 0750 ${config.services.freshrss.user} ${config.services.freshrss.user} - -" - "d '${config.services.freshrss.dataDir}/users' 0750 ${config.services.freshrss.user} ${config.services.freshrss.user} - -" - "d '${config.services.freshrss.dataDir}/favicons' 0750 ${config.services.freshrss.user} ${config.services.freshrss.user} - -" + "d '${appDir}' 0750 freshrss freshrss - -" + "d '${dataDir}' 0750 freshrss freshrss - -" + "d '${appDir}/extensions' 0750 freshrss freshrss - -" ]; # Create the database postgres.databases = [ "freshrss" ]; - # Only run freshrss after ceph has been mounted - systemd.services.freshrss-config = { - after = [ "cephfs.mount" ]; - }; - systemd.services.nginx = { - after = [ "cephfs.mount" ]; - serviceConfig = { - Environment = [ - "OIDC_ENABLED=1" - "OIDC_PROVIDER_METADATA_URL=https://auth.kallestruik.nl/application/o/freshrss/.well-known/openid-configuration" - "OIDC_X_FORWARDED_HEADERS=\"X-Forwarded-Port X-Forwarded-Proto X-Forwarded-Host\"" - "OIDC_SCOPES=\"openid email profile\"" + podman.containers = { + "freshrss" = { + imageMetadata = dockerImages.freshrss; + autoStart = true; + environment = { + TZ = "Europe/Amsterdam"; + CRON_MIN = "3,33"; + OIDC_ENABLED = "1"; + OIDC_PROVIDER_METADATA_URL = "https://auth.kallestruik.nl/application/o/freshrss/.well-known/openid-configuration"; + OIDC_X_FORWARDED_HEADERS = "X-Forwarded-Port X-Forwarded-Proto X-Forwarded-Host"; + OIDC_SCOPES = "openid email profile"; + }; + environmentFiles = [ + config.sops.templates."freshrss-secret.env".path + ]; + volumes = [ + "${dataDir}:/var/www/FreshRSS/data" + "${appDir}/extensions:/var/www/FreshRSS/extensions" + ]; + ports = [ + "1342:80" ]; - EnvironmentFile = config.sops.templates."freshrss-secret.env".path; - }; - }; - - # Enable and configure the service - services.freshrss = { - enable = true; - baseUrl = "https://${cfg.domain}"; - virtualHost = cfg.domain; - dataDir = "/cephfs/appdata/freshrss"; - authType = "http_auth"; - - database = { - type = "pgsql"; - passFile = secrets."freshrss/db_pass".path; }; }; }; diff --git a/secrets/cloud.yaml b/secrets/cloud.yaml index 988857f..d81421c 100644 --- a/secrets/cloud.yaml +++ b/secrets/cloud.yaml @@ -1,5 +1,4 @@ freshrss: - db_pass: ENC[AES256_GCM,data:6/DOnp9vzUUdibx1FdEMucgXzxsyae7UHwDMC7byaQ8YrQmkGCCDi3Q4ZqE=,iv:LS/IMe97HifOq5uoP5n0++vMLfaiJC6FOQ7tKmR5438=,tag:XLhYQ5N+HbrUOPY6VVB8qA==,type:str] client_id: ENC[AES256_GCM,data:pn/rhQ4AOngFUAk+Ty0Ms0Vrq2/ZwJj6O1dVKBxNloZnW5i6cEQWvQ==,iv:plsNXFQLNyYlb5EIZZM3AmF2BqGbHDftq6X54w5kBhc=,tag:3FZpwjWQ8O2sIfbaGhsl8Q==,type:str] client_secret: ENC[AES256_GCM,data:86taBVM/JdN0cfLC7Yfl5OPuK55jLDedzYyv+iRZTViZSBfUCoQKLqiZOznHXEH07qJCGSJ9QjmaGy6DbtXjZ1OHAX/9egr8yx0GNdtaoDbzNxYEY0hhzxmMJHdVa5qRaiw+yZNLUzXFBXYjRCltKncAk2h2O+PRnjvgWeYqnzQ=,iv:vlkWwBLcxDGZRWyVRpm8DBQ0ZAPRsB6J/0j+Ucg1p9s=,tag:r/lXsVBncl3d+6kS389GoQ==,type:str] postgres: @@ -37,8 +36,8 @@ sops: aWxTNjVPTmZGMUJFK2ZCMTg1eHlEeTAK7EPDDmFXMGSe96L6vv7ZCrebLxITYHQ/ TmMTLj6YN+PsdVv3AgKnOytgJll5/GFsmvR5HnDuHaEqDI71q+8nIQ== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-04-11T21:12:13Z" - mac: ENC[AES256_GCM,data:4UJQIwojeJJ+OP2GQfvQUcYG89YeaxHsIvGy3NyTM7W0EhJXPOMfn3laXaiFARcXcenEvchnAoX3DcfNMWouXkzrlWJkESj9OTXBLYQxr0BR1VrrgLyG6L4fXE/+Nse35v8OT3KfdGP46QC3SGCHCValS26mWClBy49MnUj/vQ4=,iv:jIp9+oaYtfoGtuMIed1L9uNg6ShXspx4G3wTMJvZS/4=,tag:XhztQl7NP9rk57nFKlRGVg==,type:str] + lastmodified: "2025-04-11T22:28:55Z" + mac: ENC[AES256_GCM,data:ke+0iinfPZYw1oPucyLnVqUtCxO+0ft+eTyL/Vr/5ir7DiFR4dIcCxyIqlrZDIFYqUNLVjyqdKFIG40PzB19EC0fAYARCT7ndKX3EfrLIo/+gZtSM8a8ErggxxI7T7tpjofyAqfeFdUvg2DclPWSCWrdTnffXt4L3rEgIy9TWzE=,iv:53zyVCr9yOHVw8d/n0AVUHX257Xz1PNvu8+Ag4/h0m4=,tag:fTS8cYIw9fMPHrOun3S1Pg==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.9.4