{ config, lib, service_configs, ... }: let fidi = service_configs.firefly_iii_data_importer; in { imports = [ # Same chicanery as services/firefly-iii.nix: the upstream module's # actual systemd units are firefly-iii-data-importer-setup.service and # phpfpm-firefly-iii-data-importer.service. Hook the zfs mount into the # `-setup` unit; the upstream `requiredBy` chain pulls phpfpm forward. (lib.serviceMountWithZpool "firefly-iii-data-importer-setup" service_configs.zpool_ssds [ fidi.dataDir ]) ]; services.firefly-iii-data-importer = { enable = true; dataDir = fidi.dataDir; # Same trick as firefly-iii: run as group caddy so caddy can read the # php-fpm unix socket without us having to override `listen.group`. group = "caddy"; virtualHost = fidi.domain; settings = { APP_ENV = "production"; APP_KEY_FILE = config.age.secrets.firefly-iii-data-importer-app-key.path; LOG_CHANNEL = "syslog"; LOG_LEVEL = "info"; # Importer → Firefly III. The /etc/hosts override below pins this hostname # to 127.0.0.1 on muffin so the importer's outbound HTTPS lands on the # local Caddy without hairpinning through the WAN gateway. The TLS cert # is the same wildcard Caddy serves externally, so verification works. FIREFLY_III_URL = "https://${service_configs.firefly_iii.domain}"; FIREFLY_III_ACCESS_TOKEN_FILE = config.age.secrets.firefly-iii-fidi-token.path; TRUSTED_PROXIES = "127.0.0.1,::1"; # SimpleFIN polls the last 90d every run; without this, every daily run # logs hundreds of "duplicate transaction" warnings as Firefly's server- # side dedup catches them. Firefly still rejects the duplicates; we just # don't see the noise. IGNORE_DUPLICATE_ERRORS = true; # CLI-driven imports only. Leave the /autoimport HTTP endpoint disabled # (default) — the systemd timer below uses `artisan importer:import` # against a static config file, which avoids exposing another web- # reachable surface that needs its own shared secret. CAN_POST_AUTOIMPORT = false; CAN_POST_FILES = false; }; }; # Pin the firefly-iii hostname to loopback on muffin so the importer's # outbound API calls hit local Caddy directly. No effect on any other host. networking.extraHosts = "127.0.0.1 ${service_configs.firefly_iii.domain}"; services.caddy.virtualHosts.${fidi.domain}.extraConfig = '' encode zstd gzip import ${config.age.secrets.caddy_auth.path} root * ${config.services.firefly-iii-data-importer.package}/public php_fastcgi unix/${config.services.phpfpm.pools.firefly-iii-data-importer.socket} file_server ''; # Daily SimpleFIN import via the importer's CLI. The unit is gated by # ConditionPathExists so it silently no-ops until the user has uploaded # `simplefin.json` (per the post-deploy operational steps). systemd.services.firefly-iii-data-importer-import = { description = "Run scheduled Firefly III data importer config (SimpleFIN)"; after = [ "phpfpm-firefly-iii-data-importer.service" "network-online.target" ]; wants = [ "network-online.target" ]; unitConfig.ConditionPathExists = fidi.simplefinConfigPath; serviceConfig = { Type = "oneshot"; User = config.services.firefly-iii-data-importer.user; Group = config.services.firefly-iii-data-importer.group; WorkingDirectory = config.services.firefly-iii-data-importer.package; ExecStart = "${config.services.firefly-iii-data-importer.package}/artisan importer:import ${fidi.simplefinConfigPath}"; # Same hardening posture as the upstream commonServiceConfig. ReadWritePaths = [ fidi.dataDir ]; PrivateTmp = true; PrivateDevices = true; ProtectSystem = "strict"; ProtectHome = "tmpfs"; ProtectKernelTunables = true; ProtectKernelModules = true; ProtectKernelLogs = true; ProtectControlGroups = true; ProtectClock = true; ProtectHostname = true; ProtectProc = "invisible"; ProcSubset = "pid"; RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX"; RestrictNamespaces = true; RestrictRealtime = true; RestrictSUIDSGID = true; LockPersonality = true; NoNewPrivileges = true; RemoveIPC = true; CapabilityBoundingSet = ""; AmbientCapabilities = ""; SystemCallArchitectures = "native"; SystemCallFilter = [ "@system-service @resources" "~@obsolete @privileged" ]; }; }; systemd.timers.firefly-iii-data-importer-import = { description = "Daily Firefly III SimpleFIN import"; wantedBy = [ "timers.target" ]; timerConfig = { OnCalendar = "daily"; RandomizedDelaySec = "1h"; Persistent = true; }; }; }