Releases: kossakovsky/selfhost-ai
Release list
v1.12.0
Added
- Open Terminal - New optional
open-terminalprofile (requiresopen-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 generatedOPEN_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 aslim/alpine/openshifttag in that mode because those images ignore it), CPU/memory limits are tunable viaOPEN_TERMINAL_CPU_LIMIT/OPEN_TERMINAL_MEMORY_LIMIT. Egress filtering is left todocker-compose.override.ymlbecause the image reads an emptyOPEN_TERMINAL_ALLOWED_DOMAINSas "block everything" and needsNET_ADMIN. (#117)
Upgrade with make update.
v1.11.0
Added
- n8n Assistant sandbox - New optional
n8n-sandboxprofile that adds n8n's own code-execution sandbox (sandbox-certs,sandbox-api,sandbox-runner-1from 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 showedCode sandbox: Not set. The installer wiresN8N_INSTANCE_AI_SANDBOX_ENABLED, the sandbox URL and key into n8n, generates the three shared secrets, and pointsN8N_INSTANCE_AI_SEARXNG_URLat 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.shinstallssysbox-cenon-interactively without restarting Docker (it pre-seedsbip/default-address-poolsindaemon.jsonwith Docker's current values) and the runner getsruntime: sysbox-runc. When Sysbox cannot be installed the installer asks before falling back to a privileged runner, records the choice inN8N_SANDBOX_RUNNER_RUNTIME/N8N_SANDBOX_RUNNER_PRIVILEGED, andmake doctorwarns while the runner is privileged.N8N_ENABLED_MODULESis exposed (empty by default) for the Agents preview. (#114)
Upgrade with make update.
v1.10.1
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 uidPrometheus; dashboards and alert rules reference the uid, so nothing is lost. Fresh installations were not affected.
Upgrade with make update.
v1.10.0
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_LABELandN8N_METRICS_INCLUDE_WORKFLOW_INFO, which exposen8n_workflow_started/success/failed/cancelled_totalcounters 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 inprometheus/rules/n8n-workflows.ymlthat remember the last non-manual success per workflow for 30 days and follow renames. Four Grafana-managed alert rules are provisioned fromgrafana/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 uidPrometheusthat the dashboards and rules reference (#110).
Fixed
- Monitoring - Prometheus never scraped the n8n workers: the
n8n-workerjob targeted a hostname that does not exist (containers aren8n-worker-1,n8n-worker-2, ...) on the task-broker port 5679 instead of the metrics port 5678.scripts/generate_n8n_workers.shnow writesprometheus/targets/n8n.jsonwith the n8n main target and one target per worker, read by Prometheus viafile_sd_configs, so the target list followsN8N_WORKER_COUNTautomatically. 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-downn8n:5678target.make doctorreports a missing or outdated targets file and a failing recording rule (#110). - Doctor -
make doctorcould never report Grafana or Prometheus as down: the check was gated on a profile named after the container, but both belong to themonitoringprofile. The check now takes the enabling profile explicitly. - n8n -
docker compose buildfailed onn8n/Dockerfile.runnerwith/bin/sh: pnpm: Permission denied(exit code 126). The upstreamn8nio/runners:stableimage rebuilt on 2026-09-02 shipspnpm.cjswithout the execute bit (pnpm 11.22.0), so thepnpm add cheerio axios moment lodashstep 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
Added
- n8n-MCP - New optional service (
n8n-mcpprofile): 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 atn8n-mcp.<domain>behind a generatedN8N_MCP_AUTH_TOKENBearer token. Caddy gates on the same token the service itself validates, because HTTP carries a singleAuthorizationheader 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, setN8N_API_KEYin.envand runmake restartto unlock workflow management. Connect withnpx -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_COUNTin.env(1-8) to runollama2,ollama3, ... alongside the existingollamacontainer, 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 anOLLAMA<N>_prefix (e.g.OLLAMA2_KEEP_ALIVE=-1) and fall back to the global value when unset, taking effect on the nextmake restart.OLLAMA<N>_GPU_DEVICESis the exception: it selects that instance's GPU, defaults to GPU N-1, and does not read the globalOLLAMA_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; usecaddy-addon/site-*.confto expose one externally. The default of1generates nothing, so existing installs are unchanged. SetOLLAMA_GPU_DEVICESas well when running several instances, otherwise the first one is unpinned and may collide withollama2-make doctorwarns 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 lockedfailures 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 inwebui.db. To opt in, setOPEN_WEBUI_DATABASE=postgresin.envand runmake restart; see the README for the required volume backup and the migration tooling. Uploaded files and the vector store stay in theopen-webuivolume 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=trueis now set for the nocodb service; its webhook and data-import SSRF protections are deliberately left enabled. Connect with hostpostgres, port5432, userpostgresand thePOSTGRES_PASSWORDfrom.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 of0.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 thekongalias upstream kept after switching from Kong to Envoy, and host-local tooling onhttp://localhost:8000is unaffected. Existing installs are migrated automatically on the nextmake updateormake restart: the new key is force-synced intosupabase/docker/.env, which is the file Compose actually interpolates from, and the legacyKONG_HTTP_PORT/KONG_HTTPS_PORTkeys are rewritten only when still on their insecure defaults. SetAPI_GW_HTTP_PORTto a plain port or a LAN address to expose it deliberately.make doctorgains an Exposed Ports section that warns when the gateway binds to all interfaces. Note that Supabase's upstream compose still publishes0.0.0.0:5432and0.0.0.0:6543for Postgres and the Supavisor pooler, and that Docker's published ports bypassufwentirely - restrict those at your cloud provider's firewall; see the new Security Notes section in the README (#108).
Upgrade
make updateExisting 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_COUNTdefaults to1, 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:8000if you run thesupabaseprofile. Caddy is unaffected. To keep it on all interfaces, setAPI_GW_HTTP_PORT=0.0.0.0:8000in.envbefore 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
Added
- Ollama — Two more runtime knobs are configurable via
.env:OLLAMA_SCHED_SPREAD(set to1to 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) andOLLAMA_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 updateBoth 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— use1or0only. Any other non-empty value is treated as enabled, sooffornowould turn it on rather than off.OLLAMA_KEEP_ALIVE— always include a unit. A bare30means 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
Added
- Ollama — Runtime tuning via
.env:OLLAMA_MAX_LOADED_MODELS,OLLAMA_NUM_PARALLEL,OLLAMA_GPU_OVERHEAD(in bytes),OLLAMA_CONTEXT_LENGTHandOLLAMA_KV_CACHE_TYPEwere hardcoded (or unavailable) indocker-compose.ymland 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). - Caddy —
host.docker.internalnow resolves from the Caddy container (viaextra_hosts: host-gateway), so customcaddy-addon/site-*.confentries 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), andcaddy-addon/README.mdgained 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 updateThe 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
Added
- Ollama / InvokeAI — Optional GPU pinning for multi-GPU hosts. Set
OLLAMA_GPU_DEVICES/INVOKEAI_GPU_DEVICESin.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_COUNTbehavior 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, thehermesprofile is dropped fromCOMPOSE_PROFILESand the container is removed automatically; the data directory./hermesand yourHERMES_*values in.envare left untouched so you can redeploy Hermes standalone with your own security model (#88).
Fixed
- Installer —
make updateno longer silently deletes.envvariables that are missing from.env.example. Custom user variables, uncommented opt-ins (e.g.SCARF_ANALYTICS=false), and the telemetryINSTALLATION_IDnow 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 to127.0.0.1unless an API token is set; aCRAWL4AI_API_TOKENis now auto-generated, so it listens on the Docker network again. Clients must sendAuthorization: Bearer <token>(token shown on the Welcome Page).make doctorandmake restartnow warn when the token is missing (#84). - Healthchecks — Fix six services being reported
unhealthywhile running fine: LightRAG, ComfyUI, Appsmith, Gotenberg and Databasus usedwget, 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). Theragflow_data:/ragflowvolume masked the application directory with files from an older image; the volume and the obsolete custom nginx config are removed. The oldlocalai_ragflow_datavolume is left on disk (reclaim withdocker volume rm localai_ragflow_dataafter 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+execso stops are immediate. Custommain.pyfiles are preserved across updates as before (#87).
Upgrade
make updateHermes 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
Fixed
- Ollama / InvokeAI — Fix
make updateresetting custom multi-GPU setups back to a single GPU. The NVIDIA GPU count was hardcoded ascount: 1indocker-compose.yml, so any manual edit was wiped by the update's git reset. The count is now read from.env(OLLAMA_GPU_COUNTandINVOKEAI_GPU_COUNT, default1; set a number, e.g.2, orallto use every available GPU), which survives updates — the variables are added to existing.envfiles automatically on the nextmake update(#81).
Upgrade
make updateMulti-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
Changed
- Project renamed to Selfhost AI — The repository moved from
kossakovsky/n8n-installtokossakovsky/selfhost-aito 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 nextmake 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 canonicalkossakovsky/n8n-installor the project's original namekossakovsky/n8n-installerare rewritten). The installer handles clones under all three directory names.
Fixed
- Installer — The nested-clone cleanup in
install.shnow 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.envwith generated secrets on re-runs) and exit silently.
Upgrade
make updateNothing 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