From 1138929f4d083931305f1f925899971b190562ae Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 9 Jan 2026 12:01:36 +0400 Subject: [PATCH] feat: headless admin creation --- backend/open_webui/env.py | 10 +++++++++ backend/open_webui/main.py | 11 ++++++++++ backend/open_webui/utils/auth.py | 36 ++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/backend/open_webui/env.py b/backend/open_webui/env.py index b934462dc8..d746978c26 100644 --- a/backend/open_webui/env.py +++ b/backend/open_webui/env.py @@ -413,6 +413,16 @@ ENABLE_SIGNUP_PASSWORD_CONFIRMATION = ( os.environ.get("ENABLE_SIGNUP_PASSWORD_CONFIRMATION", "False").lower() == "true" ) +#################################### +# Admin Account Runtime Creation +#################################### + +# Optional env vars for creating an admin account on startup +# Useful for headless/automated deployments +WEBUI_ADMIN_EMAIL = os.environ.get("WEBUI_ADMIN_EMAIL", "") +WEBUI_ADMIN_PASSWORD = os.environ.get("WEBUI_ADMIN_PASSWORD", "") +WEBUI_ADMIN_NAME = os.environ.get("WEBUI_ADMIN_NAME", "Admin") + WEBUI_AUTH_TRUSTED_EMAIL_HEADER = os.environ.get( "WEBUI_AUTH_TRUSTED_EMAIL_HEADER", None ) diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 46a3350021..9b1ae53bed 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -486,6 +486,10 @@ from open_webui.env import ( AIOHTTP_CLIENT_SESSION_SSL, ENABLE_STAR_SESSIONS_MIDDLEWARE, ENABLE_PUBLIC_ACTIVE_USERS_COUNT, + # Admin Account Runtime Creation + WEBUI_ADMIN_EMAIL, + WEBUI_ADMIN_PASSWORD, + WEBUI_ADMIN_NAME, ) @@ -510,6 +514,7 @@ from open_webui.utils.auth import ( decode_token, get_admin_user, get_verified_user, + create_admin_user, ) from open_webui.utils.plugin import install_tool_and_function_dependencies from open_webui.utils.oauth import ( @@ -588,6 +593,12 @@ async def lifespan(app: FastAPI): if LICENSE_KEY: get_license_data(app, LICENSE_KEY) + # Create admin account from env vars if specified and no users exist + if WEBUI_ADMIN_EMAIL and WEBUI_ADMIN_PASSWORD: + if create_admin_user(WEBUI_ADMIN_EMAIL, WEBUI_ADMIN_PASSWORD, WEBUI_ADMIN_NAME): + # Disable signup since we now have an admin + app.state.config.ENABLE_SIGNUP = False + # This should be blocking (sync) so functions are not deactivated on first /get_models calls # when the first user lands on the / route. log.info("Installing external dependencies of functions and tools...") diff --git a/backend/open_webui/utils/auth.py b/backend/open_webui/utils/auth.py index 7301e647bd..133dc3c7f3 100644 --- a/backend/open_webui/utils/auth.py +++ b/backend/open_webui/utils/auth.py @@ -24,6 +24,8 @@ from opentelemetry import trace from open_webui.utils.access_control import has_permission from open_webui.models.users import Users +from open_webui.models.auths import Auths + from open_webui.constants import ERROR_MESSAGES @@ -420,3 +422,37 @@ def get_admin_user(user=Depends(get_current_user)): detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) return user + + +def create_admin_user(email: str, password: str, name: str = "Admin"): + """ + Create an admin user from environment variables. + Used for headless/automated deployments. + Returns the created user or None if creation failed. + """ + + if not email or not password: + return None + + if Users.has_users(): + log.debug("Users already exist, skipping admin creation") + return None + + log.info(f"Creating admin account from environment variables: {email}") + try: + hashed = get_password_hash(password) + user = Auths.insert_new_auth( + email=email.lower(), + password=hashed, + name=name, + role="admin", + ) + if user: + log.info(f"Admin account created successfully: {email}") + return user + else: + log.error("Failed to create admin account from environment variables") + return None + except Exception as e: + log.error(f"Error creating admin account: {e}") + return None