at 25.11-pre 6.6 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7let 8 cfg = config.services.karakeep; 9 10 karakeepEnv = lib.mkMerge [ 11 { DATA_DIR = "/var/lib/karakeep"; } 12 (lib.mkIf cfg.meilisearch.enable { 13 MEILI_ADDR = "http://127.0.0.1:${toString config.services.meilisearch.listenPort}"; 14 }) 15 (lib.mkIf cfg.browser.enable { 16 BROWSER_WEB_URL = "http://127.0.0.1:${toString cfg.browser.port}"; 17 }) 18 cfg.extraEnvironment 19 ]; 20 21 environmentFiles = [ 22 "/var/lib/karakeep/settings.env" 23 ] ++ (lib.optional (cfg.environmentFile != null) cfg.environmentFile); 24in 25{ 26 options = { 27 services.karakeep = { 28 enable = lib.mkEnableOption "Enable the Karakeep service"; 29 package = lib.mkPackageOption pkgs "karakeep" { }; 30 31 extraEnvironment = lib.mkOption { 32 description = '' 33 Environment variables to pass to Karakaeep. This is how most settings 34 can be configured. Changing DATA_DIR is possible but not supported. 35 36 See https://docs.karakeep.app/configuration/ 37 ''; 38 type = lib.types.attrsOf lib.types.str; 39 default = { }; 40 example = lib.literalExpression '' 41 { 42 PORT = "1234"; 43 DISABLE_SIGNUPS = "true"; 44 DISABLE_NEW_RELEASE_CHECK = "true"; 45 } 46 ''; 47 }; 48 49 environmentFile = lib.mkOption { 50 type = lib.types.nullOr lib.types.path; 51 default = null; 52 description = '' 53 An optional path to an environment file that will be used in the web and workers 54 services. This is useful for loading private keys. 55 ''; 56 example = "/var/lib/karakeep/secrets.env"; 57 }; 58 59 browser = { 60 enable = lib.mkOption { 61 description = '' 62 Enable the karakeep-browser service that runs a chromium instance in 63 the background with debugging ports exposed. This is necessary for 64 certain features like screenshots. 65 ''; 66 type = lib.types.bool; 67 default = true; 68 }; 69 port = lib.mkOption { 70 description = "The port the browser should run on."; 71 type = lib.types.port; 72 default = 9222; 73 }; 74 exe = lib.mkOption { 75 description = "The browser executable (must be Chrome-like)."; 76 type = lib.types.str; 77 default = "${pkgs.chromium}/bin/chromium"; 78 defaultText = lib.literalExpression "\${pkgs.chromium}/bin/chromium"; 79 example = lib.literalExpression "\${pkgs.google-chrome}/bin/google-chrome-stable"; 80 }; 81 }; 82 83 meilisearch = { 84 enable = lib.mkOption { 85 type = lib.types.bool; 86 default = true; 87 description = '' 88 Enable Meilisearch and configure Karakeep to use it. Meilisearch is 89 required for text search. 90 ''; 91 }; 92 }; 93 }; 94 }; 95 96 config = lib.mkIf cfg.enable { 97 environment.systemPackages = [ cfg.package ]; 98 99 users.groups.karakeep = { }; 100 users.users.karakeep = { 101 isSystemUser = true; 102 group = "karakeep"; 103 }; 104 105 services.meilisearch = lib.mkIf cfg.meilisearch.enable { 106 enable = true; 107 }; 108 109 systemd.services.karakeep-init = { 110 description = "Initialize Karakeep Data"; 111 wantedBy = [ "multi-user.target" ]; 112 after = [ "network.target" ]; 113 partOf = [ "karakeep.service" ]; 114 path = [ pkgs.openssl ]; 115 script = '' 116 umask 0077 117 118 if [ ! -f "$STATE_DIRECTORY/settings.env" ]; then 119 cat <<EOF >"$STATE_DIRECTORY/settings.env" 120 # Generated by NixOS Karakeep module 121 MEILI_MASTER_KEY=$(openssl rand -base64 36) 122 NEXTAUTH_SECRET=$(openssl rand -base64 36) 123 EOF 124 fi 125 126 export DATA_DIR="$STATE_DIRECTORY" 127 exec "${cfg.package}/lib/karakeep/migrate" 128 ''; 129 serviceConfig = { 130 Type = "oneshot"; 131 RemainAfterExit = true; 132 User = "karakeep"; 133 Group = "karakeep"; 134 StateDirectory = "karakeep"; 135 PrivateTmp = "yes"; 136 }; 137 }; 138 139 systemd.services.karakeep-workers = { 140 description = "Karakeep Workers"; 141 wantedBy = [ "multi-user.target" ]; 142 after = [ 143 "network.target" 144 "karakeep-init.service" 145 ]; 146 partOf = [ "karakeep.service" ]; 147 path = [ 148 pkgs.monolith 149 pkgs.yt-dlp 150 ]; 151 environment = karakeepEnv; 152 serviceConfig = { 153 User = "karakeep"; 154 Group = "karakeep"; 155 ExecStart = "${cfg.package}/lib/karakeep/start-workers"; 156 StateDirectory = "karakeep"; 157 EnvironmentFile = environmentFiles; 158 PrivateTmp = "yes"; 159 }; 160 }; 161 162 systemd.services.karakeep-web = { 163 description = "Karakeep Web"; 164 wantedBy = [ "multi-user.target" ]; 165 after = [ 166 "network.target" 167 "karakeep-init.service" 168 "karakeep-workers.service" 169 ]; 170 partOf = [ "karakeep.service" ]; 171 environment = karakeepEnv; 172 serviceConfig = { 173 ExecStart = "${cfg.package}/lib/karakeep/start-web"; 174 User = "karakeep"; 175 Group = "karakeep"; 176 StateDirectory = "karakeep"; 177 EnvironmentFile = environmentFiles; 178 PrivateTmp = "yes"; 179 }; 180 }; 181 182 systemd.services.karakeep-browser = lib.mkIf cfg.browser.enable { 183 wantedBy = [ "multi-user.target" ]; 184 after = [ "network.target" ]; 185 partOf = [ "karakeep.service" ]; 186 script = '' 187 export HOME="$CACHE_DIRECTORY" 188 exec ${cfg.browser.exe} \ 189 --headless --no-sandbox --disable-gpu --disable-dev-shm-usage \ 190 --remote-debugging-address=127.0.0.1 \ 191 --remote-debugging-port=${toString cfg.browser.port} \ 192 --hide-scrollbars \ 193 --user-data-dir="$STATE_DIRECTORY" 194 ''; 195 serviceConfig = { 196 Type = "simple"; 197 Restart = "on-failure"; 198 199 CacheDirectory = "karakeep-browser"; 200 StateDirectory = "karakeep-browser"; 201 202 DevicePolicy = "closed"; 203 DynamicUser = true; 204 LockPersonality = true; 205 NoNewPrivileges = true; 206 PrivateDevices = true; 207 PrivateTmp = true; 208 PrivateUsers = true; 209 ProtectClock = true; 210 ProtectControlGroups = true; 211 ProtectHostname = true; 212 ProtectKernelLogs = true; 213 ProtectKernelModules = true; 214 ProtectKernelTunables = true; 215 ProtectSystem = "strict"; 216 RestrictNamespaces = true; 217 RestrictRealtime = true; 218 }; 219 }; 220 }; 221 222 meta = { 223 maintainers = [ lib.maintainers.three ]; 224 }; 225}