NousResearch/hermes-agent

Open WebUI first-admin signup race condition fixes

Cluster 36121 · acp adapter/bootstrap. Data as of

Nothing open on GitHub. Fix merged in #56178 on 1 Jul 2026. Check it covers your case.

The short answer

0open issues
0open PRs
4items grouped
Known?
Yes. 4 related items grouped here, 1 issue already closed.
Fix event
A fix was merged to main in PR #56178. Check it covers your case. No release data is tracked.
Tracker
The maintainers' tracker marks this unresolved. That is separate from the fix event.
Still open
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.

Open issues0

No open issues.

Open PRs0

No open pull requests.

Fixes on record

Merged to main. A stamp counts the issues a fix is linked to.

  • #56178 chore(scripts): drop Open WebUI local bootstrap script

    merged to main

    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

    Show the diff
    • /dev/null
      @@ -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
      @@ -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
      @@ -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

2 PRs closed without merging

From the close comments: superseded by another PR 2

  • #36143 fix(scripts): prevent Open WebUI first-admin LAN race (#36121) · superseded by another PR → #36121, #56178, #36243
  • #36243 fix(security): lock down open webui signup bootstrap · superseded by another PR → #36143, #36121, #56178
Closed issues · 1
  • Closed#36121OpenWebUI first-admin race when ENABLE_SIGNUP=true (default) + OPEN_WEBUI_HOST=0.0.0.0 (LAN bind)
How this cluster was grouped
  • Link evidence (structural links throughout): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
  • Pairwise link density 0.50: the share of item 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.

Pick up a Lab task

Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.

Open the Lab

At a glance

Subsystem
acp adapter/bootstrap
Merged PRs
#56178
Closed issues
1
Attempts
2 PRs closed without merging
Fix link checked
1 Jul 2026

For your agent

The same facts, typed.