Skip to main content

Hardening Open WebUI

Open WebUI is a self-hosted application built for private, trusted networks. It gives authenticated users access to powerful capabilities including model inference, tool execution, and code pipelines. The security model assumes that anyone who can reach the instance has been intentionally granted access by an administrator.

This guide covers the configuration options available for hardening your deployment. Each section explains what a setting does, what the default is, and how to change it. It is not an exhaustive security guide, and securing your deployment is ultimately your responsibility. Your environment and threat model will determine which of these are relevant to you.

Network Placement

Open WebUI is built for private, trusted networks. While it can be made accessible over the public internet, doing so means relying solely on application-level authentication to protect access to your models, tools, and data. If you do expose it publicly, at minimum you should place it behind a VPN (WireGuard, Tailscale), a zero-trust proxy (Cloudflare Access, Pomerium), or a reverse proxy with authentication and IP allowlisting.

DDoS protection and brute-force prevention (rate limiting on login endpoints, connection throttling, fail2ban) should also be handled at the proxy or network layer.

If you are deploying Open WebUI for the first time, start with the Quick Reference at the bottom of this page for a prioritized summary, then read the sections relevant to your setup.


Secret Key

The WEBUI_SECRET_KEY is used to sign JWTs (login tokens) and derive encryption keys for OAuth session data.

How the default works:

When running via Docker (start.sh) or open-webui serve, the application checks whether WEBUI_SECRET_KEY is set as an environment variable. If it is not, a random key is generated automatically and saved to .webui_secret_key inside the data directory. On subsequent restarts, the saved key is reloaded. This means that for single-instance deployments, no manual configuration is needed.

When you need to set it explicitly:

If you run multiple Open WebUI instances behind a load balancer, every instance must share the same key. Otherwise, a token signed by one instance will be rejected by another, causing login failures. Generate a key with openssl rand -base64 32 and pass it as an environment variable to all replicas.

Rotation: Changing the key invalidates all existing sessions. Users will need to sign in again.


Authentication and Signup

Registration

By default, signup is open and the first user to register becomes the administrator. After your admin account exists, you can control registration:

# Disable new signups entirely
ENABLE_SIGNUP=false

If you want to allow signups but require manual approval, leave signups enabled and rely on the default user role:

# New users are placed in "pending" status until an admin approves them (this is the default)
DEFAULT_USER_ROLE=pending

Password validation

Open WebUI does not enforce password complexity by default. To enable it:

ENABLE_PASSWORD_VALIDATION=true
PASSWORD_VALIDATION_REGEX_PATTERN='^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\w\s]).{8,}$'
PASSWORD_VALIDATION_HINT='Minimum 8 characters with uppercase, lowercase, number, and special character.'

Passwords are hashed with bcrypt before storage. Bcrypt truncates inputs at 72 bytes, and Open WebUI enforces this limit.

Admin account from environment variables

For automated deployments, you can create the admin account at startup:

WEBUI_ADMIN_EMAIL=admin@yourcompany.com
WEBUI_ADMIN_PASSWORD=your-strong-password
WEBUI_ADMIN_NAME=Admin

This only takes effect when no users exist in the database. Once the admin is created, signup is automatically disabled.

SSO-only environments

If all authentication is handled by an OAuth/OIDC provider, you can hide the local login form entirely:

ENABLE_LOGIN_FORM=false

This removes the email/password form from the UI, steering all users through your SSO flow. You can also disable local password authentication at the backend level:

ENABLE_PASSWORD_AUTH=false

When serving Open WebUI over HTTPS (see HTTPS Configuration), configure cookies accordingly:

WEBUI_SESSION_COOKIE_SECURE=true
WEBUI_SESSION_COOKIE_SAME_SITE=strict
VariableDefaultWhat it does
WEBUI_SESSION_COOKIE_SECUREfalseWhen true, cookies are only sent over HTTPS connections.
WEBUI_SESSION_COOKIE_SAME_SITElaxControls whether cookies are sent with cross-site requests. strict offers the most protection.

These also apply to OAuth cookies unless overridden with WEBUI_AUTH_COOKIE_SECURE and WEBUI_AUTH_COOKIE_SAME_SITE.

Token expiry

