From 79ae7112659fa92ac1b785b577150a9e6d643da9 Mon Sep 17 00:00:00 2001 From: Andrew Baek Date: Wed, 26 Nov 2025 18:50:24 +0400 Subject: [PATCH 01/17] Updated SearXNG Web Search Documents --- docs/features/web-search/searxng.md | 219 +++++++++------------------- static/images/web_search_toggle.png | Bin 9412 -> 12786 bytes 2 files changed, 66 insertions(+), 153 deletions(-) diff --git a/docs/features/web-search/searxng.md b/docs/features/web-search/searxng.md index fcbc79c..82082fc 100644 --- a/docs/features/web-search/searxng.md +++ b/docs/features/web-search/searxng.md @@ -21,15 +21,15 @@ To configure SearXNG optimally for use with Open WebUI, follow these steps: **Step 1: `git clone` SearXNG Docker and navigate to the folder:** -1. Create a New Directory `searxng-docker` +1. Clone the repository `searxng-docker` - Clone the searxng-docker repository. This folder will contain your SearXNG configuration files. Refer to the [SearXNG documentation](https://docs.searxng.org/) for configuration instructions. + Clone the searxng-docker repository. This will create a new directory called `searxng-docker`, which will contain your SearXNG configuration files. Refer to the [SearXNG documentation](https://docs.searxng.org/) for configuration instructions. ```bash git clone https://github.com/searxng/searxng-docker.git ``` -Navigate to the `searxng-docker` repository: +Navigate to the `searxng-docker` repository, and run all commands from there: ```bash cd searxng-docker @@ -49,7 +49,7 @@ cd searxng-docker # * uncomment LETSENCRYPT_EMAIL, and replace by your email (require to create a Let's Encrypt certificate) -SEARXNG_HOSTNAME=localhost:8080/ +SEARXNG_HOSTNAME=localhost # LETSENCRYPT_EMAIL= @@ -68,8 +68,18 @@ SEARXNG_HOSTNAME=localhost:8080/ 3. Remove the `localhost` restriction by modifying the `docker-compose.yaml` file: +If port 8080 is already in use, change `0.0.0.0:8080` to `0.0.0.0:[available port]` in the command before running it. + +Run the appropriate command for your operating system: + +- **Linux** ```bash -sed -i "s/127.0.0.1:8080/0.0.0.0:8080/" +sed -i 's/127.0.0.1:8080/0.0.0.0:8080/' docker-compose.yaml +``` + +- **macOS**: +```bash +sed -i '' 's/127.0.0.1:8080/0.0.0.0:8080/' docker-compose.yaml ``` **Step 4: Grant Necessary Permissions** @@ -77,13 +87,15 @@ sed -i "s/127.0.0.1:8080/0.0.0.0:8080/" 4. Allow the container to create new config files by running the following command in the root directory: ```bash -sudo chmod a+rwx searxng-docker/searxng +sudo chmod a+rwx searxng ``` **Step 5: Create a Non-Restrictive `limiter.toml` File** 5. Create a non-restrictive `searxng-docker/searxng/limiter.toml` config file: +*If the file already exists, append the missing lines to it.* +
@@ -112,172 +124,72 @@ pass_ip = [] 6. Delete the default `searxng-docker/searxng/settings.yml` file if it exists, as it will be regenerated on the first launch of SearXNG: ```bash -rm searxng-docker/searxng/settings.yml +rm searxng/settings.yml ``` **Step 7: Create a Fresh `settings.yml` File** -:::note - -On the first run, you must remove `cap_drop: - ALL` from the `docker-compose.yaml` file for the `searxng` service to successfully create `/etc/searxng/uwsgi`.ini. This is necessary because the `cap_drop: - ALL` directive removes all capabilities, including those required for the creation of the `uwsgi.ini` file. After the first run, you should re-add `cap_drop: - ALL` to the `docker-compose.yaml` file for security reasons. - -::: - 7. Bring up the container momentarily to generate a fresh settings.yml file: +If the container name caddy, redis, searxng is already in use, change it to another name of your choice in the docker-compose.yaml file. + ```bash docker compose up -d ; sleep 10 ; docker compose down ``` -**Step 8: Add Formats and Update Port Number** +After the initial run, add `cap_drop: - ALL` to the `docker-compose.yaml` file for security reasons. + +
+docker-compose.yaml + +```yaml +searxng: + container_name: searxng + image: docker.io/searxng/searxng:latest + restart: unless-stopped + networks: + - searxng + ports: + - "0.0.0.0:9630:8080" + volumes: + - ./searxng:/etc/searxng:rw + - searxng-data:/var/cache/searxng:rw + environment: + - SEARXNG_BASE_URL=https://${SEARXNG_HOSTNAME:-localhost}/ + logging: + driver: "json-file" + options: + max-size: "1m" + max-file: "1" + cap_drop: + - ALL +``` + +
+ +**Step 8: Add Formats** 8. Add HTML and JSON formats to the `searxng-docker/searxng/settings.yml` file: +- **Linux** ```bash -sed -i 's/formats: \[\"html\"\/]/formats: [\"html\", \"json\"]/' searxng-docker/searxng/settings.yml +sed -i 's/- html/- html\n - json/' searxng/settings.yml ``` -Generate a secret key for your SearXNG instance: +- **macOS** +```bash +sed -i '' 's/- html/- html\n - json/' searxng/settings.yml +``` + +**Step 9: Run the Server** + +9. Start the container with the following command: ```bash -sed -i "s|ultrasecretkey|$(openssl rand -hex 32)|g" searxng-docker/searxng/settings.yml +docker compose up -d ``` -Windows users can use the following powershell script to generate the secret key: - -```powershell -$randomBytes = New-Object byte[] 32 -(New-Object Security.Cryptography.RNGCryptoServiceProvider).GetBytes($randomBytes) -$secretKey = -join ($randomBytes | ForEach-Object { "{0:x2}" -f $_ }) -(Get-Content searxng-docker/searxng/settings.yml) -replace 'ultrasecretkey', $secretKey | Set-Content searxng-docker/searxng/settings.yml -``` - -Update the port number in the `server` section to match the one you set earlier (in this case, `8080`): - -```bash -sed -i 's/port: 8080/port: 8080/' searxng-docker/searxng/settings.yml -``` - -Change the `bind_address` as desired: - -```bash -sed -i 's/bind_address: "0.0.0.0"/bind_address: "127.0.0.1"/' searxng-docker/searxng/settings.yml -``` - -#### Configuration Files - -#### searxng-docker/searxng/settings.yml (Extract) - -The default `settings.yml` file contains many engine settings. Below is an extract of what the default `settings.yml` file might look like: - - -
- -searxng-docker/searxng/settings.yml - -```yaml - -# see https://docs.searxng.org/admin/settings/settings.html#settings-use-default-settings -use_default_settings: true - -server: - # base_url is defined in the SEARXNG_BASE_URL environment variable, see .env and docker-compose.yml - secret_key: "ultrasecretkey" # change this! - limiter: true # can be disabled for a private instance - image_proxy: true - port: 8080 - bind_address: "0.0.0.0" - -ui: - static_use_hash: true - -search: - safe_search: 0 - autocomplete: "" - default_lang: "" - formats: - - html - - json # json is required - # remove format to deny access, use lower case. - # formats: [html, csv, json, rss] -redis: - # URL to connect redis database. Is overwritten by ${SEARXNG_REDIS_URL}. - # https://docs.searxng.org/admin/settings/settings_redis.html#settings-redis - url: redis://redis:6379/0 -``` - -The port in the settings.yml file for SearXNG should match that of the port number in your docker-compose.yml file for SearXNG. - -
- -**Step 9: Update `uwsgi.ini` File** - -9. Ensure your `searxng-docker/searxng/uwsgi.ini` file matches the following: - - -
- -searxng-docker/searxng/uwsgi.ini - -```ini -[uwsgi] - -# Who will run the code -uid = searxng -gid = searxng - -# Number of workers (usually CPU count) - -# default value: %k (= number of CPU core, see Dockerfile) -workers = %k - -# Number of threads per worker - -# default value: 4 (see Dockerfile) -threads = 4 - -# The right granted on the created socket -chmod-socket = 666 - -# Plugin to use and interpreter config -single-interpreter = true -master = true -plugin = python3 -lazy-apps = true -enable-threads = 4 - -# Module to import -module = searx.webapp - -# Virtualenv and python path -pythonpath = /usr/local/searxng/ -chdir = /usr/local/searxng/searx/ - -# automatically set processes name to something meaningful -auto-procname = true - -# Disable request logging for privacy -disable-logging = true -log-5xx = true - -# Set the max size of a request (request-body excluded) -buffer-size = 8192 - -# No keep alive - -# See https://github.com/searx/searx-docker/issues/24 -add-header = Connection: close - -# uwsgi serves the static files -static-map = /static=/usr/local/searxng/searx/static - -# expires set to one day -static-expires = /* 86400 -static-gzip-all = True -offload-threads = 4 -``` - -
+The searXNG will be available at http://localhost:8080 (or the port number you set earlier). ## 2. Alternative Setup @@ -412,6 +324,7 @@ docker exec -it open-webui curl http://host.docker.internal:8080/search?q=this+i 3. Set `Web Search Engine` from dropdown menu to `searxng` 4. Set `Searxng Query URL` to one of the following examples: +- `http://localhost:8080/search?q=` (using the host and exposed port, suitable for Docker-based setups) - `http://searxng:8080/search?q=` (using the container name and exposed port, suitable for Docker-based setups) - `http://host.docker.internal:8080/search?q=` (using the `host.docker.internal` DNS name and the host port, suitable for Docker-based setups) - `http:///search?q=` (using a local domain name, suitable for local network access) @@ -426,7 +339,7 @@ docker exec -it open-webui curl http://host.docker.internal:8080/search?q=this+i ## 5. Using Web Search in a Chat -To access Web Search, Click on the + next to the message input field. +To access Web Search, Click the Integrations button next to the + icon. Here you can toggle Web Search On/Off. diff --git a/static/images/web_search_toggle.png b/static/images/web_search_toggle.png index 7071d1efabb44c495462cf5649e11d519cc64417..5eb71f2e48901931612ec6efade0f53bb7a01318 100644 GIT binary patch literal 12786 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 S@SDg%z(+|=Rkj3f6!1U6jew>A literal 9412 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 ZboQno(%1=Sc!Uvxw77y;1;{AyKLCTmJn{el From f1d6906eb74e47f99c19680b37380430a9c21010 Mon Sep 17 00:00:00 2001 From: silentoplayz Date: Thu, 27 Nov 2025 04:50:20 -0500 Subject: [PATCH 02/17] docs: Notion MCP refac --- docs/tutorials/integrations/mcp-notion.mdx | 128 ++++----------------- 1 file changed, 24 insertions(+), 104 deletions(-) diff --git a/docs/tutorials/integrations/mcp-notion.mdx b/docs/tutorials/integrations/mcp-notion.mdx index deb5ecb..0cbc350 100644 --- a/docs/tutorials/integrations/mcp-notion.mdx +++ b/docs/tutorials/integrations/mcp-notion.mdx @@ -21,10 +21,14 @@ This tutorial is a community contribution and is not supported by the Open WebUI ## Prerequisites -Regardless of the connection method chosen, you must first create an internal integration within Notion. +:::info Note for Streamable HTTP +If you plan to use **Method 1 (Streamable HTTP)**, the OAuth flow may handle the integration creation automatically. However, we highly recommend following the steps below regardless. This ensures you have granular control over page permissions and a valid **Internal Integration Secret** available for troubleshooting or manual configuration. +::: + +Regardless of the connection method chosen, you should create an internal integration within Notion to ensure you have the necessary credentials and permission scopes. ### 1. Create Internal Integration -1. Navigate to [Notion My Integrations](https://www.notion.so/my-integrations). +1. Navigate to **[Notion My Integrations](https://www.notion.so/my-integrations)**. 2. Click the **+ New integration** button. 3. Fill in the required fields: * **Integration Name:** Give it a recognizable name (e.g., "Open WebUI MCP"). @@ -50,9 +54,9 @@ Once saved, you will be directed to the configuration page. 3. Click **Save changes** if you modified any capabilities. :::warning Security: Risk to Workspace Data -While the Notion MCP server limits the scope of the API (e.g., databases cannot be deleted), exposing your workspace to LLMs carries a **non-zero risk** to your data. +While the Notion MCP server limits the scope of the API (e.g., databases cannot be deleted), exposing your workspace to LLMs carries a **non-zero risk**. -**Security-conscious users** can create a safer, **Read-Only** integration by unchecking **Update content** and **Insert content** in this step. The AI will be able to search and answer questions based on your notes but will be physically unable to modify or create pages. +**Security-conscious users** can create a safer, **Read-Only** integration by unchecking **Update content** and **Insert content**. The AI will be able to search and answer questions based on your notes but will be physically unable to modify or create pages. ::: :::danger Secret Safety @@ -246,7 +250,7 @@ If you are using **Method 1 (Streamable HTTP)**, you must perform the On-Demand :::note Security: Frequent Re-authentication For security reasons, Notion's OAuth session may expire after a period of inactivity or if you restart your Open WebUI instance. If this happens, you will see a `Failed to connect to MCP server 'ntn'` error. -This is **intended behavior** by Notion to keep your workspace secure. To refresh your session, revist steps 1-4 of this option to complete the "Connect with Notion MCP" authorization flow again, which will refresh your session. +This is **intended behavior** by Notion to keep your workspace secure. To refresh your session, revisit steps 1-4 of this option to complete the "Connect with Notion MCP" authorization flow again. ::: ![Notion OAuth Screen: Shows the 'Connect with Notion MCP' authorization page with the workspace dropdown selected.](/images/mcp-notion/notion-setup-step7.png) @@ -260,7 +264,7 @@ You can configure a specific model to have Notion access enabled by default for 4. Check the box for **Notion**. 5. Click **Save & Update**. -## Best Practice: Create a Notion Agent +## Building a Specialized Notion Agent For the most reliable experience, we recommend creating a dedicated "Notion Assistant" model. This allows you to provide a specialized **System Prompt**, a helpful **Knowledge Base**, and quick-start **Prompt Suggestions** that teaches the model how to navigate Notion's structure. @@ -335,7 +339,6 @@ You are the Notion Workspace Manager, an intelligent agent connected directly to ```
- 7. **Attach Knowledge Base:** * In the **Knowledge** section, click **Select Knowledge**. * In the modal that appears, find and select the **Notion MCP Docs** knowledge base you created in Step 1. @@ -343,7 +346,7 @@ You are the Notion Workspace Manager, an intelligent agent connected directly to :::warning Performance Tuning While the knowledge base helps the model understand Notion's capabilities, injecting large amounts of documentation can sometimes interfere with tool calling on smaller models (overloading the context). -If you notice the model failing to call tools correctly or hallucinating parameters, **detach the knowledge base** and rely solely on the System Prompt provided above or use your own custom system prompt. +If you notice the model failing to call tools correctly or hallucinating parameters, **detach the knowledge base** and rely solely on the System Prompt provided above. ::: 8. **Add Prompt Suggestions:** @@ -362,99 +365,15 @@ Under the **Prompts** section, click the **+** button to add a few helpful start ![Model Creation Screen: Shows the model settings with Name 'Notion Assistant', description, and the Notion System Prompt filled out.](/images/mcp-notion/notion-setup-step11.png) -## Supported Tools & Usage - -Once enabled, the model will have access to a powerful suite of tools to manage your Notion workspace. The server automatically handles converting Notion's block-based structure into Markdown for the AI, and converts the AI's Markdown back into Notion blocks. +## Supported Tools :::tip Workflow Best Practice LLMs cannot "browse" Notion like a human. For most actions, the model first needs to know the **Page ID or URL**. Always ask the model to **search** for a page first before asking it to read or modify it. ::: -## šŸ”Ž Search & Retrieval +This integration supports a wide range of tools for searching, reading, creating, and updating Notion pages and databases. -- **`notion-search`** – Full‑text / metadata search across Notion (and linked tools) - - **Input:** query string (e.g., `ready for dev`) - - **Returns:** list of object IDs + brief metadata - - **Prompt example:** ā€œFind all project pages that mention **ā€˜ready for dev’**.ā€ - - **Note:** IDs returned here are required for almost every other command. - -- **`notion-fetch`** *(aka `read-page`)* – Pull a page or database content by URL or ID - - **Input:** page/database URL **or** ID - - **Returns:** Markdown‑formatted content of the page/database - - **Prompt example:** ā€œWhat are the product requirements from this ticket `https://notion.so/page-url`?ā€ - - **Note:** Gives you a clean Markdown view, ready for further processing. - -## šŸ› ļø Content Management - -- **`notion-create-pages`** – Create a brand‑new page - - **Input:** parent page ID, title, property map, body (Markdown format) - - **Returns:** new page ID & URL - - **Prompt example:** ā€œCreate a meeting‑notes page for today’s stand‑up with action items.ā€ - - **Key:** **Parent page ID is mandatory**. - -- **`notion-update-page`** – Patch a page’s **properties** (status, tags, dates, etc.) - - **Input:** page ID + property map - - **Returns:** updated page object - - **Prompt example:** ā€œChange the status of this task from **ā€˜In Progress’** to **ā€˜Complete’**.ā€ - - **Key:** Does **not** edit the page’s body blocks. - -- **`notion-append-block`** – Add a block (text, checklist, heading, etc.) to the end of a page - - **Input:** page ID + block payload (JSON format) - - **Returns:** updated page version - - **Prompt example:** ā€œAdd a checklist item to the bottom of the shopping‑list page.ā€ - -- **`notion-move-pages`** – Move one or many pages/databases under a new parent - - **Input:** source page/database ID(s) + destination parent ID - - **Returns:** new parent relationship (page now lives under the target) - - **Prompt example:** ā€œMove my weekly meeting‑notes page to the **ā€˜Team Meetings’** page.ā€ - -- **`notion-duplicate-page`** – Clone a page (asynchronous – returns a job ID) - - **Input:** source page ID (optional target parent) - - **Returns:** job ID → duplicated page ID once the job finishes - - **Prompt example:** ā€œDuplicate my project‑template page for the new Q3 initiative.ā€ - -## šŸ“Š Database Management - -- **`notion-create-database`** – Spin up a new database with a custom schema - - **Input:** parent page ID, title, property definitions (type, name, options) - - **Returns:** new database ID & URL - - **Prompt example:** ā€œCreate a database to track customer feedback with fields for **name**, **priority**, and **status**.ā€ - -- **`notion-update-database`** – Alter a database’s schema (add/rename fields) or rename the DB itself - - **Input:** database ID + schema changes (add property, rename, etc.) - - **Returns:** updated database object - - **Prompt example:** ā€œAdd a **ā€˜Status’** field to our project database to track completion.ā€ - -## šŸ’¬ Collaboration & Workspace - -- **`notion-create-comment`** – Post a comment on a page - - **Input:** page ID + comment text - - **Returns:** comment ID & timestamp - - **Prompt example:** ā€œLeave a note on the quarterly review page about budget concerns.ā€ - -- **`notion-get-comments`** – List every comment on a page (supports pagination) - - **Input:** page ID - - **Returns:** array of comment objects - - **Prompt example:** ā€œList all comments on the project‑requirements section.ā€ - -- **`notion-get-users`** – Fetch **all** workspace members - - **Input:** *(none)* - - **Returns:** array of user objects - - **Prompt example:** ā€œWho are the members of this workspace?ā€ - -- **`notion-get-user`** – Get a single user’s profile (by ID or email) - - **Input:** user ID or email address - - **Returns:** user object (name, avatar, email, etc.) - - **Prompt example:** ā€œLook up the profile of the person assigned to this task.ā€ - -- **`notion-get-teams`** – Retrieve all **teamspaces** (formerly ā€œteamsā€) in the workspace - - **Input:** *(none)* - - **Returns:** array of team objects - -- **`notion-get-self`** – Information about the bot itself and the workspace it’s linked to - - **Input:** *(none)* - - **Returns:** bot metadata + workspace metadata (ID, name, domain, etc.) - - **Prompt example:** ā€œWhich Notion workspace am I currently connected to?ā€ +For a complete list of available tools, their schemas, and specific usage examples, please refer to the **[official Notion MCP documentation](https://developers.notion.com/docs/mcp-supported-tools)**. ## Rate Limits Standard [API request limits](https://developers.notion.com/reference/request-limits) apply to your use of Notion MCP, totaled across all tool calls. @@ -468,7 +387,9 @@ If you encounter rate limit errors, prompt your model to reduce the number of pa ## Troubleshooting -### Error: `Failed to connect to MCP server 'ntn'` +### Connection Errors + +#### `Failed to connect to MCP server 'ntn'` ![MCP Connection Error: Shows a red error message in the chat 'Failed to connect to MCP server 'ntn'.](/images/mcp-notion/notion-setup-step12.png) @@ -480,27 +401,26 @@ If you encounter rate limit errors, prompt your model to reduce the number of pa 4. This will trigger the redirect to Notion's authorization page to complete the "Connect with Notion MCP" authorization flow again. 5. Once authorized successfully, the connection will work across all chats again, including for models with the tool enabled by default. -### Error: `OAuth callback failed: mismatching_state` - +#### `OAuth callback failed: mismatching_state` ![OAuth Error Toast: Shows the red error notification 'OAuth callback failed: mismatching_state: CSRF Warning! State not equal in request and response'.](/images/mcp-notion/notion-setup-step13.png) -If you receive this red error toast when registering the client or connecting via the tool toggle, it is likely due to a URL mismatch. - * **Cause:** You are likely accessing Open WebUI via `localhost` (e.g., `http://localhost:3000`), but your instance is configured with a public domain via the `WEBUI_URL` environment variable (e.g., `https://chat.mydomain.com`). The OAuth session state created on `localhost` is lost when the callback redirects to your public domain. * **Fix:** Access your Open WebUI instance using the **exact URL** defined in `WEBUI_URL` (your public domain) and perform the setup again. **Do not use `localhost` for OAuth setups if a domain is configured.** -### Error: `Object not found` +### Usage Errors + +#### `Object not found` * **Cause:** The Integration Token is valid, but the specific page has not been shared with the integration. * **Fix:** In Notion, go to your Integration settings > **Access** tab and ensure the page is checked, or visit the page directly and check the **Connections** menu to ensure your integration is listed and selected. -### Error: `Tool execution failed` (Local Method) +#### `Tool execution failed` (Local Method) * **Cause:** Open WebUI is unable to execute the local command (npx/docker) because it is missing from the container, or the configuration is incorrect. * **Fix:** Native local execution is not supported. Ensure you are using **MCPO** (Method 2) to bridge these commands, rather than entering them directly into Open WebUI's config, or switch to **Method 1 (Streamable HTTP)** in the Configuration section above. This runs on Notion's servers and requires no local dependencies. -### Error: `missing_property` when creating a page +#### `missing_property` when creating a page * **Cause:** The model is trying to create a page without specifying a **Parent ID**. Notion requires every page to exist inside another page or database. * **Fix:** Instruct the model in your prompt: *"Search for my 'Notes' page first, get its ID, and create the new page inside there."* -### Error: `RateLimitedError` (429) +#### `RateLimitedError` (429) * **Cause:** You have exceeded Notion's API limits (approx. 3 requests/second). * **Fix:** Ask the model to perform actions sequentially rather than all at once (e.g., "Search for X, then wait, then search for Y"). From 8cf906925fcdc18470a44d2cc0fd110dabfd44a1 Mon Sep 17 00:00:00 2001 From: silentoplayz Date: Thu, 27 Nov 2025 04:53:27 -0500 Subject: [PATCH 03/17] wording --- docs/tutorials/integrations/mcp-notion.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/integrations/mcp-notion.mdx b/docs/tutorials/integrations/mcp-notion.mdx index 0cbc350..80c2756 100644 --- a/docs/tutorials/integrations/mcp-notion.mdx +++ b/docs/tutorials/integrations/mcp-notion.mdx @@ -373,7 +373,7 @@ LLMs cannot "browse" Notion like a human. For most actions, the model first need This integration supports a wide range of tools for searching, reading, creating, and updating Notion pages and databases. -For a complete list of available tools, their schemas, and specific usage examples, please refer to the **[official Notion MCP documentation](https://developers.notion.com/docs/mcp-supported-tools)**. +For a complete list of available tools, their descriptions, and specific usage examples, please refer to the **[official Notion MCP documentation](https://developers.notion.com/docs/mcp-supported-tools)**. ## Rate Limits Standard [API request limits](https://developers.notion.com/reference/request-limits) apply to your use of Notion MCP, totaled across all tool calls. From 1719934e103ee986ee5cecfbf15b9793d242f607 Mon Sep 17 00:00:00 2001 From: silentoplayz Date: Thu, 27 Nov 2025 06:16:02 -0500 Subject: [PATCH 04/17] docs: Notion MCP refactor --- docs/tutorials/integrations/mcp-notion.mdx | 335 ++++++++++----------- 1 file changed, 163 insertions(+), 172 deletions(-) diff --git a/docs/tutorials/integrations/mcp-notion.mdx b/docs/tutorials/integrations/mcp-notion.mdx index 80c2756..c344471 100644 --- a/docs/tutorials/integrations/mcp-notion.mdx +++ b/docs/tutorials/integrations/mcp-notion.mdx @@ -19,15 +19,167 @@ This integration utilizes the official Notion MCP server, which specializes in * This tutorial is a community contribution and is not supported by the Open WebUI team. It serves as a demonstration on how to customize Open WebUI for your specific use case. Want to contribute? Check out the [contributing tutorial](/tutorials/tips/contributing-tutorial/). ::: -## Prerequisites +## Method 1: Streamable HTTP (Recommended) -:::info Note for Streamable HTTP -If you plan to use **Method 1 (Streamable HTTP)**, the OAuth flow may handle the integration creation automatically. However, we highly recommend following the steps below regardless. This ensures you have granular control over page permissions and a valid **Internal Integration Secret** available for troubleshooting or manual configuration. +This method connects directly to Notion's hosted MCP endpoint (`https://mcp.notion.com/mcp`). It utilizes standard OAuth and is **natively supported** by Open WebUI without extra containers. + +:::info Preferred Method +**Streamable HTTP** is preferred for its simplicity and enhanced security. It handles authentication via Notion's official OAuth flow, meaning you do not need to manually manage secrets or integration tokens. ::: -Regardless of the connection method chosen, you should create an internal integration within Notion to ensure you have the necessary credentials and permission scopes. +### 1. Configure Tool +You can automatically prefill the connection settings by importing the JSON configuration below. -### 1. Create Internal Integration +1. Navigate to **Admin Panel > Settings > External Tools**. +2. Click the **+** (Plus) button to add a new tool. +3. Click **Import** (top right of the modal). +4. Paste the following JSON snippet: + +```json title="Notion Remote MCP Configuration" +[ + { + "type": "mcp", + "url": "https://mcp.notion.com/mcp", + "spec_type": "url", + "spec": "", + "path": "openapi.json", + "auth_type": "oauth_2.1", + "key": "", + "info": { + "id": "ntn", + "name": "Notion", + "description": "A note-taking and collaboration platform that allows users to create, organize, and share notes, databases, and other content." + } + } +] +``` + +5. **Register:** Click the **Register Client** button (next to the Auth dropdown). +6. Click **Save**. + +![Open WebUI Tool Config: Shows the External Tools modal with the JSON imported and Register Client button highlighted.](/images/mcp-notion/notion-setup-step5.png) + +### 2. Authenticate & Grant Access +Once the tool is added, you must authenticate to link your specific workspace. + +1. Open any chat window. +2. Click the **+** (Plus) button in the chat input bar. +3. Navigate to **Integrations > Tools**. +4. Toggle the **Notion** switch to **ON**. + +![Chat Interface Toggle: Shows the chat input bar with the '+' menu open, 'Integrations' selected, and the 'Notion' tool toggled ON.](/images/mcp-notion/notion-setup-step6.png) + +5. **Authorize:** You will be redirected to a "Connect with Notion MCP" screen. + * Ensure the correct **Workspace** is selected in the dropdown. + * Click **Continue**. + +:::note Security: Frequent Re-authentication +For security reasons, Notion's OAuth session may expire after a period of inactivity or if you restart your Open WebUI instance. If this happens, you will see a `Failed to connect to MCP server 'ntn'` error. + +This is **intended behavior** by Notion to keep your workspace secure. To refresh your session, revisit the steps above to complete the "Connect with Notion MCP" authorization flow again. +::: + +![Notion OAuth Screen: Shows the 'Connect with Notion MCP' authorization page with the workspace dropdown selected.](/images/mcp-notion/notion-setup-step7.png) + +--- + +## Method 2: Self-Hosted via MCPO (Advanced) + +This method is for advanced users who prefer to run the MCP server locally within their own infrastructure using **MCPO**. Unlike Streamable HTTP, this method requires you to manually manage your own credentials. + +Direct local execution (stdio) of MCP servers is not natively supported in Open WebUI. To run the Notion MCP server locally (using Docker or Node.js) within your infrastructure, you must use **MCPO** to bridge the connection. + +:::info Prerequisites +To use this method, you must first create an internal integration to obtain a **Secret Key**. Please complete the **[Creating an Internal Integration](#creating-an-internal-integration)** section below before proceeding with the configuration steps here. +::: + +### 1. Configure MCPO +Follow the installation instructions in the [MCPO Repository](https://github.com/open-webui/mcpo) to get it running. Configure your MCPO instance to run the Notion server using one of the runtimes below by adding the JSON block to your `mcpo-config.json` file. + +**Note:** Replace `secret_YOUR_KEY_HERE` with the secret obtained from the [Creating an Internal Integration](#creating-an-internal-integration) section. + + + + This configuration uses the official Node.js package. + + ```json title="mcpo-config.json" + { + "mcpServers": { + "notion": { + "command": "npx", + "args": [ + "-y", + "@notionhq/notion-mcp-server" + ], + "env": { + "NOTION_TOKEN": "secret_YOUR_KEY_HERE" + } + } + } + } + ``` + + + This configuration uses the official Docker image. + + ```json title="mcpo-config.json" + { + "mcpServers": { + "notion": { + "command": "docker", + "args": [ + "run", + "--rm", + "-i", + "-e", + "NOTION_TOKEN", + "mcp/notion" + ], + "env": { + "NOTION_TOKEN": "secret_YOUR_KEY_HERE" + } + } + } + } + ``` + + + +### 2. Connect Open WebUI +Once MCPO is running and configured with Notion: + +1. Navigate to **Admin Panel > Settings > External Tools**. +2. Click the **+** (Plus) button. +3. Click **Import** (top right of the modal). +4. Paste the following JSON snippet (update the URL with your MCPO address): + +```json title="MCPO Connection JSON" +[ + { + "type": "openapi", + "url": "http://:/notion", + "spec_type": "url", + "spec": "", + "path": "openapi.json", + "auth_type": "bearer", + "key": "", + "info": { + "id": "notion-local", + "name": "Notion (Local)", + "description": "Local Notion integration via MCPO" + } + } +] +``` +5. Click **Save**. + +--- + +## Creating an Internal Integration + +Required for **Method 2**, creating an internal integration within Notion ensures you have the necessary credentials and permission scopes readily available. + +### 1. Create Integration 1. Navigate to **[Notion My Integrations](https://www.notion.so/my-integrations)**. 2. Click the **+ New integration** button. 3. Fill in the required fields: @@ -45,7 +197,7 @@ You **must** select **Internal** for the integration type. Public integrations r ### 2. Configure Capabilities & Copy Secret Once saved, you will be directed to the configuration page. -1. **Copy Secret:** Locate the **Internal Integration Secret** field. Click **Show** and copy this key. You will need it for Open WebUI. +1. **Copy Secret:** Locate the **Internal Integration Secret** field. Click **Show** and copy this key. You will need it for MCPO configuration. 2. **Review Capabilities:** Ensure the following checkboxes are selected under the "Capabilities" section: * āœ… **Read content** * āœ… **Update content** @@ -65,10 +217,10 @@ Your **Internal Integration Secret** allows access to your Notion data. Treat it ![Notion Capabilities Config: Shows the Internal Integration Secret revealed and the three content capability checkboxes selected.](/images/mcp-notion/notion-setup-step2.png) -### 3. Grant Page Access +### 3. Grant Page Access (Manual) :::danger Critical Step: Permissions -By default, your new integration has **zero access** to your workspace. It cannot see *any* pages until you explicitly invite it. If you skip this step, the AI will return "Object not found" errors. +By default, your new internal integration has **zero access** to your workspace. It cannot see *any* pages until you explicitly invite it. If you skip this step, the AI will return "Object not found" errors. ::: You can grant access centrally or on a per-page basis. @@ -91,172 +243,11 @@ Still in the Notion Integration dashboard: ![Notion Page Connection: Shows a Notion page with the '...' menu open, the 'Connect' submenu active, and the integration being selected.](/images/mcp-notion/notion-setup-step4.png) -## Configuration +--- -There are two ways to connect Notion. We recommend **Streamable HTTP** for the easiest setup experience (OAuth), or **Local CLI** for advanced control using your integration token. +## Configuration: Always On (Optional) -The **Streamable HTTP** method is natively supported and recommended for most users for the easiest setup experience (OAuth). - -To run the server locally (using Docker or Node.js), you must use the **MCPO Bridge**. - - - - This method connects directly to Notion's hosted MCP endpoint (`https://mcp.notion.com/mcp`). It utilizes standard OAuth and is **natively supported** by Open WebUI without extra containers. - - ### Quick Setup via Import - You can automatically prefill the connection settings by importing the JSON configuration below. - - 1. Navigate to **Admin Panel > Settings > External Tools**. - 2. Click the **+** (Plus) button to add a new tool. - 3. Click **Import** (top right of the modal). - 4. Paste the following JSON snippet: - - ```json title="Notion Remote MCP Configuration" - [ - { - "type": "mcp", - "url": "https://mcp.notion.com/mcp", - "spec_type": "url", - "spec": "", - "path": "openapi.json", - "auth_type": "oauth_2.1", - "key": "", - "info": { - "id": "ntn", - "name": "Notion", - "description": "A note-taking and collaboration platform that allows users to create, organize, and share notes, databases, and other content." - } - } - ] - ``` - - 5. **Enter Key:** Paste your **Internal Integration Secret** (starts with `secret_`) into the "Key" field. - 6. **Register:** Click the **Register Client** button (next to the Auth dropdown). - 7. Click **Save**. - - ![Open WebUI Tool Config: Shows the External Tools modal with the JSON imported, Key pasted, and Register Client button highlighted.](/images/mcp-notion/notion-setup-step5.png) - - - - - Direct local execution (stdio) of MCP servers is not natively supported in Open WebUI. To run the Notion MCP server using `docker` or `npx` within your infrastructure, you must use **MCPO**. - - MCPO acts as a bridge, running your local commands and exposing them to Open WebUI via a local HTTP endpoint. - - ### Step 1: Deploy MCPO - Follow the installation instructions in the [MCPO Repository](https://github.com/open-webui/mcpo) to get it running (usually done via Docker). - - ### Step 2: Configure MCPO - Configure your MCPO instance to run the Notion server using one of the runtimes below. Add the appropriate JSON block to your `mcpo-config.json` file. - - - - This configuration uses the official Node.js package. - - ```json title="mcpo-config.json" - { - "mcpServers": { - "notion": { - "command": "npx", - "args": [ - "-y", - "@notionhq/notion-mcp-server" - ], - "env": { - "NOTION_TOKEN": "secret_YOUR_KEY_HERE" - } - } - } - } - ``` - - - This configuration runs the server as an isolated container. - - ```json title="mcpo-config.json" - { - "mcpServers": { - "notion": { - "command": "docker", - "args": [ - "run", - "--rm", - "-i", - "-e", - "NOTION_TOKEN", - "mcp/notion" - ], - "env": { - "NOTION_TOKEN": "secret_YOUR_KEY_HERE" - } - } - } - } - ``` - - - - ### Step 3: Connect Open WebUI - Once MCPO is running and configured with Notion: - - 1. Navigate to **Admin Panel > Settings > External Tools**. - 2. Click the **+** (Plus) button. - 3. Click **Import** (top right of the modal). - 4. Paste the following JSON snippet (update the URL with your MCPO address): - - ```json title="MCPO Connection JSON" - [ - { - "type": "openapi", - "url": "http://:/notion", - "spec_type": "url", - "spec": "", - "path": "openapi.json", - "auth_type": "bearer", - "key": "", - "info": { - "id": "notion-local", - "name": "Notion (Local)", - "description": "Local Notion integration via MCPO" - } - } - ] - ``` - 5. Click **Save**. - - - -## Enabling the Tool - -After configuring the connection in the Admin Panel, you must enable the tool for the AI to use it. - -:::tip Initial Authentication -If you are using **Method 1 (Streamable HTTP)**, you must perform the On-Demand step below at least once to trigger the OAuth flow. If using **Method 2 (MCPO)**, authentication is handled by the API key in your configuration. -::: - -### Option 1: On-Demand (Per Chat) - -1. Open a new chat. -2. Click the **+** (Plus) button in the chat input bar. -3. Navigate to **Integrations > Tools**. -4. Toggle the **Notion** switch to **ON**. - -![Chat Interface Toggle: Shows the chat input bar with the '+' menu open, 'Integrations' selected, and the 'Notion' tool toggled ON.](/images/mcp-notion/notion-setup-step6.png) - -5. **Authorize:** (Method 1 Only) You will be redirected to a "Connect with Notion MCP" screen. - * Ensure the correct **Workspace** (the one you configured in step 1) is selected in the dropdown. - * Click **Continue**. - -:::note Security: Frequent Re-authentication -For security reasons, Notion's OAuth session may expire after a period of inactivity or if you restart your Open WebUI instance. If this happens, you will see a `Failed to connect to MCP server 'ntn'` error. - -This is **intended behavior** by Notion to keep your workspace secure. To refresh your session, revisit steps 1-4 of this option to complete the "Connect with Notion MCP" authorization flow again. -::: - -![Notion OAuth Screen: Shows the 'Connect with Notion MCP' authorization page with the workspace dropdown selected.](/images/mcp-notion/notion-setup-step7.png) - -### Option 2: Always On (Model Default) -You can configure a specific model to have Notion access enabled by default for every conversation. +By default, users must toggle the tool **ON** in the chat menu. You can configure a specific model to have Notion access enabled by default for every conversation. 1. Go to **Workspace > Models**. 2. Click the **pencil icon** to edit a model. From e45855fb9813c7fa654174d518df2e656041a62a Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 27 Nov 2025 19:08:13 -0500 Subject: [PATCH 05/17] Update index.mdx --- docs/enterprise/index.mdx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/enterprise/index.mdx b/docs/enterprise/index.mdx index ccdd9bb..3d54013 100644 --- a/docs/enterprise/index.mdx +++ b/docs/enterprise/index.mdx @@ -38,14 +38,19 @@ Explore how other organizations are driving real impact with Open WebUI. ## Let’s Talk + **sales@openwebui.com** — Send us your deployment **end user count (seats)**, and let’s explore how we can work together! -:::info +:::info Enterprise licenses and partnership opportunities are available **exclusively to registered entities and organizations**. At this time, we are unable to accommodate individual users. We appreciate your understanding and interest. -To help us respond quickly and efficiently to your inquiry, **please use your official work email address**, Personal email accounts (e.g. gmail.com, hotmail.com, icloud.com, yahoo.com etc.) are often flagged by our system and will not be answered. +**We are not seeking, open to, or in need of any form of disguised collaboration or contribution pitches/offers.** Any attempt to characterize engineering assistance, co-development, or roadmap input **as an alternative to our enterprise licensing program will not receive a response**. All organizational engagement with Open WebUI occurs **solely and exclusively through enterprise licensing**. +::: + +:::tip +To help us respond quickly and efficiently to your inquiry, **please use your official work email address**, Personal email accounts (e.g. gmail.com, hotmail.com, icloud.com, yahoo.com etc.) are often flagged by our system and will not be answered. ::: From 627a6d1eee492454c75e1bb3616195e40f0fee86 Mon Sep 17 00:00:00 2001 From: silentoplayz Date: Fri, 28 Nov 2025 05:43:14 -0500 Subject: [PATCH 06/17] docs: Add manual Alembic database migration guide This change adds a new, comprehensive Docusaurus page that provides instructions on how to manually apply Alembic database migrations. This is in response to a GitHub discussion where users were encountering issues with automatic migrations after updating the application. --- .../manual-database-migration.md | 158 ++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 docs/troubleshooting/manual-database-migration.md diff --git a/docs/troubleshooting/manual-database-migration.md b/docs/troubleshooting/manual-database-migration.md new file mode 100644 index 0000000..21f8ea4 --- /dev/null +++ b/docs/troubleshooting/manual-database-migration.md @@ -0,0 +1,158 @@ +--- +sidebar_position: 900 +title: Manual Alembic Database Migration Guide +--- + +This guide provides step-by-step instructions for manually applying Alembic database migrations in Open WebUI. Migrations are typically run automatically on startup, but you may need to run them manually for maintenance, debugging, or deployment scenarios. + +## Prerequisites + +- Ensure you have a Python environment with Open WebUI dependencies installed. +- Your database connection must be configured via the `DATABASE_URL` environment variable. +- You need access to the backend directory of your Open WebUI installation. + +## Accessing the Container (for Docker installations) + +If you are running Open WebUI in a Docker container, you'll first need to get a shell into the container: + +```bash +docker exec -it open-webui /bin/bash +``` + +:::note +Replace `open-webui` with the name of your container if it's different. +::: + +## Manual Migration Commands + +This section provides instructions for running Alembic commands. The correct directory path depends on whether you are running Open WebUI from a local installation or within a Docker container. + +### 1. Navigate to the Correct Directory + +#### Local Installation +If you are running Open WebUI from a local clone of the repository, navigate to the `backend/open_webui` directory from the repository root: +```bash +cd backend/open_webui +``` + +#### Docker Container +After accessing the container with `docker exec`, you will be in the `/app/backend` directory. From there, navigate to the `open_webui` directory: +```bash +cd open_webui +``` + +:::info +All subsequent Alembic commands must be run from this directory (`/app/backend/open_webui` inside the container or `backend/open_webui` in a local setup), where the `alembic.ini` file is located. +::: + +### 2. Check the Current Database Revision + +To see the current revision of your database, run: + +```bash +alembic current +``` + +### 3. Apply All Pending Migrations (Upgrade) + +To upgrade your database to the latest version, which applies all pending migrations, run: + +```bash +alembic upgrade head +``` + +### 4. Upgrade to a Specific Revision + +You can upgrade to a specific migration by providing its revision ID: + +```bash +alembic upgrade +``` + +### 5. Downgrade to the Previous Revision + +To revert the last migration, use: + +```bash +alembic downgrade -1 +``` + +### 6. Downgrade to a Specific Revision + +You can also downgrade to a specific revision: + +```bash +alembic downgrade +``` + +### 7. View Migration History + +To see the history of all migrations, including their revision IDs, run: + +```bash +alembic history +``` + +:::tip +The `alembic history` command is useful for finding the revision ID to use with the `upgrade` and `downgrade` commands. +::: + +## Common Scenarios + +### Fresh Database Setup + +For a new database, run the following command to apply all migrations: + +```bash +alembic upgrade head +``` + +### Specific Migration Issues + +If a migration fails, you can resolve it with the following steps: +1. Check the current revision: `alembic current` +2. Identify the problematic revision from the error message. +3. Downgrade to the previous revision: `alembic downgrade -1` +4. Fix the underlying issue (e.g., a missing constraint). +5. Run the upgrade again: `alembic upgrade head` + +### Production Deployment + +When deploying to a production environment: + +:::danger[Backup Your Database] +**Always back up your database before running migrations in a production environment.** +::: + +1. Run migrations during a maintenance window to avoid service disruptions. +2. Verify the migration was successful with `alembic current`. + +## Troubleshooting + +### `InvalidForeignKey` Error + +If you encounter an error similar to `sqlalchemy.exc.ProgrammingError: (psycopg2.errors.InvalidForeignKey) there is no unique constraint matching given keys for referenced table "user"`, it's likely that a primary key constraint is missing on the `user` table. + +To fix this, you need to connect to your PostgreSQL database and run the following SQL command: + +```sql +ALTER TABLE public."user" ADD CONSTRAINT user_pk PRIMARY KEY (id); +``` + +After running this command, you can retry the `alembic upgrade head` command. + +### Migration Path Issues + +If you encounter path resolution issues, ensure you are running the `alembic` commands from the correct directory (`open_webui` inside the Docker container, or `backend/open_webui` in a local setup) where the `alembic.ini` file is located. + +### Database Connection + +Verify that your `DATABASE_URL` environment variable is correctly set and that the database is accessible from where you are running the commands. + +## Notes + +:::note +The application automatically runs migrations on startup via the `run_migrations()` function in `config.py`. Manual migrations are useful for debugging, controlled deployments, or when automatic migration is disabled. +::: + +- Some migrations include data transformation logic that may take a significant amount of time to run on large datasets. From 173422191c3cbfa0e376f42f6508ecc69bcae0a8 Mon Sep 17 00:00:00 2001 From: silentoplayz Date: Fri, 28 Nov 2025 06:22:26 -0500 Subject: [PATCH 07/17] Update manual-database-migration.md --- .../manual-database-migration.md | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/docs/troubleshooting/manual-database-migration.md b/docs/troubleshooting/manual-database-migration.md index 21f8ea4..9236f9f 100644 --- a/docs/troubleshooting/manual-database-migration.md +++ b/docs/troubleshooting/manual-database-migration.md @@ -30,13 +30,17 @@ This section provides instructions for running Alembic commands. The correct dir ### 1. Navigate to the Correct Directory #### Local Installation + If you are running Open WebUI from a local clone of the repository, navigate to the `backend/open_webui` directory from the repository root: + ```bash cd backend/open_webui ``` #### Docker Container + After accessing the container with `docker exec`, you will be in the `/app/backend` directory. From there, navigate to the `open_webui` directory: + ```bash cd open_webui ``` @@ -110,11 +114,12 @@ alembic upgrade head ### Specific Migration Issues If a migration fails, you can resolve it with the following steps: -1. Check the current revision: `alembic current` -2. Identify the problematic revision from the error message. -3. Downgrade to the previous revision: `alembic downgrade -1` -4. Fix the underlying issue (e.g., a missing constraint). -5. Run the upgrade again: `alembic upgrade head` + +1. Check the current revision: `alembic current` +2. Identify the problematic revision from the error message. +3. Downgrade to the previous revision: `alembic downgrade -1` +4. Fix the underlying issue (e.g., a missing constraint). +5. Run the upgrade again: `alembic upgrade head` ### Production Deployment @@ -124,8 +129,8 @@ When deploying to a production environment: **Always back up your database before running migrations in a production environment.** ::: -1. Run migrations during a maintenance window to avoid service disruptions. -2. Verify the migration was successful with `alembic current`. +1. Run migrations during a maintenance window to avoid service disruptions. +2. Verify the migration was successful with `alembic current`. ## Troubleshooting @@ -141,6 +146,16 @@ ALTER TABLE public."user" ADD CONSTRAINT user_pk PRIMARY KEY (id); After running this command, you can retry the `alembic upgrade head` command. +### Incorrect Autogenerated Migrations + +When creating a new migration, the `alembic revision --autogenerate` command can sometimes create an incorrect migration file that attempts to drop existing tables. This can happen if Alembic has trouble detecting the current state of your database schema. + +If you encounter this issue, here are a few things to try: + +1. **Ensure Your Database is Up-to-Date:** Before generating a new migration, make sure your database is fully upgraded to the latest revision by running `alembic upgrade head`. An out-of-date database is a common cause of this problem. +2. **Create a Manual Migration:** For simple changes, you can avoid `--autogenerate` altogether by creating a manual migration file. This gives you full control over the `upgrade()` and `downgrade()` functions. +3. **Start Fresh:** If your database schema is in a state that is difficult to recover from, the simplest solution may be to start with a fresh installation. + ### Migration Path Issues If you encounter path resolution issues, ensure you are running the `alembic` commands from the correct directory (`open_webui` inside the Docker container, or `backend/open_webui` in a local setup) where the `alembic.ini` file is located. From c2eb0cbfb88b4c5a14d7d852845a8412de051957 Mon Sep 17 00:00:00 2001 From: silentoplayz Date: Fri, 28 Nov 2025 06:36:14 -0500 Subject: [PATCH 08/17] Update manual-database-migration.md --- docs/troubleshooting/manual-database-migration.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/troubleshooting/manual-database-migration.md b/docs/troubleshooting/manual-database-migration.md index 9236f9f..bc8b710 100644 --- a/docs/troubleshooting/manual-database-migration.md +++ b/docs/troubleshooting/manual-database-migration.md @@ -156,6 +156,14 @@ If you encounter this issue, here are a few things to try: 2. **Create a Manual Migration:** For simple changes, you can avoid `--autogenerate` altogether by creating a manual migration file. This gives you full control over the `upgrade()` and `downgrade()` functions. 3. **Start Fresh:** If your database schema is in a state that is difficult to recover from, the simplest solution may be to start with a fresh installation. +### Migrations in Multi-Server Deployments + +:::warning[Update All Instances Simultaneously] +If you are running Open WebUI in a load-balanced, multi-server environment, it is critical that you **update all instances of the application at the same time.** + +A rolling update, where servers are updated one by one, can cause service disruptions. If the first server to be updated applies a destructive migration (e.g., dropping a column), all other servers still running the old code will immediately encounter errors, as they will be trying to access a database schema that is no longer compatible. +::: + ### Migration Path Issues If you encounter path resolution issues, ensure you are running the `alembic` commands from the correct directory (`open_webui` inside the Docker container, or `backend/open_webui` in a local setup) where the `alembic.ini` file is located. From 9799fb40c984bc5449fca6bc656a7fde1b8728f5 Mon Sep 17 00:00:00 2001 From: Andrew Baek Date: Fri, 28 Nov 2025 19:06:27 +0400 Subject: [PATCH 09/17] Update searxng.md --- docs/features/web-search/searxng.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/features/web-search/searxng.md b/docs/features/web-search/searxng.md index 82082fc..7de9c98 100644 --- a/docs/features/web-search/searxng.md +++ b/docs/features/web-search/searxng.md @@ -131,7 +131,7 @@ rm searxng/settings.yml 7. Bring up the container momentarily to generate a fresh settings.yml file: -If the container name caddy, redis, searxng is already in use, change it to another name of your choice in the docker-compose.yaml file. +If you have multiple containers running with the same name, such as caddy, redis, or searxng, you need to rename them in the docker-compose.yaml file to avoid conflicts. ```bash docker compose up -d ; sleep 10 ; docker compose down @@ -139,6 +139,8 @@ docker compose up -d ; sleep 10 ; docker compose down After the initial run, add `cap_drop: - ALL` to the `docker-compose.yaml` file for security reasons. +If Open WebUI is running in the same Docker network as Searxng, you may remove the `0.0.0.0` and only specify the port mapping. In this case, Open WebUI can access Searxng directly using the container name. +
docker-compose.yaml @@ -150,7 +152,7 @@ searxng: networks: - searxng ports: - - "0.0.0.0:9630:8080" + - "0.0.0.0:8080:8080" # use 8080:8080 if containers are in the same Docker network volumes: - ./searxng:/etc/searxng:rw - searxng-data:/var/cache/searxng:rw @@ -324,7 +326,7 @@ docker exec -it open-webui curl http://host.docker.internal:8080/search?q=this+i 3. Set `Web Search Engine` from dropdown menu to `searxng` 4. Set `Searxng Query URL` to one of the following examples: -- `http://localhost:8080/search?q=` (using the host and exposed port, suitable for Docker-based setups) +- `http://localhost:8080/search?q=` (using the host and host port, suitable for Docker-based setups) - `http://searxng:8080/search?q=` (using the container name and exposed port, suitable for Docker-based setups) - `http://host.docker.internal:8080/search?q=` (using the `host.docker.internal` DNS name and the host port, suitable for Docker-based setups) - `http:///search?q=` (using a local domain name, suitable for local network access) From 1b6cfa9850c4b69242baf1159f86e83451784991 Mon Sep 17 00:00:00 2001 From: silentoplayz Date: Fri, 28 Nov 2025 12:13:47 -0500 Subject: [PATCH 10/17] refac --- .../manual-database-migration.md | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/docs/troubleshooting/manual-database-migration.md b/docs/troubleshooting/manual-database-migration.md index bc8b710..6fae393 100644 --- a/docs/troubleshooting/manual-database-migration.md +++ b/docs/troubleshooting/manual-database-migration.md @@ -49,7 +49,37 @@ cd open_webui All subsequent Alembic commands must be run from this directory (`/app/backend/open_webui` inside the container or `backend/open_webui` in a local setup), where the `alembic.ini` file is located. ::: -### 2. Check the Current Database Revision +### 2. Set Environment Variables (Docker Only) + +:::danger[Critical Step for Docker Users] +When you open a shell in a Docker container with `docker exec`, the application's environment variables are **not** automatically loaded. You must set them manually before running any Alembic commands to avoid errors. +::: + +You will need to export the following variables: + +1. `PYTHONPATH`: This tells Python where to find the application's modules. +2. `DATABASE_URL`: This is the connection string for your database. +3. `WEBUI_SECRET_KEY`: This is a required variable for the application's authentication system. + +You can find the values for `DATABASE_URL` and `WEBUI_SECRET_KEY` in your `docker-compose.yaml` file or the `docker run` command you used to start the container. + +Before proceeding, export the variables in your container shell: + +```bash +export PYTHONPATH=.:../ +export DATABASE_URL="your-database-url-here" +export WEBUI_SECRET_KEY="your-secret-key-here" +``` + +For example, for a PostgreSQL database, it might look like this: + +```bash +export PYTHONPATH=.:../ +export DATABASE_URL="postgresql://user:password@host:port/database" +export WEBUI_SECRET_KEY="t0p-s3cr3t" +``` + +### 3. Check the Current Database Revision To see the current revision of your database, run: @@ -57,7 +87,7 @@ To see the current revision of your database, run: alembic current ``` -### 3. Apply All Pending Migrations (Upgrade) +### 4. Apply All Pending Migrations (Upgrade) To upgrade your database to the latest version, which applies all pending migrations, run: @@ -65,7 +95,7 @@ To upgrade your database to the latest version, which applies all pending migrat alembic upgrade head ``` -### 4. Upgrade to a Specific Revision +### 5. Upgrade to a Specific Revision You can upgrade to a specific migration by providing its revision ID: @@ -73,7 +103,7 @@ You can upgrade to a specific migration by providing its revision ID: alembic upgrade ``` -### 5. Downgrade to the Previous Revision +### 6. Downgrade to the Previous Revision To revert the last migration, use: @@ -81,7 +111,7 @@ To revert the last migration, use: alembic downgrade -1 ``` -### 6. Downgrade to a Specific Revision +### 7. Downgrade to a Specific Revision You can also downgrade to a specific revision: @@ -89,7 +119,7 @@ You can also downgrade to a specific revision: alembic downgrade ``` -### 7. View Migration History +### 8. View Migration History To see the history of all migrations, including their revision IDs, run: From 6bf1cadbb6a1ae403864d6963b0cf43f3febb263 Mon Sep 17 00:00:00 2001 From: silentoplayz Date: Fri, 28 Nov 2025 13:18:14 -0500 Subject: [PATCH 11/17] Update manual-database-migration.md --- .../manual-database-migration.md | 759 ++++++++++++++---- 1 file changed, 613 insertions(+), 146 deletions(-) diff --git a/docs/troubleshooting/manual-database-migration.md b/docs/troubleshooting/manual-database-migration.md index 6fae393..23cc31a 100644 --- a/docs/troubleshooting/manual-database-migration.md +++ b/docs/troubleshooting/manual-database-migration.md @@ -1,211 +1,678 @@ --- sidebar_position: 900 -title: Manual Alembic Database Migration Guide +title: Manual Alembic Database Migration +sidebar_label: Manual Migration +description: Complete guide for manually running Alembic database migrations when Open WebUI's automatic migration fails or requires direct intervention. +keywords: [alembic, migration, database, troubleshooting, sqlite, postgresql, docker] --- -This guide provides step-by-step instructions for manually applying Alembic database migrations in Open WebUI. Migrations are typically run automatically on startup, but you may need to run them manually for maintenance, debugging, or deployment scenarios. +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; -## Prerequisites +## Overview -- Ensure you have a Python environment with Open WebUI dependencies installed. -- Your database connection must be configured via the `DATABASE_URL` environment variable. -- You need access to the backend directory of your Open WebUI installation. +Open WebUI automatically runs database migrations on startup. **Manual migration is rarely needed** and should only be performed in specific failure scenarios or maintenance situations. -## Accessing the Container (for Docker installations) +:::info When Manual Migration is Required +You need manual migration only if: -If you are running Open WebUI in a Docker container, you'll first need to get a shell into the container: - -```bash -docker exec -it open-webui /bin/bash -``` - -:::note -Replace `open-webui` with the name of your container if it's different. +- Open WebUI logs show specific migration errors during startup +- You're performing offline database maintenance +- Automatic migration fails after a version upgrade +- You're migrating between database types (SQLite ↔ PostgreSQL) +- A developer has instructed you to run migrations manually ::: -## Manual Migration Commands - -This section provides instructions for running Alembic commands. The correct directory path depends on whether you are running Open WebUI from a local installation or within a Docker container. - -### 1. Navigate to the Correct Directory - -#### Local Installation - -If you are running Open WebUI from a local clone of the repository, navigate to the `backend/open_webui` directory from the repository root: - -```bash -cd backend/open_webui -``` - -#### Docker Container - -After accessing the container with `docker exec`, you will be in the `/app/backend` directory. From there, navigate to the `open_webui` directory: - -```bash -cd open_webui -``` - -:::info -All subsequent Alembic commands must be run from this directory (`/app/backend/open_webui` inside the container or `backend/open_webui` in a local setup), where the `alembic.ini` file is located. +:::danger Critical Warning +Manual migration can corrupt your database if performed incorrectly. **Always create a verified backup before proceeding.** ::: -### 2. Set Environment Variables (Docker Only) +## Prerequisites Checklist -:::danger[Critical Step for Docker Users] -When you open a shell in a Docker container with `docker exec`, the application's environment variables are **not** automatically loaded. You must set them manually before running any Alembic commands to avoid errors. +Before starting, ensure you have: + +- [ ] **Root/admin access** to your Open WebUI installation +- [ ] **Database location confirmed** (default: `/app/backend/data/webui.db` in Docker) +- [ ] **Open WebUI completely stopped** (no running processes) +- [ ] **Backup created and verified** (see below) +- [ ] **Access to container or Python environment** where Open WebUI runs + +:::warning Stop All Processes First +Database migrations cannot run while Open WebUI is active. You **must** stop all Open WebUI processes before attempting manual migration. ::: -You will need to export the following variables: +## Step 1: Create and Verify Backup -1. `PYTHONPATH`: This tells Python where to find the application's modules. -2. `DATABASE_URL`: This is the connection string for your database. -3. `WEBUI_SECRET_KEY`: This is a required variable for the application's authentication system. +### Backup Your Database -You can find the values for `DATABASE_URL` and `WEBUI_SECRET_KEY` in your `docker-compose.yaml` file or the `docker run` command you used to start the container. + + + ```bash title="Terminal" + # Find your database location first + docker inspect open-webui | grep -A 5 Mounts -Before proceeding, export the variables in your container shell: + # Create timestamped backup + cp /path/to/webui.db /path/to/webui.db.backup.$(date +%Y%m%d_%H%M%S) + ``` + + + ```bash title="Terminal" + pg_dump -h localhost -U your_user -d open_webui_db > backup_$(date +%Y%m%d_%H%M%S).sql + ``` + + -```bash -export PYTHONPATH=.:../ -export DATABASE_URL="your-database-url-here" -export WEBUI_SECRET_KEY="your-secret-key-here" +### Verify Backup Integrity + +**Critical:** Test that your backup is readable before proceeding. + + + + ```bash title="Terminal - Verify Backup" + # Test backup can be opened + sqlite3 /path/to/webui.db.backup "SELECT count(*) FROM user;" + + # Verify schema matches + sqlite3 /path/to/webui.db ".schema" > current-schema.sql + sqlite3 /path/to/webui.db.backup ".schema" > backup-schema.sql + diff current-schema.sql backup-schema.sql + ``` + + + ```bash title="Terminal - Verify Backup" + # Verify backup file is not empty and contains SQL + head -n 20 backup_*.sql + grep -c "CREATE TABLE" backup_*.sql + ``` + + + +:::tip Backup Storage +Store backups on a **different disk or volume** than your database to protect against disk failure. +::: + +## Step 2: Diagnose Current State + +Before attempting any fixes, gather information about your database state. + +### Access Your Environment + + + + ```bash title="Terminal" + # Stop Open WebUI first + docker stop open-webui + + # Enter container for diagnostics + docker run --rm -it \ + -v open-webui:/app/backend/data \ + --entrypoint /bin/bash \ + ghcr.io/open-webui/open-webui:main + ``` + + :::note Default Directory + When you enter the container, you'll be in `/app`. The Alembic configuration is at `/app/backend/open_webui/alembic.ini`. + ::: + + + ```bash title="Terminal" + # Navigate to Open WebUI installation + cd /path/to/open-webui/backend/open_webui + + # Activate virtual environment if used + source ../../venv/bin/activate # Linux/Mac + # venv\Scripts\activate # Windows + ``` + + + +### Run Diagnostic Commands + +Navigate to the directory containing `alembic.ini`: + +```bash title="Terminal - Navigate to Alembic Directory" +cd /app/backend/open_webui # Docker +# OR +cd /path/to/open-webui/backend/open_webui # Local ``` -For example, for a PostgreSQL database, it might look like this: +Execute these read-only diagnostic commands: -```bash -export PYTHONPATH=.:../ -export DATABASE_URL="postgresql://user:password@host:port/database" -export WEBUI_SECRET_KEY="t0p-s3cr3t" -``` +```bash title="Terminal - Diagnostics (Safe - Read Only)" +# Verify alembic.ini exists +ls -la alembic.ini -### 3. Check the Current Database Revision +# Check current migration version +alembic current -v -To see the current revision of your database, run: +# Check target (latest) version +alembic heads -```bash -alembic current -``` - -### 4. Apply All Pending Migrations (Upgrade) - -To upgrade your database to the latest version, which applies all pending migrations, run: - -```bash -alembic upgrade head -``` - -### 5. Upgrade to a Specific Revision - -You can upgrade to a specific migration by providing its revision ID: - -```bash -alembic upgrade -``` - -### 6. Downgrade to the Previous Revision - -To revert the last migration, use: - -```bash -alembic downgrade -1 -``` - -### 7. Downgrade to a Specific Revision - -You can also downgrade to a specific revision: - -```bash -alembic downgrade -``` - -### 8. View Migration History - -To see the history of all migrations, including their revision IDs, run: - -```bash +# List all migration history alembic history + +# Check for branching (indicates issues) +alembic branches ``` -:::tip -The `alembic history` command is useful for finding the revision ID to use with the `upgrade` and `downgrade` commands. +**Expected output:** + +``` +# alembic current should show something like: +ae1027a6acf (head) + +# If you see multiple heads or branching, your migration history has issues +``` + +:::info Understanding Output + +- `alembic current` = what version your database thinks it's at +- `alembic heads` = what version the code expects +- If `current` is older than `heads`, you have pending migrations +- If `current` equals `heads`, your database is up-to-date ::: -## Common Scenarios +
+Check Actual Database Tables -### Fresh Database Setup +Verify what's actually in your database: -For a new database, run the following command to apply all migrations: + + + ```bash title="Terminal" + sqlite3 /app/backend/data/webui.db ".tables" + sqlite3 /app/backend/data/webui.db "SELECT * FROM alembic_version;" + ``` + + + ```bash title="Terminal" + psql -h localhost -U user -d dbname -c "\dt" + psql -h localhost -U user -d dbname -c "SELECT * FROM alembic_version;" + ``` + + -```bash +
+ +## Step 3: Configure Environment + +Set required environment variables for manual Alembic execution. + +```bash title="Terminal - Set Environment Variables" +# Required: Database URL +# For Docker with SQLite (note the 4 slashes for absolute path) +export DATABASE_URL="sqlite:////app/backend/data/webui.db" + +# For local install with SQLite (relative path from open_webui directory) +export DATABASE_URL="sqlite:///../data/webui.db" + +# For PostgreSQL +export DATABASE_URL="postgresql://user:password@localhost:5432/open_webui_db" +``` + +:::warning Path Syntax for SQLite + +- `sqlite:////app/...` = 4 slashes total (absolute path) +- `sqlite:///data/...` = 3 slashes total (relative path) +- The extra slash after `sqlite:///` makes it absolute +::: + +## Step 4: Apply Migrations + +### Standard Upgrade (Most Common) + +If diagnostics show you have pending migrations (`current` < `heads`), upgrade to latest: + +```bash title="Terminal - Upgrade to Latest" +# Ensure you're in the correct directory +cd /app/backend/open_webui + +# Run upgrade alembic upgrade head ``` -### Specific Migration Issues +**Watch for these outputs:** -If a migration fails, you can resolve it with the following steps: +```bash +INFO [alembic.runtime.migration] Context impl SQLiteImpl. +INFO [alembic.runtime.migration] Will assume non-transactional DDL. +# highlight-next-line +INFO [alembic.runtime.migration] Running upgrade abc123 -> def456, add_new_column +``` -1. Check the current revision: `alembic current` -2. Identify the problematic revision from the error message. -3. Downgrade to the previous revision: `alembic downgrade -1` -4. Fix the underlying issue (e.g., a missing constraint). -5. Run the upgrade again: `alembic upgrade head` +:::note "Will assume non-transactional DDL" +This is a **normal informational message** for SQLite, not an error. SQLite doesn't support rollback of schema changes, so migrations run without transaction protection. -### Production Deployment - -When deploying to a production environment: - -:::danger[Backup Your Database] -**Always back up your database before running migrations in a production environment.** +If the process appears to hang after this message, wait 2-3 minutes - some migrations take time. If it's truly stuck, check for database locks (see troubleshooting). ::: -1. Run migrations during a maintenance window to avoid service disruptions. -2. Verify the migration was successful with `alembic current`. +### Upgrade to Specific Version + +If you need to apply migrations up to a specific point: + +```bash title="Terminal - Upgrade to Specific Version" +# List available versions first +alembic history + +# Upgrade to specific revision +alembic upgrade ae1027a6acf +``` + +### Downgrade (Rollback) + +:::danger Data Loss Risk +Downgrading can cause **permanent data loss** if the migration removed columns or tables. Only downgrade if you understand the consequences. +::: + +```bash title="Terminal - Downgrade Migrations" +# Downgrade one version +alembic downgrade -1 + +# Downgrade to specific version +alembic downgrade + +# Nuclear option: Remove all migrations (rarely needed) +alembic downgrade base +``` + +## Step 5: Verify Migration Success + +After running migrations, confirm everything is correct: + +```bash title="Terminal - Post-Migration Verification" +# Verify current version matches expected +alembic current + +# Should show (head) indicating you're at latest +# Example: ae1027a6acf (head) + +# Confirm no pending migrations +alembic upgrade head --sql | head -20 +# If output contains only comments or is empty, you're up to date +``` + +### Test Application Startup + + + + ```bash title="Terminal" + # Exit the diagnostic container + exit + + # Start Open WebUI normally + docker start open-webui + + # Watch logs for migration confirmation + docker logs -f open-webui + ``` + + + ```bash title="Terminal" + # Start Open WebUI + python -m open_webui.main + + # Watch for successful startup messages + ``` + + + +**Successful startup logs:** + +``` +INFO: [db] Database initialization complete +INFO: [main] Open WebUI starting on http://0.0.0.0:8080 +``` ## Troubleshooting -### `InvalidForeignKey` Error +### "No config file 'alembic.ini' found" -If you encounter an error similar to `sqlalchemy.exc.ProgrammingError: (psycopg2.errors.InvalidForeignKey) there is no unique constraint matching given keys for referenced table "user"`, it's likely that a primary key constraint is missing on the `user` table. +**Cause:** You're in the wrong directory. -To fix this, you need to connect to your PostgreSQL database and run the following SQL command: +**Solution:** -```sql -ALTER TABLE public."user" ADD CONSTRAINT user_pk PRIMARY KEY (id); +```bash title="Terminal" +# Find alembic.ini location +find /app -name "alembic.ini" 2>/dev/null # Docker +find . -name "alembic.ini" # Local + +# Navigate to that directory +cd /app/backend/open_webui # Most common path ``` -After running this command, you can retry the `alembic upgrade head` command. +### "Target database is not up to date" -### Incorrect Autogenerated Migrations +**Cause:** Your database version doesn't match expected schema. -When creating a new migration, the `alembic revision --autogenerate` command can sometimes create an incorrect migration file that attempts to drop existing tables. This can happen if Alembic has trouble detecting the current state of your database schema. +**Diagnosis:** -If you encounter this issue, here are a few things to try: +```bash title="Terminal - Diagnose Version Mismatch" +# Check what database thinks its version is +alembic current -1. **Ensure Your Database is Up-to-Date:** Before generating a new migration, make sure your database is fully upgraded to the latest revision by running `alembic upgrade head`. An out-of-date database is a common cause of this problem. -2. **Create a Manual Migration:** For simple changes, you can avoid `--autogenerate` altogether by creating a manual migration file. This gives you full control over the `upgrade()` and `downgrade()` functions. -3. **Start Fresh:** If your database schema is in a state that is difficult to recover from, the simplest solution may be to start with a fresh installation. +# Check what code expects +alembic heads -### Migrations in Multi-Server Deployments +# Compare +``` -:::warning[Update All Instances Simultaneously] -If you are running Open WebUI in a load-balanced, multi-server environment, it is critical that you **update all instances of the application at the same time.** +**Solution depends on diagnosis:** -A rolling update, where servers are updated one by one, can cause service disruptions. If the first server to be updated applies a destructive migration (e.g., dropping a column), all other servers still running the old code will immediately encounter errors, as they will be trying to access a database schema that is no longer compatible. + + + **Scenario:** `alembic current` shows older version than `alembic heads` + + **Fix:** You simply need to apply pending migrations. + + ```bash title="Terminal" + alembic upgrade head + ``` + + + **Scenario:** `alembic current` shows correct version, but you still see errors + + **Cause:** Someone manually modified the database schema without migrations, or a previous migration partially failed. + + **Fix:** Restore from backup - you have database corruption. + + ```bash title="Terminal" + # Stop everything + docker stop open-webui + + # Restore backup + cp /path/to/webui.db.backup /path/to/webui.db + + # Try migration again + alembic upgrade head + ``` + + + **Scenario:** New database that needs initial schema + + **Fix:** Run migrations from scratch. + + ```bash title="Terminal" + alembic upgrade head + ``` + + + +:::danger Never Use "alembic stamp" as a Fix +You may see advice to run `alembic stamp head` to "fix" version mismatches. **This is dangerous.** + +`alembic stamp` tells Alembic "pretend this migration was applied" without actually running it. This creates permanent database corruption where Alembic thinks your schema is up-to-date when it isn't. + +**Only use `alembic stamp head` if:** + +- You manually created all tables using `create_all()` and need to mark them as migrated +- You're a developer initializing a fresh database that matches current schema + +**Never use it to "fix" migration errors.** ::: -### Migration Path Issues +### Process Hangs After "Will assume non-transactional DDL" -If you encounter path resolution issues, ensure you are running the `alembic` commands from the correct directory (`open_webui` inside the Docker container, or `backend/open_webui` in a local setup) where the `alembic.ini` file is located. +**Understanding the message:** This is **not an error**. It's informational. SQLite doesn't support transactional DDL, so Alembic is warning that migrations can't be rolled back automatically. -### Database Connection +**If genuinely stuck:** -Verify that your `DATABASE_URL` environment variable is correctly set and that the database is accessible from where you are running the commands. + + + Some migrations (especially those adding indexes or modifying large tables) take several minutes. -## Notes + **Action:** Wait 3-5 minutes before assuming it's stuck. + + + Another process might have locked the database. + + ```bash title="Terminal - Check for Locks" + # Find processes using database file + fuser /app/backend/data/webui.db + + # Kill any orphaned processes + pkill -f "open-webui" + + # Verify nothing running + ps aux | grep open-webui + + # Try migration again + alembic upgrade head + ``` + + + If the database is corrupted, migration will hang. + + ```bash title="Terminal - Check Integrity" + sqlite3 /app/backend/data/webui.db "PRAGMA integrity_check;" + ``` + + If integrity check fails, restore from backup. + + + +### Autogenerate Detects Removed Tables + +**Symptom:** You ran `alembic revision --autogenerate` and it wants to drop existing tables. + +:::warning Don't Run Autogenerate +**Regular users should NEVER run `alembic revision --autogenerate`.** This command is for developers creating new migration files, not for applying existing migrations. + +The command you want is `alembic upgrade head` (no `revision`, no `--autogenerate`). +::: + +**If you accidentally created a bad migration file:** + +```bash title="Terminal - Remove Bad Migration" +# List migration files +ls -la /app/backend/open_webui/migrations/versions/ + +# Delete the incorrect auto-generated file (newest file) +rm /app/backend/open_webui/migrations/versions/_*.py + +# Restore to known good state +git checkout /app/backend/open_webui/migrations/ # If using git +``` + +**Technical context:** The "autogenerate detects removed tables" issue occurs because Open WebUI's Alembic metadata configuration doesn't import all model definitions. This causes autogenerate to compare against incomplete metadata, thinking tables should be removed. This is a developer-level issue that doesn't affect users running `alembic upgrade`. + +### Peewee to Alembic Transition Issues + +**Background:** Older Open WebUI versions (pre-0.4.x) used Peewee migrations. Current versions use Alembic. + +**Symptoms:** + +- Both `migratehistory` and `alembic_version` tables exist +- Errors about "migration already applied" + +**What happens automatically:** + +1. Open WebUI's `internal/db.py` runs old Peewee migrations first via `handle_peewee_migration()` +2. Then `config.py` runs Alembic migrations via `run_migrations()` +3. Both systems should work transparently + +**If automatic transition fails:** + +```bash title="Terminal - Manual Transition" +# Check if old Peewee migrations exist +sqlite3 /app/backend/data/webui.db "SELECT * FROM migratehistory;" 2>/dev/null + +# If Peewee migrations exist, ensure they completed +# Then run Alembic migrations +cd /app/backend/open_webui +alembic upgrade head +``` + +:::tip +If upgrading from very old Open WebUI versions (< 0.3.x), consider a fresh install with data export/import rather than attempting to migrate the database schema across multiple major version changes. +::: + +## Advanced Operations + +### Generate SQL Without Applying + +For review or audit purposes, generate the SQL that would be executed: + +```bash title="Terminal - Generate Migration SQL" +# Generate SQL for pending migrations +alembic upgrade head --sql > /tmp/migration-plan.sql + +# Review what would be applied +cat /tmp/migration-plan.sql +``` + +**Use cases:** + +- DBA review in enterprise environments +- Understanding what changes will occur +- Debugging migration issues +- Applying migrations in restricted environments + +:::info When to Use This +This is advanced functionality for DBAs or DevOps engineers. Regular users should just run `alembic upgrade head` directly. +::: + +### Offline Migration (No Network) + +If your database server is offline or isolated: + +```bash title="Terminal - Offline Migration Workflow" +# 1. Generate SQL on development machine +alembic upgrade head --sql > upgrade-to-head.sql + +# 2. Transfer SQL file to production +scp upgrade-to-head.sql production-server:/tmp/ + +# 3. On production, apply SQL manually +sqlite3 /app/backend/data/webui.db < /tmp/upgrade-to-head.sql + +# 4. Update alembic_version table manually +sqlite3 /app/backend/data/webui.db \ + "UPDATE alembic_version SET version_num='';" +``` + +:::danger Manual alembic_version Updates +Only update `alembic_version` if you've **actually applied** the corresponding migrations. Lying to Alembic about migration state causes permanent corruption. +::: + +## Recovery Procedures + +### Recovery from Failed Migration + +:::danger SQLite Has No Rollback +SQLite migrations are **non-transactional**. If a migration fails halfway through, your database is in a partially-migrated state. The only safe recovery is restoring from backup. +::: + +**Symptoms of partial migration:** + +- Some tables exist, others don't match expected schema +- Foreign key violations +- Missing columns that migration should have added +- Application errors about missing database fields + +**Recovery steps:** + +```bash title="Terminal - Restore from Backup" +# 1. Stop Open WebUI immediately +docker stop open-webui + +# 2. Verify backup integrity +sqlite3 /path/to/webui.db.backup "PRAGMA integrity_check;" + +# 3. Restore backup +cp /path/to/webui.db.backup /path/to/webui.db + +# 4. Investigate root cause before retrying +docker logs open-webui > migration-failure-logs.txt + +# 5. Get help with logs before attempting migration again +``` + +:::warning Do Not Use "stamp" to Fix Failed Migrations +Never use `alembic stamp` to mark a partially-failed migration as complete. This leaves your database in a corrupt state. +::: + +### Validate Database Integrity + +Before and after migrations, verify your database isn't corrupted: + + + + ```bash title="Terminal - SQLite Integrity Check" + sqlite3 /app/backend/data/webui.db "PRAGMA integrity_check;" + + # Should output: ok + # If it outputs anything else, database is corrupted + ``` + + + ```bash title="Terminal - PostgreSQL Integrity Check" + # Check for table corruption + psql -h localhost -U user -d dbname -c "SELECT * FROM pg_stat_database WHERE datname='open_webui_db';" + + # Vacuum and analyze + psql -h localhost -U user -d dbname -c "VACUUM ANALYZE;" + ``` + + + +## Post-Migration Checklist + +After successful migration, verify: + +- [ ] `alembic current` shows `(head)` indicating latest version +- [ ] Open WebUI starts without errors +- [ ] Can log in successfully +- [ ] Core features work (chat, model selection, etc.) +- [ ] No error messages in logs +- [ ] Data appears intact (users, chats, models) +- [ ] Backup can be safely archived after 1 week of stability + +:::tip Keep Recent Backups +Retain backups from before major migrations for at least 1-2 weeks. Issues sometimes appear days later during specific workflows. +::: + +## Getting Help + +If migrations continue to fail after following this guide: + +**Gather diagnostic information:** + +```bash title="Terminal - Collect Diagnostic Data" +# Version information +docker logs open-webui 2>&1 | head -20 > diagnostics.txt + +# Migration state +cd /app/backend/open_webui +alembic current -v >> diagnostics.txt +alembic history >> diagnostics.txt + +# Database info (SQLite) +sqlite3 /app/backend/data/webui.db ".tables" >> diagnostics.txt +sqlite3 /app/backend/data/webui.db "SELECT * FROM alembic_version;" >> diagnostics.txt + +# Full migration log +alembic upgrade head 2>&1 >> diagnostics.txt +``` + +**Where to get help:** + +1. **Open WebUI GitHub Issues:** https://github.com/open-webui/open-webui/issues + - Search existing issues first + - Include your `diagnostics.txt` file + - Specify your Open WebUI version and installation method + +2. **Open WebUI Discord Community** + - Real-time support from community members + - Share error messages and diagnostics + +3. **Provide this information:** + - Open WebUI version + - Installation method (Docker/local) + - Database type (SQLite/PostgreSQL) + - Output of `alembic current` and `alembic history` + - Complete error messages + - What you were doing when it failed :::note -The application automatically runs migrations on startup via the `run_migrations()` function in `config.py`. Manual migrations are useful for debugging, controlled deployments, or when automatic migration is disabled. +Do not share your `webui.db` database file publicly - it contains user credentials and sensitive data. Only share the diagnostic text output. ::: - -- Some migrations include data transformation logic that may take a significant amount of time to run on large datasets. From 8da0d9f76be2b3951ce4423012bfb3abc32d43d8 Mon Sep 17 00:00:00 2001 From: silentoplayz Date: Fri, 28 Nov 2025 20:49:25 -0500 Subject: [PATCH 12/17] refac --- .../manual-database-migration.md | 103 ++++++++++++------ 1 file changed, 72 insertions(+), 31 deletions(-) diff --git a/docs/troubleshooting/manual-database-migration.md b/docs/troubleshooting/manual-database-migration.md index 23cc31a..a3f2297 100644 --- a/docs/troubleshooting/manual-database-migration.md +++ b/docs/troubleshooting/manual-database-migration.md @@ -126,22 +126,61 @@ Before attempting any fixes, gather information about your database state. -### Run Diagnostic Commands +### Navigate to Alembic Directory and Set Environment -Navigate to the directory containing `alembic.ini`: +Navigate to the directory containing `alembic.ini` and configure required environment variables: -```bash title="Terminal - Navigate to Alembic Directory" +```bash title="Terminal - Navigate and Configure Environment" +# Navigate to Alembic directory cd /app/backend/open_webui # Docker # OR cd /path/to/open-webui/backend/open_webui # Local + +# Verify alembic.ini exists +ls -la alembic.ini ``` +### Set Required Environment Variables + +```bash title="Terminal - Set Environment Variables" +# Required: Database URL +# For Docker with SQLite (4 slashes for absolute path) +export DATABASE_URL="sqlite:////app/backend/data/webui.db" + +# For local install with SQLite (relative path) +export DATABASE_URL="sqlite:///../data/webui.db" + +# For PostgreSQL +export DATABASE_URL="postgresql://user:password@localhost:5432/open_webui_db" + +# Required: WEBUI_SECRET_KEY +# Get from existing file +export WEBUI_SECRET_KEY=$(cat /app/backend/data/.webui_secret_key) + +# If .webui_secret_key doesn't exist, generate one +# export WEBUI_SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_hex(32))") +# echo $WEBUI_SECRET_KEY > /app/backend/data/.webui_secret_key + +# Verify both are set +echo "DATABASE_URL: $DATABASE_URL" +echo "WEBUI_SECRET_KEY: ${WEBUI_SECRET_KEY:0:10}..." +``` + +:::danger Both Variables Required +Alembic commands will fail with `Required environment variable not found` if `WEBUI_SECRET_KEY` is missing. Open WebUI's code imports `env.py` which validates this variable exists before Alembic can even connect to the database. +::: + +:::warning Path Syntax for SQLite + +- `sqlite:////app/...` = 4 slashes total (absolute path: `sqlite://` + `/` + `/app/...`) +- `sqlite:///../data/...` = 3 slashes total (relative path) +::: + +### Run Diagnostic Commands + Execute these read-only diagnostic commands: ```bash title="Terminal - Diagnostics (Safe - Read Only)" -# Verify alembic.ini exists -ls -la alembic.ini - # Check current migration version alembic current -v @@ -194,30 +233,7 @@ Verify what's actually in your database:
-## Step 3: Configure Environment - -Set required environment variables for manual Alembic execution. - -```bash title="Terminal - Set Environment Variables" -# Required: Database URL -# For Docker with SQLite (note the 4 slashes for absolute path) -export DATABASE_URL="sqlite:////app/backend/data/webui.db" - -# For local install with SQLite (relative path from open_webui directory) -export DATABASE_URL="sqlite:///../data/webui.db" - -# For PostgreSQL -export DATABASE_URL="postgresql://user:password@localhost:5432/open_webui_db" -``` - -:::warning Path Syntax for SQLite - -- `sqlite:////app/...` = 4 slashes total (absolute path) -- `sqlite:///data/...` = 3 slashes total (relative path) -- The extra slash after `sqlite:///` makes it absolute -::: - -## Step 4: Apply Migrations +## Step 3: Apply Migrations ### Standard Upgrade (Most Common) @@ -275,7 +291,7 @@ alembic downgrade alembic downgrade base ``` -## Step 5: Verify Migration Success +## Step 4: Verify Migration Success After running migrations, confirm everything is correct: @@ -325,6 +341,31 @@ INFO: [main] Open WebUI starting on http://0.0.0.0:8080 ## Troubleshooting +### "Required environment variable not found" + +**Cause:** `WEBUI_SECRET_KEY` environment variable is missing. + +**Solution:** + +```bash title="Terminal - Fix Missing Secret Key" +# Method 1: Use existing key from file +export WEBUI_SECRET_KEY=$(cat /app/backend/data/.webui_secret_key) + +# Method 2: If file doesn't exist, generate new key +export WEBUI_SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_hex(32))") +echo $WEBUI_SECRET_KEY > /app/backend/data/.webui_secret_key + +# Verify it's set +echo "WEBUI_SECRET_KEY: ${WEBUI_SECRET_KEY:0:10}..." + +# Try alembic again +alembic current -v +``` + +:::warning Why This Happens +Open WebUI's `env.py` file imports models, which import `open_webui.env`, which validates that `WEBUI_SECRET_KEY` exists. Without it, Python crashes before Alembic can even connect to the database. +::: + ### "No config file 'alembic.ini' found" **Cause:** You're in the wrong directory. From 5d77524bee737cf42c25c241239d52eed3b5947c Mon Sep 17 00:00:00 2001 From: silentoplayz Date: Fri, 28 Nov 2025 21:20:15 -0500 Subject: [PATCH 13/17] is this what you wanted? (NF reference) --- .../manual-database-migration.md | 219 ++++++++++++++++-- 1 file changed, 204 insertions(+), 15 deletions(-) diff --git a/docs/troubleshooting/manual-database-migration.md b/docs/troubleshooting/manual-database-migration.md index a3f2297..2ca0c60 100644 --- a/docs/troubleshooting/manual-database-migration.md +++ b/docs/troubleshooting/manual-database-migration.md @@ -110,8 +110,12 @@ Before attempting any fixes, gather information about your database state. ghcr.io/open-webui/open-webui:main ``` - :::note Default Directory - When you enter the container, you'll be in `/app`. The Alembic configuration is at `/app/backend/open_webui/alembic.ini`. + :::note Verify Your Location + Check where you are after entering the container: + ```bash + pwd + ``` + The Alembic configuration is at `/app/backend/open_webui/alembic.ini`. Navigate there regardless of your starting directory. ::: @@ -131,24 +135,27 @@ Before attempting any fixes, gather information about your database state. Navigate to the directory containing `alembic.ini` and configure required environment variables: ```bash title="Terminal - Navigate and Configure Environment" -# Navigate to Alembic directory +# First, verify where you are +pwd + +# Navigate to Alembic directory (adjust path if your pwd is different) cd /app/backend/open_webui # Docker # OR cd /path/to/open-webui/backend/open_webui # Local -# Verify alembic.ini exists +# Verify alembic.ini exists in current directory ls -la alembic.ini ``` ### Set Required Environment Variables -```bash title="Terminal - Set Environment Variables" -# Required: Database URL -# For Docker with SQLite (4 slashes for absolute path) -export DATABASE_URL="sqlite:////app/backend/data/webui.db" + + -# For local install with SQLite (relative path) -export DATABASE_URL="sqlite:///../data/webui.db" +```bash title="Terminal - Set Environment Variables (Docker)" +# Required: Database URL +# For SQLite (4 slashes for absolute path) +export DATABASE_URL="sqlite:////app/backend/data/webui.db" # For PostgreSQL export DATABASE_URL="postgresql://user:password@localhost:5432/open_webui_db" @@ -166,6 +173,39 @@ echo "DATABASE_URL: $DATABASE_URL" echo "WEBUI_SECRET_KEY: ${WEBUI_SECRET_KEY:0:10}..." ``` + + + +```bash title="Terminal - Set Environment Variables (Local)" +# Required: Database URL +# For SQLite (relative path from backend/open_webui directory) +export DATABASE_URL="sqlite:///../data/webui.db" + +# For absolute path +export DATABASE_URL="sqlite:////full/path/to/webui.db" + +# For PostgreSQL +export DATABASE_URL="postgresql://user:password@localhost:5432/open_webui_db" + +# Required: WEBUI_SECRET_KEY +# If using .env file, Alembic may not pick it up automatically - export manually +export WEBUI_SECRET_KEY=$(cat ../data/.webui_secret_key) + +# Or if you have it in your environment already +# export WEBUI_SECRET_KEY="your-existing-key" + +# Verify both are set +echo "DATABASE_URL: $DATABASE_URL" +echo "WEBUI_SECRET_KEY: ${WEBUI_SECRET_KEY:0:10}..." +``` + +:::note Local Installation Environment +Local installations often have `DATABASE_URL` in a `.env` file, but Alembic's `env.py` may not automatically load `.env` files. You must explicitly export these variables in your shell before running Alembic commands. +::: + + + + :::danger Both Variables Required Alembic commands will fail with `Required environment variable not found` if `WEBUI_SECRET_KEY` is missing. Open WebUI's code imports `env.py` which validates this variable exists before Alembic can even connect to the database. ::: @@ -190,6 +230,9 @@ alembic heads # List all migration history alembic history +# Show pending migrations (what would be applied) +alembic upgrade head --sql | head -30 + # Check for branching (indicates issues) alembic branches ``` @@ -207,6 +250,7 @@ ae1027a6acf (head) - `alembic current` = what version your database thinks it's at - `alembic heads` = what version the code expects +- `alembic upgrade head --sql` = preview SQL that would be executed (doesn't apply changes) - If `current` is older than `heads`, you have pending migrations - If `current` equals `heads`, your database is up-to-date ::: @@ -259,7 +303,13 @@ INFO [alembic.runtime.migration] Running upgrade abc123 -> def456, add_new_colu :::note "Will assume non-transactional DDL" This is a **normal informational message** for SQLite, not an error. SQLite doesn't support rollback of schema changes, so migrations run without transaction protection. -If the process appears to hang after this message, wait 2-3 minutes - some migrations take time. If it's truly stuck, check for database locks (see troubleshooting). +If the process appears to hang after this message, wait 2-3 minutes - some migrations take time, especially: + +- Migrations that add indexes to large tables (1M+ rows: 1-5 minutes) +- Migrations with data transformations (100K+ rows: 30 seconds to several minutes) +- Migrations that rebuild tables (SQLite doesn't support all ALTER operations) + +For very large databases (10M+ rows), consider running migrations during a maintenance window and monitoring progress with `sqlite3 /path/to/webui.db ".tables"` in another terminal. ::: ### Upgrade to Specific Version @@ -298,13 +348,20 @@ After running migrations, confirm everything is correct: ```bash title="Terminal - Post-Migration Verification" # Verify current version matches expected alembic current - # Should show (head) indicating you're at latest # Example: ae1027a6acf (head) # Confirm no pending migrations alembic upgrade head --sql | head -20 # If output contains only comments or is empty, you're up to date + +# Verify key tables exist (SQLite) +sqlite3 /app/backend/data/webui.db ".tables" | grep -E "user|chat|model" +# Should show user, chat, model tables among others + +# Test a simple query to ensure schema is intact +sqlite3 /app/backend/data/webui.db "SELECT COUNT(*) FROM user;" +# Should return a number, not an error ``` ### Test Application Startup @@ -320,6 +377,9 @@ alembic upgrade head --sql | head -20 # Watch logs for migration confirmation docker logs -f open-webui + + # Look for successful startup, then test in browser + # Navigate to http://localhost:8080 and verify login page loads ``` @@ -328,6 +388,7 @@ alembic upgrade head --sql | head -20 python -m open_webui.main # Watch for successful startup messages + # Test by navigating to http://localhost:8080 ``` @@ -339,6 +400,13 @@ INFO: [db] Database initialization complete INFO: [main] Open WebUI starting on http://0.0.0.0:8080 ``` +**Smoke test after startup:** + +- Can access login page +- Can log in with existing credentials +- Can view chat history +- No JavaScript console errors + ## Troubleshooting ### "Required environment variable not found" @@ -347,7 +415,10 @@ INFO: [main] Open WebUI starting on http://0.0.0.0:8080 **Solution:** -```bash title="Terminal - Fix Missing Secret Key" + + + +```bash title="Terminal - Fix Missing Secret Key (Docker)" # Method 1: Use existing key from file export WEBUI_SECRET_KEY=$(cat /app/backend/data/.webui_secret_key) @@ -362,6 +433,27 @@ echo "WEBUI_SECRET_KEY: ${WEBUI_SECRET_KEY:0:10}..." alembic current -v ``` + + + +```bash title="Terminal - Fix Missing Secret Key (Local)" +# Method 1: Use existing key from file +export WEBUI_SECRET_KEY=$(cat ../data/.webui_secret_key) + +# Method 2: Check if it's in your .env file +grep WEBUI_SECRET_KEY .env +# Then export it: export WEBUI_SECRET_KEY="value-from-env-file" + +# Verify it's set +echo "WEBUI_SECRET_KEY: ${WEBUI_SECRET_KEY:0:10}..." + +# Try alembic again +alembic current -v +``` + + + + :::warning Why This Happens Open WebUI's `env.py` file imports models, which import `open_webui.env`, which validates that `WEBUI_SECRET_KEY` exists. Without it, Python crashes before Alembic can even connect to the database. ::: @@ -373,12 +465,18 @@ Open WebUI's `env.py` file imports models, which import `open_webui.env`, which **Solution:** ```bash title="Terminal" +# Find your container name if not 'open-webui' +docker ps + # Find alembic.ini location find /app -name "alembic.ini" 2>/dev/null # Docker find . -name "alembic.ini" # Local # Navigate to that directory cd /app/backend/open_webui # Most common path + +# Verify you're in the right place +ls -la alembic.ini ``` ### "Target database is not up to date" @@ -443,12 +541,14 @@ You may see advice to run `alembic stamp head` to "fix" version mismatches. **Th `alembic stamp` tells Alembic "pretend this migration was applied" without actually running it. This creates permanent database corruption where Alembic thinks your schema is up-to-date when it isn't. -**Only use `alembic stamp head` if:** +**Only use `alembic stamp ` if:** - You manually created all tables using `create_all()` and need to mark them as migrated - You're a developer initializing a fresh database that matches current schema +- You imported a database backup from another system and need to mark it at the correct revision +- You've manually applied migrations via raw SQL and need to update the version tracking -**Never use it to "fix" migration errors.** +**Never use it to "fix" migration errors or skip failed migrations.** ::: ### Process Hangs After "Will assume non-transactional DDL" @@ -547,8 +647,97 @@ alembic upgrade head If upgrading from very old Open WebUI versions (< 0.3.x), consider a fresh install with data export/import rather than attempting to migrate the database schema across multiple major version changes. ::: +### PostgreSQL Foreign Key Errors + +:::info PostgreSQL Only +This troubleshooting applies only to PostgreSQL databases. SQLite handles foreign keys differently. +::: + +**Symptom:** Errors like `psycopg2.errors.InvalidForeignKey: there is no unique constraint matching given keys for referenced table "user"` + +**Cause:** PostgreSQL requires explicit primary key constraints that were missing in older schema versions. + +**Solution for PostgreSQL:** + +```sql title="PostgreSQL Fix" +-- Connect to your PostgreSQL database +psql -h localhost -U your_user -d open_webui_db + +-- Add missing primary key constraint (PostgreSQL syntax) +ALTER TABLE public."user" ADD CONSTRAINT user_pk PRIMARY KEY (id); + +-- Verify constraint was added +\d+ public."user" +``` + +**Note:** The `public.` schema prefix and quoted `"user"` identifier are PostgreSQL-specific. This SQL will not work on SQLite or MySQL. + ## Advanced Operations +### Production and Multi-Server Deployments + +:::warning Rolling Updates Can Cause Failures +In multi-server deployments, running different code versions simultaneously during rolling updates can cause errors if the new code expects schema changes that haven't been applied yet, or if old code is incompatible with new schema. +::: + +**Recommended deployment strategies:** + + + + +Run migrations as a one-time job before deploying new application code: + +```bash title="Kubernetes Job Example" +# 1. Run migration job +kubectl apply -f migration-job.yaml + +# 2. Wait for completion +kubectl wait --for=condition=complete job/openwebui-migration + +# 3. Deploy new application version +kubectl rollout restart deployment/openwebui +``` + +This ensures schema is updated before any new code runs. + + + + +Take the application offline during migration: + +```bash title="Maintenance Workflow" +# 1. Stop all application instances +docker-compose down + +# 2. Run migrations +docker run --rm -v open-webui:/app/backend/data \ + ghcr.io/open-webui/open-webui:main \ + bash -c "cd /app/backend/open_webui && alembic upgrade head" + +# 3. Start all instances with new code +docker-compose up -d +``` + +Simplest approach but requires downtime. + + + + +Maintain two identical environments and switch traffic after migration: + +```bash title="Blue-Green Workflow" +# 1. Green (new) environment gets migrated database +# 2. Deploy new code to green environment +# 3. Test green environment thoroughly +# 4. Switch traffic from blue to green +# 5. Keep blue as instant rollback option +``` + +Zero downtime but requires double infrastructure. + + + + ### Generate SQL Without Applying For review or audit purposes, generate the SQL that would be executed: From 7b732b64293e79a7a23414df1defd396feb529e0 Mon Sep 17 00:00:00 2001 From: silentoplayz Date: Fri, 28 Nov 2025 23:13:11 -0500 Subject: [PATCH 14/17] Update mcp-notion.mdx --- docs/tutorials/integrations/mcp-notion.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/integrations/mcp-notion.mdx b/docs/tutorials/integrations/mcp-notion.mdx index c344471..ce0111f 100644 --- a/docs/tutorials/integrations/mcp-notion.mdx +++ b/docs/tutorials/integrations/mcp-notion.mdx @@ -255,7 +255,7 @@ By default, users must toggle the tool **ON** in the chat menu. You can configur 4. Check the box for **Notion**. 5. Click **Save & Update**. -## Building a Specialized Notion Agent +## Building a Specialized Notion Agent (Optional) For the most reliable experience, we recommend creating a dedicated "Notion Assistant" model. This allows you to provide a specialized **System Prompt**, a helpful **Knowledge Base**, and quick-start **Prompt Suggestions** that teaches the model how to navigate Notion's structure. From 6d870b26739cb309c56f697ead9345683c8aca93 Mon Sep 17 00:00:00 2001 From: silentoplayz Date: Fri, 28 Nov 2025 23:13:28 -0500 Subject: [PATCH 15/17] Update models.md --- docs/features/workspace/models.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/workspace/models.md b/docs/features/workspace/models.md index 78eab8c..add8249 100644 --- a/docs/features/workspace/models.md +++ b/docs/features/workspace/models.md @@ -94,7 +94,7 @@ From the main list view in the `Models` section, click the ellipsis (`...`) next - **Clone**: Create a copy of a model configuration, which will be appended with `-clone`. :::note -You cannot clone a raw Base Model directly; you must create a custom model first before cloning it. +A raw Base Model can be cloned as a custom Workspace model, but it will not clone the raw Base Model itself. ::: - **Copy Link**: Copies a direct URL to the model settings. From 6b8d7c21ec0395510a707f620f9ae6010bda3b72 Mon Sep 17 00:00:00 2001 From: silentoplayz Date: Fri, 28 Nov 2025 23:13:56 -0500 Subject: [PATCH 16/17] Update permissions.md --- docs/features/rbac/permissions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/features/rbac/permissions.md b/docs/features/rbac/permissions.md index 03acdbe..b82cc6f 100644 --- a/docs/features/rbac/permissions.md +++ b/docs/features/rbac/permissions.md @@ -34,7 +34,7 @@ Chat permissions determine what actions users can perform within chat conversati Features permissions control access to specialized capabilities within Open WebUI: -- **Web Search**: Toggle to allow users to perform web searches during chat sessions. (Environment variable: `ENABLE_RAG_WEB_SEARCH`) +- **Web Search**: Toggle to allow users to perform web searches during chat sessions. (Environment variable: `ENABLE_WEB_SEARCH`) - **Image Generation**: Toggle to allow users to generate images. (Environment variable: `ENABLE_IMAGE_GENERATION`) - **Code Interpreter**: Toggle to allow users to use the code interpreter feature. (Environment variable: `USER_PERMISSIONS_FEATURES_CODE_INTERPRETER`) - **Direct Tool Servers**: Toggle to allow users to connect directly to tool servers. (Environment variable: `USER_PERMISSIONS_FEATURES_DIRECT_TOOL_SERVERS`) @@ -60,7 +60,7 @@ By default, Open WebUI applies the following permission settings: **Features Permissions**: -- Web Search: Enabled (`ENABLE_RAG_WEB_SEARCH=True`) +- Web Search: Enabled (`ENABLE_WEB_SEARCH=True`) - Image Generation: Enabled (`ENABLE_IMAGE_GENERATION=True`) - Code Interpreter: Enabled (`USER_PERMISSIONS_FEATURES_CODE_INTERPRETER`) - Direct Tool Servers: Disabled (`USER_PERMISSIONS_FEATURES_DIRECT_TOOL_SERVERS=False`) From 0cb1e0fd1a171084d9acb1888bbc1feb430ab5b6 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 1 Dec 2025 03:57:26 -0500 Subject: [PATCH 17/17] Update index.mdx --- docs/enterprise/index.mdx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/docs/enterprise/index.mdx b/docs/enterprise/index.mdx index 3d54013..e4be46b 100644 --- a/docs/enterprise/index.mdx +++ b/docs/enterprise/index.mdx @@ -38,22 +38,18 @@ Explore how other organizations are driving real impact with Open WebUI. ## Let’s Talk +:::tip +To help us respond quickly and efficiently to your inquiry, **please use your official work email address**, Personal email accounts (e.g. gmail.com, hotmail.com, proton.me, icloud.com, yahoo.com etc.) are often flagged by our system and will not be answered. +::: **sales@openwebui.com** — Send us your deployment **end user count (seats)**, and let’s explore how we can work together! - :::info Enterprise licenses and partnership opportunities are available **exclusively to registered entities and organizations**. At this time, we are unable to accommodate individual users. We appreciate your understanding and interest. **We are not seeking, open to, or in need of any form of disguised collaboration or contribution pitches/offers.** Any attempt to characterize engineering assistance, co-development, or roadmap input **as an alternative to our enterprise licensing program will not receive a response**. All organizational engagement with Open WebUI occurs **solely and exclusively through enterprise licensing**. ::: - -:::tip -To help us respond quickly and efficiently to your inquiry, **please use your official work email address**, Personal email accounts (e.g. gmail.com, hotmail.com, icloud.com, yahoo.com etc.) are often flagged by our system and will not be answered. -::: - - Take your AI strategy to the next level with our **premium enterprise solutions**, crafted for organizations that demand **expert consulting, tailored deployment, and dedicated support.** :::warning