diff --git a/docs/features/authentication-access/auth/sso/index.mdx b/docs/features/authentication-access/auth/sso/index.mdx index cfa1042f78..38e22c5776 100644 --- a/docs/features/authentication-access/auth/sso/index.mdx +++ b/docs/features/authentication-access/auth/sso/index.mdx @@ -40,6 +40,7 @@ You cannot have Microsoft **and** Google as OIDC providers simultaneously. | `OAUTH_CLIENT_INFO_ENCRYPTION_KEY` | `WEBUI_SECRET_KEY` | A secret key for encrypting OAuth client information stored on the server - used for OAuth 2.1 authentication for MCP servers. | | `ENABLE_OAUTH_ID_TOKEN_COOKIE` | `true` | For backward compatibility. Controls if the legacy `oauth_id_token` cookie is set. Recommended to set to `false`. | | `ENABLE_OAUTH_TOKEN_EXCHANGE` | `false` | Enables the token exchange endpoint for external apps to exchange OAuth tokens for Open WebUI JWTs. | +| `ENABLE_OAUTH_BACKCHANNEL_LOGOUT` | `false` | Enables OIDC Back-Channel Logout endpoint (`POST /oauth/backchannel-logout`) for IdP-initiated logout. Requires Redis for JWT revocation. | | `OAUTH_MAX_SESSIONS_PER_USER` | `10` | Maximum concurrent OAuth sessions per user per provider. Prevents unbounded growth while allowing multi-device usage. | :::warning @@ -80,6 +81,29 @@ Open WebUI also supports **OAuth Token Exchange**, allowing external application To enable this feature, set `ENABLE_OAUTH_TOKEN_EXCHANGE=true`. See the [`ENABLE_OAUTH_TOKEN_EXCHANGE`](/reference/env-configuration#enable_oauth_token_exchange) environment variable documentation for details on usage, request/response examples, and security considerations. +### OIDC Back-Channel Logout + +Open WebUI supports **OIDC Back-Channel Logout**, which allows your identity provider (IdP) to notify Open WebUI of user logout events directly server-to-server, without requiring a browser redirect. + +To enable this feature, set `ENABLE_OAUTH_BACKCHANNEL_LOGOUT=true`. + +When enabled, Open WebUI exposes: + +- `POST /oauth/backchannel-logout` + +The endpoint expects a form-encoded `logout_token` issued by your IdP and validates it against your configured OAuth/OIDC provider metadata and JWKS. + +:::warning + +Redis is strongly recommended and effectively required for full logout enforcement. + +- With Redis configured, Open WebUI revokes existing JWTs for affected users and removes stored OAuth sessions. +- Without Redis, Open WebUI can delete stored OAuth sessions, but already issued JWTs remain valid until expiration. + +::: + +See [`ENABLE_OAUTH_BACKCHANNEL_LOGOUT`](/reference/env-configuration#enable_oauth_backchannel_logout) for implementation details and behavior notes. + ### Google To configure a Google OAuth client, please refer to [Google's documentation](https://support.google.com/cloud/answer/6158849) on how to create a Google OAuth client for a **web application**. @@ -147,6 +171,12 @@ No additional configuration is required in Microsoft Entra ID. The `offline_acce ::: +:::tip Role Mapping with Microsoft Entra ID + +If you use Entra ID **app roles** to control who gets `admin` vs `user` access in Open WebUI, you also need to configure [OAuth Role Management](#oauth-role-management) below. In particular, make sure you set `OAUTH_ALLOWED_ROLES` and `OAUTH_ADMIN_ROLES` in addition to `ENABLE_OAUTH_ROLE_MANAGEMENT=true` β€” otherwise all users will be created with the default role regardless of their Entra ID assignment. + +::: + ### GitHub To configure a GitHub OAuth Client, please refer to [GitHub's documentation](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps) on how to create a OAuth App or GitHub App for a **web application**. diff --git a/docs/features/authentication-access/rbac/index.mdx b/docs/features/authentication-access/rbac/index.mdx index b06d7e41f8..52c0c6b1f5 100644 --- a/docs/features/authentication-access/rbac/index.mdx +++ b/docs/features/authentication-access/rbac/index.mdx @@ -13,6 +13,14 @@ Open WebUI implements a flexible and secure **Role-Based Access Control (RBAC)** The security model is **Additive**. Users start with their default rights, and Group memberships **add** capabilities. A user effectively has the *union* of all rights granted by their Roles and Groups. ::: +:::warning Scope of RBAC vs Provider Credentials +RBAC controls what users can do **inside Open WebUI** (features, resources, and UI/API actions). + +RBAC does **not** replace least-privilege configuration for external providers. If you connect an OpenAI-compatible proxy/provider (for example LiteLLM, OpenRouter, or custom gateways), use provider credentials that are scoped for inference usage in your deployment. + +Avoid configuring management/master keys for general user traffic unless your deployment explicitly requires that level of trust. +::: + ## Documentation Guide * [β€πŸ”‘ **Roles**](./roles.md) diff --git a/docs/features/authentication-access/rbac/permissions.md b/docs/features/authentication-access/rbac/permissions.md index 0a4e904ebb..acfa8a574d 100644 --- a/docs/features/authentication-access/rbac/permissions.md +++ b/docs/features/authentication-access/rbac/permissions.md @@ -12,6 +12,12 @@ Administrators can manage permissions in two primary ways: Users with the `Pending` role have no access until approved, `Admin` users have full administrative access, and `User` accounts are subject to the permission system described below. +:::warning RBAC Scope Boundary +RBAC permissions control what users can do inside Open WebUI. + +RBAC does not replace provider-side least-privilege design. For OpenAI-compatible providers/proxies (including LiteLLM), configure credentials with the minimum required scope for your deployment. +::: + :::info Permission Logic Permissions in Open WebUI are **additive**. * A user's effective permissions are the combination of **Global Defaults** and all their **Group Memberships**. @@ -111,6 +117,18 @@ Controls access to broad platform capabilities. | **Code Interpreter** | Ability to use the Python Code Interpreter. | | **Direct Tool Servers** | Ability to connect to custom Tool Servers in settings. | | **Memories** | Access to the Memories feature for persistent user context. | +| **Automations** | Ability for non-admin users to access the Automations page and create, edit, run, pause, or delete their own scheduled automations. | + +:::info Automations Permission Scope + +For Automations access: + +1. **Permission Check for Non-Admins**: Users with the `user` role need **Features > Automations** (`features.automations`). +2. **Admins Are Exempt from `features.automations`**: Users with the `admin` role can access Automations without that specific permission. + +Default permission can be configured via [`USER_PERMISSIONS_FEATURES_AUTOMATIONS`](/reference/env-configuration#user_permissions_features_automations). + +::: ### 5. Settings Permissions Controls access to user settings areas. diff --git a/docs/features/chat-conversations/audio/speech-to-text/env-variables.md b/docs/features/chat-conversations/audio/speech-to-text/env-variables.md index d9efb9df09..0a2ef37c89 100644 --- a/docs/features/chat-conversations/audio/speech-to-text/env-variables.md +++ b/docs/features/chat-conversations/audio/speech-to-text/env-variables.md @@ -80,10 +80,10 @@ If using the `:cuda` Docker image with an older GPU, set `WHISPER_COMPUTE_TYPE=f | Variable | Description | Default | |----------|-------------|---------| -| `AUDIO_TTS_ENGINE` | TTS engine: empty (disabled), `openai`, `elevenlabs`, `azure`, `transformers` | empty | +| `AUDIO_TTS_ENGINE` | TTS engine: empty (disabled), `openai`, `mistral`, `elevenlabs`, `azure`, `transformers` | empty | | `AUDIO_TTS_MODEL` | TTS model | `tts-1` | | `AUDIO_TTS_VOICE` | Default voice | `alloy` | -| `AUDIO_TTS_SPLIT_ON` | Split text on: `punctuation` or `none` | `punctuation` | +| `AUDIO_TTS_SPLIT_ON` | Split text on: `punctuation`, `paragraphs`, or `none` | `punctuation` | | `AUDIO_TTS_API_KEY` | API key for ElevenLabs or Azure TTS | empty | ### OpenAI-Compatible TTS @@ -94,6 +94,17 @@ If using the `:cuda` Docker image with an older GPU, set `WHISPER_COMPUTE_TYPE=f | `AUDIO_TTS_OPENAI_API_KEY` | OpenAI TTS API key | empty | | `AUDIO_TTS_OPENAI_PARAMS` | Additional JSON params for OpenAI TTS | empty | +### Mistral TTS + +| Variable | Description | Default | +|----------|-------------|---------| +| `AUDIO_TTS_MISTRAL_API_KEY` | Mistral TTS API key | empty | +| `AUDIO_TTS_MISTRAL_API_BASE_URL` | Mistral API base URL | `https://api.mistral.ai/v1` | + +:::info +When `AUDIO_TTS_ENGINE=mistral`, Open WebUI uses `mistral-tts-latest` when `AUDIO_TTS_MODEL` is empty. +::: + ### Azure TTS | Variable | Description | Default | diff --git a/docs/features/chat-conversations/audio/speech-to-text/mistral-voxtral-integration.md b/docs/features/chat-conversations/audio/speech-to-text/mistral-voxtral-integration.md index f844d0ec2b..0999b58e46 100644 --- a/docs/features/chat-conversations/audio/speech-to-text/mistral-voxtral-integration.md +++ b/docs/features/chat-conversations/audio/speech-to-text/mistral-voxtral-integration.md @@ -7,6 +7,10 @@ title: "Mistral Voxtral STT" This guide covers how to use Mistral's Voxtral model for Speech-to-Text with Open WebUI. Voxtral is Mistral's speech-to-text model that provides accurate transcription. +:::tip Looking for TTS? +See the companion guide: [Using Mistral for Text-to-Speech](/features/chat-conversations/audio/text-to-speech/mistral-tts-integration) +::: + ## Requirements - A Mistral API key diff --git a/docs/features/chat-conversations/audio/text-to-speech/mistral-tts-integration.md b/docs/features/chat-conversations/audio/text-to-speech/mistral-tts-integration.md new file mode 100644 index 0000000000..cb32f1cff2 --- /dev/null +++ b/docs/features/chat-conversations/audio/text-to-speech/mistral-tts-integration.md @@ -0,0 +1,107 @@ +--- +sidebar_position: 2 +title: "Mistral TTS Integration" +--- + +# Using Mistral for Text-to-Speech + +This guide covers how to use Mistral's Text-to-Speech API with Open WebUI. + +:::tip Looking for STT? +See the companion guide: [Using Mistral Voxtral for Speech-to-Text](/features/media-generation/audio/speech-to-text/mistral-voxtral-integration) +::: + +## Requirements + +- A Mistral API key +- Open WebUI installed and running + +## Quick Setup (UI) + +1. Click your **profile icon** (bottom-left corner) +2. Select **Admin Panel** +3. Click **Settings** -> **Audio** tab +4. Configure the following: + +| Setting | Value | +|---------|-------| +| **Text-to-Speech Engine** | `MistralAI` | +| **API Base URL** | `https://api.mistral.ai/v1` | +| **API Key** | Your Mistral API key | +| **TTS Model** | `mistral-tts-latest` (or leave empty for default) | +| **TTS Voice** | Choose from available voices | + +5. Click **Save** + +## Available Models + +| Model | Description | +|-------|-------------| +| `mistral-tts-latest` | Default model used for Mistral TTS | + +:::info +If `AUDIO_TTS_MODEL` is empty, Open WebUI defaults to `mistral-tts-latest` for Mistral TTS. +::: + +## Environment Variables Setup + +If you prefer to configure via environment variables: + +```yaml +services: + open-webui: + image: ghcr.io/open-webui/open-webui:main + environment: + - AUDIO_TTS_ENGINE=mistral + - AUDIO_TTS_MISTRAL_API_KEY=your-mistral-api-key + - AUDIO_TTS_MISTRAL_API_BASE_URL=https://api.mistral.ai/v1 + - AUDIO_TTS_MODEL=mistral-tts-latest + - AUDIO_TTS_VOICE= + # ... other configuration +``` + +### All Mistral TTS Environment Variables + +| Variable | Description | Default | +|----------|-------------|---------| +| `AUDIO_TTS_ENGINE` | Set to `mistral` | empty (uses browser-only TTS) | +| `AUDIO_TTS_MISTRAL_API_KEY` | Your Mistral API key | empty | +| `AUDIO_TTS_MISTRAL_API_BASE_URL` | Mistral API base URL | `https://api.mistral.ai/v1` | +| `AUDIO_TTS_MODEL` | TTS model | `mistral-tts-latest` (effective default for Mistral engine) | +| `AUDIO_TTS_VOICE` | Voice ID | empty | + +## Choosing Voices + +Open WebUI queries the configured Mistral endpoint for available voices and shows them in the **TTS Voice** selector. + +If voices are not listed: +- Confirm your API key is valid +- Verify the API base URL is reachable from the Open WebUI server/container +- Check logs for `/audio/voices` request errors + +## Testing TTS + +1. Start a new chat +2. Send a message to any model +3. Click the **speaker icon** on the AI response to hear it read aloud + +## Troubleshooting + +### "Mistral API key is required for Mistral TTS" + +1. Confirm `AUDIO_TTS_MISTRAL_API_KEY` is set (or entered in Admin Audio settings) +2. Save settings and retry + +### No voices shown in the dropdown + +1. Verify network access from Open WebUI to `AUDIO_TTS_MISTRAL_API_BASE_URL` +2. Check Open WebUI logs for Mistral voice list errors +3. Confirm your key has permission to access Mistral audio APIs + +### TTS request fails + +1. Verify `AUDIO_TTS_ENGINE=mistral` +2. Try leaving the model empty (uses `mistral-tts-latest`) +3. Try another voice ID from the fetched list + +For broader audio debugging, see the [Audio Troubleshooting Guide](/troubleshooting/audio). diff --git a/docs/features/chat-conversations/chat-features/automations.mdx b/docs/features/chat-conversations/chat-features/automations.mdx new file mode 100644 index 0000000000..f164768bce --- /dev/null +++ b/docs/features/chat-conversations/chat-features/automations.mdx @@ -0,0 +1,119 @@ +--- +sidebar_position: 11 +title: "Automations" +--- + +# Automations + +Automations let you schedule prompts to run automatically at recurring times. Each run creates a chat and executes through the normal chat completion pipeline, so model defaults, tools, filters, and other pipeline behavior still apply. + +## What You Can Automate + +- Run a prompt on a schedule (hourly, daily, weekly, monthly, custom RRULE) +- Trigger a run manually with **Run Now** +- Pause/resume automations without deleting them +- Review execution history for each automation +- Optionally attach a terminal server and working directory for runs that need terminal context + +## Access Control + +Automations are permission-gated for non-admin users. + +- **Admins**: always have access to Automations +- **Users**: require the **Features > Automations** permission + +See [RBAC Permissions](/features/authentication-access/rbac/permissions#4-features-permissions) for the permission category. + +To grant user access: + +1. Open **Admin Panel > Users > Groups** +2. Edit **Default permissions** or a specific group +3. Enable **Features > Automations** + +You can also set this default via [`USER_PERMISSIONS_FEATURES_AUTOMATIONS`](/reference/env-configuration#user_permissions_features_automations). + +## Admin Limits + +Administrators can set global limits on automation usage for non-admin users. These are configured via environment variables. **Admins bypass all limits.** + +| Setting | Effect | Env Variable | +|---------|--------|--------------| +| **Max Automation Count** | Caps the number of automations a user can create | [`AUTOMATION_MAX_COUNT`](/reference/env-configuration#automation_max_count) | +| **Min Recurrence Interval** | Rejects schedules that run more frequently than the configured interval (in seconds) | [`AUTOMATION_MIN_INTERVAL`](/reference/env-configuration#automation_min_interval) | + +- **Max count** is checked only on creation. Existing automations are not deleted if the limit is lowered. +- **Min interval** is checked on both creation and update. One-time automations (`COUNT=1`) are exempt. +- Both default to empty (no limit). Set to a positive integer to enforce. + +## Create an Automation + +1. Open **User Menu > Automations** +2. Click **New Automation** +3. Set: + - **Title** + - **Instructions** (prompt) + - **Model** + - **Schedule** +4. (Optional) Select a **Terminal** server and **Working Directory** +5. Click **Create** + +After creation, Open WebUI opens the dedicated automation editor page at `/automations/{id}`. + +## Edit and Manage + +From the Automations list, click an automation to open its dedicated editor page. + +On the editor page, you can: + +- Update title, instructions, model, schedule, and terminal settings +- Save changes +- Run immediately with **Run now** +- Pause/resume automation state +- Delete the automation +- Review execution logs and open run chats + +Execution logs are paginated with infinite scroll in the editor, so large run histories load incrementally. + +## Scheduling + +Supported schedule modes: + +- **Once** +- **Hourly** +- **Daily** +- **Weekly** +- **Monthly** +- **Custom** (`RRULE`) + +Custom schedules accept standard RRULE syntax. Invalid or exhausted rules are rejected. + +## Notes + +- Automations run in the background worker loop on a polling interval. +- Every run records a status (`success` or `error`) and optional error details. +- Deleting an automation also removes its run history. + +## Managing Automations from Chat + +When using **Native Function Calling Mode** with a capable model, automations can also be created and managed directly from within a chat conversation using builtin tools. This allows you to say things like *"Schedule a daily summary report at 9am"* and the model will create the automation for you. + +### Available tools + +| Tool | What it does | +|------|-------------| +| `create_automation` | Create a new scheduled automation with a name, prompt, RRULE schedule, and optional model ID | +| `update_automation` | Update an existing automation's name, prompt, schedule, or model | +| `list_automations` | List your scheduled automations with status, schedule, and next runs | +| `toggle_automation` | Pause or resume a scheduled automation | +| `delete_automation` | Delete a scheduled automation and all its run history | + +### Requirements + +For chat-based automation tools to be available: + +1. **Native Function Calling** must be enabled for the model +2. **Builtin Tools** capability must be enabled for the model +3. **Automations** category must be enabled in the model's Builtin Tools settings (enabled by default) +4. The user must have the **Features > Automations** permission (admins always pass) + +See the [Builtin Tools reference](/features/extensibility/plugin/tools#built-in-system-tools-nativeagentic-mode) for full details on all builtin tools. diff --git a/docs/features/chat-conversations/chat-features/history-search.mdx b/docs/features/chat-conversations/chat-features/history-search.mdx index 24a9a27a03..e315220c90 100644 --- a/docs/features/chat-conversations/chat-features/history-search.mdx +++ b/docs/features/chat-conversations/chat-features/history-search.mdx @@ -13,9 +13,12 @@ All your conversations are automatically saved in the **Sidebar**. * **Persistence**: Chats are saved to the internal database (`webui.db`) and are available across all your devices. * **Organization**: Chats are grouped by time period (Today, Yesterday, Previous 7 Days, etc.). +* **Unread Indicator**: Chats with new activity show an unread dot in the sidebar until you open them. * **Renaming**: Titles are automatically generated by a task model, but you can manually rename any chat by clicking the pencil icon next to its title. * **Archivial**: Instead of deleting, you can **Archive** chats to remove them from the main list while keeping them downloadable and searchable. +Open WebUI tracks read state per chat and updates it when you open a conversation, so unread indicators stay in sync across sessions. + ## Searching Your History You can search through your conversations using the global search bar in the sidebar. diff --git a/docs/features/chat-conversations/chat-features/index.mdx b/docs/features/chat-conversations/chat-features/index.mdx index 46e82aa28d..c9689570b6 100644 --- a/docs/features/chat-conversations/chat-features/index.mdx +++ b/docs/features/chat-conversations/chat-features/index.mdx @@ -27,6 +27,10 @@ Open WebUI provides a comprehensive set of chat features designed to enhance you - **[πŸ’¬ Follow-Up Prompts](./follow-up-prompts.md)**: Automatic generation of suggested follow-up questions after model responses. +- **[⏱️ Automations](./automations.mdx)**: Schedule prompts to run automatically (hourly/daily/weekly/monthly/custom RRULE) and manage recurring runs. + +- **[βœ… Task Management](./task-management.mdx)**: Let agentic models keep a structured task/todo list in chat for multi-step workflows and transparent progress tracking. + - **Skill Mentions**: Use `$` in the chat input to mention and activate [Skills](/features/workspace/skills) on-the-fly, injecting their manifests into the conversation. - **Writing & Content Blocks**: Responses from models that include colon-fence blocks (e.g., `:::writing`, `:::code_execution`, `:::search_results`) are automatically rendered as formatted content in a styled container with a copy button. This is commonly used by newer OpenAI models to distinguish different types of output (prose, code results, search results) from the main response text. diff --git a/docs/features/chat-conversations/chat-features/task-management.mdx b/docs/features/chat-conversations/chat-features/task-management.mdx new file mode 100644 index 0000000000..db50838af4 --- /dev/null +++ b/docs/features/chat-conversations/chat-features/task-management.mdx @@ -0,0 +1,62 @@ +--- +sidebar_position: 12 +title: "Task Management" +--- + +# Task Management + +Task Management gives agentic models a structured way to plan and track multi-step work in a chat. Instead of keeping an implicit plan in free text, the model can maintain a live task list with explicit statuses. + +## Why This Matters for Agentic AI + +For simple Q&A, a single response is enough. For true agentic workflows (research, debugging, migrations, investigations), models need a reliable execution loop: + +1. break down work, +2. execute steps, +3. update progress, +4. adapt the plan. + +Task lists make that loop visible to the user and reduce failures caused by skipped or forgotten steps. + +## How It Works + +The model uses two built-in tools to manage the list: + +- `create_tasks` β€” called once at the start of multi-step work to lay out the full checklist. +- `update_task` β€” called after finishing each step, to mark a single task by id as `pending`, `in_progress`, `completed`, or `cancelled`. + +When these tools are used: + +- Tasks are stored at the chat level +- The UI shows progress in-chat (e.g., completed vs total) +- Status changes are reflected in real time + +Supported statuses: + +- `pending` +- `in_progress` +- `completed` +- `cancelled` + +## Enabling It + +Task Management is controlled per model in Builtin Tools: + +1. Go to **Workspace > Models > Edit** +2. Ensure **Capabilities > Builtin Tools** is enabled +3. Under builtin categories, keep **Task Management** enabled + +See [Built-in System Tools](/features/extensibility/plugin/tools#built-in-system-tools-nativeagentic-mode) for tool details. + +## Best Practices + +- Use task lists for requests that need multiple concrete steps +- Keep only one task in `in_progress` at a time +- Mark tasks `completed` immediately after finishing +- Cancel stale tasks explicitly instead of leaving them pending + +## Related Features + +- [Reasoning & Thinking Models](./reasoning-models.mdx) +- [Automations](./automations.mdx) +- [Tool Development / Built-in Tools](/features/extensibility/plugin/tools) diff --git a/docs/features/chat-conversations/direct-connections.mdx b/docs/features/chat-conversations/direct-connections.mdx index 91c2ee71d5..2999df3b0c 100644 --- a/docs/features/chat-conversations/direct-connections.mdx +++ b/docs/features/chat-conversations/direct-connections.mdx @@ -29,6 +29,12 @@ With **Direct Connections**, the browser communicates directly with the API prov 2. **CORS Configuration**: Since the browser is making the request, the API provider must have **Cross-Origin Resource Sharing (CORS)** configured to allow requests from your Open WebUI domain. * *Note: Many strict providers (like official OpenAI) might block direct browser requests due to CORS policies. This feature is often best used with flexible providers or internal API gateways.* +:::warning Security Recommendation: Provider Key Scope +Use least-privilege provider credentials for Direct Connections. + +If your provider supports scoped keys, prefer inference-only keys for regular usage. Avoid using management/master keys for day-to-day user traffic. +::: + ## User Configuration Once enabled by the admin, users can configure their own connections: diff --git a/docs/features/chat-conversations/web-search/agentic-search.mdx b/docs/features/chat-conversations/web-search/agentic-search.mdx index 29c2137f40..37ea410d72 100644 --- a/docs/features/chat-conversations/web-search/agentic-search.mdx +++ b/docs/features/chat-conversations/web-search/agentic-search.mdx @@ -50,6 +50,7 @@ In **Default Mode** (non-native), the chat toggle controls whether web search is ### `search_web` (Snippets only) When the model invokes `search_web`: * **Action**: It queries your search engine and receives a list of titles, links, and snippets. +* **Result Count Behavior**: If the model omits `count`, Open WebUI uses the admin-configured `WEB_SEARCH_RESULT_COUNT`. If the model provides `count`, the value is capped at the same admin maximum. * **No RAG**: Unlike traditional search, **no data is stored in a Vector DB**. No chunking or embedding occurs. * **Result**: The model sees exactly what a human sees on a search results page. If the snippet contains the answer, the model responds. If not, the model must decide to "deep dive" into a link. @@ -83,7 +84,7 @@ Interleaved Thinking is the ability for models to alternate between **reasoning* ``` Model calls: search_web("React security vulnerabilities 2026") ``` -- Receives snippets from 5-10 search results +- Receives snippets based on the admin-configured `WEB_SEARCH_RESULT_COUNT` (or a smaller model-provided `count`) - Sees references to npm packages and CVE databases **Step 3: Gap Analysis πŸ€”** diff --git a/docs/features/chat-conversations/web-search/providers/brave.md b/docs/features/chat-conversations/web-search/providers/brave.md index f19c440c44..240150404b 100644 --- a/docs/features/chat-conversations/web-search/providers/brave.md +++ b/docs/features/chat-conversations/web-search/providers/brave.md @@ -31,11 +31,11 @@ Add the following environment variables to your Open WebUI `docker-compose.yaml` services: open-webui: environment: - ENABLE_RAG_WEB_SEARCH: True - RAG_WEB_SEARCH_ENGINE: "brave" + ENABLE_WEB_SEARCH: True + WEB_SEARCH_ENGINE: "brave" BRAVE_SEARCH_API_KEY: "YOUR_API_KEY" - RAG_WEB_SEARCH_RESULT_COUNT: 3 - RAG_WEB_SEARCH_CONCURRENT_REQUESTS: 1 + WEB_SEARCH_RESULT_COUNT: 3 + WEB_SEARCH_CONCURRENT_REQUESTS: 1 ``` ### Rate Limiting (Free Tier) @@ -45,7 +45,7 @@ Brave's free tier API enforces a strict limit of **1 request per second**. If yo **Recommended configuration for free tier users:** - Set "Concurrent Requests" in Admin Panel > Settings > Web Search to `1`. Alternatively use environment variables: -- Set `RAG_WEB_SEARCH_CONCURRENT_REQUESTS: 1` to ensure requests are processed sequentially rather than in parallel. +- Set `WEB_SEARCH_CONCURRENT_REQUESTS: 1` to ensure requests are processed sequentially rather than in parallel. **Automatic retry behavior:** @@ -58,12 +58,12 @@ Open WebUI automatically handles 429 rate limit responses from the Brave API. Wh This means that even if your connection is fast enough to send multiple sequential requests within a second, the automatic retry mechanism should recover gracefully without user intervention. :::tip -If you are on Brave's paid tier with higher rate limits, you can increase `RAG_WEB_SEARCH_CONCURRENT_REQUESTS` for faster parallel searches. +If you are on Brave's paid tier with higher rate limits, you can increase `WEB_SEARCH_CONCURRENT_REQUESTS` for faster parallel searches. ::: :::info Understanding Concurrency & Rate Limits -The `RAG_WEB_SEARCH_CONCURRENT_REQUESTS` setting controls concurrency **per individual search request**, not globally across the entire application. +The `WEB_SEARCH_CONCURRENT_REQUESTS` setting controls concurrency **per individual search request**, not globally across the entire application. - **When this is NOT an issue**: For single-user instances or low-traffic setups where users rarely hit "Enter" at the exact same second, setting concurrency to `1` is usually sufficient to stay within the Free Tier limits (1 req/sec). - **When this IS an issue**: If multiple users trigger web searches at the exact same moment (e.g., 3 users searching in the same second), Open WebUI will process these requests in parallel. Each user's request creates its own connection pool, meaning 3 requests will be sent to the API simultaneously, triggering a rate limit error on the Free Tier. diff --git a/docs/features/chat-conversations/web-search/providers/mojeek.md b/docs/features/chat-conversations/web-search/providers/mojeek.md index 81f45be440..80e5c5e3dd 100644 --- a/docs/features/chat-conversations/web-search/providers/mojeek.md +++ b/docs/features/chat-conversations/web-search/providers/mojeek.md @@ -39,9 +39,9 @@ Add the following environment variables to your Open WebUI `docker-compose.yaml` services: open-webui: environment: - ENABLE_RAG_WEB_SEARCH: True - RAG_WEB_SEARCH_ENGINE: "mojeek" + ENABLE_WEB_SEARCH: True + WEB_SEARCH_ENGINE: "mojeek" MOJEEK_SEARCH_API_KEY: "YOUR_MOJEEK_API_KEY" - RAG_WEB_SEARCH_RESULT_COUNT: 3 - RAG_WEB_SEARCH_CONCURRENT_REQUESTS: 1 + WEB_SEARCH_RESULT_COUNT: 3 + WEB_SEARCH_CONCURRENT_REQUESTS: 1 ``` diff --git a/docs/features/chat-conversations/web-search/providers/searxng.md b/docs/features/chat-conversations/web-search/providers/searxng.md index d2715c91b6..9cbba60b44 100644 --- a/docs/features/chat-conversations/web-search/providers/searxng.md +++ b/docs/features/chat-conversations/web-search/providers/searxng.md @@ -211,10 +211,10 @@ Add the following environment variables to your Open WebUI `docker-compose.yaml` services: open-webui: environment: - ENABLE_RAG_WEB_SEARCH: True - RAG_WEB_SEARCH_ENGINE: "searxng" - RAG_WEB_SEARCH_RESULT_COUNT: 3 - RAG_WEB_SEARCH_CONCURRENT_REQUESTS: 10 + ENABLE_WEB_SEARCH: True + WEB_SEARCH_ENGINE: "searxng" + WEB_SEARCH_RESULT_COUNT: 3 + WEB_SEARCH_CONCURRENT_REQUESTS: 10 SEARXNG_QUERY_URL: "http://searxng:8080/search?q=" ``` diff --git a/docs/features/chat-conversations/web-search/providers/yandex.md b/docs/features/chat-conversations/web-search/providers/yandex.md index 3b0c81e475..c311490ee9 100644 --- a/docs/features/chat-conversations/web-search/providers/yandex.md +++ b/docs/features/chat-conversations/web-search/providers/yandex.md @@ -33,8 +33,8 @@ Add the following environment variables to your Open WebUI `docker-compose.yaml` services: open-webui: environment: - ENABLE_RAG_WEB_SEARCH: True - RAG_WEB_SEARCH_ENGINE: "yandex" + ENABLE_WEB_SEARCH: True + WEB_SEARCH_ENGINE: "yandex" YANDEX_WEB_SEARCH_API_KEY: "YOUR_YANDEX_CLOUD_API_KEY" # Optional: Override default search URL # YANDEX_WEB_SEARCH_URL: "https://searchapi.api.cloud.yandex.net/v2/web/search" diff --git a/docs/features/chat-conversations/web-search/providers/youcom.md b/docs/features/chat-conversations/web-search/providers/youcom.md index a48766d71f..37d4e8150c 100644 --- a/docs/features/chat-conversations/web-search/providers/youcom.md +++ b/docs/features/chat-conversations/web-search/providers/youcom.md @@ -37,11 +37,11 @@ Add the following environment variables to your Open WebUI `docker-compose.yaml` services: open-webui: environment: - ENABLE_RAG_WEB_SEARCH: True - RAG_WEB_SEARCH_ENGINE: "youcom" + ENABLE_WEB_SEARCH: True + WEB_SEARCH_ENGINE: "youcom" YOUCOM_API_KEY: "YOUR_API_KEY" - RAG_WEB_SEARCH_RESULT_COUNT: 3 - RAG_WEB_SEARCH_CONCURRENT_REQUESTS: 10 + WEB_SEARCH_RESULT_COUNT: 3 + WEB_SEARCH_CONCURRENT_REQUESTS: 10 ``` ### Admin Panel Setup diff --git a/docs/features/extensibility/plugin/tools/index.mdx b/docs/features/extensibility/plugin/tools/index.mdx index 43327c1581..01a9d78039 100644 --- a/docs/features/extensibility/plugin/tools/index.mdx +++ b/docs/features/extensibility/plugin/tools/index.mdx @@ -238,6 +238,15 @@ These models excel at multi-step reasoning, proper JSON formatting, and autonomo | `search_channel_messages` | Search for specific messages inside accessible channels. | | `view_channel_message` | View a specific message or its details in a channel. | | `view_channel_thread` | View a full message thread/replies in a channel. | +| **Task Management** | *Requires per-model "Task Management" category enabled (default: on).* | +| `create_tasks` | Create a structured task checklist for the current chat. Called once at the start of multi-step work to define all steps. | +| `update_task` | Update the status of a single task by id (`pending`, `in_progress`, `completed`, `cancelled`). Called after finishing each step. | +| **Automations** | *Requires per-model "Automations" category enabled (default: on) AND user has `features.automations` permission (admins always pass).* | +| `create_automation` | Create a scheduled automation with a name, prompt, RRULE schedule, and optional model ID. | +| `update_automation` | Update an existing automation's name, prompt, schedule, or model. | +| `list_automations` | List the user's scheduled automations with status, schedule, and next runs. | +| `toggle_automation` | Pause or resume a scheduled automation. | +| `delete_automation` | Delete a scheduled automation and all its run history. | | **Skills** | *Requires at least one skill to be attached to the model via **Workspace/Admin Panel β†’ Models β†’ Edit β†’ Skills**. The model receives a summary of attached skills in its system prompt and can call `view_skill` to load full instructions on demand. No separate builtin tools category checkbox is needed β€” attaching a skill is the only requirement.* | | `view_skill` | Load the full instructions of a skill by name. The tool is injected when skills are attached; resolving a skill still follows normal ownership/access-grant checks. | | **Time Tools** | *Requires per-model "Time & Calculation" category enabled (default: on).* | @@ -267,7 +276,7 @@ Quick rule: `list_knowledge` and `list_knowledge_bases` are mutually exclusive. | Tool | Parameters | Output | |------|------------|--------| | **Search & Web** | | | -| `search_web` | `query` (required), `count` (default: 5) | Array of `{title, link, snippet}` | +| `search_web` | `query` (required), `count` (default: admin-configured `WEB_SEARCH_RESULT_COUNT`; capped at admin maximum when provided) | Array of `{title, link, snippet}` | | `fetch_url` | `url` (required) | Plain text content (max 50,000 chars) | | **Knowledge Base** | | | | `list_knowledge` | None | `{knowledge_bases: [{id, name, description, file_count, files: [{id, filename}]}], files: [{id, filename}], notes: [{id, title}]}` | @@ -302,6 +311,15 @@ Quick rule: `list_knowledge` and `list_knowledge_bases` are mutually exclusive. | `search_channel_messages` | `query` (required), `count` (default: 10), `start_timestamp`, `end_timestamp` | Array of `{channel_id, channel_name, message_id, content_snippet, is_thread_reply, parent_id, created_at}` | | `view_channel_message` | `message_id` (required) | `{id, content, user_name, created_at, reply_count}` | | `view_channel_thread` | `parent_message_id` (required) | `{channel_id, channel_name, thread_id, message_count, messages: [...]}` | +| **Task Management** | | | +| `create_tasks` | `tasks` (required): list of `{content (required), status (default: pending), id (optional, auto-generated)}` | `{tasks: [...], summary: {total, pending, in_progress, completed, cancelled}}` | +| `update_task` | `id` (required), `status` (default: `completed`; one of `pending`, `in_progress`, `completed`, `cancelled`) | `{tasks: [...], summary: {total, pending, in_progress, completed, cancelled}}` | +| **Automations** | | | +| `create_automation` | `name` (required), `prompt` (required), `rrule` (required), `model_id` (optional β€” defaults to current chat model) | `{status, id, name, model_id, is_active, next_runs}` | +| `update_automation` | `automation_id` (required), `name`, `prompt`, `rrule`, `model_id` (all optional β€” only provided fields are changed) | `{status, id, name, model_id, is_active, next_runs}` | +| `list_automations` | `status` (optional: `"active"`, `"paused"`, or omit for all), `count` (default: 10) | `{automations: [{id, name, prompt_snippet, model_id, rrule, is_active, last_run_at, next_runs}], total}` | +| `toggle_automation` | `automation_id` (required) | `{status, id, name, is_active}` | +| `delete_automation` | `automation_id` (required) | `{status, message}` | | **Skills** | | | | `view_skill` | `name` (required) | `{name, content}` | | **Time Tools** | | | @@ -403,6 +421,8 @@ When the **Builtin Tools** capability is enabled, you can further control which | **Image Generation** | `generate_image`, `edit_image` | Generate and edit images | | **Code Interpreter** | `execute_code` | Execute code in a sandboxed environment | | **Channels** | `search_channels`, `search_channel_messages`, `view_channel_message`, `view_channel_thread` | Search channels and channel messages | +| **Task Management** | `create_tasks`, `update_task` | Create a structured task/todo list and update individual task statuses in the active chat | +| **Automations** | `create_automation`, `update_automation`, `list_automations`, `toggle_automation`, `delete_automation` | Create and manage scheduled automations from chat | All categories are **enabled by default**. Disabling a category prevents those specific tools from being injected, while keeping other categories active. @@ -433,6 +453,22 @@ These per-category toggles only appear when the main **Builtin Tools** capabilit Enabling a per-model category toggle does **not** override global feature flags. For example, if `ENABLE_NOTES` is disabled globally (Admin Panel), Notes tools will not be available even if the "Notes" category is enabled for the model. The per-model toggles only allow you to *further restrict* what's already availableβ€”they cannot enable features that are disabled at the global level. ::: +:::warning User-Level Permissions Also Apply +Builtin tools that correspond to an RBAC feature permission are also gated by the user's **Features** permissions. Even if a tool category is enabled on the model and the global feature flag is on, the tool will **not** be injected if the user lacks the corresponding `features.*` permission. Admins always pass these checks. + +| Tool Category | Required `features.*` Permission | +|---------------|----------------------------------| +| Memory | `features.memories` | +| Web Search | `features.web_search` | +| Image Generation | `features.image_generation` | +| Code Interpreter | `features.code_interpreter` | +| Notes | `features.notes` | +| Channels | `features.channels` | +| Automations | `features.automations` | + +This ensures that RBAC permissions are respected end-to-end β€” disabling a feature for a user prevents the model from calling those tools on their behalf, not just hiding the UI. +::: + :::tip Per-Chat Feature Toggles (Web Search, Image Generation, Code Interpreter) **Web Search**, **Image Generation**, and **Code Interpreter** built-in tools have an additional layer of control: the **per-chat feature toggle** in the chat input bar. For these tools to be injected in Native Mode, **all three conditions** must be met: @@ -473,6 +509,8 @@ This is fundamentally different from a single-shot tool call. In an interleaved This behavior is what transforms a standard chatbot into an **Agentic AI** capable of solving complex, multi-step problems autonomously. +For long-running workflows, combine interleaved tool use with `create_tasks` (to lay out the plan upfront) and `update_task` (to mark each step done as work progresses) so the model can plan explicitly, track progress, and keep users aligned on next actions. + --- --- diff --git a/docs/features/index.mdx b/docs/features/index.mdx index b9f84e51a3..93fa725e4c 100644 --- a/docs/features/index.mdx +++ b/docs/features/index.mdx @@ -28,6 +28,8 @@ Your conversations are the core of Open WebUI. Chat with Ollama, OpenAI, Anthrop | πŸ—‚οΈ **Folders, tags, pins** | Organize conversations however you work | | 🎀 **Voice & audio** | Speech-to-text, text-to-speech, hands-free voice & video calls | | πŸ–ΌοΈ **Image generation** | Create and edit images with DALL-E, Gemini, ComfyUI, and more | +| ⏱️ **Automations** | Schedule prompts to run automatically on recurring schedules | +| βœ… **Task management** | Models maintain structured task lists for multi-step workflows | [**Explore chat features β†’**](/features/chat-conversations/chat-features) Β· [**Audio β†’**](/features/chat-conversations/audio) Β· [**Image Generation β†’**](/features/chat-conversations/image-generation-and-editing) diff --git a/docs/features/open-terminal/index.md b/docs/features/open-terminal/index.md index b06d0a3f81..2d1e49d11d 100644 --- a/docs/features/open-terminal/index.md +++ b/docs/features/open-terminal/index.md @@ -83,4 +83,4 @@ Open Terminal requires models with **native function calling** support. Frontier ## Enterprise Multi-User -Need isolated, per-user terminal containers for your team? **[Terminals](./terminals/)** provisions a dedicated Open Terminal instance for every user with automatic lifecycle management, resource controls, and policy-based environments. \ No newline at end of file +Need isolated, per-user terminal containers for your team? **[Terminals](./advanced/terminals/)** provisions a dedicated Open Terminal instance for every user with automatic lifecycle management, resource controls, and policy-based environments. diff --git a/docs/features/workspace/models.md b/docs/features/workspace/models.md index 00bcdc82b7..2e55cb1a39 100644 --- a/docs/features/workspace/models.md +++ b/docs/features/workspace/models.md @@ -94,7 +94,7 @@ Toggle what the model can do and bind resources: | **Web Search** | Enable the configured search provider | | **Code Interpreter** | Enable Python code execution | | **Image Generation** | Enable image generation | -| **Builtin Tools** | Control which tool categories are available: Time, Memory, Chats, Notes, Knowledge, Channels | +| **Builtin Tools** | Control which tool categories are available: Time, Memory, Chats, Notes, Knowledge, Channels, Task Management, Automations | | **File Context** | When enabled, attached files are processed via RAG. When disabled, no file content is extracted | | **TTS Voice** | Set a specific voice for this model's responses | @@ -140,7 +140,7 @@ To download new base models, go to **Settings > Connections > Ollama** or type ` Administrators can set baseline capabilities and parameters that apply to all models via **Admin Panel > Settings > Models > βš™οΈ (gear icon)**. - **Default Model Metadata** (`DEFAULT_MODEL_METADATA`): Baseline capabilities (vision, web search, file context, code interpreter, builtin tools). Per-model overrides always win on conflicts. -- **Default Model Params** (`DEFAULT_MODEL_PARAMS`): Baseline inference parameters (temperature, top_p, max_tokens, function_calling). Per-model values take precedence when explicitly set. +- **Default Model Params** (`DEFAULT_MODEL_PARAMS`): Baseline inference parameters (temperature, top_p, max_tokens, function_calling). Per-model values take precedence when explicitly set. This value is loaded from the environment as JSON; invalid JSON is ignored and falls back to `{}`. ### Merge behavior diff --git a/docs/getting-started/advanced-topics/hardening.md b/docs/getting-started/advanced-topics/hardening.md index 5232066ac5..9c93bcca21 100644 --- a/docs/getting-started/advanced-topics/hardening.md +++ b/docs/getting-started/advanced-topics/hardening.md @@ -125,7 +125,20 @@ Setting `JWT_EXPIRES_IN=-1` disables token expiration entirely. Open WebUI will ### 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. +:::warning Token Revocation Requires Redis + +Without Redis, **signing out does not invalidate a user's token**. The token remains valid and usable until it expires naturally (default: 4 weeks). This means: + +- A stolen or leaked token cannot be revoked by signing out +- Changing a user's password does not invalidate their existing sessions +- Admin-initiated account deactivation does not immediately block access +- OIDC back-channel logout cannot revoke tokens + +With Redis configured, Open WebUI supports per-token revocation. When a user signs out, changes their password, or is deactivated by an admin, their token is added to a revocation list that auto-expires. This is the intended production behavior. + +**If you cannot deploy Redis**, shorten `JWT_EXPIRES_IN` (e.g., `1h` or `4h`) to limit the window of exposure. See the [Redis tutorial](/tutorials/integrations/redis) for setup instructions. + +::: --- @@ -241,7 +254,7 @@ OAUTH_ALLOWED_ROLES=user,admin,superadmin 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. +When enabled, an OAuth login with an email matching an existing local account will merge the two. **This is not recommended.** It 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 β€” effectively an account takeover. Keep this set to `false` unless you have verified that your provider enforces email verification. ### Session limits @@ -257,7 +270,7 @@ 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: +If your reverse proxy handles authentication (Authelia, Authentik, oauth2-proxy), you can pass the authenticated identity to Open WebUI via HTTP headers. **This is possible but risky depending on your setup** β€” incorrect configuration allows any client to authenticate as any user by forging the header: ```bash WEBUI_AUTH_TRUSTED_EMAIL_HEADER=X-Forwarded-Email @@ -380,6 +393,14 @@ ENABLE_ADMIN_CHAT_ACCESS=true BYPASS_MODEL_ACCESS_CONTROL=false ``` +### OpenAI API passthrough + +```bash +ENABLE_OPENAI_API_PASSTHROUGH=false +``` + +The OpenAI router includes a catch-all proxy endpoint (`/{path:path}`) that forwards any request to the upstream OpenAI-compatible API using the admin-configured API key. **This is disabled by default and should be kept disabled.** When enabled, any authenticated user can reach any upstream endpoint β€” including endpoints not natively handled by Open WebUI β€” using the admin's credentials and without model-level access control. Only enable this if you explicitly need direct passthrough to upstream API endpoints and understand the security implications. + ### Data sharing and export Several features control how data can be shared or exported: @@ -665,15 +686,18 @@ The table below summarizes the key hardening actions covered in this guide. Each | [Disable open signup](#registration) | `ENABLE_SIGNUP=true` | `ENABLE_SIGNUP=false` | | [Enable password validation](#password-validation) | Disabled | `ENABLE_PASSWORD_VALIDATION=true` | | [Secure cookies](#cookie-settings) | `Secure=false`, `SameSite=lax` | `Secure=true`, `SameSite=strict` | +| [Enable token revocation](#token-revocation) | No revocation (no Redis) | Configure Redis or shorten `JWT_EXPIRES_IN` | | [Restrict CORS](#cors) | `*` | Your specific domain(s) | | [Set security headers](#security-headers) | None | HSTS, X-Frame-Options, CSP | | [Restrict OAuth domains](#domain-and-group-restrictions) | All allowed | `OAUTH_ALLOWED_DOMAINS=yourdomain.com` | | [Enable audit logging](#audit-logging) | `NONE` | `METADATA` or higher | | [Restrict API key endpoints](#endpoint-restrictions) | All endpoints | `ENABLE_API_KEYS_ENDPOINT_RESTRICTIONS=true` | +| [Keep API passthrough disabled](#openai-api-passthrough) | Disabled | Keep `ENABLE_OPENAI_API_PASSTHROUGH=false` | | [Disable auto pip install](#dependency-installation) | Enabled | `ENABLE_PIP_INSTALL_FRONTMATTER_REQUIREMENTS=false` | | [Review community sharing](#data-sharing-and-export) | `true` | Disable if sensitive data | | [Review direct connections](#data-sharing-and-export) | `false` | Keep disabled unless needed | | [Use PostgreSQL](#postgresql) | SQLite | PostgreSQL | | [Verify outbound TLS](#outbound-tls) | Enabled | Keep enabled | +| [Enable offline mode](#offline-mode) | Disabled | `OFFLINE_MODE=true` for air-gapped environments | | [Structured logging](#structured-logging) | Text | `LOG_FORMAT=json` | | [Keep updated](#keeping-open-webui-updated) | N/A | Latest stable release | diff --git a/docs/getting-started/advanced-topics/scaling.md b/docs/getting-started/advanced-topics/scaling.md index 6462f6d7c1..4789feda63 100644 --- a/docs/getting-started/advanced-topics/scaling.md +++ b/docs/getting-started/advanced-topics/scaling.md @@ -71,7 +71,7 @@ ENABLE_WEBSOCKET_SUPPORT=true **Key things to know:** -- Redis is **not needed** for single-instance deployments. +- Redis is **not needed** for single-instance deployments for basic functionality. However, **without Redis, signing out does not revoke tokens** β€” they remain valid until they expire (default: 4 weeks). If your deployment is production-facing or handles sensitive data, Redis is strongly recommended even for a single instance, or alternatively shorten `JWT_EXPIRES_IN` to limit exposure. See [Token Revocation](/getting-started/advanced-topics/hardening#token-revocation) in the Hardening guide for details. - If you're using Redis Sentinel for high availability, also set `REDIS_SENTINEL_HOSTS` and consider setting `REDIS_SOCKET_CONNECT_TIMEOUT=5` to prevent hangs during failover. - For AWS Elasticache or other managed Redis Cluster services, set `REDIS_CLUSTER=true`. - Make sure your Redis server has `timeout 1800` and a high enough `maxclients` (10000+) to prevent connection exhaustion over time. @@ -357,15 +357,17 @@ ENABLE_DB_MIGRATIONS=false | Scenario | PostgreSQL | Redis | External Vector DB | Ext. Content Extraction | Ext. Embeddings | Shared Storage | |---|:---:|:---:|:---:|:---:|:---:|:---:| | Single user / evaluation | βœ— | βœ— | βœ— | βœ— | βœ— | βœ— | -| Small team (< 50 users, single instance) | Recommended | βœ— | βœ— | Recommended | βœ— | βœ— | +| Small team (< 50 users, single instance) | Recommended | Recommended† | βœ— | Recommended | βœ— | βœ— | | Multiple Uvicorn workers | **Required** | **Required** | **Required** | **Strongly Recommended** | **Strongly Recommended** | βœ— (same filesystem) | | Multiple instances / HA | **Required** | **Required** | **Required** | **Strongly Recommended** | **Strongly Recommended** | **Optional** (NFS or S3) | | Large scale (1000+ users) | **Required** | **Required** | **Required** | **Strongly Recommended** | **Strongly Recommended** | **Optional** (NFS or S3) | +†Without Redis, signing out and password changes do **not** revoke tokens β€” they remain valid until `JWT_EXPIRES_IN` expires (default: 4 weeks). For production deployments handling sensitive data, Redis is recommended for proper token revocation. See [Token Revocation](/getting-started/advanced-topics/hardening#token-revocation). + :::note About "External Vector DB" The default ChromaDB uses a local SQLite backend that crashes under multi-process access. "External Vector DB" means either a client-server database (PGVector, Milvus, Qdrant, Pinecone) or ChromaDB running as a separate HTTP server. See [Step 4](#step-4--switch-to-an-external-vector-database) for details. ::: :::note About "Shared Storage" -For multiple instances, all replicas need access to the same uploaded files. A **shared filesystem mount** (local drive, NFS, EFS, CephFS) is sufficient β€” cloud object storage (S3/GCS/Azure) is a scalable alternative, butt not a requirement. Files use UUID-based unique names, so there are no write conflicts. See [Step 5](#step-5--share-file-storage-across-instances) for details. +For multiple instances, all replicas need access to the same uploaded files. A **shared filesystem mount** (local drive, NFS, EFS, CephFS) is sufficient β€” cloud object storage (S3/GCS/Azure) is a scalable alternative, but not a requirement. Files use UUID-based unique names, so there are no write conflicts. See [Step 5](#step-5--share-file-storage-across-instances) for details. ::: diff --git a/docs/getting-started/quick-start/connect-a-provider/starting-with-openai-compatible.mdx b/docs/getting-started/quick-start/connect-a-provider/starting-with-openai-compatible.mdx index da945f3d4f..46b52a2559 100644 --- a/docs/getting-started/quick-start/connect-a-provider/starting-with-openai-compatible.mdx +++ b/docs/getting-started/quick-start/connect-a-provider/starting-with-openai-compatible.mdx @@ -511,6 +511,12 @@ Each connection has a **toggle switch** that lets you enable or disable it witho LiteLLM is useful as a **universal bridge** when you want to use a provider that doesn't natively support the OpenAI API standard, or when you want to load-balance across multiple providers. ::: + :::warning Security Recommendation: Key Scope + For multi-user deployments, avoid using provider management/master keys for your main Open WebUI connection. + + Prefer least-privilege provider credentials (inference-scoped keys where supported). This reduces blast radius if users invoke provider-specific endpoints through OpenAI-compatible integrations. + ::: + diff --git a/docs/getting-started/quick-start/tab-docker/ManualDocker.md b/docs/getting-started/quick-start/tab-docker/ManualDocker.md index 65d37fba81..80b79d7bba 100644 --- a/docs/getting-started/quick-start/tab-docker/ManualDocker.md +++ b/docs/getting-started/quick-start/tab-docker/ManualDocker.md @@ -49,9 +49,9 @@ Visit [http://localhost:3000](http://localhost:3000). For production environments, pin a specific version instead of using floating tags: ```bash -docker pull ghcr.io/open-webui/open-webui:v0.8.6 -docker pull ghcr.io/open-webui/open-webui:v0.8.6-cuda -docker pull ghcr.io/open-webui/open-webui:v0.8.6-ollama +docker pull ghcr.io/open-webui/open-webui:v0.9.0 +docker pull ghcr.io/open-webui/open-webui:v0.9.0-cuda +docker pull ghcr.io/open-webui/open-webui:v0.9.0-ollama ``` --- diff --git a/docs/getting-started/updating.mdx b/docs/getting-started/updating.mdx index 8f8f557bd8..9796b610b7 100644 --- a/docs/getting-started/updating.mdx +++ b/docs/getting-started/updating.mdx @@ -31,9 +31,9 @@ The `:main` tag always points to the **latest build**. It's convenient but can i For stability, pin a specific release tag: ``` -ghcr.io/open-webui/open-webui:v0.8.6 -ghcr.io/open-webui/open-webui:v0.8.6-cuda -ghcr.io/open-webui/open-webui:v0.8.6-ollama +ghcr.io/open-webui/open-webui:v0.9.0 +ghcr.io/open-webui/open-webui:v0.9.0-cuda +ghcr.io/open-webui/open-webui:v0.9.0-ollama ``` Browse all available tags on the [GitHub releases page](https://github.com/open-webui/open-webui/releases). diff --git a/docs/reference/database-schema.md b/docs/reference/database-schema.md index 69050c5c08..2d71fba5ce 100644 --- a/docs/reference/database-schema.md +++ b/docs/reference/database-schema.md @@ -10,7 +10,7 @@ This tutorial is a community contribution and is not supported by the Open WebUI ::: > [!WARNING] -> This documentation was created/updated based on version 0.8.6 and updated for recent migrations. +> This documentation reflects schema changes up to Open WebUI v0.9.0. ## Open-WebUI Internal SQLite Database @@ -85,6 +85,8 @@ Here is a complete list of tables in Open-WebUI's SQLite database. The tables ar | 29 | tag | Manages tags/labels for content categorization | | 30 | tool | Stores configurations for system tools and integrations | | 31 | user | Maintains user profiles and account information | +| 32 | automation | Stores user-defined scheduled automations | +| 33 | automation_run | Stores execution history for automation runs | Note: there are two additional tables in Open-WebUI's SQLite database that are not related to Open-WebUI's core functionality, that have been excluded: @@ -189,6 +191,50 @@ Things to know about the channel_file table: | pinned | Boolean | default=False, nullable | Pin status | | meta | JSON | server_default="{}" | Metadata including tags | | folder_id | Text | nullable | Parent folder ID | +| tasks | JSON | nullable | Chat-level task/todo list used by agentic workflows | +| summary | Text | nullable | Optional chat summary text | +| last_read_at | BigInteger | nullable | Last read timestamp used for unread indicators | + +Things to know about the chat table: + +- `tasks` and `summary` support structured planning/status UX in chat sessions. +- `last_read_at` is used by sidebar unread state logic (compare with `updated_at`). + +## Automation Table + +| **Column Name** | **Data Type** | **Constraints** | **Description** | +| --------------- | ------------- | ----------------------- | --------------- | +| id | Text | PRIMARY KEY | Unique identifier (UUID) | +| user_id | Text | NOT NULL | Owner of the automation | +| name | Text | NOT NULL | Automation display name | +| data | JSON | NOT NULL | Automation payload (`prompt`, `model_id`, `rrule`, optional terminal config) | +| meta | JSON | nullable | Optional metadata | +| is_active | Boolean | NOT NULL, default=True | Active/paused state | +| last_run_at | BigInteger | nullable | Last execution time | +| next_run_at | BigInteger | nullable | Next scheduled execution time | +| created_at | BigInteger | NOT NULL | Creation timestamp | +| updated_at | BigInteger | NOT NULL | Last update timestamp | + +Things to know about the automation table: + +- `next_run_at` is indexed for efficient due-run polling. +- `data.rrule` defines recurrence and drives scheduler calculations. + +## Automation Run Table + +| **Column Name** | **Data Type** | **Constraints** | **Description** | +| --------------- | ------------- | --------------- | --------------- | +| id | Text | PRIMARY KEY | Unique identifier (UUID) | +| automation_id | Text | NOT NULL | Reference to automation | +| chat_id | Text | nullable | Chat created by this run (if available) | +| status | Text | NOT NULL | Run status (`success` / `error`) | +| error | Text | nullable | Error details when status is `error` | +| created_at | BigInteger | NOT NULL | Execution record timestamp | + +Things to know about the automation_run table: + +- Indexed by `automation_id` for fast per-automation run history queries. +- Rows are deleted when an automation is deleted. ## Chat File Table @@ -896,4 +942,3 @@ To use SQLCipher with existing data, you must either: | `DATABASE_POOL_RECYCLE` | `3600` | Pool connection recycle time in seconds | For more details, see the [Environment Variable Configuration](/reference/env-configuration) documentation. - diff --git a/docs/reference/env-configuration.mdx b/docs/reference/env-configuration.mdx index d182fa1686..a8c565d05c 100644 --- a/docs/reference/env-configuration.mdx +++ b/docs/reference/env-configuration.mdx @@ -12,7 +12,7 @@ As new variables are introduced, this page will be updated to reflect the growin :::info -This page is up-to-date with Open WebUI release version [v0.8.5](https://github.com/open-webui/open-webui/releases/tag/v0.8.5), but is still a work in progress to later include more accurate descriptions, listing out options available for environment variables, defaults, and improving descriptions. +This page is up-to-date with Open WebUI release version [v0.9.0](https://github.com/open-webui/open-webui/releases/tag/v0.9.0), but is still a work in progress to later include more accurate descriptions, listing out options available for environment variables, defaults, and improving descriptions. ::: @@ -205,6 +205,15 @@ is also being used and set to `True`. **Never disable this if OAUTH/SSO is not b - Description: Sets global default parameters (temperature, top_p, max_tokens, seed, etc.) for all models. These defaults are applied as a baseline at chat completion time β€” per-model parameter overrides always take precedence. Configurable via **Admin Settings β†’ Models**. - Persistence: This environment variable is a `PersistentConfig` variable. Stored at config key `models.default_params`. +:::info + +`DEFAULT_MODEL_PARAMS` is read from the environment as a JSON string at startup. + +- Use valid JSON (for example: `{"temperature":0.7,"function_calling":"native"}`) +- If parsing fails, Open WebUI logs the error and falls back to `{}` + +::: + #### `DEFAULT_USER_ROLE` - Type: `str` @@ -265,6 +274,31 @@ is also being used and set to `True`. **Never disable this if OAUTH/SSO is not b - Description: Sets the maximum number of files processing allowed per folder. - Persistence: This environment variable is a `PersistentConfig` variable. It can be configured in the **Admin Panel > Settings > General > Folder Max File Count**. Default is none (empty string) which is unlimited. +#### `AUTOMATION_MAX_COUNT` + +- Type: `int` +- Default: `("") empty string` (unlimited) +- Description: Sets the maximum number of automations a non-admin user can create. When set to a positive integer, users who reach this limit will receive a `403 Forbidden` error when attempting to create additional automations. Admins bypass this limit. +- Persistence: This environment variable is a `PersistentConfig` variable. + +#### `AUTOMATION_MIN_INTERVAL` + +- Type: `int` (seconds) +- Default: `("") empty string` (no minimum) +- Description: Sets the minimum allowed interval in seconds between automation recurrences for non-admin users. When set, any automation schedule that recurs more frequently than this value will be rejected with a `400 Bad Request` error. One-time automations (`COUNT=1`) are exempt from this check. Admins bypass this limit. +- Persistence: This environment variable is a `PersistentConfig` variable. + +:::tip Common values for AUTOMATION_MIN_INTERVAL + +| Value | Meaning | +|-------|---------| +| `60` | Minimum 1 minute between runs | +| `300` | Minimum 5 minutes between runs | +| `900` | Minimum 15 minutes between runs | +| `3600` | Minimum 1 hour between runs | + +::: + #### `ENABLE_NOTES` - Type: `bool` @@ -663,6 +697,28 @@ If this variable is unset or invalid, Open WebUI falls back to `AIOHTTP_CLIENT_T - Default: `True` - Description: Controls SSL/TLS verification specifically for tool server connections via AIOHTTP client. +#### `AIOHTTP_POOL_CONNECTIONS` + +- Type: `int` +- Default: unset (unlimited) +- Description: Maximum number of total concurrent connections in the shared AIOHTTP client pool used for outbound requests (Ollama, OpenAI-compatible endpoints, etc.). When unset, there is no total cap. Lower this if you need to bound total upstream concurrency. + +#### `AIOHTTP_POOL_CONNECTIONS_PER_HOST` + +- Type: `int` +- Default: unset (unlimited) +- Description: Maximum number of concurrent connections to any single host in the shared AIOHTTP pool. When unset, there is no per-host cap. Useful for staying under provider-side rate or connection limits. + +#### `AIOHTTP_POOL_DNS_TTL` + +- Type: `int` +- Default: `300` +- Description: DNS cache TTL in seconds for the shared AIOHTTP pool. Negative or invalid values fall back to `300`. Increase for stable infrastructure; decrease if upstream hosts change IPs frequently. + +:::info +Open WebUI reuses a single long-lived AIOHTTP client session for outbound HTTP traffic, enabling TCP/TLS connection reuse, a shared DNS cache, and bounded concurrency. The three variables above tune this pool; they do not need to be set in typical deployments. +::: + #### `REQUESTS_VERIFY` - Type: `bool` @@ -838,6 +894,12 @@ By default, audit logging uses **blacklist mode** β€” all paths are logged excep - Example: `sk-124781258123` - Persistence: This environment variable is a `PersistentConfig` variable. +:::warning Provider Key Scope (Important) +For OpenAI-compatible backends and proxies (including LiteLLM), configure least-privilege keys for regular user traffic whenever possible. + +Do not use provider management/master keys unless your deployment explicitly requires that trust level. +::: + #### `OPENAI_API_KEYS` - Type: `str` @@ -845,6 +907,18 @@ By default, audit logging uses **blacklist mode** β€” all paths are logged excep - Example: `sk-124781258123;sk-4389759834759834` - Persistence: This environment variable is a `PersistentConfig` variable. +#### `ENABLE_OPENAI_API_PASSTHROUGH` + +- Type: `bool` +- Default: `False` +- Description: When enabled, the OpenAI proxy's catch-all endpoint (`/{path:path}`) forwards any request to the upstream OpenAI-compatible API using the admin-configured API key and without additional access control. When disabled (default), the catch-all returns `403 Forbidden`. Other routers (Ollama, Responses) do not have catch-all proxies. + +:::danger + +**Keep this disabled unless you explicitly need it.** The catch-all proxy forwards requests to the upstream API using the admin's API key with no model-level access control. Any authenticated user can reach any upstream endpoint β€” including endpoints not natively handled by Open WebUI β€” using the admin's credentials. Only enable this if you understand and accept these implications. + +::: + ### Tasks #### `TASK_MODEL` @@ -1671,21 +1745,39 @@ When setting a custom `PASSWORD_VALIDATION_REGEX_PATTERN`, always set `PASSWORD_ #### `WEBUI_SECRET_KEY` - Type: `str` -- Default: `t0p-s3cr3t` -- Docker Default: Randomly generated on first start -- Description: Overrides the randomly generated string used for JSON Web Token and **encryption of sensitive data** (like OAuth tokens for MCP). +- Default: Automatically generated (see below) +- Description: The secret key used for signing JSON Web Tokens (JWTs) and **encrypting sensitive data** at rest (including OAuth tokens for MCP). Can be set via the `WEBUI_SECRET_KEY` environment variable or the legacy `WEBUI_JWT_SECRET_KEY` variable (deprecated). + +:::info How the secret key is generated + +You do **not** need to manually set this variable for a secure installation β€” **all standard launch methods automatically generate and persist a cryptographically random key on first start:** + +| Launch method | Auto-generates? | Persisted to | +|---|---|---| +| **Docker** (`start.sh`) | βœ… Yes | `.webui_secret_key` file inside the container | +| **pip install** (`open-webui serve`) | βœ… Yes | `.webui_secret_key` file in the working directory | +| **Development** (`open-webui dev`, direct `uvicorn`) | ❌ No | N/A β€” uses the code-level fallback | -:::danger Critical for Docker/Production +The code-level fallback value (`t0p-s3cr3t`) exists **only** for development convenience and is **never used** when Open WebUI is launched through the standard Docker or `open-webui serve` methods. Both of those methods check for the environment variable first, and if it is not set, generate a secure random key, save it to a file, and inject it into the environment β€” all before the application starts. -You **MUST** set `WEBUI_SECRET_KEY` to a secure, persistent value. +::: + +:::danger Recommended: Set an explicit, persistent value + +While the auto-generated key is secure, it is tied to a file inside the container or working directory. **If the container is recreated (not just restarted) and the key file is not in a persisted volume, a new key is generated**, which causes: + +1. **All existing user sessions become invalid** (users are logged out). +2. **All OAuth sessions become invalid.** +3. **MCP Tools break** (Error: `Error decrypting tokens`) because tokens encrypted with the previous key cannot be decrypted. -If you do NOT set this: -1. It will be randomly generated each time the container restarts/recreates. -2. **All OAuth sessions will become invalid.** -3. **MCP Tools will break** (Error: `Error decrypting tokens`) because they cannot decrypt the tokens stored with the previous key. -4. You will be logged out. +To avoid this, explicitly set `WEBUI_SECRET_KEY` to a secure, persistent value that survives container recreates: -**Do not leave this unset in production.** +```bash +# Generate a secure key +openssl rand -hex 32 +``` + +Then pass it as an environment variable in your Docker Compose or deployment configuration. ::: @@ -1693,7 +1785,7 @@ If you do NOT set this: **Required for Multi-Worker and Multi-Node Deployments AND HIGHLY RECOMMENDED IN SINGLE-WORKER ENVIRONMENTS** -When deploying Open WebUI with `UVICORN_WORKERS > 1` or in a multi-node/worker cluster with a load balancer (e.g. helm/kubectl/kubernetes/k8s, you **must** set this variable. Without it, the following issues will occur: +When deploying Open WebUI with `UVICORN_WORKERS > 1` or in a multi-node/worker cluster with a load balancer (e.g. helm/kubectl/kubernetes/k8s), you **must** set this variable to the **same value across all replicas**. Without it, the following issues will occur: - Session management will fail across workers - Application state will be inconsistent between instances @@ -3539,7 +3631,7 @@ Allow only specific domains: WEB_FETCH_FILTER_LIST="example.com,trusted-site.org - Type: `int` - Default: `3` -- Description: Maximum number of search results to crawl. +- Description: Maximum number of web search results to crawl. In Native/Agentic tool calling, this is also the default `search_web` result count when the model omits `count`, and the maximum cap when the model provides `count`. - Persistence: This environment variable is a `PersistentConfig` variable. #### `WEB_SEARCH_CONCURRENT_REQUESTS` @@ -4211,6 +4303,7 @@ Note: If none of the specified languages are available and `en` was not in your - Options: - `""` (empty string) - **Disables backend TTS.** When empty, TTS requests do not reach the backend. All TTS is handled client-side using the browser's Web Speech API or the user-configurable "Browser Kokoro" option in User Settings. - `openai` - Uses an OpenAI-compatible API for Text-to-Speech. + - `mistral` - Uses Mistral's Text-to-Speech API. - `elevenlabs` - Uses ElevenLabs engine for Text-to-Speech. - `azure` - Uses Azure Cognitive Services for Text-to-Speech. - `transformers` - Uses a local SentenceTransformers-based model for Text-to-Speech (runs on the backend). @@ -4292,6 +4385,28 @@ Note: If none of the specified languages are available and `en` was not in your - Example: `{"speed": 1.0}` - Persistence: This environment variable is a `PersistentConfig` variable. +### Mistral Text-to-Speech + +#### `AUDIO_TTS_MISTRAL_API_KEY` + +- Type: `str` +- Default: `None` +- Description: Sets the API key used for Mistral Text-to-Speech. +- Persistence: This environment variable is a `PersistentConfig` variable. + +#### `AUDIO_TTS_MISTRAL_API_BASE_URL` + +- Type: `str` +- Default: `https://api.mistral.ai/v1` +- Description: Sets the base URL used for Mistral Text-to-Speech. +- Persistence: This environment variable is a `PersistentConfig` variable. + +:::info + +When `AUDIO_TTS_ENGINE=mistral`, Open WebUI uses `mistral-tts-latest` when `AUDIO_TTS_MODEL` is empty. + +::: + ### Elevenlabs Text-to-Speech #### `ELEVENLABS_API_BASE_URL` @@ -4851,6 +4966,33 @@ curl -X POST "http://localhost:8080/api/v1/oauth/google/token/exchange" \ - The OAuth provider must be properly configured - The token exchange uses the same user lookup logic as regular OAuth login (by OAuth `sub` claim first, then by email if `OAUTH_MERGE_ACCOUNTS_BY_EMAIL` is enabled) +#### `ENABLE_OAUTH_BACKCHANNEL_LOGOUT` + +- Type: `bool` +- Default: `False` +- Description: Enables OpenID Connect Back-Channel Logout support. When enabled, Open WebUI exposes `POST /oauth/backchannel-logout` so your identity provider can trigger server-side logout without browser redirects. +- Usage: Set to `true` to enable the endpoint. Your identity provider should send a form-encoded `logout_token` that follows the OpenID Connect Back-Channel Logout 1.0 specification. + +:::warning + +**Redis Requirement for JWT Revocation** + +Back-channel logout revokes existing Open WebUI JWT sessions through Redis-based revocation keys. Without Redis, Open WebUI can still remove stored OAuth sessions, but already-issued JWTs remain valid until they naturally expire. + +For production SSO deployments, especially with multiple workers or replicas, configure `REDIS_URL` when enabling this feature. + +::: + +:::info + +**Behavior Notes** + +- The endpoint returns `200` with an empty body for valid requests, including cases where no matching user is found. +- Invalid or malformed `logout_token` requests return `400` with `invalid_request` details. +- Back-channel logout revokes users by provider + `sub` claim matching. `sid`-only logout matching is not currently supported. + +::: + #### `OAUTH_CLIENT_INFO_ENCRYPTION_KEY` - Type: `str` @@ -5612,6 +5754,24 @@ This setting is compliant with [RFC 6749 Section 6](https://datatracker.ietf.org - Description: Enables or disables user permission to use the [memory feature](/features/chat-conversations/memory). - Persistence: This environment variable is a `PersistentConfig` variable. +#### `USER_PERMISSIONS_FEATURES_AUTOMATIONS` + +- Type: `str` +- Default: `False` +- Description: Enables or disables Automations access for non-admin users. When enabled, users can access `/automations` and manage their own scheduled automations. +- Persistence: This environment variable is a `PersistentConfig` variable. + +:::info + +This setting maps to **Features > Automations** in RBAC permissions. + +- Non-admin users need this permission to access and use Automations. +- Admin users are exempt from this specific permission check. + +See [Permissions](/features/authentication-access/rbac/permissions#4-features-permissions) for role/permission behavior. + +::: + #### `USER_PERMISSIONS_FEATURES_FOLDERS` - Type: `str` @@ -6358,7 +6518,7 @@ Redis serves as the central state store that allows multiple Open WebUI instance **Single Instance Deployments** -If you're running Open WebUI as a single instance with `UVICORN_WORKERS=1` (the default), Redis is **not required**. The application will function normally without it. +If you're running Open WebUI as a single instance with `UVICORN_WORKERS=1` (the default), Redis is **not required** for basic functionality. However, without Redis, signing out and password changes do **not** invalidate existing JWT tokens β€” they remain valid until they expire (default: 4 weeks). For production deployments, either configure Redis or shorten [`JWT_EXPIRES_IN`](#jwt_expires_in). See [Token Revocation](/getting-started/advanced-topics/hardening#token-revocation) for details. ::: @@ -6441,7 +6601,7 @@ Redis Cluster mode is fully compatible with OpenTelemetry instrumentation. When - Type: `float` (seconds) or empty string for None - Default: None (no timeout, uses redis-py library default) -- Description: Sets the socket connection timeout in seconds for Redis and Sentinel connections. This timeout applies to the initial TCP connection establishment. When set, it prevents indefinite blocking when attempting to connect to unreachable Redis nodes. +- Description: Sets the socket connection timeout in seconds for all Redis client connections, including Sentinel, Cluster, and plain URL modes. This timeout applies to the initial TCP connection establishment. When set, it prevents indefinite blocking when attempting to connect to unreachable Redis nodes. :::danger @@ -6466,6 +6626,23 @@ If `WEBSOCKET_REDIS_OPTIONS` is not set, `REDIS_SOCKET_CONNECT_TIMEOUT` will be ::: +#### `REDIS_SOCKET_KEEPALIVE` + +- Type: `bool` +- Default: `False` +- Description: Enables TCP `SO_KEEPALIVE` on all Redis client sockets (plain, cluster, and sentinel connections, both sync and async). When enabled, the operating system kernel sends TCP keepalive probes on idle connections, detecting half-closed sockets (e.g., after a silent firewall/load balancer reset or a NIC flap) before the next Redis command lands on them. + +:::tip When to enable + +Enable this setting in environments where: +- A firewall or load balancer sits between the application and Redis and may silently drop idle connections +- Network instability can cause connections to become half-open without notification +- You want an additional layer of dead-connection detection alongside `REDIS_HEALTH_CHECK_INTERVAL` + +`REDIS_SOCKET_KEEPALIVE` operates at the TCP level (kernel-driven probes), while `REDIS_HEALTH_CHECK_INTERVAL` operates at the application level (redis-py PING commands). They are complementary and can be used together for maximum reliability. + +::: + #### `REDIS_SENTINEL_MAX_RETRY_COUNT` - Type: `int` @@ -6478,6 +6655,33 @@ If `WEBSOCKET_REDIS_OPTIONS` is not set, `REDIS_SOCKET_CONNECT_TIMEOUT` will be - Default: None - Description: Optional reconnect delay in milliseconds for Redis Sentinel retry logic, applied consistently across both synchronous and asynchronous Redis operations. This improves stability during Sentinel failover by preventing tight retry loops. When unset or invalid, retry behavior remains unchanged. +#### `REDIS_HEALTH_CHECK_INTERVAL` + +- Type: `int` (seconds) +- Default: None (disabled) +- Description: How often (in seconds) redis-py should PING an idle pooled connection before reusing it. When set to a positive integer, redis-py will PING any pooled connection that has been idle longer than this interval before handing it back to a caller. This detects stale/dead connections before a real command lands on them, preventing `ConnectionError: Connection reset by peer` errors. Set to `0` or leave empty to disable. + +:::tip Recommended for production + +Set `REDIS_HEALTH_CHECK_INTERVAL` to a value **shorter** than both: +- Your Redis server's `timeout` setting (e.g., `timeout 1800`) +- Any firewall or load balancer idle timeout on the path to Redis + +A typical value is `60` (seconds). This keeps actively-used pooled connections warm (the PING resets the server's idle timer) while still allowing the Redis server to reap truly orphaned connections via its `timeout` setting. + +::: + +:::info How it works + +When enabled, redis-py performs a lightweight `PING` on checkout for any connection that has been idle longer than the configured interval. This serves two purposes: + +1. **Detects dead connections** β€” stale sockets are identified and replaced before your application code runs a command on them +2. **Keeps active connections alive** β€” the PING resets the Redis server's per-connection idle timer, preventing the server from reaping connections that are still in the pool + +Without this setting, if your Redis server has a `timeout` configured (recommended to prevent connection exhaustion), the first request that grabs a reaped socket from the pool will fail with a `ConnectionError`. + +::: + #### `WEBSOCKET_REDIS_LOCK_TIMEOUT` - Type: `int` diff --git a/docs/security.mdx b/docs/security.mdx index 32d7cd6e86..63a35bdfb6 100644 --- a/docs/security.mdx +++ b/docs/security.mdx @@ -147,6 +147,12 @@ More generally, **reports describing ANY attack chain that involves Tools or Fun These scenarios represent **admin negligence** or **environment compromise**, not vulnerabilities in Open WebUI itself. See [our Security Policy](https://github.com/open-webui/open-webui/security) and the [Plugin Security documentation](/features/extensibility/plugin/) for details. +## Production Deployment Security + +Open WebUI is designed for private, trusted networks and ships with defaults optimized for ease of setup. Production deployments handling sensitive data should review the [Hardening Guide](https://docs.openwebui.com/getting-started/advanced-topics/hardening) for a comprehensive checklist. + +A key consideration: **without Redis, signing out and password changes do not revoke existing JWT tokens** β€” they remain valid until they expire (default: 4 weeks). This means compromised tokens cannot be invalidated, and admin-initiated account deactivation does not immediately block access. For production deployments, either configure [Redis](https://docs.openwebui.com/tutorials/integrations/redis) or shorten `JWT_EXPIRES_IN` to limit the window of exposure. See [Token Revocation](https://docs.openwebui.com/getting-started/advanced-topics/hardening#token-revocation) for details. + ## Product Security Process - Internal and periodic external reviews of our architecture and pipelines diff --git a/docs/troubleshooting/audio.mdx b/docs/troubleshooting/audio.mdx index 5d7ed6a01e..d54bc89385 100644 --- a/docs/troubleshooting/audio.mdx +++ b/docs/troubleshooting/audio.mdx @@ -22,7 +22,7 @@ Admins can configure server-wide audio defaults: Here you can configure: - **Speech-to-Text Engine** β€” Choose between local Whisper, OpenAI, Azure, Deepgram, or Mistral - **Whisper Model** β€” Select model size for local STT (tiny, base, small, medium, large) -- **Text-to-Speech Engine** β€” Choose between OpenAI-compatible, ElevenLabs, Azure, local Transformers, or disable backend TTS (browser-only) +- **Text-to-Speech Engine** β€” Choose between OpenAI-compatible, Mistral, ElevenLabs, Azure, local Transformers, or disable backend TTS (browser-only) - **TTS Voice** β€” Select the default voice - **API Keys and Base URLs** β€” Configure external service connections @@ -71,6 +71,27 @@ environment: β†’ See full guides: [Speech-to-Text](/category/speech-to-text) | [Text-to-Speech](/category/text-to-speech) +### Fast Setup: Mistral STT + TTS (Paid) + +If you prefer Mistral's audio stack: + +**In Admin Panel β†’ Settings β†’ Audio:** +- **STT Engine:** `MistralAI` | **Model:** `voxtral-mini-latest` (or leave empty) +- **TTS Engine:** `MistralAI` | **Model:** `mistral-tts-latest` (or leave empty) | **Voice:** choose from list +- Enter your Mistral API key in both sections + +Or via environment variables: +```yaml +environment: + - AUDIO_STT_ENGINE=mistral + - AUDIO_STT_MISTRAL_API_KEY=... + - AUDIO_TTS_ENGINE=mistral + - AUDIO_TTS_MISTRAL_API_KEY=... + - AUDIO_TTS_MODEL=mistral-tts-latest +``` + +β†’ See guides: [Mistral Voxtral STT](/features/chat-conversations/audio/speech-to-text/mistral-voxtral-integration) | [Mistral TTS](/features/chat-conversations/audio/text-to-speech/mistral-tts-integration) + ### Free Setup: Local Whisper + Edge TTS For a completely free setup: @@ -400,12 +421,14 @@ curl http://your-tts-service:port/health | Variable | Description | |----------|-------------| -| `AUDIO_TTS_ENGINE` | TTS engine: `""` (empty, disables backend TTS - uses browser), `openai`, `elevenlabs`, `azure`, `transformers` | +| `AUDIO_TTS_ENGINE` | TTS engine: `""` (empty, disables backend TTS - uses browser), `openai`, `mistral`, `elevenlabs`, `azure`, `transformers` | | `AUDIO_TTS_MODEL` | TTS model to use (default: `tts-1`) | | `AUDIO_TTS_VOICE` | Default voice for TTS (default: `alloy`) | | `AUDIO_TTS_API_KEY` | API key for ElevenLabs or Azure TTS | | `AUDIO_TTS_OPENAI_API_BASE_URL` | Base URL for OpenAI-compatible TTS | | `AUDIO_TTS_OPENAI_API_KEY` | API key for OpenAI-compatible TTS | +| `AUDIO_TTS_MISTRAL_API_KEY` | API key for Mistral TTS | +| `AUDIO_TTS_MISTRAL_API_BASE_URL` | Base URL for Mistral TTS | ### STT Environment Variables diff --git a/docs/troubleshooting/sso.mdx b/docs/troubleshooting/sso.mdx index 7b433dd980..bd5e524797 100644 --- a/docs/troubleshooting/sso.mdx +++ b/docs/troubleshooting/sso.mdx @@ -462,3 +462,13 @@ If using a reverse proxy, test OAuth directly against Open WebUI: --- By carefully configuring both your OAuth provider and your Open WebUI environment β€” and keeping critical login endpoints immune from caching β€” you can eliminate nearly all SSO/OAuth login problems. + +--- + +:::warning Token Revocation Requires Redis + +Without Redis, **signing out does not revoke JWT tokens** β€” they remain valid until they expire (default: 4 weeks). This is especially relevant for SSO/OAuth deployments where you may need to revoke access quickly (e.g., when an employee leaves the organization). Password changes and admin-initiated account deactivation also cannot revoke existing tokens without Redis. + +For production SSO deployments, configure Redis or shorten `JWT_EXPIRES_IN` to limit exposure. See [Token Revocation](/getting-started/advanced-topics/hardening#token-revocation) and the [Redis tutorial](/tutorials/integrations/redis) for details. + +::: diff --git a/docs/troubleshooting/web-search.mdx b/docs/troubleshooting/web-search.mdx index 0cbd074658..8437c96141 100644 --- a/docs/troubleshooting/web-search.mdx +++ b/docs/troubleshooting/web-search.mdx @@ -68,6 +68,8 @@ If web search returns empty content or poor quality results, the issue is often - **Check result count**: Adjust `WEB_SEARCH_RESULT_COUNT` to control how many results are fetched. + In Native/Agentic tool calling, if the model omits `count` for `search_web`, Open WebUI uses `WEB_SEARCH_RESULT_COUNT` by default. If the model provides `count`, it is capped at the same admin-configured maximum. + - **Try different loaders**: Configure `WEB_LOADER_ENGINE` to use `playwright` for JavaScript-heavy sites or `firecrawl`/`tavily` for better extraction. For more details on context window issues, see the [RAG Troubleshooting Guide](./rag). @@ -103,4 +105,3 @@ Key variables: | `WEB_LOADER_ENGINE` | Content extraction engine | --- - diff --git a/docs/tutorials/auth-sso/entra-group-name-sync.md b/docs/tutorials/auth-sso/entra-group-name-sync.md index 67cb4d8b79..2879e2c122 100644 --- a/docs/tutorials/auth-sso/entra-group-name-sync.md +++ b/docs/tutorials/auth-sso/entra-group-name-sync.md @@ -199,6 +199,28 @@ Admin users' group memberships are **not** automatically updated via OAuth group ::: +## Hybrid AD Groups (On-Premises Active Directory) + +The `cloud_displayname` approach described above works for **cloud-native** Entra ID security groups. However, if your organization syncs groups from an **on-premises Active Directory** to Entra ID, those synced groups may still appear as GUIDs in Open WebUI even after following the steps above. + +This happens because `cloud_displayname` only resolves names for groups that originate in Entra ID. Groups synced from on-prem AD require a different token configuration. + +### Fix: Use sAMAccountName for Hybrid Groups + +1. In the **Azure Portal**, navigate to your **App Registration** +2. Go to **Token configuration** +3. If you already have a groups claim, click on it to edit. Otherwise, click **Add groups claim** +4. Under the **ID** token type, set the group identifier format to **sAMAccountName** +5. Click **Save** + +This tells Entra ID to include the on-prem `sAMAccountName` attribute for AD-synced groups, which resolves to the human-readable group name. + +:::info Mixed Environments + +If you have **both** cloud-native and on-prem AD-synced groups, using `sAMAccountName` will correctly resolve names for both types. + +::: + ## Additional Resources - [SSO (OAuth, OIDC, Trusted Header)](/features/authentication-access/auth/sso) - OAuth configuration overview diff --git a/docs/tutorials/integrations/redis.md b/docs/tutorials/integrations/redis.md index 6a0fc0f392..c7ed5f5961 100644 --- a/docs/tutorials/integrations/redis.md +++ b/docs/tutorials/integrations/redis.md @@ -21,7 +21,15 @@ Redis serves two distinct purposes in Open WebUI, and understanding when it's re ### Single Instance Deployments -If you're running Open WebUI as a **single instance** with `UVICORN_WORKERS=1` (the default), Redis is **completely optional and not strictly needed**. The application will function normally without it for all operations. +If you're running Open WebUI as a **single instance** with `UVICORN_WORKERS=1` (the default), Redis is **not required for basic functionality**. The application will function normally without it for most operations. + +:::warning Security: Token Revocation Requires Redis + +Without Redis, **signing out does not invalidate a user's JWT token**. The token remains valid and usable until it expires naturally (default: 4 weeks). Password changes and admin-initiated account deactivation also cannot revoke existing tokens without Redis. + +For production-facing deployments, either configure Redis or shorten `JWT_EXPIRES_IN` to limit the window of exposure. See the [Hardening guide](/getting-started/advanced-topics/hardening#token-revocation) for details. + +::: ### Multi-Worker and Multi-Instance Deployments @@ -288,6 +296,29 @@ To enhance resilience during Sentinel failoverβ€”the window when a new master is - **`REDIS_SENTINEL_MAX_RETRY_COUNT`**: Sets the maximum number of retries for Redis operations when using Sentinel (Default: `2`). - **`REDIS_RECONNECT_DELAY`**: Adds an optional delay in **milliseconds** between retry attempts (e.g., `REDIS_RECONNECT_DELAY=500`). This prevents tight retry loops that may otherwise overwhelm the event loop or block the application before a new master is ready. +#### Connection Health Checks + +If your Redis server has a `timeout` configured (recommended β€” see above), pooled connections that sit idle longer than that timeout will be reaped server-side. Without health checks, the next request that grabs one of those dead sockets will fail with `ConnectionError: Connection reset by peer`. + +- **`REDIS_HEALTH_CHECK_INTERVAL`**: How often (in seconds) redis-py should PING an idle pooled connection before reusing it (e.g., `REDIS_HEALTH_CHECK_INTERVAL=60`). The value must be **shorter** than your Redis server's `timeout` and any firewall/load balancer idle timeout on the path to Redis. Set to `0` or leave empty to disable. +- **`REDIS_SOCKET_KEEPALIVE`**: Enables TCP `SO_KEEPALIVE` on all Redis client sockets (e.g., `REDIS_SOCKET_KEEPALIVE=True`). When enabled, the OS kernel sends TCP keepalive probes on idle connections, detecting half-closed sockets caused by silent firewall/load balancer resets or network flaps at the TCP level. + +These two mechanisms are complementary: +- `REDIS_HEALTH_CHECK_INTERVAL` works at the **application level** β€” redis-py PINGs idle connections on checkout, validating the socket and resetting the server's idle timer. +- `REDIS_SOCKET_KEEPALIVE` works at the **TCP level** β€” the kernel detects dead peers even when no application-level traffic is flowing. + +:::tip Recommended pairing + +For robust production deployments, configure all three layers together: + +| Mechanism | Level | Covers | Example | +|-----------|-------|--------|---------| +| `timeout 1800` (redis.conf) | Server | Reaps leaked/orphaned connections the app forgot about | Safety net | +| `REDIS_HEALTH_CHECK_INTERVAL=60` | Application | Detects dead sockets before real commands use them; keeps pooled connections alive | Active protection | +| `REDIS_SOCKET_KEEPALIVE=True` | TCP/Kernel | Detects half-closed sockets from silent network resets (firewalls, LBs, NIC flaps) | Network-level protection | + +::: + ### Redis Cluster Mode For deployments using Redis Cluster (including managed services like **AWS Elasticache Serverless**), enable cluster mode with the following configuration: @@ -340,6 +371,12 @@ REDIS_SOCKET_CONNECT_TIMEOUT=5 REDIS_SENTINEL_MAX_RETRY_COUNT=5 REDIS_RECONNECT_DELAY=1000 +# Recommended: detect stale pooled connections (must be < Redis server timeout) +REDIS_HEALTH_CHECK_INTERVAL=60 + +# Recommended: enable TCP keepalive for dead-peer detection at the kernel level +REDIS_SOCKET_KEEPALIVE=True + # Optional REDIS_KEY_PREFIX="open-webui" ``` @@ -631,8 +668,42 @@ REDIS_KEY_PREFIX="openwebui-dev" # For Docker docker restart redis-valkey + ``` + +**Prevention:** Always configure `timeout` to a reasonable value (e.g., 1800 seconds). The timeout only affects idle TCP connections, not user sessions β€” it's safe and recommended. Pair this with `REDIS_HEALTH_CHECK_INTERVAL` on the client side (see below). + +#### Issue: "Connection reset by peer" errors on first request after idle period + +**Symptoms:** + +- Sporadic `redis.exceptions.ConnectionError: Connection reset by peer` in logs +- Errors tend to appear after periods of low activity (nights, weekends) +- The request that triggers the error fails with a 500 Internal Server Error, but subsequent requests succeed +- More common when Redis server `timeout` is configured (which it should be β€” see above) + +**Cause:** The Redis server reaped an idle connection (via its `timeout` setting), but the pooled socket in redis-py was not aware it was dead. The next request that grabbed that socket from the pool sent a command to a closed connection. + +**Solution:** + +Set the `REDIS_HEALTH_CHECK_INTERVAL` environment variable to a value **shorter** than your Redis server's `timeout`: + +```bash +# Redis server timeout is 1800s (30 min), so check every 60s +REDIS_HEALTH_CHECK_INTERVAL=60 +``` + +This tells redis-py to PING any pooled connection that has been idle for more than 60 seconds before reusing it. If the connection is dead, it is replaced transparently. The PING also resets the server's idle timer, keeping actively-used connections alive. + +**How to choose the right value:** + +| Your Redis `timeout` | Suggested `REDIS_HEALTH_CHECK_INTERVAL` | +|-----------------------|-----------------------------------------| +| 300 (5 min) | 30 | +| 900 (15 min) | 60 | +| 1800 (30 min) | 60 | +| 3600 (1 hour) | 120 | -**Prevention:** Always configure `timeout` to a reasonable value (e.g., 1800 seconds). The timeout only affects idle TCP connections, not user sessions β€” it's safe and recommended. +The health check interval should also be shorter than any firewall or load balancer idle timeout between the application and Redis. ### Additional Resources diff --git a/src/css/custom.css b/src/css/custom.css index 862f6b8779..ed8ade294a 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -43,7 +43,7 @@ } /* Mobile nav height fix */ -@media screen and (width <=996px) { +@media screen and (width <= 996px) { :root { --ifm-navbar-height: 100%; } @@ -167,6 +167,7 @@ code { [data-theme="dark"] code { color: #ccc; + background-color: #222; } [data-theme="light"] code { @@ -189,21 +190,6 @@ code { border-radius: 16px !important; } -/* ─── Shiki light/dark mode toggle (CSS variables strategy) ─── */ -[data-theme="light"] .shiki-code-block pre, -[data-theme="light"] .shiki-code-block pre span { - color: var(--shiki-light) !important; -} - -[data-theme="dark"] .shiki-code-block pre, -[data-theme="dark"] .shiki-code-block pre span { - color: var(--shiki-dark) !important; -} - -[data-theme="dark"] .shiki-code-block pre { - background-color: var(--shiki-dark-bg, #1a1a1a) !important; -} - /* ─── Shiki code block styling ─── */ .shiki-code-block { margin-bottom: var(--ifm-leading); @@ -222,13 +208,19 @@ code { } /* stylelint-enable no-descending-specificity */ +/* ─── Shiki light/dark mode toggle (CSS variables strategy) ─── */ +[data-theme="light"] .shiki-code-block pre, +[data-theme="light"] .shiki-code-block pre span { + color: var(--shiki-light) !important; +} + [data-theme="light"] .shiki-code-block pre { background-color: #f3f3f3; } /* stylelint-disable-next-line no-duplicate-selectors */ [data-theme="dark"] .shiki-code-block pre { - background-color: #1a1a1a; + background-color: var(--shiki-dark-bg, #1a1a1a) !important; } .shiki-code-block-content { @@ -274,6 +266,10 @@ code { } /* stylelint-enable no-descending-specificity */ +.shiki-code-block:hover .shiki-copy-button { + opacity: 0.4; +} + [data-theme="light"] .theme-code-block pre { background-color: #f3f3f3; } @@ -343,6 +339,10 @@ article p a { margin-bottom: 4px; } +.notbold a { + font-weight: 400 !important; +} + [data-theme="light"] article p a { color: #333; text-decoration-color: #ccc; @@ -379,7 +379,7 @@ article p a { } /* ─── Article max width ─── */ -@media screen and (width >=997px) { +@media screen and (width >= 997px) { article { max-width: 700px; margin-left: auto; @@ -389,7 +389,7 @@ article p a { } /* ─── Heading sizes ─── */ -@media screen and (width <=996px) { +@media screen and (width <= 996px) { h1 { font-size: 1.5rem !important; font-weight: 600; @@ -405,7 +405,7 @@ article p a { } } -@media screen and (width >=997px) { +@media screen and (width >= 997px) { h1 { font-size: 1.75rem !important; } @@ -657,7 +657,7 @@ a.footer__link-item:hover { gap: 0.25rem; } -@media screen and (width >=997px) { +@media screen and (width >= 997px) { .header-github-link, .header-discord-link { font-size: 0; @@ -699,7 +699,7 @@ a.footer__link-item:hover { } /* ─── Sidebar menu spacing ─── */ -@media screen and (width >=997px) { +@media screen and (width >= 997px) { .menu_node_modules-\@docusaurus-theme-classic-lib-theme-DocSidebar-Desktop-Content-styles-module { padding: 0 !important; } @@ -759,7 +759,7 @@ a.footer__link-item:hover { filter: invert(1); } -@media screen and (width >=997px) { +@media screen and (width >= 997px) { .hero--container { padding: 60px 200px; }