JWTs control how long a user stays logged in. The default is 4w (4 weeks). You can shorten this:

JWT_EXPIRES_IN=24h

Setting JWT_EXPIRES_IN=-1 disables token expiration entirely. Open WebUI will log a warning if this is set.

Token revocation

With Redis configured, Open WebUI supports per-token revocation. When a user signs out, their token is added to a revocation list that auto-expires. Without Redis, tokens remain valid until they expire naturally.


CORS

Cross-Origin Resource Sharing (CORS) controls which websites can make requests to your Open WebUI API from a browser. For example, if your Open WebUI instance is at https://chat.yourcompany.com, CORS determines whether a script running on a different domain can interact with it.

The default CORS_ALLOW_ORIGIN is *, which allows any origin. Open WebUI logs a warning at startup when this is the case.

To restrict it to your domain:

CORS_ALLOW_ORIGIN=https://chat.yourcompany.com

Multiple origins are separated with semicolons:

CORS_ALLOW_ORIGIN=https://chat.yourcompany.com;https://internal.yourcompany.com

If you use a desktop app with a custom URL scheme, add it via:

CORS_ALLOW_CUSTOM_SCHEME=app

Security Headers

Open WebUI includes a SecurityHeadersMiddleware that injects HTTP security headers into responses. None are set by default, so you opt in to each one via environment variables.

The following is a recommended starting configuration for production deployments:

# HTTP Strict Transport Security: tells browsers to only use HTTPS
HSTS=max-age=31536000;includeSubDomains

# Prevents the page from being embedded in iframes on other sites
XFRAME_OPTIONS=DENY

# Prevents browsers from MIME-type sniffing
XCONTENT_TYPE=nosniff

# Controls how much referrer information is sent with requests
REFERRER_POLICY=strict-origin-when-cross-origin

# Restricts access to browser features
PERMISSIONS_POLICY=camera=(),microphone=(),geolocation=()

# Content Security Policy
CONTENT_SECURITY_POLICY=default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'
tip

If you set a Content Security Policy, start permissive and tighten incrementally. An overly strict CSP will break the frontend. Browser dev tools will show you which resources are being blocked.


HTTPS and TLS

Open WebUI does not terminate TLS itself. Place it behind a reverse proxy (Nginx, Caddy, HAProxy) that handles HTTPS. See the HTTPS Reference for step-by-step proxy configurations.

Once HTTPS is in place:

WEBUI_SESSION_COOKIE_SECURE=true
HSTS=max-age=31536000;includeSubDomains

Trusted proxy IPs

Open WebUI uses --forwarded-allow-ips to determine which proxies are trusted to send X-Forwarded-For headers. By default, this is set to * (trust all), which is appropriate when Open WebUI is on an isolated network behind a single reverse proxy. If your network topology is more complex, restrict it to your proxy's IP:

FORWARDED_ALLOW_IPS=192.168.1.100

OAuth and SSO

If you use an OAuth/OIDC provider for authentication, several options help you control access.

Domain and group restrictions

# Only allow users with email addresses from specific domains
OAUTH_ALLOWED_DOMAINS=yourcompany.com

# Block specific IdP groups
OAUTH_BLOCKED_GROUPS='["contractors-external", "temp-accounts"]'

Role mapping

Map IdP roles to Open WebUI roles so access is managed at the identity provider:

ENABLE_OAUTH_ROLE_MANAGEMENT=true
OAUTH_ROLES_CLAIM=roles
OAUTH_ADMIN_ROLES=admin,superadmin
OAUTH_ALLOWED_ROLES=user,admin,superadmin

Account merging

OAUTH_MERGE_ACCOUNTS_BY_EMAIL=false

When enabled, an OAuth login with an email matching an existing local account will merge the two. This is convenient but depends on your OAuth provider reliably verifying email addresses. If your provider does not guarantee email verification, a user who controls a matching email could gain access to the existing account.

Session limits

# Maximum concurrent OAuth sessions per user per provider (default: 10)
OAUTH_MAX_SESSIONS_PER_USER=5

# Enable IdP-initiated back-channel logout (requires Redis)
ENABLE_OAUTH_BACKCHANNEL_LOGOUT=true

Trusted Header Authentication

