Clauses 1 through 3 of the Open WebUI licence are the BSD 3-Clause text. Clause 4 is not: it prohibits altering, removing, obscuring or replacing Open WebUI branding, with exactly three exceptions, the first of which is deployments where end users, defined as individual natural persons with direct access to the application, do not exceed fifty in any rolling thirty day period. The clause was committed on 18 April 2025 and first shipped in v0.6.6 on 5 May 2025, then restructured on 14 April 2026, so any summary you read that describes a contributor carve-out is quoting superseded text. The GitHub API reports the repository licence as NOASSERTION rather than an OSI identifier, and contributing requires signing a CLA. LibreChat and AnythingLLM are both plain MIT. On identity, LibreChat is the only one of the three with native SAML alongside LDAP and OIDC, Open WebUI ships LDAP and one OIDC provider with no SAML, and AnythingLLM has three fixed roles plus a token-link bridge you write yourself. On audit, Open WebUI defaults AUDIT_LOG_LEVEL to NONE and, once enabled, excludes /chats, /chat and /folders by default, so the naive configuration records everything except the conversations. Count the natural persons with direct access to your instance over the last thirty days before you argue about features.
Read the Open WebUI LICENSE file before you compare Open WebUI vs LibreChat vs AnythingLLM on anything else. Clauses 1 through 3 are the BSD 3-Clause text you were expecting. Clause 4 is not. It prohibits licensees from altering, removing, obscuring or replacing any Open WebUI branding, "including but not limited to the name, logo, or any visual, textual, or symbolic identifiers that distinguish the software and its interfaces, in any deployment or distribution", with exactly three exceptions. The first is deployments where the total number of end users, defined in the clause as individual natural persons with direct access to the application, "does not exceed fifty (50) within any rolling thirty (30) day period".
That is the sentence that decides most enterprise rollouts, and almost no comparison article quotes it. An internal assistant is the single piece of software a company is most likely to want under its own name and inside its own design system. Above fifty people, doing that requires written permission or an enterprise licence, and the licence text calls the alternative a material breach. LibreChat and AnythingLLM are both plain MIT with no equivalent clause.
Everything below was read against specific releases on 17 August 2026: Open WebUI v0.11.0 (released 27 July 2026), LibreChat v0.8.7 (24 June 2026, with a v0.8.8 release candidate tagged since) and AnythingLLM v1.16.0 (13 August 2026). Star counts, roughly 150,000, 42,000 and 65,000 respectively, tell you about community size and nothing about whether a thing clears a control review. Four questions decide that: licence, identity, audit and where documents physically live.
The licence reads BSD-3 until you reach clause 4
The file is titled "Open WebUI License". It is not titled BSD 3-Clause, and that difference is load-bearing.
The NOASSERTION value is the one that generates the ticket. Most software composition analysis tooling reads that field rather than the file, so an Open WebUI dependency surfaces in a scan as an unrecognised licence needing manual review. Answer that before someone else finds it.
The dates matter if you are reconciling an older assessment. The branding clause was committed on 18 April 2025 and first shipped in v0.6.6 on 5 May 2025, so anything approved before then was approved against a repository that was, in substance, BSD 3-Clause. It was restructured again on 14 April 2026, shipping in v0.9.0 on 21 April, collapsing three clauses into one and changing the exceptions. The repository root now also carries LICENSE_HISTORY and LICENSE_NOTICE, and the current text says materials under prior licences keep those original terms.
Exactly three exceptions, and the one people keep inventing
Here they are, in the licence's own numbering. Exception (i): deployments or distributions where total end users do not exceed fifty within any rolling thirty day period. Exception (ii): the licensee has obtained specific prior written permission from the copyright holder. Exception (iii): the licensee has obtained a duly executed enterprise licence expressly permitting the modification. There is no fourth: no internal-use exception, no non-commercial exception, no academic research exception. If a summary says otherwise, open the file. One source of confusion is worth naming, because it comes from a real earlier version rather than thin air. Before the April 2026 restructure, the second exception required the licensee to be an official contributor with a substantive change merged into the main branch, and to hold written permission. The current text drops the contributor requirement. Any analysis quoting a contributor carve-out is quoting superseded text. Read the threshold literally, because a procurement reviewer will. Fifty individual natural persons with direct access, within any rolling thirty day period. Not seats licensed, not a monthly average, not concurrent sessions. One pilot week in which sixty people log in puts a rebranded instance outside exception (i). If your rollout crosses fifty at any point, rebranding without permission is not one of your three lawful options. None of this makes Open WebUI a bad choice. It makes the choice a procurement decision rather than a UI preference, which is the same reframing that governs the cloud versus on-premise security and cost comparison and, further upstream, the break-even math on self-hosting versus API billing.
| Open WebUI v0.11.0 | LibreChat v0.8.7 | AnythingLLM v1.16.0 | |
|---|---|---|---|
| Licence file | Open WebUI License: BSD-3 clauses 1 to 3 plus branding clause 4 | MIT | MIT |
| GitHub API licence field | NOASSERTION, name Other | MIT | MIT |
| Branding restriction | Yes, above 50 end users per rolling 30 days | None | None |
| Contributor agreement | CLA required, CONTRIBUTOR_LICENSE_AGREEMENT at repo root | None | None |
| Passes an approved-licence list unmodified | No | Yes | Yes |
Identity: what each one does with the directory you already run
This is where the three genuinely diverge, and where "put a reverse proxy in front of it" stops satisfying anyone.
Open WebUI. LDAP is off until you set ENABLE_LDAP=true, and the defaults then deserve a second look: LDAP_SERVER_HOST is localhost, LDAP_SERVER_PORT is 389, and LDAP_ATTRIBUTE_FOR_USERNAME is uid, which is not the attribute an Active Directory forest hands you. LDAP_USE_TLS and LDAP_VALIDATE_CERT both default to true, correctly, but LDAP_CA_CERT_FILE is empty, so an internal certificate authority means mounting the CA file rather than turning validation off.
# Open WebUI against an internal Active Directory ENABLE_LDAP=true LDAP_SERVER_HOST=dc01.corp.internal LDAP_SERVER_PORT=636 LDAP_USE_TLS=true LDAP_VALIDATE_CERT=true LDAP_CA_CERT_FILE=/run/secrets/corp-root-ca.pem LDAP_ATTRIBUTE_FOR_USERNAME=sAMAccountName # default is uid LDAP_ATTRIBUTE_FOR_MAIL=mail LDAP_APP_DN="CN=svc-openwebui,OU=Service,DC=corp,DC=internal" LDAP_SEARCH_BASE="OU=Staff,DC=corp,DC=internal" ENABLE_LDAP_GROUP_MANAGEMENT=true # default False LDAP_ATTRIBUTE_FOR_GROUPS=memberOf
For OIDC the surface is OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, OPENID_PROVIDER_URL and OAUTH_SCOPES (default openid email profile), one provider at a time. Role and group mapping are separate opt-ins: ENABLE_OAUTH_ROLE_MANAGEMENT and ENABLE_OAUTH_GROUP_MANAGEMENT both default to false, OAUTH_ROLES_CLAIM to roles and OAUTH_GROUP_CLAIM to groups.
SAML is the gap. Open WebUI's documented options are OAuth, OIDC and trusted headers, so a SAML estate means terminating the assertion at a proxy and passing WEBUI_AUTH_TRUSTED_EMAIL_HEADER through. That moves your entire authentication boundary into the proxy: if the container port is reachable from anywhere else, any caller who sets the header is any user they name. Bind the app to the proxy network only and test it from a third host.
LibreChat is the strongest of the three here and it is not close. LDAP, OIDC and SAML are all native. The OIDC surface includes OPENID_REQUIRED_ROLE and OPENID_ADMIN_ROLE for authorisation, plus OPENID_ROLE_SYNC_ENABLED (false by default) to keep roles in step with the provider. One documented constraint saves an afternoon: if OpenID is enabled, SAML is automatically disabled. You get one federated protocol, not both.
# LibreChat SAML, from the shipped environment template SAML_ENTRY_POINT=https://idp.corp.internal/sso/saml SAML_ISSUER=librechat-prod SAML_CERT=/run/secrets/idp-signing.crt SAML_CALLBACK_URL=/oauth/saml/callback SAML_SESSION_SECRET=/run/secrets/saml-session # SAML_USE_AUTHN_RESPONSE_SIGNED=true # sign the whole response, not just the assertion
AnythingLLM has three fixed roles and no federation. Admin has full access to the entire system. Manager can view all workspaces and manage all properties except the LLM, embedder and vector database settings. Default can only send chats to workspaces they are explicitly added to, and cannot see or edit workspaces or system settings. That is a clean model, and it is the whole model. SIMPLE_SSO_ENABLED covers the federation gap by letting your own service mint a single-use login link through /api/v1/users/{id}/issue-auth-token, valid for one hour. It is a bridge you write, run and secure, holding an admin-scoped key. Weigh that against the role-based access control patterns for AI applications you are being asked to evidence.
| Capability | Open WebUI v0.11.0 | LibreChat v0.8.7 | AnythingLLM v1.16.0 |
|---|---|---|---|
| Local accounts | Yes, ENABLE_SIGNUP true by default | Yes, ALLOW_EMAIL_LOGIN | Yes, multi-user mode |
| LDAP and Active Directory | Native, ENABLE_LDAP (default false) | Native, LDAP_URL and friends | No |
| OIDC | Native, one provider via OPENID_PROVIDER_URL | Native, OPENID_ISSUER plus role sync | No |
| SAML | Not native, needs a proxy plus trusted headers | Native, SAML_ENTRY_POINT, SAML_CERT | No |
| Group sync from the IdP | ENABLE_OAUTH_GROUP_MANAGEMENT, ENABLE_LDAP_GROUP_MANAGEMENT, both false by default | OPENID_ROLE_SYNC_ENABLED, false by default | No |
| Role model | Admin, user, plus groups | Built-in USER and ADMIN roles, permissions per role | Fixed: admin, manager, default |
| New user default state | DEFAULT_USER_ROLE is pending | Configurable registration gates | Created by an admin |
The audit trail a regulated review actually asks to see
Every review asks the same four things: who accessed what, when, from where, and can you produce it for a date range. Test each tool against that, not against whether the word "audit" appears in a feature list.
The Open WebUI default is counterintuitive enough to spell out. AUDIT_LOG_LEVEL is NONE, so a fresh install writes no audit log. Turn it on and AUDIT_EXCLUDED_PATHS defaults to /chats,/chat,/folders, precisely the conversation paths. Only POST, PUT, PATCH and DELETE are audited unless you set ENABLE_AUDIT_GET_REQUESTS=true, so reads of existing conversations are invisible. Bodies are truncated at MAX_BODY_LOG_SIZE, 2048 bytes. Sign-in, sign-out and sign-up are always logged regardless of path filters; unauthenticated requests elsewhere are skipped entirely.
# Open WebUI: an audit configuration that records the thing you were asked about. # AUDIT_INCLUDED_PATHS is a whitelist and takes precedence over the exclude list. AUDIT_LOG_LEVEL=REQUEST_RESPONSE AUDIT_INCLUDED_PATHS=/chats,/chat/completions,/files,/knowledge ENABLE_AUDIT_GET_REQUESTS=true MAX_BODY_LOG_SIZE=16384 AUDIT_LOG_FILE_ROTATION_SIZE=100MB ENABLE_AUDIT_STDOUT=true # ship to your collector, default is False
Two more Open WebUI defaults belong in the same review, because they are on and broad: ENABLE_ADMIN_CHAT_ACCESS and ENABLE_ADMIN_EXPORT both default to true, so any admin account can read and export every conversation on the instance. In a regulated deployment that is a privileged-access control with a named owner, or it is a finding.
AnythingLLM's event log covers login successes and failures, user messaging, configuration changes and file uploads, each entry carrying event type, user, timestamp and detail. That is a genuine access record and the best of the three out of the box. The documentation defines no retention or export, so treat the application database as the system of record and back it up accordingly.
LibreChat writes application logs to a bind-mounted directory and exposes an administration panel, which is operational logging rather than an access record. Whatever you pick, the durable answer is to emit the record from the gateway in front of the model rather than from the UI, which is the same argument as in preventing data leakage in AI applications: the layer everything traverses is the layer worth instrumenting.
| Open WebUI v0.11.0 | LibreChat v0.8.7 | AnythingLLM v1.16.0 | |
|---|---|---|---|
| Dedicated audit stream | Yes, off by default (AUDIT_LOG_LEVEL=NONE) | Application logs, bind-mounted ./logs | Event logs in the admin interface |
| Detail levels | METADATA, REQUEST, REQUEST_RESPONSE | Log level only | Fixed event schema |
| Prompt and response capture | Only at REQUEST_RESPONSE, and paths must be re-included | Not a first-class feature | Records that a user messaged, not a full transcript |
| Default blind spot | /chats, /chat, /folders excluded | No structured access record | No documented retention or export |
| Where it lands | {DATA_DIR}/audit.log, rotates at 10MB | Container-side log files | Application database |
RAG as a bolt-on versus RAG as the product
All three do retrieval. Only one is organised around it.
AnythingLLM makes the workspace the unit of everything. Each workspace is a separate namespace in the vector store, a LanceDB table by default, and VECTOR_DB also accepts pgvector, chroma, qdrant, milvus, weaviate, pinecone, zilliz and astra. The default user role can only chat in workspaces it was explicitly added to, so document permission and chat permission are one object rather than two. That is the reason to choose it. The embedder and the vector store are instance-level, not per-workspace, which the role definitions make plain: the manager role can manage everything except the LLM, embedder and vector database.
Open WebUI defaults VECTOR_DB to chroma, with documents attached to chats or promoted into knowledge collections shared through groups. Retrieval is a capability of the chat product rather than its organising principle, so document access becomes a second permission model layered over the first.
LibreChat runs retrieval in a separate container: a rag_api service backed by pgvector, reachable at RAG_API_URL=http://rag_api:8000, with embeddings configured on that service through EMBEDDINGS_PROVIDER and EMBEDDINGS_MODEL and uploaded files bind-mounted to ./uploads. Architecturally that is the cleanest split of the three. Operationally the embedding call gets its own egress path, credential and network policy entry, separate from the chat backend.
If documents are the workload, pick AnythingLLM and inherit its permission model. If chat is the workload and documents are attachments, the extra layer in the other two is a fair trade.
Pointing all three at a backend inside the enclave
All three speak the OpenAI-compatible surface, so any of them will sit in front of a server you run. The differences are in what else you have to declare.
# Open WebUI in front of a vLLM server on the internal network. # Semicolon-separated, and OPENAI_API_BASE_URLS wins over OPENAI_API_BASE_URL. ENABLE_OPENAI_API=true OPENAI_API_BASE_URLS=http://vllm.enclave.internal:8000/v1 OPENAI_API_KEYS=dummy-token-your-gateway-checks ENABLE_OLLAMA_API=false # default is True; turn it off if you do not run Ollama
# AnythingLLM against the same server, plus its own embedder decision. LLM_PROVIDER='generic-openai' GENERIC_OPEN_AI_BASE_PATH='http://vllm.enclave.internal:8000/v1' GENERIC_OPEN_AI_MODEL_PREF='Qwen/Qwen3-32B' GENERIC_OPEN_AI_MODEL_TOKEN_LIMIT=32768 GENERIC_OPEN_AI_CUSTOM_HEADERS="X-Tenant:risk-ops" EMBEDDING_ENGINE='generic-openai' EMBEDDING_BASE_PATH='http://embed.enclave.internal:8001/v1' EMBEDDING_MODEL_MAX_CHUNK_LENGTH=8192
GENERIC_OPEN_AI_MODEL_TOKEN_LIMIT is the field that quietly costs you a week. It is a number you assert rather than one the server reports, and the shipped example uses 4096. Set it below the model's real context window and long documents are silently truncated; set it above and you get server-side rejections that read as flaky infrastructure. GENERIC_OPEN_AI_CUSTOM_HEADERS is the escape hatch for a gateway that wants a tenant or auth header, and routing all three UIs through one gateway is what makes the audit record above possible at all.
Which server sits behind that URL has real throughput consequences, worked through in Ollama versus vLLM for self-hosted inference. AnythingLLM's EMBEDDING_ENGINE defaults to native, embedding on the instance with a MiniLM checkpoint it downloads, so on a disconnected network that checkpoint is one more artefact to stage.
Upgrades and disconnected networks
Three specific hazards, one per tool.
LibreChat's compose file is six services, and its images ride a moving tag. The API, an administration panel, MongoDB started with mongod --noauth, Meilisearch, a pgvector image and the retrieval API, with the LibreChat images tagged latest from a project registry. The pgvector service ships POSTGRES_USER: myuser and POSTGRES_PASSWORD: mypassword in the file. None of that is a defect in a quickstart and all of it is a finding in production. Override the credentials, require authentication on MongoDB, and mirror every image by digest: latest is not a version, and a disconnected mirror that resolved it last month is not reproducible.
AnythingLLM's documented run command includes --cap-add SYS_ADMIN. That is there for the in-container browser used by the collector, and on a hardened host it is a conversation with your platform team rather than a flag you paste. Have it before the pilot, not at the change advisory board.
Open WebUI persists configuration into its database. ENABLE_PERSISTENT_CONFIG defaults to true, so many settings are read from the environment on first boot and from the database afterwards. The failure mode is common: you change an environment variable during an upgrade, restart, and nothing happens, because the stored value wins. Treat first boot as the moment the environment file matters, and change persistent settings through the interface or the API afterwards.
The general offline failure mode is shared: the model is the artefact everyone remembers to stage, while tokeniser corpora, OCR language packs and embedding checkpoints are the ones that are not. They fail at first use rather than at boot, which is why an air-gapped instance looks healthy for a week. We covered that pattern, and Open WebUI's document parsing behaviour specifically, in running vLLM in an air-gapped deployment.
The decision table
| Your situation | Pick | Why |
|---|---|---|
| Under 50 people, no rebranding pressure, want the largest ecosystem | Open WebUI | Exception (i) covers you, and its plugin and model surface is the widest |
| Over 50 people and the UI must carry your name | LibreChat or AnythingLLM | MIT, no branding clause, no permission to obtain |
| Over 50 people, Open WebUI already chosen | Open WebUI plus an enterprise licence | Written permission or an executed enterprise licence are the only lawful paths |
| SAML estate, no appetite for proxy-based auth | LibreChat | Native SAML, native LDAP, native OIDC, no reverse proxy required |
| Active Directory with group-driven authorisation | Open WebUI or LibreChat | Both map directory groups; AnythingLLM has three fixed roles |
| Documents are the workload | AnythingLLM | Workspace is both the retrieval namespace and the permission boundary |
| Auditor wants prompt-level records | Open WebUI, reconfigured | Only one with a REQUEST_RESPONSE audit level, and its defaults exclude the chat paths |
| Approved-licence list, no exceptions process | LibreChat or AnythingLLM | Both report MIT; Open WebUI reports NOASSERTION |
What to do this week
Start with the number, not the shortlist. Pull the last thirty days of distinct authenticated users from whatever assistant you already run, or from the pilot plan, and write down whether it exceeds fifty. That single figure decides whether the Open WebUI branding clause is a footnote or a procurement blocker, and it takes an afternoon rather than a bake-off.
Then run two checks against what you have deployed. Run grep -c 'branding' LICENSE in the tree you actually built from, so the licence you assessed is the licence you shipped. Then confirm whether AUDIT_LOG_LEVEL is set at all and, if it is, whether /chats is still in the exclude list. Broader controls for the surrounding stack are in our AI for business pillar.
In these reviews the component that fails is never the chat interface. It is the sentence in a licence file nobody opened, and an audit log switched on but configured to skip the conversations.
FAQ
Quick answers to the questions this post tends to raise.



