diff --git a/hosts/caddy/default.nix b/hosts/caddy/default.nix index 1364fec..f8d035e 100644 --- a/hosts/caddy/default.nix +++ b/hosts/caddy/default.nix @@ -55,6 +55,12 @@ in }; }; + firefly-iii.proxy = { + enable = true; + domain = p.domains.public; + host = p.hosts.firefly-iii; + }; + immich.proxy = { enable = true; domain = p.domains.public; diff --git a/hosts/default.nix b/hosts/default.nix index 070eb7f..3451afa 100644 --- a/hosts/default.nix +++ b/hosts/default.nix @@ -233,6 +233,16 @@ in # specialArgs = { }; }; + firefly-iii = nixpkgs.lib.nixosSystem { + pkgs = pkgs "x86_64-linux"; + modules = [ + myModules + proxmoxModule + ./firefly-iii + agenix.nixosModules.default + ]; + # specialArgs = { }; + }; open-webui = nixpkgs-unstable.lib.nixosSystem { pkgs = pkgs-unstable "x86_64-linux"; @@ -255,4 +265,5 @@ in ]; # specialArgs = { }; }; + } diff --git a/hosts/deployments.nix b/hosts/deployments.nix index a783b05..86b3ab8 100644 --- a/hosts/deployments.nix +++ b/hosts/deployments.nix @@ -34,6 +34,7 @@ in "portainer" "vaultwarden" "immich" + "firefly-iii" "paperless" ]; }; @@ -136,6 +137,15 @@ in ]; }; + firefly-iii.deployment = { + targetHost = hosts.firefly-iii; + tags = [ + "lxc" + "bacco" + "firefly-iii" + ]; + }; + open-webui.deployment = { targetHost = hosts.open-webui; tags = [ diff --git a/hosts/firefly-iii/default.nix b/hosts/firefly-iii/default.nix new file mode 100644 index 0000000..98ed9bb --- /dev/null +++ b/hosts/firefly-iii/default.nix @@ -0,0 +1,41 @@ +{ + config, + pkgs, + lib, + ... +}: +{ + + age.secrets = { + firefly-iii-app-key = { + file = ../../secrets/firefly-iii-app-key.age; + owner = config.services.firefly-iii.user; + group = config.services.firefly-iii.group; + }; + firefly-iii-mailgun-key = { + file = ../../secrets/firefly-iii-mailgun-key.age; + owner = config.services.firefly-iii.user; + group = config.services.firefly-iii.group; + }; + }; + + my = { + utils = { + commons.enable = true; + lxc-standard.enable = true; + }; + + services.firefly-iii = { + enable = true; + accessToken = config.age.secrets.firefly-iii-app-key.path; + mailgun_key = config.age.secrets.firefly-iii-mailgun-key.path; + }; + + virtualisation.proxmox.enable = true; + }; + + # Extra packages + environment.systemPackages = with pkgs; [ ]; + + system.stateVersion = "24.11"; +} diff --git a/hosts/parameters.nix b/hosts/parameters.nix index 00be2e2..af5d758 100644 --- a/hosts/parameters.nix +++ b/hosts/parameters.nix @@ -17,6 +17,7 @@ shadowsocks = "shadowsocks.internal"; librechat = "librechat.internal"; immich = "immich.internal"; + firefly-iii = "firefly-iii.internal"; open-webui = "open-webui.home"; paperless = "paperless.internal"; }; diff --git a/modules/services/default.nix b/modules/services/default.nix index 64567d5..897ac6f 100644 --- a/modules/services/default.nix +++ b/modules/services/default.nix @@ -2,6 +2,7 @@ imports = [ ./authentik.nix ./dashy.nix + ./firefly-iii.nix ./immich.nix ./media-mgr.nix ./nextcloud.nix diff --git a/modules/services/firefly-iii.nix b/modules/services/firefly-iii.nix new file mode 100644 index 0000000..fb88095 --- /dev/null +++ b/modules/services/firefly-iii.nix @@ -0,0 +1,179 @@ +{ + lib, + config, + pkgs, + ... +}: +let + cfg = config.my.services.firefly-iii; + dbName = "firefly-iii"; + appPort = 9080; + dataImpPort = 9081; +in +{ + + options.my.services.firefly-iii = { + enable = lib.mkEnableOption "Enable Firefly-III budgeting app"; + + accessToken = lib.mkOption { + type = lib.types.path; + default = ""; + description = '' + Access token for Firefly-III + ''; + }; + + # age.secrets.firefly-iii-mailgun-key.file = ../../secrets/firefly-iii-mailgun-key.age; + mailgun_key = lib.mkOption { + type = lib.types.path; + default = ""; + description = '' + Mailgun API key for sending emails + ''; + }; + + proxy = { + enable = lib.mkEnableOption "Set the proxy entry for this service"; + + domain = lib.mkOption { + default = "example.com"; + type = lib.types.str; + description = '' + The domain where Caddy is reachable + ''; + }; + + subdomain = lib.mkOption { + default = "money"; + type = lib.types.str; + description = '' + The subdomain where Immich is reachable + ''; + }; + + host = lib.mkOption { + default = "localhost"; + type = lib.types.str; + description = '' + host name where the service is running + ''; + }; + + }; + }; + + config = lib.mkMerge [ + (lib.mkIf cfg.enable { + + my.services.postgresql = { + enable = true; + ensures = [ + { + username = config.services.firefly-iii.user; + database = dbName; + } + ]; + }; + + services.firefly-iii = { + enable = true; + enableNginx = true; + + settings = { + APP_ENV = "production"; + APP_URL = "https://${cfg.proxy.subdomain}.${cfg.proxy.domain}"; + SITE_OWNER = "davide@pasetto.me"; + DEFAULT_LANGUAGE = "en_US"; + TZ = "Europe/Rome"; + TRUSTED_PROXIES = "**"; + SEND_ERROR_MESSAGE = "true"; + SEND_REPORT_JOURNALS = "false"; + # AUTHENTICATION_GUARD = "web"; + AUTHENTICATION_GUARD = "remote_user_guard"; + AUTHENTICATION_GUARD_HEADER = "X-Authentik-Username"; + AUTHENTICATION_GUARD_EMAIL = "X-Authentik-Email"; + + PGSQL_SCHEMA = "public"; + DB_CONNECTION = "pgsql"; + DB_DATABASE = dbName; + DB_USERNAME = config.services.firefly-iii.user; + + MAILGUN_ENDPOINT = "api.eu.mailgun.net"; + MAILGUN_DOMAIN = "pazpi.top"; + MAILGUN_SECRET_FILE = cfg.mailgun_key; + + # Exactly 32 chars + APP_KEY_FILE = cfg.accessToken; + }; + + }; + + services.firefly-iii-data-importer = { + enable = true; + enableNginx = true; + virtualHost = "firefly-iii-data-importer"; + settings = { + FIREFLY_III_ACCESS_TOKEN = cfg.accessToken; + }; + }; + + networking.firewall.allowedTCPPorts = [ + appPort + dataImpPort + ]; + + services.nginx.virtualHosts = { + ${config.services.firefly-iii.virtualHost} = { + listen = [ + { + addr = "0.0.0.0"; + port = appPort; + } + ]; + }; + ${config.services.firefly-iii-data-importer.virtualHost} = { + listen = [ + { + addr = "0.0.0.0"; + port = dataImpPort; + } + ]; + }; + }; + + }) + + (lib.mkIf cfg.proxy.enable { + services.caddy = with cfg.proxy; { + virtualHosts."${subdomain}.${domain}".extraConfig = '' + # directive execution order is only as stated if enclosed with route. + route { + # always forward outpost path to actual outpost + reverse_proxy /outpost.goauthentik.io/* https://auth.pasetto.me { + header_up Host {http.reverse_proxy.upstream.hostport} + } + + # forward authentication to outpost + forward_auth https://auth.pasetto.me { + uri /outpost.goauthentik.io/auth/caddy + + # capitalization of the headers is important, otherwise they will be empty + copy_headers X-Authentik-Username X-Authentik-Email + + # optional, in this config trust all private ranges, should probably be set to the outposts IP + trusted_proxies private_ranges + } + + # Firefly-III + reverse_proxy http://${host}:${toString appPort} + + } + + reverse_proxy http://${host}:${toString appPort} + import cloudflare_${domain} + + ''; + }; + }) + ]; +} diff --git a/secrets.nix b/secrets.nix index 2c8e870..87ba153 100644 --- a/secrets.nix +++ b/secrets.nix @@ -27,6 +27,8 @@ let dns02-admin-password = [ machines.dns02 ]; dns02-dhcp-failover = [ machines.dns02 ]; shadowsocks-password = [ machines.shadowsocks ]; + firefly-iii-app-key = [ machines.firefly-iii ]; + firefly-iii-mailgun-key = [ machines.firefly-iii ]; paperless-admin = [ machines.paperless ]; paperless-oauth2-client-secret = [ machines.paperless ]; }; diff --git a/ssh-keys.nix b/ssh-keys.nix index 02f47a4..3d3e3df 100644 --- a/ssh-keys.nix +++ b/ssh-keys.nix @@ -20,6 +20,7 @@ rec { dns01 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII7BdiP/dCE6FHoJylcBKQ5AXz06UpLHNyeuvfLVccSi"; dns02 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ+HIq6/ebjiv71xDozdOTn5AdnXgr1fGqIzXnH7Not+"; shadowsocks = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINQ4qYaS5ccciH7BNyrF5+J3d4JtHJNr1R256/ulEtxl"; + firefly-iii = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGYkXjRqmuTMg56EmAx8s1M/VQojM7akF/ao+jJLYgFB"; paperless = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILRNgDyk3TuMooG4ZCv7SOgXh0ql1/1hhhng7uSnsLeK"; };