If your reverse proxy handles authentication (Authelia, Authentik, oauth2-proxy), you can pass the authenticated identity to Open WebUI via HTTP headers:

WEBUI_AUTH_TRUSTED_EMAIL_HEADER=X-Forwarded-Email
WEBUI_AUTH_TRUSTED_NAME_HEADER=X-Forwarded-Name
warning

When using trusted headers, your proxy must strip these headers from incoming client requests before injecting its own values. If the proxy does not strip them, any client can send a forged header and authenticate as any user. This is the most common misconfiguration with trusted header auth. Consult your proxy's documentation for how to strip upstream headers.


LDAP

When using LDAP for authentication, enable TLS to protect credentials in transit:

ENABLE_LDAP=true
LDAP_USE_TLS=true
LDAP_VALIDATE_CERT=true
LDAP_CA_CERT_FILE=/path/to/ca-cert.pem

Without TLS, LDAP credentials are transmitted in plaintext. You can restrict cipher suites with LDAP_CIPHERS if needed.


Database

PostgreSQL

For production deployments, PostgreSQL provides better concurrency and reliability than the default SQLite:

DATABASE_URL=postgresql://user:password@db-host:5432/openwebui

See the Scaling Guide for migration details. Use strong, unique credentials and keep the database on an internal network.

SQLCipher

For SQLite deployments that need encryption at rest, Open WebUI supports SQLCipher:

DATABASE_TYPE=sqlite+sqlcipher

Connection pool tuning

For PostgreSQL, tune the connection pool to match your usage:

DATABASE_POOL_SIZE=15
DATABASE_POOL_MAX_OVERFLOW=20
DATABASE_POOL_TIMEOUT=30
DATABASE_POOL_RECYCLE=3600

Total connections across your deployment = pool size x number of instances. Keep this below your PostgreSQL max_connections limit (default 100).


API Keys

API keys provide programmatic access to Open WebUI with the same permissions as the user who created them.

# Enable API key creation (default: disabled for non-admin users)
ENABLE_API_KEYS=true

Endpoint restrictions

You can limit which API routes a key is allowed to call:

ENABLE_API_KEYS_ENDPOINT_RESTRICTIONS=true
API_KEYS_ALLOWED_ENDPOINTS=/api/chat/completions,/api/v1/models

This is useful when distributing keys to external services or automations, where you want to limit what a compromised key can access.

User permissions

By default, only admins can create API keys. To allow regular users:

USER_PERMISSIONS_FEATURES_API_KEYS=true

Access Control

Open WebUI uses a layered permission system with roles, groups, and per-resource access grants.

Roles

RoleCapabilities
adminFull system access, user management, all configuration
userChat access, permitted models and resources
pendingNo access until approved by admin

Key settings

# Default role for new users (default: pending)
DEFAULT_USER_ROLE=pending

# Whether admins bypass resource-level access control (default: true)
BYPASS_ADMIN_ACCESS_CONTROL=true

# Whether admins can view all user chats (default: true)
ENABLE_ADMIN_CHAT_ACCESS=true

# Whether all users can access all models regardless of group restrictions (default: false)
BYPASS_MODEL_ACCESS_CONTROL=false

Data sharing and export

Several features control how data can be shared or exported:

# Allow users to share chats with other authenticated users (default: true)
ENABLE_COMMUNITY_SHARING=true

# Allow admins to bulk export all user chats from the database (default: true)
ENABLE_ADMIN_EXPORT=true

# Allow users to connect directly to model providers with their own API keys,
# bypassing the server-side proxy (default: false)
ENABLE_DIRECT_CONNECTIONS=false

ENABLE_COMMUNITY_SHARING lets users generate share links for their chats. Any authenticated user with the link can view the chat. If your deployment contains sensitive conversations, consider setting this to false.

ENABLE_DIRECT_CONNECTIONS, when enabled, allows users to configure their own API keys and model endpoints in the browser. These connections are made from the backend, so the user's API key is sent to the Open WebUI server. This is off by default.

Workspace permissions

These settings control what regular users can do in the shared workspace:

