{ config, lib, pkgs, ... }: let cfg = config.services.noisepics; in { options.services.noisepics = { enable = lib.mkEnableOption "Noisepics community photo gallery"; domain = lib.mkOption { type = lib.types.str; default = "noisepics.extremist.software"; description = "Domain name for the gallery"; }; port = lib.mkOption { type = lib.types.port; default = 2284; description = "Internal port for Piwigo"; }; dataDir = lib.mkOption { type = lib.types.str; default = "/var/lib/noisepics"; description = "Directory for Piwigo data (local DB, config, cache)"; }; storageDir = lib.mkOption { type = lib.types.str; default = "/mnt/noisepics-storage"; description = "Mount point for Hetzner Storage Box (photos live here)"; }; storagebox = { enable = lib.mkEnableOption "Hetzner Storage Box mount"; address = lib.mkOption { type = lib.types.str; default = ""; description = "Hetzner Storage Box address (e.g. uXXXXXX.your-storagebox.de)"; }; credentialsFile = lib.mkOption { type = lib.types.str; default = ""; description = "Path to a file containing username=... and password=... for the storage box"; }; }; }; config = lib.mkIf cfg.enable { # Piwigo runs via its NixOS service (PHP + nginx/caddy upstream) # Using the OCI container approach since Piwigo isn't packaged in nixpkgs virtualisation.oci-containers.containers.noisepics = { image = "lscr.io/linuxserver/piwigo:latest"; ports = [ "127.0.0.1:${toString cfg.port}:80" ]; volumes = [ "${cfg.dataDir}/config:/config" "${cfg.storageDir}/galleries:/gallery" "/run/mysqld:/run/mysqld" ]; environment = { PUID = "1000"; PGID = "1000"; TZ = "America/Los_Angeles"; }; }; # MariaDB for Piwigo services.mysql = { enable = true; package = pkgs.mariadb; ensureDatabases = [ "piwigo" ]; ensureUsers = [ { name = "piwigo"; ensurePermissions = { "piwigo.*" = "ALL PRIVILEGES"; }; } ]; }; # Caddy virtualhost services.caddy.virtualHosts.${cfg.domain} = { extraConfig = '' rate_limit { zone noisepics_per_ip { key {remote.ip} events 120 window 1m } } reverse_proxy localhost:${toString cfg.port} ''; }; # Data directories systemd.tmpfiles.rules = [ "d ${cfg.dataDir} 0755 1000 1000 -" "d ${cfg.dataDir}/config 0755 1000 1000 -" "d ${cfg.storageDir} 0755 1000 1000 -" "d ${cfg.storageDir}/galleries 0755 1000 1000 -" ]; # Hetzner Storage Box mount fileSystems.${cfg.storageDir} = lib.mkIf cfg.storagebox.enable { device = "//${cfg.storagebox.address}/backup"; fsType = "cifs"; options = [ "credentials=${cfg.storagebox.credentialsFile}" "vers=3.0" "uid=1000" "gid=1000" "iocharset=utf8" "nofail" "_netdev" "x-systemd.automount" "x-systemd.idle-timeout=60" ]; }; }; }