grafana-alloy: don't build the frontend twice
[NixPkgs.git] / nixos / modules / services / web-apps / photoprism.nix
blobec4126b420cd5e6132a0fb4ef451ca6aa10dd5ea
1 { config, pkgs, lib, ... }:
2 let
3   cfg = config.services.photoprism;
5   env = {
6     PHOTOPRISM_ORIGINALS_PATH = cfg.originalsPath;
7     PHOTOPRISM_STORAGE_PATH = cfg.storagePath;
8     PHOTOPRISM_IMPORT_PATH = cfg.importPath;
9     PHOTOPRISM_HTTP_HOST = cfg.address;
10     PHOTOPRISM_HTTP_PORT = toString cfg.port;
11   } // (
12     lib.mapAttrs (_: toString) cfg.settings
13   );
15   manage = pkgs.writeShellScript "manage" ''
16     set -o allexport # Export the following env vars
17     ${lib.toShellVars env}
18     eval "$(${config.systemd.package}/bin/systemctl show -pUID,MainPID photoprism.service | ${pkgs.gnused}/bin/sed "s/UID/ServiceUID/")"
19     exec ${pkgs.util-linux}/bin/nsenter \
20       -t $MainPID -m -S $ServiceUID -G $ServiceUID --wdns=${cfg.storagePath} \
21       ${cfg.package}/bin/photoprism "$@"
22   '';
25   meta.maintainers = with lib.maintainers; [ stunkymonkey ];
27   options.services.photoprism = {
29     enable = lib.mkEnableOption "Photoprism web server";
31     passwordFile = lib.mkOption {
32       type = lib.types.nullOr lib.types.path;
33       default = null;
34       description = ''
35         Admin password file.
36       '';
37     };
39     address = lib.mkOption {
40       type = lib.types.str;
41       default = "localhost";
42       description = ''
43         Web interface address.
44       '';
45     };
47     port = lib.mkOption {
48       type = lib.types.port;
49       default = 2342;
50       description = ''
51         Web interface port.
52       '';
53     };
55     originalsPath = lib.mkOption {
56       type = lib.types.path;
57       default = null;
58       example = "/data/photos";
59       description = ''
60         Storage path of your original media files (photos and videos).
61       '';
62     };
64     importPath = lib.mkOption {
65       type = lib.types.str;
66       default = "import";
67       description = ''
68         Relative or absolute to the `originalsPath` from where the files should be imported.
69       '';
70     };
72     storagePath = lib.mkOption {
73       type = lib.types.path;
74       default = "/var/lib/photoprism";
75       description = ''
76         Location for sidecar, cache, and database files.
77       '';
78     };
80     package = lib.mkPackageOption pkgs "photoprism" { };
82     settings = lib.mkOption {
83       type = lib.types.attrsOf lib.types.str;
84       default = { };
85       description = ''
86         See [the getting-started guide](https://docs.photoprism.app/getting-started/config-options/) for available options.
87       '';
88       example = {
89         PHOTOPRISM_DEFAULT_LOCALE = "de";
90         PHOTOPRISM_ADMIN_USER = "root";
91       };
92     };
93   };
95   config = lib.mkIf cfg.enable {
96     systemd.services.photoprism = {
97       description = "Photoprism server";
99       serviceConfig = {
100         Restart = "on-failure";
101         User = "photoprism";
102         Group = "photoprism";
103         DynamicUser = true;
104         StateDirectory = "photoprism";
105         WorkingDirectory = "/var/lib/photoprism";
106         RuntimeDirectory = "photoprism";
107         ReadWritePaths = [ cfg.originalsPath cfg.importPath cfg.storagePath ];
109         LoadCredential = lib.optionalString (cfg.passwordFile != null)
110           "PHOTOPRISM_ADMIN_PASSWORD:${cfg.passwordFile}";
112         CapabilityBoundingSet = "";
113         LockPersonality = true;
114         PrivateDevices = true;
115         PrivateUsers = true;
116         ProtectClock = true;
117         ProtectControlGroups = true;
118         ProtectHome = true;
119         ProtectHostname = true;
120         ProtectKernelLogs = true;
121         ProtectKernelModules = true;
122         ProtectKernelTunables = true;
123         RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
124         RestrictNamespaces = true;
125         RestrictRealtime = true;
126         SystemCallArchitectures = "native";
127         SystemCallFilter = [ "@system-service" "~@setuid @keyring" ];
128         UMask = "0066";
129       } // lib.optionalAttrs (cfg.port < 1024) {
130         AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
131         CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
132       };
134       wantedBy = [ "multi-user.target" ];
135       environment = env;
137       # reminder: easier password configuration will come in https://github.com/photoprism/photoprism/pull/2302
138       preStart = ''
139         ln -sf ${manage} photoprism-manage
141         ${lib.optionalString (cfg.passwordFile != null) ''
142           export PHOTOPRISM_ADMIN_PASSWORD=$(cat "$CREDENTIALS_DIRECTORY/PHOTOPRISM_ADMIN_PASSWORD")
143         ''}
144         exec ${cfg.package}/bin/photoprism migrations run -f
145       '';
147       script = ''
148         ${lib.optionalString (cfg.passwordFile != null) ''
149           export PHOTOPRISM_ADMIN_PASSWORD=$(cat "$CREDENTIALS_DIRECTORY/PHOTOPRISM_ADMIN_PASSWORD")
150         ''}
151         exec ${cfg.package}/bin/photoprism start
152       '';
153     };
154   };