Skip to content

Releases: kossakovsky/selfhost-ai

v1.12.0

Choose a tag to compare

@kossakovsky kossakovsky released this 11 Sep 18:39
ddf5efd

Added

  • Open Terminal - New optional open-terminal profile (requires open-webui) that adds Open Terminal, an execution environment for Open WebUI agents: a Linux shell with a persistent home, runtime apt/pip/npm installs, local services with port proxying and Jupyter kernels, so an agent can produce an artifact instead of describing how to. Internal only (http://open-terminal:8000, no Caddy route); the admin connects it once under Admin Settings → Integrations → Open Terminal with the generated OPEN_TERMINAL_API_KEY, and grants access to users or groups there. Multi-user mode is on by default (one unprivileged Linux account per Open WebUI user, volume on /home; the installer refuses a slim/alpine/openshift tag in that mode because those images ignore it), CPU/memory limits are tunable via OPEN_TERMINAL_CPU_LIMIT / OPEN_TERMINAL_MEMORY_LIMIT. Egress filtering is left to docker-compose.override.yml because the image reads an empty OPEN_TERMINAL_ALLOWED_DOMAINS as "block everything" and needs NET_ADMIN. (#117)

Upgrade with make update.

v1.11.0

Choose a tag to compare

@kossakovsky kossakovsky released this 09 Sep 18:48
d90a1fd

Added

  • n8n Assistant sandbox - New optional n8n-sandbox profile that adds n8n's own code-execution sandbox (sandbox-certs, sandbox-api, sandbox-runner-1 from n8n-sandbox-service) so the built-in AI Assistant works on self-hosted n8n (and the Agents preview, except its knowledge base, which needs Daytona); until now the Instance AI settings page showed Code sandbox: Not set. The installer wires N8N_INSTANCE_AI_SANDBOX_ENABLED, the sandbox URL and key into n8n, generates the three shared secrets, and points N8N_INSTANCE_AI_SEARXNG_URL at the bundled SearXNG while that profile is active; the model API key is added in the n8n UI (Settings → Instance AI). The Docker-in-Docker runner is isolated with Sysbox: scripts/setup_sysbox.sh installs sysbox-ce non-interactively without restarting Docker (it pre-seeds bip/default-address-pools in daemon.json with Docker's current values) and the runner gets runtime: sysbox-runc. When Sysbox cannot be installed the installer asks before falling back to a privileged runner, records the choice in N8N_SANDBOX_RUNNER_RUNTIME / N8N_SANDBOX_RUNNER_PRIVILEGED, and make doctor warns while the runner is privileged. N8N_ENABLED_MODULES is exposed (empty by default) for the Agents preview. (#114)

Upgrade with make update.

v1.10.1

Choose a tag to compare

@kossakovsky kossakovsky released this 02 Sep 20:48

Fixed

  • Monitoring - Upgrading an existing installation to 1.10.0 left Grafana in a restart loop with Datasource provisioning error: data source not found. The Prometheus data source already existed with a random uid, and Grafana cannot change the uid of an existing data source when provisioning pins one. The provisioning file now deletes the data source by name before recreating it with the fixed uid Prometheus; dashboards and alert rules reference the uid, so nothing is lost. Fresh installations were not affected.

Upgrade with make update.

v1.10.0

Choose a tag to compare

@kossakovsky kossakovsky released this 02 Sep 20:35
2a1d4cf

Added

  • Monitoring - The n8n Grafana dashboard now shows whether workflows actually run, not just whether the n8n process is healthy. n8n is started with N8N_METRICS_INCLUDE_MESSAGE_EVENT_BUS_METRICS, N8N_METRICS_INCLUDE_WORKFLOW_ID_LABEL, N8N_METRICS_INCLUDE_WORKFLOW_NAME_LABEL and N8N_METRICS_INCLUDE_WORKFLOW_INFO, which expose n8n_workflow_started/success/failed/cancelled_total counters labelled per workflow plus id-to-name gauges, and a new "Workflow Executions" section adds three panels: executions by outcome over time, executions per workflow, and time since each active workflow's last successful execution. The last one is backed by Prometheus recording rules in prometheus/rules/n8n-workflows.yml that remember the last non-manual success per workflow for 30 days and follow renames. Four Grafana-managed alert rules are provisioned from grafana/provisioning/alerting/n8n-workflows.yml: "n8n workflow failed" (a non-manual execution failed in the last 15 minutes - runs from the editor are excluded), "n8n workflow stalled" (an active workflow has had no success for 24 hours), "n8n workflow has no recorded success" (active for 24 hours without ever succeeding since monitoring started - catches workflows that were already broken at upgrade time) and "n8n metrics target down" (Prometheus cannot scrape n8n or a worker). The 24-hour thresholds are global and tunable in that file; provisioned rules are read-only in the UI. Alerts follow Grafana's default notification policy, whose built-in email contact point delivers nothing without SMTP - create a contact point and select it under Alerting > Notification policies. The Prometheus data source now has the fixed uid Prometheus that the dashboards and rules reference (#110).

Fixed

  • Monitoring - Prometheus never scraped the n8n workers: the n8n-worker job targeted a hostname that does not exist (containers are n8n-worker-1, n8n-worker-2, ...) on the task-broker port 5679 instead of the metrics port 5678. scripts/generate_n8n_workers.sh now writes prometheus/targets/n8n.json with the n8n main target and one target per worker, read by Prometheus via file_sd_configs, so the target list follows N8N_WORKER_COUNT automatically. The generator runs on every install and update and removes the file when n8n is deselected, so a monitoring-only install no longer carries a permanently-down n8n:5678 target. make doctor reports a missing or outdated targets file and a failing recording rule (#110).
  • Doctor - make doctor could never report Grafana or Prometheus as down: the check was gated on a profile named after the container, but both belong to the monitoring profile. The check now takes the enabling profile explicitly.
  • n8n - docker compose build failed on n8n/Dockerfile.runner with /bin/sh: pnpm: Permission denied (exit code 126). The upstream n8nio/runners:stable image rebuilt on 2026-09-02 ships pnpm.cjs without the execute bit (pnpm 11.22.0), so the pnpm add cheerio axios moment lodash step could not start even as root. The Dockerfile now restores the bit on the symlink target before running pnpm; the fix is a no-op once upstream republishes a correct image (#111).

v1.9.0

Choose a tag to compare

@kossakovsky kossakovsky released this 27 Aug 23:07
9b01721

Added

  • n8n-MCP - New optional service (n8n-mcp profile): a Model Context Protocol server that exposes n8n's full node catalogue, property schemas and workflow templates to AI coding assistants, plus workflow-management tools once an n8n API key is configured. Served at n8n-mcp.<domain> behind a generated N8N_MCP_AUTH_TOKEN Bearer token. Caddy gates on the same token the service itself validates, because HTTP carries a single Authorization header and MCP clients send only a Bearer token - basic auth would make the endpoint unusable for every client. Ships in documentation-only mode; create an API key in n8n under Settings > n8n API, set N8N_API_KEY in .env and run make restart to unlock workflow management. Connect with npx -y mcp-remote https://n8n-mcp.<domain>/mcp --header "Authorization: Bearer <token>". Note that outside n8n Enterprise an API key grants full account access (#104).
  • Ollama - Optional multiple instances for multi-GPU hosts. Set OLLAMA_INSTANCE_COUNT in .env (1-8) to run ollama2, ollama3, ... alongside the existing ollama container, each pinnable to its own GPU so a large model stays resident instead of being swapped out. The runtime tuning variables (KEEP_ALIVE, NUM_PARALLEL, MAX_LOADED_MODELS, CONTEXT_LENGTH, KV_CACHE_TYPE, GPU_OVERHEAD, SCHED_SPREAD) can be set per instance with an OLLAMA<N>_ prefix (e.g. OLLAMA2_KEEP_ALIVE=-1) and fall back to the global value when unset, taking effect on the next make restart. OLLAMA<N>_GPU_DEVICES is the exception: it selects that instance's GPU, defaults to GPU N-1, and does not read the global OLLAMA_GPU_DEVICES. All instances share one model store, so each model is downloaded once. Extra instances are internal only (http://ollama2:11434) with no published ports, matching the rest of the stack; use caddy-addon/site-*.conf to expose one externally. The default of 1 generates nothing, so existing installs are unchanged. Set OLLAMA_GPU_DEVICES as well when running several instances, otherwise the first one is unpinned and may collide with ollama2 - make doctor warns about this (#107).

Changed

  • Open WebUI - New installations now store chats, users and settings in the stack's shared PostgreSQL instead of SQLite, removing the sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) database is locked failures that appear with several tabs or devices open, and placing the data in the same backup as the rest of the stack. Existing installations are deliberately left on SQLite: Open WebUI does not migrate data between backends, so switching would present an empty interface while the old chats stayed in webui.db. To opt in, set OPEN_WEBUI_DATABASE=postgres in .env and run make restart; see the README for the required volume backup and the migration tooling. Uploaded files and the vector store stay in the open-webui volume in both modes (#105).

Fixed

  • NocoDB - Fix "Connection to internal hosts is not allowed" (older builds: "Forbidden host name or IP address") when adding the stack's own PostgreSQL, or any container, as an external data source. NocoDB 2026.05.2 added SSRF protection that rejects any data-source host resolving to a private IP range, which covers every hostname on the Docker network, so this broke silently for anyone who updated after that release. NC_ALLOW_LOCAL_EXTERNAL_DBS=true is now set for the nocodb service; its webhook and data-import SSRF protections are deliberately left enabled. Connect with host postgres, port 5432, user postgres and the POSTGRES_PASSWORD from .env (#106).

Security

  • Supabase - The API gateway host port is now bound to loopback by default (API_GW_HTTP_PORT=127.0.0.1:8000) instead of 0.0.0.0:8000, where it attracted continuous internet-wide scanning for no functional benefit. External access already went through Caddy, which reaches the gateway over the Docker network via the kong alias upstream kept after switching from Kong to Envoy, and host-local tooling on http://localhost:8000 is unaffected. Existing installs are migrated automatically on the next make update or make restart: the new key is force-synced into supabase/docker/.env, which is the file Compose actually interpolates from, and the legacy KONG_HTTP_PORT/KONG_HTTPS_PORT keys are rewritten only when still on their insecure defaults. Set API_GW_HTTP_PORT to a plain port or a LAN address to expose it deliberately. make doctor gains an Exposed Ports section that warns when the gateway binds to all interfaces. Note that Supabase's upstream compose still publishes 0.0.0.0:5432 and 0.0.0.0:6543 for Postgres and the Supavisor pooler, and that Docker's published ports bypass ufw entirely - restrict those at your cloud provider's firewall; see the new Security Notes section in the README (#108).

Upgrade

make update

Existing installations are unchanged unless you opt in. Specifically:

  • Open WebUI stays on SQLite. Only fresh installs get PostgreSQL, because Open WebUI does not migrate data between backends — switching would show an empty interface while your chats stayed in webui.db. See "Open WebUI: SQLite or PostgreSQL" in the README for the backup and migration steps.
  • Ollama still runs one instance. OLLAMA_INSTANCE_COUNT defaults to 1, which generates nothing.
  • n8n-MCP is off until you select it in the wizard.

Two changes do apply automatically:

  • NocoDB gains NC_ALLOW_LOCAL_EXTERNAL_DBS=true, so internal data sources work again. Its webhook and data-import SSRF protections stay on.
  • The Supabase API gateway moves to 127.0.0.1:8000 if you run the supabase profile. Caddy is unaffected. To keep it on all interfaces, set API_GW_HTTP_PORT=0.0.0.0:8000 in .env before updating — an address you set yourself is preserved.

Afterwards, make doctor gains checks for the Open WebUI backend, exposed Supabase ports, the n8n-MCP token and per-instance Ollama containers.

Still exposed after this release

The Supabase profile's supavisor service publishes 0.0.0.0:5432 and 0.0.0.0:6543 from upstream's own compose file, and Docker's published ports bypass ufw entirely. Restrict these at your cloud provider's firewall. The pooler port can be closed by setting POOLER_PROXY_PORT_TRANSACTION=127.0.0.1:6543 in supabase/docker/.env; 5432 cannot, because POSTGRES_PORT is reused as a bare numeric port in Supabase's own connection strings. See the new Security Notes section in the README.

v1.8.2

Choose a tag to compare

@kossakovsky kossakovsky released this 24 Jul 18:54
c9b7b23

Added

  • Ollama — Two more runtime knobs are configurable via .env: OLLAMA_SCHED_SPREAD (set to 1 to spread every model across all GPUs instead of packing each onto one GPU — packing can strand free VRAM on a multi-GPU host until a model fits nowhere and falls back to slow CPU/GPU hybrid execution) and OLLAMA_KEEP_ALIVE (how long an idle model stays in VRAM, e.g. 20m, for faster switching between frequently used models). Both default to empty, so Ollama's stock behavior (spread off, keep-alive 5m) is unchanged for existing installs (#102).

Upgrade

make update

Both variables are added to your .env automatically as empty values, so nothing changes until you opt in. On a multi-GPU host, set OLLAMA_SCHED_SPREAD=1 (and optionally OLLAMA_KEEP_ALIVE=20m) in .env, then run make restart.

Two upstream parsing quirks are worth knowing before you edit .env by hand:

  • OLLAMA_SCHED_SPREAD — use 1 or 0 only. Any other non-empty value is treated as enabled, so off or no would turn it on rather than off.
  • OLLAMA_KEEP_ALIVE — always include a unit. A bare 30 means 30 seconds, not minutes; an unparseable value silently falls back to the 5m default, and a negative value keeps models loaded indefinitely.

OLLAMA_SCHED_SPREAD is a no-op on single-GPU and CPU hosts.

Full Changelog: v1.8.1...v1.8.2

v1.8.1

Choose a tag to compare

@kossakovsky kossakovsky released this 23 Jul 19:53
5920dd6

Added

  • Ollama — Runtime tuning via .env: OLLAMA_MAX_LOADED_MODELS, OLLAMA_NUM_PARALLEL, OLLAMA_GPU_OVERHEAD (in bytes), OLLAMA_CONTEXT_LENGTH and OLLAMA_KV_CACHE_TYPE were hardcoded (or unavailable) in docker-compose.yml and are now configurable, so multi-GPU hosts can keep more models resident and reserve VRAM for other tools sharing a GPU. The previously hardcoded values stay as the stack's defaults, and the two new variables are unset/zero by default so Ollama's stock behavior applies — existing installs are unaffected (#99).
  • Caddyhost.docker.internal now resolves from the Caddy container (via extra_hosts: host-gateway), so custom caddy-addon/site-*.conf entries can reverse-proxy services running on the host machine (#100).

Changed

  • Docs — README now documents the update-safe extension points (caddy-addon/site-*.conf, docker-compose.override.yml, .env), and caddy-addon/README.md gained a reverse-proxy example for stack-external services, including the UFW rule needed for container-to-host traffic. The persistent-Caddy-entries mechanism requested in #100 already existed but was easy to miss (#100).

Upgrade

make update

The new OLLAMA_* variables are added to your .env automatically with behavior-preserving values — edit them and run make restart to tune. To expose a service running outside the stack, drop a site-<name>.conf file into caddy-addon/ (see caddy-addon/README.md); it survives future updates.

Full Changelog: v1.8.0...v1.8.1

v1.8.0

Choose a tag to compare

@kossakovsky kossakovsky released this 20 Jul 20:03
1e8796f

Added

  • Ollama / InvokeAI — Optional GPU pinning for multi-GPU hosts. Set OLLAMA_GPU_DEVICES / INVOKEAI_GPU_DEVICES in .env (e.g. OLLAMA_GPU_DEVICES=1,2) to restrict a service to specific NVIDIA GPU IDs, so different workloads can own different GPUs. When the variable is empty (default), the existing count-based *_GPU_COUNT behavior is unchanged. NVIDIA profiles only; requires Docker Compose v2.24.4+ (#83).

Removed

  • Hermes Agent — Removed from the stack. An infrastructure-management agent should not run inside the environment it manages: it blurs the security boundary and creates a circular dependency. On the next make update, the hermes profile is dropped from COMPOSE_PROFILES and the container is removed automatically; the data directory ./hermes and your HERMES_* values in .env are left untouched so you can redeploy Hermes standalone with your own security model (#88).

Fixed

  • Installermake update no longer silently deletes .env variables that are missing from .env.example. Custom user variables, uncommented opt-ins (e.g. SCARF_ANALYTICS=false), and the telemetry INSTALLATION_ID now survive updates under a # --- Preserved user variables (not in template) --- section (#90).
  • Crawl4AI — Fix the service being unreachable from other containers (n8n got ECONNREFUSED). Crawl4AI 0.9+ binds to 127.0.0.1 unless an API token is set; a CRAWL4AI_API_TOKEN is now auto-generated, so it listens on the Docker network again. Clients must send Authorization: Bearer <token> (token shown on the Welcome Page). make doctor and make restart now warn when the token is missing (#84).
  • Healthchecks — Fix six services being reported unhealthy while running fine: LightRAG, ComfyUI, Appsmith, Gotenberg and Databasus used wget, which does not exist in their images; each now probes with a tool the image actually ships. PaddleOCR probed / (404) and now probes /health (#85).
  • RagFlow — Fix startup crash-loop (nginx: [emerg] open() "/etc/nginx/conf.d/ragflow.conf" failed). The ragflow_data:/ragflow volume masked the application directory with files from an older image; the volume and the obsolete custom nginx config are removed. The old localai_ragflow_data volume is left on disk (reclaim with docker volume rm localai_ragflow_data after a successful start) (#86).
  • python-runner — Fix the default container restart-looping forever. The default script now stays alive with an idle loop, and the service uses init: true + exec so stops are immediate. Custom main.py files are preserved across updates as before (#87).

Upgrade

make update

Hermes users: the service is removed from the stack automatically; your ./hermes data stays on disk for standalone redeployment. Crawl4AI users: after updating, take the new API token from the Welcome Page and add the Authorization: Bearer <token> header to your requests.

Full Changelog: v1.7.2...v1.8.0

v1.7.2

Choose a tag to compare

@kossakovsky kossakovsky released this 13 Jul 21:03
ecfc551

Fixed

  • Ollama / InvokeAI — Fix make update resetting custom multi-GPU setups back to a single GPU. The NVIDIA GPU count was hardcoded as count: 1 in docker-compose.yml, so any manual edit was wiped by the update's git reset. The count is now read from .env (OLLAMA_GPU_COUNT and INVOKEAI_GPU_COUNT, default 1; set a number, e.g. 2, or all to use every available GPU), which survives updates — the variables are added to existing .env files automatically on the next make update (#81).

Upgrade

make update

Multi-GPU users: after updating, set OLLAMA_GPU_COUNT=2 (or all) in .env and run make restart once. The setting now persists across all future updates.

Full Changelog: v1.7.1...v1.7.2

v1.7.1

Choose a tag to compare

@kossakovsky kossakovsky released this 09 Jul 22:19
9817f3e

Changed

  • Project renamed to Selfhost AI — The repository moved from kossakovsky/n8n-install to kossakovsky/selfhost-ai to reflect that the stack has grown well beyond n8n. GitHub redirects all old links and git remotes automatically, so existing installations keep working without changes. On the next make update, remotes still pointing at an old URL are repointed to the new one automatically (protocol preserved; fork remotes are never touched — only remotes targeting the canonical kossakovsky/n8n-install or the project's original name kossakovsky/n8n-installer are rewritten). The installer handles clones under all three directory names.

Fixed

  • Installer — The nested-clone cleanup in install.sh now verifies that the parent directory is actually a copy of this repository before removing anything. Previously, cloning into a same-named plain folder (e.g. ~/selfhost-ai/selfhost-ai) made the installer delete the fresh clone (including .env with generated secrets on re-runs) and exit silently.

Upgrade

make update

Nothing else is required. Existing installations update in place through GitHub's redirect, and the updater repoints your git remote to the new URL automatically (forks are untouched). If you prefer migrating to a fresh clone instead, copy .env and the supabase//dify/ directories from the old checkout — Docker volumes are reused automatically (-p localai), but secrets and external-stack data live in those files.

Full Changelog: v1.7.0...v1.7.1