1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8 cfg = config.services.immich-public-proxy;
9 format = pkgs.formats.json { };
10 inherit (lib)
11 types
12 mkIf
13 mkOption
14 mkEnableOption
15 ;
16in
17{
18 options.services.immich-public-proxy = {
19 enable = mkEnableOption "Immich Public Proxy";
20 package = lib.mkPackageOption pkgs "immich-public-proxy" { };
21
22 immichUrl = mkOption {
23 type = types.str;
24 description = "URL of the Immich instance";
25 };
26
27 port = mkOption {
28 type = types.port;
29 default = 3000;
30 description = "The port that IPP will listen on.";
31 };
32 openFirewall = mkOption {
33 type = types.bool;
34 default = false;
35 description = "Whether to open the IPP port in the firewall";
36 };
37
38 settings = mkOption {
39 type = types.submodule {
40 freeformType = format.type;
41 };
42 default = { };
43 description = ''
44 Configuration for IPP. See <https://github.com/alangrainger/immich-public-proxy/blob/main/README.md#additional-configuration> for options and defaults.
45 '';
46 };
47 };
48
49 config = mkIf cfg.enable {
50 systemd.services.immich-public-proxy = {
51 description = "Immich public proxy for sharing albums publicly without exposing your Immich instance";
52 after = [ "network.target" ];
53 wantedBy = [ "multi-user.target" ];
54 environment = {
55 IMMICH_URL = cfg.immichUrl;
56 IPP_PORT = builtins.toString cfg.port;
57 IPP_CONFIG = "${format.generate "config.json" cfg.settings}";
58 };
59 serviceConfig = {
60 ExecStart = lib.getExe cfg.package;
61 SyslogIdentifier = "ipp";
62 User = "ipp";
63 Group = "ipp";
64 DynamicUser = true;
65 Type = "simple";
66 Restart = "on-failure";
67 RestartSec = 3;
68
69 # Hardening
70 CapabilityBoundingSet = "";
71 NoNewPrivileges = true;
72 PrivateUsers = true;
73 PrivateTmp = true;
74 PrivateDevices = true;
75 PrivateMounts = true;
76 ProtectClock = true;
77 ProtectControlGroups = true;
78 ProtectHome = true;
79 ProtectHostname = true;
80 ProtectKernelLogs = true;
81 ProtectKernelModules = true;
82 ProtectKernelTunables = true;
83 RestrictAddressFamilies = [
84 "AF_INET"
85 "AF_INET6"
86 "AF_UNIX"
87 ];
88 RestrictNamespaces = true;
89 RestrictRealtime = true;
90 RestrictSUIDSGID = true;
91 };
92 };
93
94 networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ];
95 };
96 meta.maintainers = with lib.maintainers; [ jaculabilis ];
97}