USER_PERMISSIONS_WORKSPACE_MODELS_ACCESS=false
USER_PERMISSIONS_WORKSPACE_KNOWLEDGE_ACCESS=false
USER_PERMISSIONS_WORKSPACE_TOOLS_ACCESS=false
USER_PERMISSIONS_WORKSPACE_PROMPTS_ACCESS=false

All default to false. Group-level overrides can enable specific permissions for specific user groups.


Audit Logging

Audit logging records API activity for compliance, debugging, and usage analysis. It is disabled by default.

AUDIT_LOG_LEVEL=METADATA
LevelWhat is logged
NONENothing (default)
METADATAUser, IP, user agent, method, URL, timestamp
REQUESTMetadata plus request body
REQUEST_RESPONSEMetadata plus request and response bodies

Output configuration

# Write to a file (default path: /app/backend/data/audit.log)
ENABLE_AUDIT_LOGS_FILE=true
AUDIT_LOGS_FILE_PATH=/app/backend/data/audit.log
AUDIT_LOG_FILE_ROTATION_SIZE=10MB

# Also send to stdout, useful for log aggregators
ENABLE_AUDIT_STDOUT=true

# Maximum bytes captured per request/response body (default: 2048)
MAX_BODY_LOG_SIZE=2048

Path filtering

# Only audit specific paths (whitelist mode)
AUDIT_INCLUDED_PATHS=auths,users,configs

# Exclude specific paths (blacklist mode, default)
AUDIT_EXCLUDED_PATHS=/chats,/chat,/folders

Authentication endpoints (signin, signout, signup) are always audited regardless of path exclusions. Passwords in request bodies are automatically redacted.


Network and Outbound Requests

Outbound TLS

Open WebUI makes outbound HTTPS requests to model APIs, embedding providers, tool servers, and web search services. Certificate verification is on by default:

REQUESTS_VERIFY=true
AIOHTTP_CLIENT_SESSION_SSL=true
AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL=true
ENABLE_WEB_LOADER_SSL_VERIFICATION=true

Offline mode

For air-gapped environments:

OFFLINE_MODE=true

This disables HuggingFace Hub downloads, version update checks, and other outbound calls. Models and embeddings must be available locally.

SSRF prevention

The RAG web loader can fetch content from URLs. By default, it cannot access local network addresses:

ENABLE_RAG_LOCAL_WEB_FETCH=false

Setting this to true allows the web loader to fetch content from private IP ranges, which may be necessary in some environments but introduces SSRF risk.

Open WebUI also blocks cloud provider metadata endpoints by default (AWS 169.254.169.254, GCP metadata.google.internal, Azure metadata.azure.com, and Alibaba Cloud 100.100.100.200). You can extend this blocklist with additional domains or IPs:

WEB_FETCH_FILTER_LIST=!internal.yourcompany.com,!10.0.0.0/8

Prefix entries with ! to block them.

File upload limits

By default, there are no size or count limits on uploaded files. To prevent storage exhaustion:

# Maximum file size in MB (no default limit)
RAG_FILE_MAX_SIZE=50

# Maximum number of files per upload operation (no default limit)
RAG_FILE_MAX_COUNT=10

# Restrict allowed file extensions (empty = all allowed)
RAG_ALLOWED_FILE_EXTENSIONS=.pdf,.txt,.md,.docx,.csv

Tools, Functions, and Pipelines

Tools and Functions run arbitrary Python code on your server with the same access as the Open WebUI process. This is fundamental to how they work, and it means they can read files, make network requests, access environment variables, and interact with the database.

For details on the security model, see the Security Policy.

Code execution

Open WebUI has two code execution features enabled by default:

# Allows code blocks in chat responses to be executed (default: true, engine: pyodide)
ENABLE_CODE_EXECUTION=true
CODE_EXECUTION_ENGINE=pyodide

# Allows the model to run code as part of its reasoning (default: true, engine: pyodide)
ENABLE_CODE_INTERPRETER=true
CODE_INTERPRETER_ENGINE=pyodide

The default engine is pyodide, which runs Python in the browser via WebAssembly and does not execute code on the server. If you switch to Jupyter (jupyter), code runs on the Jupyter server, which has server-side access. Secure the Jupyter instance accordingly if using this engine.

Safe Mode

If a Function causes problems at startup, you can deactivate all Functions by starting in Safe Mode:

