{ config, lib, pkgs, ... }: let cfg = config.my.virtualisation.portainer; in { options.my.virtualisation.portainer = { enable = lib.mkEnableOption "Run Portainer"; version = lib.mkOption { type = lib.types.str; default = "latest"; description = '' Portainer version to use, default is latest ''; }; portainerDataDir = lib.mkOption { type = lib.types.str; default = "/var/lib/portainer"; description = '' Where Portainer will save its data ''; }; enableWatchtower = lib.mkOption { type = lib.types.bool; default = false; description = '' Enable Watchtower to automatically update Portainer ''; }; environmentSecrets = lib.mkOption { type = lib.types.str; default = ""; description = '' Secrets for container in a environment file ''; }; 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 = "portainer"; type = lib.types.str; description = '' The subdomain where Portainer will be reachable ''; }; host = lib.mkOption { default = "localhost"; type = lib.types.str; description = '' host name where the download manager stack is running ''; }; }; }; config = lib.mkMerge [ (lib.mkIf cfg.enable { my.virtualisation.docker.enable = true; virtualisation.oci-containers = { backend = "docker"; # Use Docker as the backend containers = { portainer = { image = "portainer/portainer-ce:latest"; ports = [ "9000:9000" ]; volumes = [ "/var/run/docker.sock:/var/run/docker.sock" "${cfg.portainerDataDir}:/data" # Add persistent volume for Portainer data ]; environmentFiles = [ cfg.environmentSecrets ]; labels = { "com.centurylinklabs.watchtower.enable" = "true"; }; autoStart = true; }; watchtower = lib.mkIf cfg.enableWatchtower { image = "containrrr/watchtower"; volumes = [ "/var/run/docker.sock:/var/run/docker.sock" ]; autoStart = true; environmentFiles = [ cfg.environmentSecrets ]; environment = { "TZ" = "Europe/Rome"; "WATCHTOWER_CLEANUP" = "true"; "WATCHTOWER_SCHEDULE" = "0 0 4 * * *"; # Run every day at 4am "WATCHTOWER_LABEL_ENABLE" = "true"; # Only update labeled containers "WATCHTOWER_NOTIFICATIONS" = "shoutrrr"; # Use shoutrrr for notifications }; }; }; }; # Ensure the directory exists and has the correct permissions systemd.tmpfiles.settings = { "10-portainerDataDir" = { ${cfg.portainerDataDir} = { d = { group = "root"; mode = "0755"; user = "root"; }; }; }; }; networking.firewall.allowedTCPPorts = [ 9000 ]; }) (lib.mkIf cfg.proxy.enable { services.caddy = with cfg.proxy; { virtualHosts."${subdomain}.${domain}".extraConfig = '' reverse_proxy http://${host}:9000 import cloudflare_${domain} ''; }; }) ]; }