diff --git a/hosts/freun-dev/secrets.nix b/hosts/freun-dev/secrets.nix index bfc985b..61a8fa7 100644 --- a/hosts/freun-dev/secrets.nix +++ b/hosts/freun-dev/secrets.nix @@ -33,6 +33,8 @@ "gitea" "gitea-actions-runner" "searx" + "open-webui" + "open-terminal-api-key" ] ) // { diff --git a/hosts/freun-dev/services.nix b/hosts/freun-dev/services.nix index 5c95b0e..f989b6d 100644 --- a/hosts/freun-dev/services.nix +++ b/hosts/freun-dev/services.nix @@ -19,6 +19,7 @@ let secrets = config.age.secrets; in { + nixpkgs.config.allowUnfree = true; imports = [ ./glance.nix ]; @@ -425,11 +426,35 @@ in }; }; + open-webui = { + enable = true; + port = 3500; + environmentFile = secrets.open-webui.path; + environment = { + ENABLE_WEB_SEARCH = "True"; + ENABLE_OLLAMA_API = "False"; + }; + subdomain = "owu"; + }; + webserver = { acme.dnsChallenge = true; tailscaleAuth.expectedTailnet = "tempel-vibes.ts.net"; }; }; + virtualisation.oci-containers.containers.open-terminal = { + image = "ghcr.io/open-webui/open-terminal:latest"; + autoStart = true; + ports = [ "127.0.0.1:3700:8000" ]; + environmentFiles = [ config.age.secrets."open-terminal-api-key".path ]; + environment = { + OPEN_TERMINAL_MULTI_USER = "true"; + }; + volumes = [ + "open-terminal-data:/home/user" + ]; + }; + virtualisation.docker.autoPrune.enable = true; } diff --git a/modules/services/default.nix b/modules/services/default.nix index b683018..f8e425f 100644 --- a/modules/services/default.nix +++ b/modules/services/default.nix @@ -34,5 +34,6 @@ ./dhcp-dns-sync ./invidious-companion.nix ./searx.nix + ./open-webui.nix ]; } diff --git a/modules/services/open-webui.nix b/modules/services/open-webui.nix new file mode 100644 index 0000000..cff2edb --- /dev/null +++ b/modules/services/open-webui.nix @@ -0,0 +1,78 @@ +{ + lib, + config, + pkgs-unstable, + ... +}: +let + cfg = config.services.open-webui; + fqdn = "${cfg.subdomain}.${config.networking.domain}"; + + open-webui-pkg = pkgs-unstable.open-webui.overridePythonAttrs (oldAttrs: { + dependencies = + oldAttrs.dependencies + ++ (with pkgs-unstable.python3Packages; [ + pgvector + psycopg2 + ]) + ++ [ + pkgs-unstable.ffmpeg + ]; + }); +in +{ + options.services.open-webui = { + subdomain = lib.mkOption { + type = lib.types.str; + }; + }; + + config = lib.mkIf cfg.enable { + services = { + open-webui = { + package = open-webui-pkg; + environment = { + ANONYMIZED_TELEMETRY = "False"; + DO_NOT_TRACK = "True"; + SCARF_NO_ANALYTICS = "True"; + WEBUI_URL = "https://${fqdn}"; + VECTOR_DB = "pgvector"; + PGVECTOR_CREATE_EXTENSION = "False"; + DATABASE_URL = "postgresql:///open-webui?host=/var/run/postgresql"; + CORS_ALLOW_ORIGIN = "https://${fqdn};http://localhost"; + }; + }; + + webserver.vHosts.${fqdn}.locations."/".proxyPort = cfg.port; + postgresql = { + enable = lib.mkDefault true; + ensureDatabases = [ "open-webui" ]; + ensureUsers = [ + { + name = "open-webui"; + ensureDBOwnership = true; + } + ]; + extensions = ps: with ps; [ pgvector ]; + }; + }; + + systemd.services.open-webui-pgvector-setup = { + description = "Ensure pgvector extension exists for open-webui"; + wantedBy = [ "open-webui.service" ]; + before = [ "open-webui.service" ]; + after = [ + "postgresql.service" + "postgresql-setup.service" + ]; + requires = [ "postgresql.service" ]; + serviceConfig = { + Type = "oneshot"; + User = "postgres"; + Group = "postgres"; + ExecStart = "${config.services.postgresql.package}/bin/psql -d open-webui -c 'CREATE EXTENSION IF NOT EXISTS vector;'"; + RemainAfterExit = true; + }; + }; + }; +} diff --git a/secrets/open-terminal-api-key.age b/secrets/open-terminal-api-key.age new file mode 100644 index 0000000..af8cde2 Binary files /dev/null and b/secrets/open-terminal-api-key.age differ diff --git a/secrets/open-webui.age b/secrets/open-webui.age new file mode 100644 index 0000000..3c616d7 Binary files /dev/null and b/secrets/open-webui.age differ diff --git a/secrets/secrets.nix b/secrets/secrets.nix index bf204d2..cb02e68 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -46,6 +46,8 @@ in "gitea-actions-runner.age".publicKeys = users ++ [ freun-dev ]; "invidious-companion.age".publicKeys = users ++ [ apu ]; "invidious.age".publicKeys = users ++ [ freun-dev ]; + "open-webui.age".publicKeys = users ++ [ freun-dev ]; + "open-terminal-api-key.age".publicKeys = users ++ [ freun-dev ]; "searx.age".publicKeys = users ++ [ freun-dev ]; "everii-vpn/de1.key.age".publicKeys = users ++ [ radish ]; "everii-vpn/ch1.key.age".publicKeys = users ++ [ radish ];