{ config, lib, pkgs, ... }: let cfg = config.my.services.ilpost-addict; # Fetch the ilpost-addict source from GitHub ilpostAddict = pkgs.fetchFromGitHub { owner = "stagadet"; repo = "ilpost-addict"; rev = "main"; sha256 = "sha256-kL7tVHXZunqGFztbVx850QQ1U5h5wY1ltIONWXwe7QQ="; }; phpPackage = pkgs.php.withExtensions ({ enabled, all }: enabled ++ [ all.curl all.dom ]); in { options.my.services.ilpost-addict = { enable = lib.mkEnableOption "Enable ilpost-addict podcast feed generator"; dataDir = lib.mkOption { type = lib.types.str; default = "/var/lib/ilpost-addict"; description = "Directory where ilpost-addict stores its data (logs, cookies)"; }; user = lib.mkOption { type = lib.types.str; default = "ilpost-addict"; description = "User which runs the ilpost-addict service"; }; group = lib.mkOption { type = lib.types.str; default = "ilpost-addict"; description = "Group which runs the ilpost-addict service"; }; port = lib.mkOption { type = lib.types.port; default = 8095; description = "Port on which Caddy serves ilpost-addict"; }; poolSettings = lib.mkOption { type = with lib.types; attrsOf (oneOf [ str int bool ]); default = { "pm" = "dynamic"; "pm.max_children" = 8; "pm.start_servers" = 2; "pm.min_spare_servers" = 1; "pm.max_spare_servers" = 4; "pm.max_requests" = 500; }; description = "PHP-FPM pool settings for ilpost-addict"; }; 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 = "ilpost-podcast"; type = lib.types.str; description = "The subdomain where ilpost-addict 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 { users.groups.${cfg.group} = { }; users.users.${cfg.user} = { home = cfg.dataDir; group = cfg.group; description = "ilpost-addict service user"; isSystemUser = true; }; # Add caddy user to ilpost-addict group so it can read the files users.users.${config.services.caddy.user}.extraGroups = [ cfg.group ]; # Create data directories # The PHP script uses relative paths (log/, cookies/) so we create them # in the www directory where the script runs from systemd.tmpfiles.rules = [ "d '${cfg.dataDir}' 0750 ${cfg.user} ${cfg.group} -" "d '${cfg.dataDir}/log' 0750 ${cfg.user} ${cfg.group} -" "d '${cfg.dataDir}/cookies' 0750 ${cfg.user} ${cfg.group} -" ]; # Setup service to copy PHP files systemd.services.ilpost-addict-setup = { wantedBy = [ "multi-user.target" ]; before = [ "phpfpm-ilpost-addict.service" ]; serviceConfig = { Type = "oneshot"; User = cfg.user; Group = cfg.group; }; script = '' # Copy the PHP source to the data directory cp ${ilpostAddict}/src/index.php ${cfg.dataDir}/index.php chmod 644 ${cfg.dataDir}/index.php ''; }; # PHP-FPM pool configuration # The chdir setting ensures the PHP script runs from dataDir # so the relative paths (log/, cookies/) resolve correctly services.phpfpm.pools.ilpost-addict = { user = cfg.user; group = cfg.group; phpPackage = phpPackage; settings = lib.mapAttrs (name: lib.mkDefault) { "listen.owner" = config.services.caddy.user; "listen.group" = config.services.caddy.group; "chdir" = cfg.dataDir; } // cfg.poolSettings; }; # Caddy configuration for serving PHP # Using :port syntax to match any hostname on this port services.caddy = { enable = true; virtualHosts.":${toString cfg.port}".extraConfig = '' root * ${cfg.dataDir} php_fastcgi unix/${config.services.phpfpm.pools.ilpost-addict.socket} file_server encode gzip log { output file ${config.services.caddy.logDir}/ilpost-addict.log } ''; }; networking.firewall.allowedTCPPorts = [ cfg.port ]; }) (lib.mkIf cfg.proxy.enable { services.caddy = with cfg.proxy; { virtualHosts."${subdomain}.${domain}".extraConfig = '' reverse_proxy http://${host}:${toString cfg.port} import cloudflare_${domain} ''; }; }) ]; }