Files
photog/module.nix
T
2026-07-02 00:53:17 +02:00

136 lines
3.9 KiB
Nix

self:
{ config, lib, pkgs, ... }:
let
cfg = config.services.photogallery;
pkg = self.packages.${pkgs.system}.default;
in {
options.services.photogallery = {
enable = lib.mkEnableOption "photogallery static photo gallery";
contentDir = lib.mkOption {
type = lib.types.str;
default = "/var/lib/photogallery/content";
description = "Directory containing images and .toml sidecars.";
};
outputDir = lib.mkOption {
type = lib.types.str;
default = "/var/lib/photogallery/public";
description = "Directory for the generated static site.";
};
baseURL = lib.mkOption {
type = lib.types.str;
example = "https://photos.example.com";
description = "Public base URL, no trailing slash.";
};
port = lib.mkOption {
type = lib.types.port;
default = 8080;
description = "Upload API port. Always bound to 127.0.0.1.";
};
nginx = {
enable = lib.mkEnableOption "nginx virtual host for photogallery";
domain = lib.mkOption {
type = lib.types.str;
example = "photos.example.com";
description = "Domain for the nginx virtual host.";
};
htpasswdFile = lib.mkOption {
type = lib.types.path;
example = "/etc/nginx/.htpasswd-gallery";
description = "Path to htpasswd file protecting the /upload endpoint.";
};
enableACME = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Enable ACME/Let's Encrypt for TLS.";
};
};
};
config = lib.mkIf cfg.enable (lib.mkMerge [
# ── Core service ──────────────────────────────────────────────────────
{
users.users.photogallery = {
isSystemUser = true;
group = "photogallery";
home = "/var/lib/photogallery";
createHome = true;
description = "photogallery service user";
};
users.groups.photogallery = {};
systemd.tmpfiles.rules = [
"d ${cfg.contentDir} 0755 photogallery photogallery -"
"d ${cfg.outputDir} 0755 photogallery photogallery -"
];
systemd.services.photogallery = {
description = "photogallery static site generator";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
User = "photogallery";
Group = "photogallery";
ExecStart = lib.escapeShellArgs [
"${pkg}/bin/photogallery"
"--content" cfg.contentDir
"--output" cfg.outputDir
"--base-url" cfg.baseURL
"--port" (toString cfg.port)
];
Restart = "on-failure";
RestartSec = "5s";
# Hardening
NoNewPrivileges = true;
PrivateTmp = true;
PrivateDevices = true;
ProtectSystem = "strict";
ProtectHome = true;
ReadWritePaths = [ cfg.contentDir cfg.outputDir ];
};
};
}
# ── Optional nginx vhost ──────────────────────────────────────────────
(lib.mkIf cfg.nginx.enable {
services.nginx = {
enable = true;
virtualHosts.${cfg.nginx.domain} = {
enableACME = cfg.nginx.enableACME;
forceSSL = cfg.nginx.enableACME;
root = cfg.outputDir;
locations."/" = {
tryFiles = "$uri $uri/ =404";
};
locations."/upload" = {
proxyPass = "http://127.0.0.1:${toString cfg.port}";
basicAuth = "gallery";
basicAuthFile = cfg.nginx.htpasswdFile;
};
};
};
})
]);
}