{ config, lib, pkgs, homeyConfig, ... }: # Mealie — recipe manager and meal planner. # # Auth model: LDAP. Users log in with the same uid/password as the rest of # the stack (OpenLDAP). No Authelia forward_auth — Mealie's own login page # handles authentication via django-auth-ldap. # # Volume layout: # /mealie/data/ → /app/data (SQLite DB, images, backups) # # Secrets consumed from sops: # mealie/secret_key let cfg = config.homey.mealie; dataDir = config.homey.storage.mountPoint; domain = homeyConfig.domain; # LDAP base DN derived from domain (zakobar.com → dc=zakobar,dc=com) ldapBaseDn = lib.concatStringsSep "," (map (p: "dc=${p}") (lib.splitString "." domain)); in { options.homey.mealie = { enable = lib.mkEnableOption "Mealie recipe manager"; image = lib.mkOption { type = lib.types.str; default = "ghcr.io/mealie-recipes/mealie:latest"; }; port = lib.mkOption { type = lib.types.port; default = 9093; description = "Host port Mealie listens on (bound to 127.0.0.1)."; }; }; config = lib.mkIf cfg.enable { # ----------------------------------------------------------------------- # Secrets # ----------------------------------------------------------------------- sops.secrets."mealie/secret_key" = { owner = "root"; }; # ----------------------------------------------------------------------- # Container # ----------------------------------------------------------------------- virtualisation.oci-containers.containers.mealie = { image = cfg.image; ports = [ "127.0.0.1:${toString cfg.port}:9000" ]; environment = { BASE_URL = "https://mealie.${domain}"; ALLOW_SIGNUP = "false"; TZ = homeyConfig.timezone; # LDAP auth — users log in with their LDAP uid and password. # Mealie binds directly as the user (no service account needed). LDAP_AUTH_ENABLED = "true"; LDAP_SERVER_URL = "ldap://openldap:389"; LDAP_ENABLE_STARTTLS = "false"; LDAP_BASE_DN = "ou=users,${ldapBaseDn}"; LDAP_BIND_TEMPLATE = "uid={username},ou=users,${ldapBaseDn}"; LDAP_ID_ATTRIBUTE = "uid"; LDAP_NAME_ATTRIBUTE = "cn"; LDAP_MAIL_ATTRIBUTE = "mail"; }; environmentFiles = [ "/run/mealie-secrets.env" ]; volumes = [ "${dataDir}/mealie/data:/app/data" ]; extraOptions = [ "--network=homey" ]; }; # ----------------------------------------------------------------------- # ExecStartPre: write ephemeral secrets env file # ----------------------------------------------------------------------- systemd.services."podman-mealie" = { serviceConfig = { ExecStartPre = [ (pkgs.writeShellScript "mealie-write-secrets" '' set -euo pipefail install -m 600 /dev/null /run/mealie-secrets.env printf '%s\n' \ "SECRET_KEY=$(cat ${config.sops.secrets."mealie/secret_key".path})" \ >> /run/mealie-secrets.env '') ]; }; postStop = "rm -f /run/mealie-secrets.env"; after = lib.mkAfter [ "mnt-data.mount" "podman-openldap.service" "podman-homey-network.service" ]; requires = lib.mkAfter [ "mnt-data.mount" "podman-homey-network.service" ]; }; # ----------------------------------------------------------------------- # Uptime Kuma monitor # ----------------------------------------------------------------------- homey.monitoring.monitors = [{ name = "Mealie"; url = "https://mealie.${domain}"; interval = 60; }]; }; }