139 lines
4.1 KiB
Nix
139 lines
4.1 KiB
Nix
# Open WebUI Module (System)
|
|
# Provides: Open WebUI chat interface as system container
|
|
#
|
|
# Usage:
|
|
# myModules.openWebUI = {
|
|
# enable = true;
|
|
# };
|
|
|
|
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
|
|
let
|
|
cfg = config.myModules.openWebUI;
|
|
in
|
|
{
|
|
options.myModules.openWebUI = {
|
|
enable = lib.mkEnableOption "Open WebUI chat interface (System Service)";
|
|
|
|
image = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "ghcr.io/open-webui/open-webui:main";
|
|
description = "Open WebUI container image";
|
|
};
|
|
|
|
dataDir = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "/var/lib/open-webui";
|
|
description = "Path to Open WebUI data directory";
|
|
};
|
|
|
|
port = lib.mkOption {
|
|
type = lib.types.port;
|
|
default = 3000;
|
|
description = "Host port for Open WebUI";
|
|
};
|
|
|
|
# Networking Defaults:
|
|
# - Ollama is on the SAME system network (antigravity-net), so we use container name 'ollama'.
|
|
# - Unified Router is a USER container, so we must access via Host gateway.
|
|
ollamaUrl = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "http://ollama:11434";
|
|
description = "URL to Ollama API (Internal Container Network)";
|
|
};
|
|
|
|
openaiBaseUrl = lib.mkOption {
|
|
type = lib.types.str;
|
|
# 10.88.0.1 is default podman gateway, or use host.containers.internal if available
|
|
default = "http://host.containers.internal:6767/v1";
|
|
description = "URL to OpenAI-compatible API (Unified Router on Host)";
|
|
};
|
|
|
|
envFile = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "/run/secrets/open_webui_env";
|
|
description = "Path to environment file with secrets";
|
|
};
|
|
|
|
apiKeyEnvFile = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "/run/secrets/rendered/api_key.env";
|
|
description = "Path to API key environment file";
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
# Ensure data directory exists
|
|
systemd.tmpfiles.rules = [
|
|
"d ${cfg.dataDir} 0750 root root -"
|
|
];
|
|
|
|
systemd.services.open-webui = {
|
|
description = "Open WebUI Container (System)";
|
|
after = [
|
|
"network-online.target"
|
|
"ollama.service"
|
|
];
|
|
wants = [ "network-online.target" ];
|
|
requires = [ "ollama.service" ]; # It depends on Ollama for local inference often
|
|
|
|
serviceConfig = {
|
|
Restart = "always";
|
|
|
|
# Hardening
|
|
ProtectSystem = "strict";
|
|
ProtectHome = true;
|
|
PrivateTmp = true;
|
|
ProtectKernelTunables = false;
|
|
ProtectControlGroups = false; # Podman needs cgroups
|
|
ProtectKernelModules = true;
|
|
|
|
# Allow Podman to write to state and data
|
|
ReadWritePaths = [
|
|
"/var/lib/containers"
|
|
"/run"
|
|
"/etc/containers" # Network configs live here
|
|
cfg.dataDir
|
|
];
|
|
|
|
# ExecStartPre to cleanup
|
|
ExecStartPre = [
|
|
"-${pkgs.podman}/bin/podman stop open-webui"
|
|
"-${pkgs.podman}/bin/podman rm open-webui"
|
|
"${pkgs.podman}/bin/podman pull ${cfg.image}"
|
|
"${pkgs.podman}/bin/podman network create antigravity-net --ignore"
|
|
# Fix ownership for UserNS (container user maps to host UID 200000)
|
|
"${pkgs.coreutils}/bin/chown -R 200000:200000 ${cfg.dataDir}"
|
|
];
|
|
ExecStart = ''
|
|
${pkgs.podman}/bin/podman run --rm --name open-webui \
|
|
--network=antigravity-net \
|
|
--dns=8.8.8.8 \
|
|
--userns=auto \
|
|
-e ENABLE_PERSISTENT_CONFIG=True \
|
|
-e OPENAI_API_BASE_URL=${cfg.openaiBaseUrl} \
|
|
-e OLLAMA_BASE_URL=${cfg.ollamaUrl} \
|
|
-e ENABLE_RAG_WEB_SEARCH=True \
|
|
-e RAG_WEB_SEARCH=True \
|
|
-e RAG_WEB_SEARCH_ENGINE=duckduckgo \
|
|
-e RAG_WEB_SEARCH_RESULT_COUNT=3 \
|
|
-e ENABLE_RAG=True \
|
|
--env-file=${cfg.envFile} \
|
|
--env-file=${cfg.apiKeyEnvFile} \
|
|
-v ${cfg.dataDir}:/app/backend/data:U \
|
|
--add-host=host.containers.internal:host-gateway \
|
|
-p 127.0.0.1:${toString cfg.port}:8080 \
|
|
${cfg.image}
|
|
'';
|
|
ExecStop = "${pkgs.podman}/bin/podman stop open-webui";
|
|
};
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
};
|
|
};
|
|
}
|