SAFE_MODE=true

This lets you access the admin panel and disable the problematic function.

Dependency installation

Tools and Functions can declare Python dependencies in their frontmatter. By default, these are installed automatically via pip:

# Set to false to prevent automatic pip installs from tool/function frontmatter
ENABLE_PIP_INSTALL_FRONTMATTER_REQUIREMENTS=false

Workspace access

Control who can create, import, and share Tools and Functions:

USER_PERMISSIONS_WORKSPACE_TOOLS_ACCESS=false
USER_PERMISSIONS_WORKSPACE_TOOLS_IMPORT=false
USER_PERMISSIONS_WORKSPACE_SKILLS_ACCESS=false

Container Hardening

Base image

The default Dockerfile uses python:3.11-slim-bookworm. If your organization requires a hardened or approved base image, you can swap it by modifying the FROM line in the Dockerfile. This is common in enterprise environments that mandate minimal, vulnerability-scanned base images.

Non-root execution

The Dockerfile supports running as a non-root user:

docker build --build-arg UID=1000 --build-arg GID=1000 .

OpenShift compatibility

For environments that run containers with arbitrary UIDs (OpenShift):

docker build --build-arg USE_PERMISSION_HARDENING=true .

Data directory

The data directory (/app/backend/data) contains the database, uploaded files, cached plugins, and the auto-generated secret key. Protect this directory with appropriate filesystem permissions and include it in your backup strategy.

Development features

The Docker image sets ENV=prod by default, which disables the Swagger/OpenAPI documentation UI at /docs. If running manually, set ENV=prod to ensure these endpoints are not exposed.


Observability

Structured logging

LOG_FORMAT=json
GLOBAL_LOG_LEVEL=INFO

JSON logging is designed for log aggregators like ELK, Datadog, or Splunk.

OpenTelemetry

ENABLE_OTEL=true
OTEL_EXPORTER_OTLP_ENDPOINT=http://your-collector:4317
OTEL_SERVICE_NAME=open-webui

For complete setup, see Monitoring and Logging Open WebUI.


SCIM Provisioning

SCIM 2.0 allows your identity provider to automatically manage user accounts:

ENABLE_SCIM=true
SCIM_TOKEN=your-bearer-token
SCIM_AUTH_PROVIDER=oidc

The SCIM token is a static bearer token that grants full user management access. Treat it with the same care as admin credentials, rotate it periodically, and only transmit it over HTTPS.


Keeping Open WebUI Updated

Running the latest version of Open WebUI ensures you have the most recent security patches and fixes. Check the changelog for security-related updates and apply them promptly.

For Docker deployments, pull the latest image and recreate the container:

docker pull ghcr.io/open-webui/open-webui:main

For multi-replica deployments, follow the rolling update procedure to avoid downtime.


Quick Reference

The table below summarizes the key hardening actions covered in this guide. Each row links to the relevant section for details.

ActionDefaultRecommended for production
Keep on private networkNo restrictionVPN, firewall, or zero-trust proxy
Serve over HTTPSHTTPHTTPS via reverse proxy
Set WEBUI_SECRET_KEY (multi-replica)Auto-generatedExplicit shared key
Disable open signupENABLE_SIGNUP=trueENABLE_SIGNUP=false
Enable password validationDisabledENABLE_PASSWORD_VALIDATION=true
Secure cookiesSecure=false, SameSite=laxSecure=true, SameSite=strict
Restrict CORS*Your specific domain(s)
Set security headersNoneHSTS, X-Frame-Options, CSP
Restrict OAuth domainsAll allowedOAUTH_ALLOWED_DOMAINS=yourdomain.com
Enable audit loggingNONEMETADATA or higher
Restrict API key endpointsAll endpointsENABLE_API_KEYS_ENDPOINT_RESTRICTIONS=true
Disable auto pip installEnabledENABLE_PIP_INSTALL_FRONTMATTER_REQUIREMENTS=false
Review community sharingtrueDisable if sensitive data
Review direct connectionsfalseKeep disabled unless needed
Use PostgreSQLSQLitePostgreSQL
Verify outbound TLSEnabledKeep enabled
Structured loggingTextLOG_FORMAT=json
Keep updatedN/ALatest stable release