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