# NousResearch/hermes-agent · Open WebUI first-admin signup race condition fixes

## Open now

- Nothing open on GitHub.

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.

## TL;DR

- 4 member(s): 0 open issue(s), 1 closed issue(s), 0 open PR(s), 1 merged PR(s), 2 PR(s) closed without merging.
- A fix was merged to main in PR #56178. Verify it addresses your case.
- **Recommended:** read PR #56178 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `unresolved`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_SPANNING`): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
- Pairwise link density `0.50`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Closed / duplicate issues

- #36121: OpenWebUI first-admin race when ENABLE_SIGNUP=true (default) + OPEN_WEBUI_HOST=0.0.0.0 (LAN bind)

## Prior & competing PRs

- **#56178: chore(scripts): drop Open WebUI local bootstrap script**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `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:
  - `/dev/null`

    ```diff
    @@ -1,349 +0,0 @@
    -#!/usr/bin/env bash
    -set -euo pipefail
    -
    -# Bootstrap Open WebUI against Hermes Agent's OpenAI-compatible API server.
    -#
    -# Idempotent by design:
    -# - ensures ~/.hermes/.env has API server settings
    -# - installs Open WebUI into ~/.local/open-webui-venv
    -# - writes a reusable launcher at ~/.local/bin/start-open-webui-hermes.sh
    -# - optionally installs a user service (launchd on macOS, systemd --user on Linux)
    -#
    -# Usage:
    -#   bash scripts/setup_open_webui.sh
    -#
    -# Optional environment overrides:
    -#   OPEN_WEBUI_PORT=8080
    -#   OPEN_WEBUI_HOST=127.0.0.1
    -#   OPEN_WEBUI_NAME='Johnny Hermes'
    -#   OPEN_WEBUI_ENABLE_SIGNUP=true
    -#   OPEN_WEBUI_ENABLE_SERVICE=auto   # auto|true|false
    -#   OPEN_WEBUI_VENV=~/.local/open-webui-venv
    -#   OPEN_WEBUI_DATA_DIR=~/.local/share/open-webui/data
    -#   HERMES_API_PORT=8642
    -#   HERMES_API_HOST=127.0.0.1
    -#   HERMES_API_MODEL_NAME='Hermes Agent'
    -
    -OPEN_WEBUI_PORT="${OPEN_WEBUI_PORT:-8080}"
    -OPEN_WEBUI_HOST="${OPEN_WEBUI_HOST:-127.0.0.1}"
    -OPEN_WEBUI_NAME="${OPEN_WEBUI_NAME:-Hermes Agent WebUI}"
    -OPEN_WEBUI_ENABLE_SIGNUP="${OPEN_WEBUI_ENABLE_SIGNUP:-true}"
    -OPEN_WEBUI_ENABLE_SERVICE="${OPEN_WEBUI_ENABLE_SERVICE:-auto}"
    -OPEN_WEBUI_VENV="${OPEN_WEBUI_VENV:-$HOME/.local/open-webui-venv}"
    -OPEN_WEBUI_DATA_DIR="${OPEN_WEBUI_DATA_DIR:-$HOME/.local/share/open-webui/data}"
    -HERMES_ENV_FILE="${HERMES_ENV_FILE:-$HOME/.hermes/.env}"
    -HERMES_API_PORT="${HERMES_API_PORT:-8642}"
    -HERMES_API_HOST="${HERMES_API_HOST:-127.0.0.1}"
    -HERMES_API_CONNECT_HOST="${HERMES_API_CONNECT_HOST:-127.0.0.1}"
    -HERMES_API_MODEL_NAME="${HERMES_API_MODEL_NAME:-Hermes Agent}"
    -HERMES_API_BASE_URL="http://${HERMES_API_CONNECT_HOST}:${HERMES_API_PORT}/v1"
    -LAUNCHER_PATH="$HOME/.local/bin/start-open-webui-hermes.sh"
    -LOG_DIR="$HOME/.hermes/logs"
    -
    -log() {
    -  printf '[open-webui-bootstrap] %s\n' "$*"
    -}
    -
    -require_cmd() {
    -  if ! command -v "$1" >/dev/null 2>&1; then
    -    echo "Missing required command: $1" >&2
    -    exit 1
    -  fi
    -}
    -
    -choose_python() {
    -  if command -v python3.11 >/dev/null 2>&1; then
    -    echo python3.11
    -  elif command -v python3 >/dev/null 2>&1; then
    -    echo python3
    -  else
    -    echo "Python 3 is required." >&2
    -    exit 1
    -  fi
    -}
    -
    -upsert_env() {
    -  local key="$1"
    -  local value="$2"
    -  local file="$3"
    -
    -  mkdir -p "$(dirname "$file")"
    -  touch "$file"
    -
    -  python3 - "$file" "$key" "$value" <<'PY'
    -from pathlib import Path
    -import sys
    -path = Path(sys.argv[1])
    -key = sys.argv[2]
    -value = sys.argv[3]
    -lines = path.read_text().splitlines() if path.exists() else []
    -out = []
    -seen = False
    -for raw in lines:
    -    stripped = raw.strip()
    -    if stripped.startswith(f"{key}="):
    -        if not seen:
    -            out.append(f"{key}={value}")
    -            seen = True
    -        continue
    -    out.append(raw)
    -if not seen:
    -    if out and out[-1] != "":
    -        out.append("")
    -    out.append(f"{key}={value}")
    -path.write_text("\n".join(out).rstrip() + "\n")
    -PY
    -}
    -
    -get_env_value() {
    -  local key="$1"
    -  local file="$2"
    -  python3 - "$file" "$key" <<'PY'
    -from pathlib import Path
    -import sys
    -path = Path(sys.argv[1])
    -key = sys.argv[2]
    -if not path.exists():
    -    raise SystemExit(0)
    -for raw in path.read_text().splitlines():
    -    line = raw.strip()
    -    if line.startswith(f"{key}="):
    -        print(line.split("=", 1)[1])
    -        raise SystemExit(0)
    -PY
    -}
    -
    -generate_secret() {
    -  python3 - <<'PY'
    -import secrets
    -print(secrets.token_urlsafe(32))
    -PY
    -}
    -
    -shell_quote() {
    -  python3 - "$1" <<'PY'
    -import shlex
    -import sys
    -print(shlex.quote(sys.argv[1]))
    -PY
    -}
    -
    -can_use_systemd_user() {
    -  [[ "$(uname -s)" == "Linux" ]] || return 1
    -  command -v systemctl >/dev/null 2>&1 || return 1
    -
    -  local uid runtime_dir bus_path
    -  uid="$(id -u)"
    -  runtime_dir="${XDG_RUNTIME_DIR:-/run/user/$uid}"
    -  bus_path="$runtime_dir/bus"
    -
    -  if [[ -z "${XDG_RUNTIME_DIR:-}" && -d "$runtime_dir" ]]; then
    -    export XDG_RUNTIME_DIR="$runtime_dir"
    -  fi
    -  if [[ -z "${DBUS_SESSION_BUS_ADDRESS:-}" && -S "$bus_path" ]]; then
    -    export DBUS_SESSION_BUS_ADDRESS="unix:path=$bus_path"
    -  fi
    -
    -  systemctl --user show-environment >/dev/null 2>&1
    -}
    -
    -install_macos_dependencies() {
    -  if [[ "$(uname -s)" == "Darwin" ]] && command -v brew >/dev/null 2>&1; then
    -    if ! command -v pandoc >/dev/null 2>&1; then
    -      log 'Installing pandoc with Homebrew (recommended by Open WebUI docs)...'
    -      brew install pandoc
    -    fi
    -  fi
    -}
    -
    -install_open_webui() {
    -  local py
    -  py="$(choose_python)"
    -  log "Using Python interpreter: $py"
    -  "$py" -m venv "$OPEN_WEBUI_VENV"
    -  # shellcheck disable=SC1090
    -  source "$OPEN_WEBUI_VENV/bin/activate"
    -  "$py" -m pip install --upgrade pip setuptools wheel
    -  "$py" -m pip install open-webui
    -}
    -
    -write_launcher() {
    -  mkdir -p "$(dirname "$LAUNCHER_PATH")" "$OPEN_WEBUI_DATA_DIR" "$LOG_DIR"
    -
    -  local quoted_data_dir quoted_name quoted_base_url quoted_host quoted_port quoted_venv
    -  quoted_data_dir="$(shell_quote "$OPEN_WEBUI_DATA_DIR")"
    -  quoted_name="$(shell_quote "$OPEN_WEBUI_NAME")"
    -  quoted_base_url="$(shell_quote "$HERMES_API_BASE_URL")"
    -  quoted_host="$(shell_quote "$OPEN_WEBUI_HOST")"
    -  quoted_port="$(shell_quote "$OPEN_WEBUI_PORT")"
    -  quoted_venv="$(shell_quote "$OPEN_WEBUI_VENV")"
    -
    -  cat > "$LAUNCHER_PATH" <<EOF
    -#!/usr/bin/env bash
    -set -euo pipefail
    -export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
    -API_KEY=[redacted:secret-assignment] - <<'PY'
    -from pathlib import Path
    -p = Path.home()/'.hermes'/'.env'
    -for raw in p.read_text().splitlines():
    -    line = raw.strip()
    -    if line.startswith('API_SERVER_KEY='):
    -        print(line.split('=', 1)[1])
    -        break
    -PY
    -)
    -export DATA_DIR=${quoted_data_dir}
    -export WEBUI_NAME=${quoted_name}
    -export ENABLE_SIGNUP=${OPEN_WEBUI_ENABLE_SIGNUP}
    -export ENABLE_PUBLIC_ACTIVE_USERS_COUNT=False
    -export ENABLE_VERSION_UPDATE_CHECK=False
    -export OPENAI_API_BASE_URL=${quoted_base_url}
    -export OPENAI_API_KEY="[redacted:secret-assignment]"
    -export ENABLE_OPENAI_API=True
    -export ENABLE_OLLAMA_API=False
    -export OFFLINE_MODE=True
    -export BYPASS_EMBEDDING_AND_RETRIEVAL=True
    -export RAG_EMBEDDING_MODEL_AUTO_UPDATE=False
    -export RAG_RERANKING_MODEL_AUTO_UPDATE=False
    -export SCARF_NO_ANALYTICS=true
    -export DO_NOT_TRACK=true
    -export ANONYMIZED_TELEMETRY=false
    -export HOST=${quoted_host}
    -export PORT=${quoted_port}
    -source ${quoted_venv}/bin/activate
    -exec open-webui serve
    -EOF
    -
    -  chmod +x "$LAUNCHER_PATH"
    -}
    -
    -ensure_env_permissions() {
    -  chmod 600 "$HERMES_ENV_FILE" 2>/dev/null || true
    -}
    -
    -install_launchd_service() {
    -  local plist="$HOME/Library/LaunchAgents/ai.openwebui.hermes.plist"
    -  mkdir -p "$(dirname "$plist")"
    -  cat > "$plist" <<EOF
    -<?xml version="1.0" encoding="UTF-8"?>
    -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    -<plist version="1.0">
    -<dict>
    -  <key>Label</key>
    -  <string>ai.openwebui.hermes</string>
    -  <key>ProgramArguments</key>
    -  <array>
    -    <string>/bin/bash</string>
    -    <string>${LAUNCHER_PATH}</string>
    -  </array>
    -  <key>RunAtLoad</key>
    -  <true/>
    -  <key>KeepAlive</key>
    -  <true/>
    -  <key>WorkingDirectory</key>
    -  <string>${HOME}</string>
    -  <key>StandardOutPath</key>
    -  <string>${LOG_DIR}/openwebui.log</string>
    -  <key>StandardErrorPath</key>
    -  <string>${LOG_DIR}/openwebui.error.log</string>
    -</dict>
    -</plist>
    -EOF
    -  launchctl bootout "gui/$(id -u)" "$plist" >/dev/null 2>&1 || true
    -  launchctl bootstrap "gui/$(id -u)" "$plist"
    -  launchctl enable "gui/$(id -u)/ai.openwebui.hermes"
    -  launchctl kickstart -k "gui/$(id -u)/ai.openwebui.hermes"
    -}
    -
    -install_systemd_user_service() {
    -  require_cmd systemctl
    -  local unit_dir="$HOME/.config/systemd/user"
    -  local unit="$unit_dir/openwebui-hermes.service"
    -  mkdir -p "$unit_dir"
    -  cat > "$unit" <<EOF
    -[Unit]
    -Description=Open WebUI connected to Hermes Agent
    -After=default.target
    -
    -[Service]
    -Type=simple
    -ExecStart=/bin/bash %h/.local/bin/start-open-webui-hermes.sh
    -Restart=always
    -RestartSec=3
    -WorkingDirectory=%h
    -StandardOutput=append:%h/.hermes/logs/openwebui.log
    -StandardError=append:%h/.hermes/logs/openwebui.error.log
    -
    -[Install]
    -WantedBy=default.target
    -EOF
    -  systemctl --user daemon-reload
    -  systemctl --user enable --now openwebui-hermes.service
    -}
    -
    -start_foreground_hint() {
    -  log "Launcher created at: ${LAUNCHER_PATH}"
    -  log "Start Open WebUI manually with: ${LAUNCHER_PATH}"
    -}
    -
    -main() {
    -  require_cmd hermes
    -  require_cmd curl
    -  require_cmd python3
    -
    -  install_macos_dependencies
    -
    -  local api_key
    -  api_key="[redacted:secret-assignment] API_SERVER_KEY "$HERMES_ENV_FILE")"
    -  if [[ -z "$api_key" ]]; then
    -    api_key="[redacted:secret-assignment]"
    -  fi
    -
    -  log 'Ensuring Hermes API server is configured...'
    -  upsert_env API_SERVER_ENABLED true "$HERMES_ENV_FILE"
    -  upsert_env API_SERVER_HOST "$HERMES_API_HOST" "$HERMES_ENV_FILE"
    -  upsert_env API_SERVER_PORT "$HERMES_API_PORT" "$HERMES_ENV_FILE"
    -  upsert_env API_SERVER_MODEL_NAME "$HERMES_API_MODEL_NAME" "$HERMES_ENV_FILE"
    -  upsert_env API_SERVER_KEY "$api_key" "$HERMES_ENV_FILE"
    -  ensure_env_permissions
    -
    -  log 'Restarting Hermes gateway so API server settings take effect...'
    -  hermes gateway restart >/dev/null 2>&1 || true
    -  sleep 4
    -  if ! curl -fsS "http://${HERMES_API_CONNECT_HOST}:${HERMES_API_PORT}/health" >/dev/null; then
    -    log 'Hermes API server did not answer on the first check. Trying to start gateway in the background...'
    -    nohup hermes gateway run >/dev/null 2>&1 &
    -    sleep 6
    -  fi
    -  curl -fsS "http://${HERMES_API_CONNECT_HOST}:${HERMES_API_PORT}/health" >/dev/null
    -
    -  log 'Installing Open WebUI into a dedicated virtualenv...'
    -  install_open_webui
    -  write_launcher
    -
    -  case "$OPEN_WEBUI_ENABLE_SERVICE" in
    -    true|auto)
    -      if [[ "$(uname -s)" == "Darwin" ]]; then
    -        install_launchd_service
    -      elif can_use_systemd_user; then
    -        install_systemd_user_service
    -      else
    -        log 'No usable user service manager detected; falling back to the launcher script.'
    -        start_foreground_hint
    -      fi
    -      ;;
    -    false)
    -      start_foreground_hint
    -      ;;
    -    *)
    -      echo "OPEN_WEBUI_ENABLE_SERVICE must be one of: auto, true, false" >&2
    -      exit 1
    -      ;;
    -  esac
    -
    -  log "Done. Open WebUI should be available at: http://${OPEN_WEBUI_HOST}:${OPEN_WEBUI_PORT}"
    -  log "Hermes API endpoint: ${HERMES_API_BASE_URL}"
    -  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.'
    -}
    -
    -main "$@"
    ```
  - `website/docs/user-guide/messaging/open-webui.md`

    ```diff
    @@ -30,44 +30,6 @@ Open WebUI talks to Hermes server-to-server, so you do not need `API_SERVER_CORS
     
     ## Quick Setup
     
    -### One-command local bootstrap (macOS/Linux, no Docker)
    -
    -If you want Hermes + Open WebUI wired together locally with a reusable launcher, run:
    -
    -```bash
    -cd ~/.hermes/hermes-agent
    -bash scripts/setup_open_webui.sh
    -```
    -
    -What the script does:
    -
    -- ensures `~/.hermes/.env` contains `API_SERVER_ENABLED`, `API_SERVER_HOST`, `API_SERVER_KEY`, `API_SERVER_PORT`, and `API_SERVER_MODEL_NAME`
    -- restarts the Hermes gateway so the API server comes up
    -- installs Open WebUI into `~/.local/open-webui-venv`
    -- writes a launcher at `~/.local/bin/start-open-webui-hermes.sh`
    -- on macOS, installs a `launchd` user service; on Linux with `systemd --user`, installs a user service there
    -
    -Defaults:
    -
    -- Hermes API: `http://127.0.0.1:8642/v1`
    -- Open WebUI: `http://127.0.0.1:8080`
    -- model name advertised to Open WebUI: `Hermes Agent`
    -
    -Useful overrides:
    -
    -```bash
    -OPEN_WEBUI_NAME='My Hermes UI' \
    -OPEN_WEBUI_ENABLE_SIGNUP=true \
    -HERMES_API_MODEL_NAME='My Hermes Agent' \
    -bash scripts/setup_open_webui.sh
    -```
    -
    -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:
    -
    -```bash
    -OPEN_WEBUI_ENABLE_SERVICE=false bash scripts/setup_open_webui.sh
    -```
    -
     ### 1. Enable the API server
     
     ```bash
    ```
  - `website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/messaging/open-webui.md`

    ```diff
    @@ -30,44 +30,6 @@ Open WebUI 与 Hermes 之间是服务器到服务器的通信，因此此集成
     
     ## 快速设置
     
    -### 本地一键引导（macOS/Linux，无需 Docker）
    -
    -如果你希望在本地将 Hermes 与 Open WebUI 连接并使用可复用的启动器，请运行：
    -
    -```bash
    -cd ~/.hermes/hermes-agent
    -bash scripts/setup_open_webui.sh
    -```
    -
    -脚本执行内容：
    -
    -- 确保 `~/.hermes/.env` 包含 `API_SERVER_ENABLED`、`API_SERVER_HOST`、`API_SERVER_KEY`、`API_SERVER_PORT` 和 `API_SERVER_MODEL_NAME`
    -- 重启 Hermes gateway 以启动 API 服务器
    -- 将 Open WebUI 安装到 `~/.local/open-webui-venv`
    -- 在 `~/.local/bin/start-open-webui-hermes.sh` 写入启动器
    -- 在 macOS 上安装 `launchd` 用户服务；在支持 `systemd --user` 的 Linux 上安装用户服务
    -
    -默认值：
    -
    -- Hermes API：`http://127.0.0.1:8642/v1`
    -- Open WebUI：`http://127.0.0.1:8080`
    -- 向 Open WebUI 公告的模型名称：`Hermes Agent`
    -
    -常用覆盖参数：
    -
    -```bash
    -OPEN_WEBUI_NAME='My Hermes UI' \
    -OPEN_WEBUI_ENABLE_SIGNUP=true \
    -HERMES_API_MODEL_NAME='My Hermes Agent' \
    -bash scripts/setup_open_webui.sh
    -```
    -
    -在 Linux 上，自动后台服务设置需要可用的 `systemd --user` 会话。如果你在无头 SSH 机器上并希望跳过服务安装，请运行：
    -
    -```bash
    -OPEN_WEBUI_ENABLE_SERVICE=false bash scripts/setup_open_webui.sh
    -```
    -
     ### 1. 启用 API 服务器
     
     ```bash
    ```
- **#36143: fix(scripts): prevent Open WebUI first-admin LAN race (#36121)**. closed without merge
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `#36121`, `#56178`, `#36243`
- **#36243: fix(security): lock down open webui signup bootstrap**. closed without merge
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `#36143`, `#36121`, `#56178`

## Fix status

- Merged to main in PR #56178 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-07-01`.
- Subsystem: `acp_adapter/bootstrap`
