Skip to content

Commit d6839a0

Browse files
backport-actions-token[bot]desimonekenjenkins
authored
Add complete Pomerium LLM guide: secure self-hosted Open WebUI behind… (#1718)
Add complete Pomerium LLM guide: secure self-hosted Open WebUI behind… (#1714) * Add complete Pomerium LLM guide: secure self-hosted Open WebUI behind Pomerium with identity-aware policies, Docker Compose setup, and inline images * cspell --------- Co-authored-by: bobby <[email protected]> Co-authored-by: Kenneth Jenkins <[email protected]>
1 parent aa791a2 commit d6839a0

File tree

8 files changed

+185
-3
lines changed

8 files changed

+185
-3
lines changed

content/docs/guides/img/llm/1.png

417 KB
Loading

content/docs/guides/img/llm/2.png

402 KB
Loading

content/docs/guides/img/llm/3.png

427 KB
Loading

content/docs/guides/img/llm/4.png

396 KB
Loading

content/docs/guides/img/llm/llm.png

586 KB
Loading

content/docs/guides/llm.mdx

+173
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
---
2+
title: Self-Hosted LLM Behind Pomerium
3+
sidebar_label: Secure LLM WebUI
4+
lang: en-US
5+
keywords:
6+
- pomerium
7+
- access proxy
8+
- llm
9+
- open webui
10+
- authentication
11+
- authorization
12+
- ollama
13+
description: Secure a self-hosted LLM web interface (Open WebUI) behind Pomerium.
14+
---
15+
16+
# Self-Hosted LLM Behind Pomerium
17+
18+
This guide shows how to run a self-hosted LLM web interface (e.g., [Open WebUI](https://github.com/open-webui/open-webui)) and protect it behind Pomerium. Similar to the [code-server guide](https://www.pomerium.com/docs/guides/code-server), this setup applies enterprise-grade access controls to a local LLM, while passing user identity information through trusted headers so the upstream application knows who’s accessing it.
19+
20+
## Why Use Open WebUI?
21+
22+
Open WebUI is a self-hosted interface for interacting with local or remote LLMs. Hosting it locally allows:
23+
24+
- Private experimentation with different LLMs
25+
- Full control over data and configuration
26+
- Integration of custom features like retrieval augmentation, voice, or browsing
27+
28+
## Why Pomerium?
29+
30+
By placing Open WebUI behind Pomerium, you can:
31+
32+
- Authenticate users with your existing IdP (e.g., Google, GitHub, corporate SSO).
33+
- Enforce policy-based access using user attributes like email domain.
34+
- Pass identity headers (e.g., `X-Pomerium-Claim-Email`) to the upstream app, letting it personalize the experience without separate logins.
35+
36+
Pomerium injects trusted identity information, so Open WebUI can recognize authenticated users and skip its own password handling.
37+
38+
## Overview
39+
40+
1. **Run Open WebUI** in Docker.
41+
2. **Configure Pomerium Zero** to secure it.
42+
3. **Access the LLM UI** through a protected URL. Pomerium handles auth, passes user identity, and ensures only allowed users access the LLM.
43+
44+
## Prerequisites
45+
46+
- [Pomerium Zero](https://console.pomerium.app/create-account) account
47+
- Docker and Docker Compose
48+
- A machine capable of running your chosen LLM backend
49+
50+
For GPU acceleration, follow Open WebUI’s CUDA instructions.
51+
52+
## Configure Pomerium Zero
53+
54+
### Create a Policy
55+
56+
Define who can access the LLM interface. For example, restrict access to your email domain:
57+
58+
1. In the Zero Console, go to **Policies****New Policy**.
59+
2. Name it **LLM Access**.
60+
3. Add an allow condition: `Domain` equals `example.com`.
61+
62+
This ensures only authenticated users with `example.com` email addresses can access the route.
63+
64+
### Create a Route
65+
66+
Map an external domain to the internal Open WebUI service. For example:
67+
68+
![Screenshot of Pomerium route editing UI showing "LLM Access" route configuration](./img/llm/1.png)
69+
70+
1. In the Zero Console, go to **Routes****New Route**.
71+
2. Name: `LLM Access`
72+
3. From: `https://llm.your-domain.pomerium.app`
73+
4. To: `http://openwebui:8080`
74+
5. Policies: Select **LLM Access**
75+
76+
Save the route. Now only authorized users can reach `llm.your-domain.pomerium.app`.
77+
78+
### Enable Websockets
79+
80+
LLM UIs often use streaming responses:
81+
82+
![Screenshot of Pomerium Timeouts configuration with Allow Websockets enabled](./img/llm/2.png)
83+
84+
- Under **Timeouts**, toggle **Allow Websockets** to `On`.
85+
86+
### Preserve Host Header & Pass Identity
87+
88+
Enable these settings so Open WebUI receives the correct host header and identity claims:
89+
90+
![Screenshot of Pomerium Headers configuration with Pass Identity Headers and Preserve Host Header enabled](./img/llm/3.png)
91+
92+
- **Pass Identity Headers**: On
93+
- **Preserve Host Header**: On
94+
95+
This ensures Pomerium forwards identity info like `X-Pomerium-Claim-Email`. In **Settings**, you can define how claims map to headers:
96+
97+
![Screenshot of Pomerium cluster settings mapping X-Pomerium-Claim-Email to the user's email](./img/llm/4.png)
98+
99+
With these settings, Open WebUI trusts the identity headers and can attribute actions to the authenticated user.
100+
101+
## Example Docker Compose
102+
103+
Use placeholders for secrets and adjust `WEBUI_URL` to your external route. If you trust Pomerium’s headers, set `WEBUI_AUTH=False` in Open WebUI.
104+
105+
```yaml
106+
version: '3.9'
107+
services:
108+
pomerium:
109+
image: pomerium/pomerium:v0.27.2
110+
ports:
111+
- 443:443
112+
restart: always
113+
environment:
114+
POMERIUM_ZERO_TOKEN: '<YOUR_CLUSTER_TOKEN>'
115+
XDG_CACHE_HOME: /var/cache
116+
volumes:
117+
- pomerium-cache:/var/cache
118+
networks:
119+
main:
120+
aliases:
121+
- authenticate.<YOUR_CLUSTER_SUBDOMAIN>.pomerium.app
122+
123+
openwebui:
124+
image: ghcr.io/open-webui/open-webui:main
125+
environment:
126+
HOST: '0.0.0.0'
127+
OLLAMA_HOST: '0.0.0.0'
128+
WEBUI_URL: 'https://llm.your-domain.pomerium.app'
129+
WEBUI_AUTH_TRUSTED_EMAIL_HEADER: 'X-Pomerium-Claim-Email'
130+
WEBUI_AUTH: 'False'
131+
ports:
132+
- 3000:8080
133+
volumes:
134+
- open-webui-data:/app/backend/data
135+
restart: always
136+
networks:
137+
main: {}
138+
139+
networks:
140+
main:
141+
142+
volumes:
143+
pomerium-cache:
144+
open-webui-data:
145+
```
146+
147+
Replace `<YOUR_CLUSTER_TOKEN>` and `YOUR_CLUSTER_SUBDOMAIN`. For GPU support, see Open WebUI docs.
148+
149+
## Run and Access
150+
151+
```bash
152+
docker compose up -d
153+
```
154+
155+
Visit `https://llm.your-domain.pomerium.app`. After authenticating via your IdP, Pomerium routes you to Open WebUI with identity headers included.
156+
157+
## Test the LLM
158+
159+
- Load a model, prompt it, and interact.
160+
- Your identity is passed through; Open WebUI sees your user email. No extra passwords needed.
161+
- The entire session is protected behind Pomerium’s authentication and authorization.
162+
163+
### Example of a Secured UI
164+
165+
![Screenshot of Open WebUI protected by Pomerium, user authenticated as "Bobby DeSimone"](./img/llm/llm.png)
166+
167+
## Next Steps
168+
169+
- Refine policies: Add group-based rules or restrict certain endpoints.
170+
- Integrate different backends: Adjust `OLLAMA_BASE_URL` or `OPENAI_API_KEY`.
171+
- Add more routes behind Pomerium to scale your secure environment.
172+
173+
You’ve successfully secured a self-hosted LLM WebUI using Pomerium, with identity-aware access control and automatic user recognition upstream.

cspell.json

+8-3
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,13 @@
182182
"yubico",
183183
"yubikey",
184184
"zenefits",
185-
"zipkin",
186-
"zonefile"
185+
"webui",
186+
"OLLAMA",
187+
"zonefile",
188+
"ollama",
189+
"CUDA",
190+
"WEBUI",
191+
"openwebui"
187192
],
188193
"ignorePaths": [
189194
"*.mp4",
@@ -196,4 +201,4 @@
196201
"package.json",
197202
"sidebars.js"
198203
]
199-
}
204+
}

sidebars.js

+4
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,10 @@ const sidebars = {
298298
type: 'doc',
299299
id: 'docs/guides/jit',
300300
},
301+
{
302+
type: 'doc',
303+
id: 'docs/guides/llm',
304+
},
301305
{
302306
type: 'doc',
303307
id: 'docs/guides/tiddlywiki',

0 commit comments

Comments
 (0)