at master 6.1 kB view raw
1{ 2 lib, 3 pkgs, 4 config, 5 ... 6}: 7 8let 9 inherit (lib) 10 concatMap 11 concatStringsSep 12 getExe 13 maintainers 14 mkEnableOption 15 mkIf 16 mkOption 17 mkPackageOption 18 optional 19 optionalAttrs 20 ; 21 inherit (lib.types) 22 bool 23 path 24 str 25 submodule 26 ; 27 28 cfg = config.services.pocket-id; 29 30 format = pkgs.formats.keyValue { }; 31 settingsFile = format.generate "pocket-id-env-vars" cfg.settings; 32in 33{ 34 meta.maintainers = with maintainers; [ 35 gepbird 36 ymstnt 37 ]; 38 39 options.services.pocket-id = { 40 enable = mkEnableOption "Pocket ID server"; 41 42 package = mkPackageOption pkgs "pocket-id" { }; 43 44 environmentFile = mkOption { 45 type = path; 46 description = '' 47 Path to an environment file loaded for the Pocket ID service. 48 49 This can be used to securely store tokens and secrets outside of the world-readable Nix store. 50 51 Example contents of the file: 52 MAXMIND_LICENSE_KEY=your-license-key 53 ''; 54 default = "/dev/null"; 55 example = "/var/lib/secrets/pocket-id"; 56 }; 57 58 settings = mkOption { 59 type = submodule { 60 freeformType = format.type; 61 62 options = { 63 APP_URL = mkOption { 64 type = str; 65 description = '' 66 The URL where you will access the app. 67 ''; 68 default = "http://localhost"; 69 }; 70 71 TRUST_PROXY = mkOption { 72 type = bool; 73 description = '' 74 Whether the app is behind a reverse proxy. 75 ''; 76 default = false; 77 }; 78 79 ANALYTICS_DISABLED = mkOption { 80 type = bool; 81 description = '' 82 Whether to disable analytics. 83 84 See [docs page](https://pocket-id.org/docs/configuration/analytics/). 85 ''; 86 default = false; 87 }; 88 }; 89 }; 90 91 default = { }; 92 93 description = '' 94 Environment variables that will be passed to Pocket ID, see 95 [configuration options](https://pocket-id.org/docs/configuration/environment-variables) 96 for supported values. 97 ''; 98 }; 99 100 dataDir = mkOption { 101 type = path; 102 default = "/var/lib/pocket-id"; 103 description = '' 104 The directory where Pocket ID will store its data, such as the database. 105 ''; 106 }; 107 108 user = mkOption { 109 type = str; 110 default = "pocket-id"; 111 description = "User account under which Pocket ID runs."; 112 }; 113 114 group = mkOption { 115 type = str; 116 default = "pocket-id"; 117 description = "Group account under which Pocket ID runs."; 118 }; 119 }; 120 121 config = mkIf cfg.enable { 122 warnings = 123 optional (cfg.settings ? MAXMIND_LICENSE_KEY) 124 "config.services.pocket-id.settings.MAXMIND_LICENSE_KEY will be stored as plaintext in the Nix store. Use config.services.pocket-id.environmentFile instead." 125 ++ 126 concatMap 127 ( 128 # Added 2025-05-27 129 setting: 130 optional (cfg.settings ? "${setting}") '' 131 config.services.pocket-id.settings.${setting} is deprecated. 132 See https://pocket-id.org/docs/setup/migrate-to-v1/ for migration instructions. 133 '' 134 ) 135 [ 136 "PUBLIC_APP_URL" 137 "PUBLIC_UI_CONFIG_DISABLED" 138 "CADDY_DISABLED" 139 "CADDY_PORT" 140 "BACKEND_PORT" 141 "POSTGRES_CONNECTION_STRING" 142 "SQLITE_DB_PATH" 143 "INTERNAL_BACKEND_URL" 144 ]; 145 146 systemd.tmpfiles.rules = [ 147 "d ${cfg.dataDir} 0755 ${cfg.user} ${cfg.group}" 148 ]; 149 150 systemd.services = { 151 pocket-id = { 152 description = "Pocket ID"; 153 after = [ "network.target" ]; 154 wantedBy = [ "multi-user.target" ]; 155 restartTriggers = [ 156 cfg.package 157 cfg.environmentFile 158 settingsFile 159 ]; 160 161 serviceConfig = { 162 Type = "simple"; 163 User = cfg.user; 164 Group = cfg.group; 165 WorkingDirectory = cfg.dataDir; 166 ExecStart = getExe cfg.package; 167 Restart = "always"; 168 EnvironmentFile = [ 169 cfg.environmentFile 170 settingsFile 171 ]; 172 173 # Hardening 174 AmbientCapabilities = ""; 175 CapabilityBoundingSet = ""; 176 DeviceAllow = ""; 177 DevicePolicy = "closed"; 178 #IPAddressDeny = "any"; # provides the service through network 179 LockPersonality = true; 180 MemoryDenyWriteExecute = true; 181 NoNewPrivileges = true; 182 PrivateDevices = true; 183 PrivateNetwork = false; # provides the service through network 184 PrivateTmp = true; 185 PrivateUsers = true; 186 ProcSubset = "pid"; 187 ProtectClock = true; 188 ProtectControlGroups = true; 189 ProtectHome = true; 190 ProtectHostname = true; 191 ProtectKernelLogs = true; 192 ProtectKernelModules = true; 193 ProtectKernelTunables = true; 194 ProtectProc = "invisible"; 195 ProtectSystem = "strict"; 196 ReadWritePaths = [ cfg.dataDir ]; 197 RemoveIPC = true; 198 RestrictAddressFamilies = [ 199 "AF_UNIX" 200 "AF_INET" 201 "AF_INET6" 202 ]; 203 RestrictNamespaces = true; 204 RestrictRealtime = true; 205 RestrictSUIDSGID = true; 206 SystemCallArchitectures = "native"; 207 SystemCallFilter = concatStringsSep " " [ 208 "~" 209 "@clock" 210 "@cpu-emulation" 211 "@debug" 212 "@module" 213 "@mount" 214 "@obsolete" 215 "@privileged" 216 "@raw-io" 217 "@reboot" 218 "@resources" 219 "@swap" 220 ]; 221 UMask = "0077"; 222 }; 223 }; 224 }; 225 226 users.users = optionalAttrs (cfg.user == "pocket-id") { 227 pocket-id = { 228 isSystemUser = true; 229 group = cfg.group; 230 description = "Pocket ID backend user"; 231 home = cfg.dataDir; 232 }; 233 }; 234 235 users.groups = optionalAttrs (cfg.group == "pocket-id") { 236 pocket-id = { }; 237 }; 238 }; 239}