{"repo":"NousResearch/hermes-agent","public_id":"36121","display_label":"Open WebUI first-admin signup race condition fixes","summary":"These items address a race condition in Open WebUI's first-admin bootstrap process when signup is enabled and the service is bound to a LAN-accessible host. Changes include security lockdowns and script modifications to prevent unauthorized account creation during initial setup.","subsystem":"acp_adapter/bootstrap","counts":{"members":4,"open_issues":0,"open_issues_distinct":0,"open_prs":0,"closed_issues":1,"merged_prs":1,"attempt_prs":2},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":56178,"merged_at":"2026-07-01T08:30:41+00:00"},"resolution":{"state":"unresolved","by":null},"freshness":{"state":"verified","last_verified_at":"2026-07-01T08:30:41+00:00","is_stale":false},"grouping":{"backbone":"STRUCTURAL_SPANNING","link_density":0.5},"fix_edges":[{"issue_number":36121,"pr_number":56178,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false,"pr_merged_at":"2026-07-01T08:30:41+00:00"}],"members":[{"kind":"issue","number":36121,"title":"OpenWebUI first-admin race when ENABLE_SIGNUP=true (default) + OPEN_WEBUI_HOST=0.0.0.0 (LAN bind)","url":null,"state":"closed"},{"kind":"pr","number":36143,"title":"fix(scripts): prevent Open WebUI first-admin LAN race (#36121)","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#36121","number":36121},{"kind":"pr","value":"#56178","number":56178},{"kind":"pr","value":"#36243","number":36243}],"category":"superseded_by_pr","implication":"superseded"},"merged":false},{"kind":"pr","number":36243,"title":"fix(security): lock down open webui signup bootstrap","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#36143","number":36143},{"kind":"pr","value":"#36121","number":36121},{"kind":"pr","value":"#56178","number":56178}],"category":"superseded_by_pr","implication":"superseded"},"merged":false},{"kind":"pr","number":56178,"title":"chore(scripts): drop Open WebUI local bootstrap script","url":null,"state":"merged","close_reason":{"category":"merged"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["scripts/setup_open_webui.sh","website/docs/user-guide/messaging/open-webui.md","website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/messaging/open-webui.md"],"fix_hunks":[{"file":"/dev/null","hunks":["@@ -1,349 +0,0 @@\n-#!/usr/bin/env bash\n-set -euo pipefail\n-\n-# Bootstrap Open WebUI against Hermes Agent's OpenAI-compatible API server.\n-#\n-# Idempotent by design:\n-# - ensures ~/.hermes/.env has API server settings\n-# - installs Open WebUI into ~/.local/open-webui-venv\n-# - writes a reusable launcher at ~/.local/bin/start-open-webui-hermes.sh\n-# - optionally installs a user service (launchd on macOS, systemd --user on Linux)\n-#\n-# Usage:\n-#   bash scripts/setup_open_webui.sh\n-#\n-# Optional environment overrides:\n-#   OPEN_WEBUI_PORT=8080\n-#   OPEN_WEBUI_HOST=127.0.0.1\n-#   OPEN_WEBUI_NAME='Johnny Hermes'\n-#   OPEN_WEBUI_ENABLE_SIGNUP=true\n-#   OPEN_WEBUI_ENABLE_SERVICE=auto   # auto|true|false\n-#   OPEN_WEBUI_VENV=~/.local/open-webui-venv\n-#   OPEN_WEBUI_DATA_DIR=~/.local/share/open-webui/data\n-#   HERMES_API_PORT=8642\n-#   HERMES_API_HOST=127.0.0.1\n-#   HERMES_API_MODEL_NAME='Hermes Agent'\n-\n-OPEN_WEBUI_PORT=\"${OPEN_WEBUI_PORT:-8080}\"\n-OPEN_WEBUI_HOST=\"${OPEN_WEBUI_HOST:-127.0.0.1}\"\n-OPEN_WEBUI_NAME=\"${OPEN_WEBUI_NAME:-Hermes Agent WebUI}\"\n-OPEN_WEBUI_ENABLE_SIGNUP=\"${OPEN_WEBUI_ENABLE_SIGNUP:-true}\"\n-OPEN_WEBUI_ENABLE_SERVICE=\"${OPEN_WEBUI_ENABLE_SERVICE:-auto}\"\n-OPEN_WEBUI_VENV=\"${OPEN_WEBUI_VENV:-$HOME/.local/open-webui-venv}\"\n-OPEN_WEBUI_DATA_DIR=\"${OPEN_WEBUI_DATA_DIR:-$HOME/.local/share/open-webui/data}\"\n-HERMES_ENV_FILE=\"${HERMES_ENV_FILE:-$HOME/.hermes/.env}\"\n-HERMES_API_PORT=\"${HERMES_API_PORT:-8642}\"\n-HERMES_API_HOST=\"${HERMES_API_HOST:-127.0.0.1}\"\n-HERMES_API_CONNECT_HOST=\"${HERMES_API_CONNECT_HOST:-127.0.0.1}\"\n-HERMES_API_MODEL_NAME=\"${HERMES_API_MODEL_NAME:-Hermes Agent}\"\n-HERMES_API_BASE_URL=\"http://${HERMES_API_CONNECT_HOST}:${HERMES_API_PORT}/v1\"\n-LAUNCHER_PATH=\"$HOME/.local/bin/start-open-webui-hermes.sh\"\n-LOG_DIR=\"$HOME/.hermes/logs\"\n-\n-log() {\n-  printf '[open-webui-bootstrap] %s\\n' \"$*\"\n-}\n-\n-require_cmd() {\n-  if ! command -v \"$1\" >/dev/null 2>&1; then\n-    echo \"Missing required command: $1\" >&2\n-    exit 1\n-  fi\n-}\n-\n-choose_python() {\n-  if command -v python3.11 >/dev/null 2>&1; then\n-    echo python3.11\n-  elif command -v python3 >/dev/null 2>&1; then\n-    echo python3\n-  else\n-    echo \"Python 3 is required.\" >&2\n-    exit 1\n-  fi\n-}\n-\n-upsert_env() {\n-  local key=\"$1\"\n-  local value=\"$2\"\n-  local file=\"$3\"\n-\n-  mkdir -p \"$(dirname \"$file\")\"\n-  touch \"$file\"\n-\n-  python3 - \"$file\" \"$key\" \"$value\" <<'PY'\n-from pathlib import Path\n-import sys\n-path = Path(sys.argv[1])\n-key = sys.argv[2]\n-value = sys.argv[3]\n-lines = path.read_text().splitlines() if path.exists() else []\n-out = []\n-seen = False\n-for raw in lines:\n-    stripped = raw.strip()\n-    if stripped.startswith(f\"{key}=\"):\n-        if not seen:\n-            out.append(f\"{key}={value}\")\n-            seen = True\n-        continue\n-    out.append(raw)\n-if not seen:\n-    if out and out[-1] != \"\":\n-        out.append(\"\")\n-    out.append(f\"{key}={value}\")\n-path.write_text(\"\\n\".join(out).rstrip() + \"\\n\")\n-PY\n-}\n-\n-get_env_value() {\n-  local key=\"$1\"\n-  local file=\"$2\"\n-  python3 - \"$file\" \"$key\" <<'PY'\n-from pathlib import Path\n-import sys\n-path = Path(sys.argv[1])\n-key = sys.argv[2]\n-if not path.exists():\n-    raise SystemExit(0)\n-for raw in path.read_text().splitlines():\n-    line = raw.strip()\n-    if line.startswith(f\"{key}=\"):\n-        print(line.split(\"=\", 1)[1])\n-        raise SystemExit(0)\n-PY\n-}\n-\n-generate_secret() {\n-  python3 - <<'PY'\n-import secrets\n-print(secrets.token_urlsafe(32))\n-PY\n-}\n-\n-shell_quote() {\n-  python3 - \"$1\" <<'PY'\n-import shlex\n-import sys\n-print(shlex.quote(sys.argv[1]))\n-PY\n-}\n-\n-can_use_systemd_user() {\n-  [[ \"$(uname -s)\" == \"Linux\" ]] || return 1\n-  command -v systemctl >/dev/null 2>&1 || return 1\n-\n-  local uid runtime_dir bus_path\n-  uid=\"$(id -u)\"\n-  runtime_dir=\"${XDG_RUNTIME_DIR:-/run/user/$uid}\"\n-  bus_path=\"$runtime_dir/bus\"\n-\n-  if [[ -z \"${XDG_RUNTIME_DIR:-}\" && -d \"$runtime_dir\" ]]; then\n-    export XDG_RUNTIME_DIR=\"$runtime_dir\"\n-  fi\n-  if [[ -z \"${DBUS_SESSION_BUS_ADDRESS:-}\" && -S \"$bus_path\" ]]; then\n-    export DBUS_SESSION_BUS_ADDRESS=\"unix:path=$bus_path\"\n-  fi\n-\n-  systemctl --user show-environment >/dev/null 2>&1\n-}\n-\n-install_macos_dependencies() {\n-  if [[ \"$(uname -s)\" == \"Darwin\" ]] && command -v brew >/dev/null 2>&1; then\n-    if ! command -v pandoc >/dev/null 2>&1; then\n-      log 'Installing pandoc with Homebrew (recommended by Open WebUI docs)...'\n-      brew install pandoc\n-    fi\n-  fi\n-}\n-\n-install_open_webui() {\n-  local py\n-  py=\"$(choose_python)\"\n-  log \"Using Python interpreter: $py\"\n-  \"$py\" -m venv \"$OPEN_WEBUI_VENV\"\n-  # shellcheck disable=SC1090\n-  source \"$OPEN_WEBUI_VENV/bin/activate\"\n-  \"$py\" -m pip install --upgrade pip setuptools wheel\n-  \"$py\" -m pip install open-webui\n-}\n-\n-write_launcher() {\n-  mkdir -p \"$(dirname \"$LAUNCHER_PATH\")\" \"$OPEN_WEBUI_DATA_DIR\" \"$LOG_DIR\"\n-\n-  local quoted_data_dir quoted_name quoted_base_url quoted_host quoted_port quoted_venv\n-  quoted_data_dir=\"$(shell_quote \"$OPEN_WEBUI_DATA_DIR\")\"\n-  quoted_name=\"$(shell_quote \"$OPEN_WEBUI_NAME\")\"\n-  quoted_base_url=\"$(shell_quote \"$HERMES_API_BASE_URL\")\"\n-  quoted_host=\"$(shell_quote \"$OPEN_WEBUI_HOST\")\"\n-  quoted_port=\"$(shell_quote \"$OPEN_WEBUI_PORT\")\"\n-  quoted_venv=\"$(shell_quote \"$OPEN_WEBUI_VENV\")\"\n-\n-  cat > \"$LAUNCHER_PATH\" <<EOF\n-#!/usr/bin/env bash\n-set -euo pipefail\n-export PATH=\"/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\"\n-API_KEY=[redacted:secret-assignment] - <<'PY'\n-from pathlib import Path\n-p = Path.home()/'.hermes'/'.env'\n-for raw in p.read_text().splitlines():\n-    line = raw.strip()\n-    if line.startswith('API_SERVER_KEY='):\n-        print(line.split('=', 1)[1])\n-        break\n-PY\n-)\n-export DATA_DIR=${quoted_data_dir}\n-export WEBUI_NAME=${quoted_name}\n-export ENABLE_SIGNUP=${OPEN_WEBUI_ENABLE_SIGNUP}\n-export ENABLE_PUBLIC_ACTIVE_USERS_COUNT=False\n-export ENABLE_VERSION_UPDATE_CHECK=False\n-export OPENAI_API_BASE_URL=${quoted_base_url}\n-export OPENAI_API_KEY=\"[redacted:secret-assignment]\"\n-export ENABLE_OPENAI_API=True\n-export ENABLE_OLLAMA_API=False\n-export OFFLINE_MODE=True\n-export BYPASS_EMBEDDING_AND_RETRIEVAL=True\n-export RAG_EMBEDDING_MODEL_AUTO_UPDATE=False\n-export RAG_RERANKING_MODEL_AUTO_UPDATE=False\n-export SCARF_NO_ANALYTICS=true\n-export DO_NOT_TRACK=true\n-export ANONYMIZED_TELEMETRY=false\n-export HOST=${quoted_host}\n-export PORT=${quoted_port}\n-source ${quoted_venv}/bin/activate\n-exec open-webui serve\n-EOF\n-\n-  chmod +x \"$LAUNCHER_PATH\"\n-}\n-\n-ensure_env_permissions() {\n-  chmod 600 \"$HERMES_ENV_FILE\" 2>/dev/null || true\n-}\n-\n-install_launchd_service() {\n-  local plist=\"$HOME/Library/LaunchAgents/ai.openwebui.hermes.plist\"\n-  mkdir -p \"$(dirname \"$plist\")\"\n-  cat > \"$plist\" <<EOF\n-<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n-<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n-<plist version=\"1.0\">\n-<dict>\n-  <key>Label</key>\n-  <string>ai.openwebui.hermes</string>\n-  <key>ProgramArguments</key>\n-  <array>\n-    <string>/bin/bash</string>\n-    <string>${LAUNCHER_PATH}</string>\n-  </array>\n-  <key>RunAtLoad</key>\n-  <true/>\n-  <key>KeepAlive</key>\n-  <true/>\n-  <key>WorkingDirectory</key>\n-  <string>${HOME}</string>\n-  <key>StandardOutPath</key>\n-  <string>${LOG_DIR}/openwebui.log</string>\n-  <key>StandardErrorPath</key>\n-  <string>${LOG_DIR}/openwebui.error.log</string>\n-</dict>\n-</plist>\n-EOF\n-  launchctl bootout \"gui/$(id -u)\" \"$plist\" >/dev/null 2>&1 || true\n-  launchctl bootstrap \"gui/$(id -u)\" \"$plist\"\n-  launchctl enable \"gui/$(id -u)/ai.openwebui.hermes\"\n-  launchctl kickstart -k \"gui/$(id -u)/ai.openwebui.hermes\"\n-}\n-\n-install_systemd_user_service() {\n-  require_cmd systemctl\n-  local unit_dir=\"$HOME/.config/systemd/user\"\n-  local unit=\"$unit_dir/openwebui-hermes.service\"\n-  mkdir -p \"$unit_dir\"\n-  cat > \"$unit\" <<EOF\n-[Unit]\n-Description=Open WebUI connected to Hermes Agent\n-After=default.target\n-\n-[Service]\n-Type=simple\n-ExecStart=/bin/bash %h/.local/bin/start-open-webui-hermes.sh\n-Restart=always\n-RestartSec=3\n-WorkingDirectory=%h\n-StandardOutput=append:%h/.hermes/logs/openwebui.log\n-StandardError=append:%h/.hermes/logs/openwebui.error.log\n-\n-[Install]\n-WantedBy=default.target\n-EOF\n-  systemctl --user daemon-reload\n-  systemctl --user enable --now openwebui-hermes.service\n-}\n-\n-start_foreground_hint() {\n-  log \"Launcher created at: ${LAUNCHER_PATH}\"\n-  log \"Start Open WebUI manually with: ${LAUNCHER_PATH}\"\n-}\n-\n-main() {\n-  require_cmd hermes\n-  require_cmd curl\n-  require_cmd python3\n-\n-  install_macos_dependencies\n-\n-  local api_key\n-  api_key=\"[redacted:secret-assignment] API_SERVER_KEY \"$HERMES_ENV_FILE\")\"\n-  if [[ -z \"$api_key\" ]]; then\n-    api_key=\"[redacted:secret-assignment]\"\n-  fi\n-\n-  log 'Ensuring Hermes API server is configured...'\n-  upsert_env API_SERVER_ENABLED true \"$HERMES_ENV_FILE\"\n-  upsert_env API_SERVER_HOST \"$HERMES_API_HOST\" \"$HERMES_ENV_FILE\"\n-  upsert_env API_SERVER_PORT \"$HERMES_API_PORT\" \"$HERMES_ENV_FILE\"\n-  upsert_env API_SERVER_MODEL_NAME \"$HERMES_API_MODEL_NAME\" \"$HERMES_ENV_FILE\"\n-  upsert_env API_SERVER_KEY \"$api_key\" \"$HERMES_ENV_FILE\"\n-  ensure_env_permissions\n-\n-  log 'Restarting Hermes gateway so API server settings take effect...'\n-  hermes gateway restart >/dev/null 2>&1 || true\n-  sleep 4\n-  if ! curl -fsS \"http://${HERMES_API_CONNECT_HOST}:${HERMES_API_PORT}/health\" >/dev/null; then\n-    log 'Hermes API server did not answer on the first check. Trying to start gateway in the background...'\n-    nohup hermes gateway run >/dev/null 2>&1 &\n-    sleep 6\n-  fi\n-  curl -fsS \"http://${HERMES_API_CONNECT_HOST}:${HERMES_API_PORT}/health\" >/dev/null\n-\n-  log 'Installing Open WebUI into a dedicated virtualenv...'\n-  install_open_webui\n-  write_launcher\n-\n-  case \"$OPEN_WEBUI_ENABLE_SERVICE\" in\n-    true|auto)\n-      if [[ \"$(uname -s)\" == \"Darwin\" ]]; then\n-        install_launchd_service\n-      elif can_use_systemd_user; then\n-        install_systemd_user_service\n-      else\n-        log 'No usable user service manager detected; falling back to the launcher script.'\n-        start_foreground_hint\n-      fi\n-      ;;\n-    false)\n-      start_foreground_hint\n-      ;;\n-    *)\n-      echo \"OPEN_WEBUI_ENABLE_SERVICE must be one of: auto, true, false\" >&2\n-      exit 1\n-      ;;\n-  esac\n-\n-  log \"Done. Open WebUI should be available at: http://${OPEN_WEBUI_HOST}:${OPEN_WEBUI_PORT}\"\n-  log \"Hermes API endpoint: ${HERMES_API_BASE_URL}\"\n-  log 'Important: Open WebUI persists connection settings after first launch. If you later save a wrong API key in the Admin UI, update/delete that connection there or reset its database.'\n-}\n-\n-main \"$@\""]},{"file":"website/docs/user-guide/messaging/open-webui.md","hunks":["@@ -30,44 +30,6 @@ Open WebUI talks to Hermes server-to-server, so you do not need `API_SERVER_CORS\n \n ## Quick Setup\n \n-### One-command local bootstrap (macOS/Linux, no Docker)\n-\n-If you want Hermes + Open WebUI wired together locally with a reusable launcher, run:\n-\n-```bash\n-cd ~/.hermes/hermes-agent\n-bash scripts/setup_open_webui.sh\n-```\n-\n-What the script does:\n-\n-- ensures `~/.hermes/.env` contains `API_SERVER_ENABLED`, `API_SERVER_HOST`, `API_SERVER_KEY`, `API_SERVER_PORT`, and `API_SERVER_MODEL_NAME`\n-- restarts the Hermes gateway so the API server comes up\n-- installs Open WebUI into `~/.local/open-webui-venv`\n-- writes a launcher at `~/.local/bin/start-open-webui-hermes.sh`\n-- on macOS, installs a `launchd` user service; on Linux with `systemd --user`, installs a user service there\n-\n-Defaults:\n-\n-- Hermes API: `http://127.0.0.1:8642/v1`\n-- Open WebUI: `http://127.0.0.1:8080`\n-- model name advertised to Open WebUI: `Hermes Agent`\n-\n-Useful overrides:\n-\n-```bash\n-OPEN_WEBUI_NAME='My Hermes UI' \\\n-OPEN_WEBUI_ENABLE_SIGNUP=true \\\n-HERMES_API_MODEL_NAME='My Hermes Agent' \\\n-bash scripts/setup_open_webui.sh\n-```\n-\n-On Linux, automatic background service setup requires a working `systemd --user` session. If you are on a headless SSH box and want to skip service installation, run:\n-\n-```bash\n-OPEN_WEBUI_ENABLE_SERVICE=false bash scripts/setup_open_webui.sh\n-```\n-\n ### 1. Enable the API server\n \n ```bash"]},{"file":"website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/messaging/open-webui.md","hunks":["@@ -30,44 +30,6 @@ Open WebUI 与 Hermes 之间是服务器到服务器的通信，因此此集成\n \n ## 快速设置\n \n-### 本地一键引导（macOS/Linux，无需 Docker）\n-\n-如果你希望在本地将 Hermes 与 Open WebUI 连接并使用可复用的启动器，请运行：\n-\n-```bash\n-cd ~/.hermes/hermes-agent\n-bash scripts/setup_open_webui.sh\n-```\n-\n-脚本执行内容：\n-\n-- 确保 `~/.hermes/.env` 包含 `API_SERVER_ENABLED`、`API_SERVER_HOST`、`API_SERVER_KEY`、`API_SERVER_PORT` 和 `API_SERVER_MODEL_NAME`\n-- 重启 Hermes gateway 以启动 API 服务器\n-- 将 Open WebUI 安装到 `~/.local/open-webui-venv`\n-- 在 `~/.local/bin/start-open-webui-hermes.sh` 写入启动器\n-- 在 macOS 上安装 `launchd` 用户服务；在支持 `systemd --user` 的 Linux 上安装用户服务\n-\n-默认值：\n-\n-- Hermes API：`http://127.0.0.1:8642/v1`\n-- Open WebUI：`http://127.0.0.1:8080`\n-- 向 Open WebUI 公告的模型名称：`Hermes Agent`\n-\n-常用覆盖参数：\n-\n-```bash\n-OPEN_WEBUI_NAME='My Hermes UI' \\\n-OPEN_WEBUI_ENABLE_SIGNUP=true \\\n-HERMES_API_MODEL_NAME='My Hermes Agent' \\\n-bash scripts/setup_open_webui.sh\n-```\n-\n-在 Linux 上，自动后台服务设置需要可用的 `systemd --user` 会话。如果你在无头 SSH 机器上并希望跳过服务安装，请运行：\n-\n-```bash\n-OPEN_WEBUI_ENABLE_SERVICE=false bash scripts/setup_open_webui.sh\n-```\n-\n ### 1. 启用 API 服务器\n \n ```bash\n"]}]}],"trust":{"default_tier":"verified","includes_suggested":false}}