{ config, lib, pkgs, homeyConfig, ... }: # Eurovision Vote — Django app for ranking Eurovision performances. # # Uses the NixOS module from the eurovote flake (eurovote.nixosModules.default). # This wrapper wires it into the homey module system: enable flag, sops secret, # and uptime monitoring. # # The app uses DynamicUser + StateDirectory so systemd owns /var/lib/eurovote/; # no tmpfiles.rules entry needed. # # Authentication: Caddy forward_auth → Authelia; the app reads the # X-Remote-User header set by Caddy (from Authelia's Remote-User). # All authenticated users get app access; /admin/* is restricted to # group:admins by Authelia's access_control rules (defined in this file). # # Secrets consumed from sops: # eurovote/secret_key let cfg = config.homey.eurovote; domain = homeyConfig.domain; in { options.homey.eurovote = { enable = lib.mkEnableOption "Eurovision Vote app" // { default = true; }; }; config = lib.mkIf cfg.enable { # ----------------------------------------------------------------------- # Secrets # ----------------------------------------------------------------------- # mode 0444: the service runs as a DynamicUser (random UID) so it cannot # read a root-owned 0400 file. /run/secrets/ itself is not world-listable # (mode 0751), so world-readable here is acceptable on a home server. sops.secrets."eurovote/secret_key" = { owner = "root"; mode = "0444"; }; # ----------------------------------------------------------------------- # Service (options provided by eurovote.nixosModules.default) # ----------------------------------------------------------------------- services.eurovote = { enable = true; port = 8007; allowedHosts = "localhost 127.0.0.1 eurovision-vote.${domain}"; secretKeyFile = config.sops.secrets."eurovote/secret_key".path; trustedOrigins = "https://eurovision-vote.${domain}"; # After SSO logout, send the user back to Authelia's logout page logoutRedirectUrl = "https://auth.${domain}/logout"; }; # ----------------------------------------------------------------------- # Authelia access control — /admin/* requires two_factor + admins group; # all other paths require one_factor. # ----------------------------------------------------------------------- homey.authelia.accessControlRules = [ { priority = 65; domain = [ "eurovision-vote.${domain}" ]; resources = [ "^/admin.*$" ]; subject = [ "group:admins" ]; policy = "two_factor"; } { priority = 66; domain = [ "eurovision-vote.${domain}" ]; resources = [ "^/admin.*$" ]; policy = "deny"; } { priority = 67; domain = [ "eurovision-vote.${domain}" ]; policy = "one_factor"; } ]; # ----------------------------------------------------------------------- # Caddy virtual host — forward_auth; X-Remote-User passed to Django's # RemoteUserMiddleware for automatic SSO login # ----------------------------------------------------------------------- homey.caddy.virtualHosts = [{ subdomain = "eurovision-vote"; port = 8007; auth = true; extraConfig = '' reverse_proxy localhost:8007 { header_up X-Remote-User {http.request.header.Remote-User} } ''; extraHttpConfig = '' reverse_proxy localhost:8007 { header_up X-Forwarded-Proto https header_up X-Remote-User {http.request.header.Remote-User} } ''; }]; # Eurovision Vote uses DynamicUser + /var/lib/eurovote — no extraDirs needed. # ----------------------------------------------------------------------- # Backup — /var/lib/eurovote holds the SQLite DB with votes # ----------------------------------------------------------------------- homey.backup.extraPaths = [ "/var/lib/eurovote" ]; # ----------------------------------------------------------------------- # Uptime Kuma monitor # ----------------------------------------------------------------------- homey.monitoring.monitors = [{ name = "Eurovision Vote"; url = "https://eurovision-vote.${domain}"; interval = 60; }]; }; }