224 lines
6.6 KiB
Nix
224 lines
6.6 KiB
Nix
{ config, lib, pkgs, ... }:
|
|
let
|
|
cfg = config.shb.karakeep;
|
|
|
|
contracts = pkgs.callPackage ../contracts {};
|
|
in
|
|
{
|
|
imports = [
|
|
../blocks/nginx.nix
|
|
];
|
|
|
|
options.shb.karakeep = {
|
|
enable = lib.mkEnableOption "the Karakeep service";
|
|
|
|
subdomain = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "Subdomain under which Karakeep will be served.";
|
|
default = "karakeep";
|
|
};
|
|
|
|
domain = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "domain under which Karakeep will be served.";
|
|
example = "mydomain.com";
|
|
};
|
|
|
|
ssl = lib.mkOption {
|
|
description = "Path to SSL files";
|
|
type = lib.types.nullOr contracts.ssl.certs;
|
|
default = null;
|
|
};
|
|
|
|
port = lib.mkOption {
|
|
type = lib.types.port;
|
|
description = "Port Karakeep listens to incoming requests.";
|
|
default = 3000;
|
|
};
|
|
|
|
environment = lib.mkOption {
|
|
default = {};
|
|
type = lib.types.attrsOf lib.types.str;
|
|
description = "Extra environment variables. See https://docs.karakeep.app/configuration/";
|
|
example = ''
|
|
{
|
|
OLLAMA_BASE_URL = "http://127.0.0.1:''${toString config.services.ollama.port}";
|
|
INFERENCE_TEXT_MODEL = "deepseek-r1:1.5b";
|
|
INFERENCE_IMAGE_MODEL = "llava";
|
|
EMBEDDING_TEXT_MODEL = "nomic-embed-text:v1.5";
|
|
INFERENCE_ENABLE_AUTO_SUMMARIZATION = "true";
|
|
INFERENCE_JOB_TIMEOUT_SEC = "200";
|
|
}
|
|
'';
|
|
};
|
|
|
|
ldap = lib.mkOption {
|
|
description = ''
|
|
Setup LDAP integration.
|
|
'';
|
|
default = {};
|
|
type = lib.types.submodule {
|
|
options = {
|
|
userGroup = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "Group users must belong to to be able to login.";
|
|
default = "karakeep_user";
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
sso = lib.mkOption {
|
|
description = ''
|
|
Setup SSO integration.
|
|
'';
|
|
default = {};
|
|
type = lib.types.submodule {
|
|
options = {
|
|
enable = lib.mkEnableOption "SSO integration.";
|
|
|
|
authEndpoint = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = null;
|
|
description = "Endpoint to the SSO provider. Leave null to not have SSO configured.";
|
|
example = "https://authelia.example.com";
|
|
};
|
|
|
|
clientID = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "Client ID for the OIDC endpoint.";
|
|
default = "karakeep";
|
|
};
|
|
|
|
authorization_policy = lib.mkOption {
|
|
type = lib.types.enum [ "one_factor" "two_factor" ];
|
|
description = "Require one factor (password) or two factor (device) authentication.";
|
|
default = "one_factor";
|
|
};
|
|
|
|
nextauthSecret = lib.mkOption {
|
|
description = "NextAuth secret.";
|
|
type = lib.types.submodule {
|
|
options = contracts.secret.mkRequester {
|
|
owner = "karakeep";
|
|
restartUnits = [ "karakeep.service" ];
|
|
};
|
|
};
|
|
};
|
|
|
|
sharedSecret = lib.mkOption {
|
|
description = "OIDC shared secret for Karakeep.";
|
|
type = lib.types.submodule {
|
|
options = contracts.secret.mkRequester {
|
|
owner = "karakeep";
|
|
restartUnits = [ "karakeep.service" ];
|
|
};
|
|
};
|
|
};
|
|
|
|
sharedSecretForAuthelia = lib.mkOption {
|
|
description = "OIDC shared secret for Authelia. Must be the same as `sharedSecret`";
|
|
type = lib.types.submodule {
|
|
options = contracts.secret.mkRequester {
|
|
mode = "0400";
|
|
ownerText = "config.shb.authelia.autheliaUser";
|
|
owner = config.shb.authelia.autheliaUser;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
backup = lib.mkOption {
|
|
description = ''
|
|
Backup state directory.
|
|
'';
|
|
default = {};
|
|
type = lib.types.submodule {
|
|
options = contracts.backup.mkRequester {
|
|
user = "karakeep";
|
|
sourceDirectories = [
|
|
"/var/lib/karakeep"
|
|
];
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
config = (lib.mkMerge [
|
|
(lib.mkIf cfg.enable {
|
|
services.karakeep = {
|
|
enable = true;
|
|
|
|
extraEnvironment = {
|
|
PORT = toString cfg.port;
|
|
DISABLE_NEW_RELEASE_CHECK = "true"; # These are handled by NixOS
|
|
} // cfg.environment;
|
|
};
|
|
|
|
shb.nginx.vhosts = [
|
|
{
|
|
inherit (cfg) subdomain domain ssl;
|
|
upstream = "http://127.0.0.1:${toString cfg.port}/";
|
|
}
|
|
];
|
|
})
|
|
(lib.mkIf (cfg.enable && cfg.sso.enable) {
|
|
shb.lldap.ensureGroups = {
|
|
${cfg.ldap.userGroup} = {};
|
|
};
|
|
|
|
shb.authelia.extraOidcAuthorizationPolicies.karakeep = {
|
|
default_policy = "deny";
|
|
rules = [
|
|
{
|
|
subject = [ "group:${cfg.ldap.userGroup}" ];
|
|
policy = cfg.sso.authorization_policy;
|
|
}
|
|
];
|
|
};
|
|
shb.authelia.oidcClients = [
|
|
{
|
|
client_id = cfg.sso.clientID;
|
|
client_secret.source = cfg.sso.sharedSecretForAuthelia.result.path;
|
|
scopes = [ "openid" "email" "profile" ];
|
|
authorization_policy = "karakeep";
|
|
redirect_uris = [
|
|
"https://${cfg.subdomain}.${cfg.domain}/api/auth/callback/custom"
|
|
];
|
|
}
|
|
];
|
|
services.karakeep = {
|
|
extraEnvironment = {
|
|
DISABLE_SIGNUPS = "false";
|
|
DISABLE_PASSWORD_AUTH = "true";
|
|
NEXTAUTH_URL = "https://${cfg.subdomain}.${cfg.domain}";
|
|
OAUTH_WELLKNOWN_URL = "${cfg.sso.authEndpoint}/.well-known/openid-configuration";
|
|
OAUTH_PROVIDER_NAME = "Single Sign-On";
|
|
OAUTH_CLIENT_ID = cfg.sso.clientID;
|
|
OAUTH_SCOPE = "openid email profile";
|
|
};
|
|
environmentFile = "/run/karakeep/secrets.env";
|
|
};
|
|
|
|
systemd.tmpfiles.rules = [
|
|
"d '/run/karakeep' 0750 root root - -"
|
|
];
|
|
systemd.services.karakeep-pre = {
|
|
script = lib.shb.replaceSecrets {
|
|
userConfig = {
|
|
NEXTAUTH_SECRET.source = cfg.sso.nextauthSecret.result.path;
|
|
OAUTH_CLIENT_SECRET.source = cfg.sso.sharedSecret.result.path;
|
|
};
|
|
resultPath = "/run/karakeep/secrets.env";
|
|
generator = lib.shb.toEnvVar;
|
|
};
|
|
serviceConfig.Type = "oneshot";
|
|
wantedBy = [ "multi-user.target" ];
|
|
before = [ "karakeep-web.service" "karakeep-workers.service" ];
|
|
requiredBy = [ "karakeep-web.service" "karakeep-workers.service" ];
|
|
};
|
|
})
|
|
]);
|
|
}
|