Add Open WebUI
This commit is contained in:
@@ -23,29 +23,35 @@ networks:
|
|||||||
configs:
|
configs:
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# nginx: reverse proxy for LocalAI (/) and Keycloak (/auth/)
|
# nginx: one server block per subdomain — no path tricks needed
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
nginx_localai_conf:
|
nginx_localai_conf:
|
||||||
content: |
|
content: |
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
listen [::]:80;
|
listen [::]:80;
|
||||||
server_name ${DOMAIN:-localhost};
|
server_name ${DOMAIN_WEBUI:-localhost};
|
||||||
|
|
||||||
client_max_body_size 512M;
|
client_max_body_size 512M;
|
||||||
|
|
||||||
location /auth/ {
|
location / {
|
||||||
proxy_pass http://keycloak:8080/auth/;
|
proxy_pass http://openwebui:8080;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Host $$host;
|
proxy_set_header Host $$host;
|
||||||
proxy_set_header X-Real-IP $$remote_addr;
|
proxy_set_header X-Real-IP $$remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
|
||||||
proxy_set_header X-Forwarded-Proto $$http_x_forwarded_proto;
|
proxy_set_header X-Forwarded-Proto $$http_x_forwarded_proto;
|
||||||
proxy_read_timeout 120s;
|
proxy_set_header Upgrade $$http_upgrade;
|
||||||
proxy_buffer_size 128k;
|
proxy_set_header Connection "upgrade";
|
||||||
proxy_buffers 4 256k;
|
proxy_read_timeout 300s;
|
||||||
proxy_busy_buffers_size 256k;
|
proxy_send_timeout 300s;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name ${DOMAIN_LOCALAI:-localhost};
|
||||||
|
client_max_body_size 512M;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://localai:8080;
|
proxy_pass http://localai:8080;
|
||||||
@@ -61,6 +67,25 @@ configs:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name ${DOMAIN_AUTH:-localhost};
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://keycloak:8080;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $$host;
|
||||||
|
proxy_set_header X-Real-IP $$remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $$http_x_forwarded_proto;
|
||||||
|
proxy_read_timeout 120s;
|
||||||
|
proxy_buffer_size 128k;
|
||||||
|
proxy_buffers 4 256k;
|
||||||
|
proxy_busy_buffers_size 256k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Terraform: main.tf — realm, client, roles, and user resources.
|
# Terraform: main.tf — realm, client, roles, and user resources.
|
||||||
# seed_users values are declared in terraform.tfvars below, not here.
|
# seed_users values are declared in terraform.tfvars below, not here.
|
||||||
@@ -80,7 +105,7 @@ configs:
|
|||||||
client_id = "admin-cli"
|
client_id = "admin-cli"
|
||||||
username = var.keycloak_admin_user
|
username = var.keycloak_admin_user
|
||||||
password = var.keycloak_admin_password
|
password = var.keycloak_admin_password
|
||||||
url = "http://keycloak:8080/auth"
|
url = "http://keycloak:8080"
|
||||||
realm = "master"
|
realm = "master"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +118,13 @@ configs:
|
|||||||
type = string
|
type = string
|
||||||
sensitive = true
|
sensitive = true
|
||||||
}
|
}
|
||||||
variable "localai_base_url" { type = string }
|
variable "localai_base_url" { type = string }
|
||||||
|
variable "openwebui_base_url" { type = string }
|
||||||
|
|
||||||
|
variable "openwebui_client_secret" {
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
variable "seed_users" {
|
variable "seed_users" {
|
||||||
type = list(object({
|
type = list(object({
|
||||||
@@ -133,12 +164,10 @@ configs:
|
|||||||
|
|
||||||
valid_redirect_uris = [
|
valid_redirect_uris = [
|
||||||
"$${var.localai_base_url}/api/auth/oidc/callback",
|
"$${var.localai_base_url}/api/auth/oidc/callback",
|
||||||
"http://localhost:8080/api/auth/oidc/callback",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
web_origins = [
|
web_origins = [
|
||||||
var.localai_base_url,
|
var.localai_base_url,
|
||||||
"http://localhost:80",
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,8 +211,38 @@ configs:
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resource "keycloak_openid_client" "openwebui" {
|
||||||
|
realm_id = keycloak_realm.localai.id
|
||||||
|
client_id = "openwebui"
|
||||||
|
name = "Open WebUI"
|
||||||
|
enabled = true
|
||||||
|
access_type = "CONFIDENTIAL"
|
||||||
|
standard_flow_enabled = true
|
||||||
|
direct_access_grants_enabled = false
|
||||||
|
service_accounts_enabled = false
|
||||||
|
client_secret = var.openwebui_client_secret
|
||||||
|
|
||||||
|
valid_redirect_uris = [
|
||||||
|
"$${var.openwebui_base_url}/oauth/oidc/callback",
|
||||||
|
]
|
||||||
|
|
||||||
|
web_origins = [
|
||||||
|
var.openwebui_base_url,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "keycloak_openid_user_realm_role_protocol_mapper" "openwebui_realm_roles" {
|
||||||
|
realm_id = keycloak_realm.localai.id
|
||||||
|
client_id = keycloak_openid_client.openwebui.id
|
||||||
|
name = "realm-roles"
|
||||||
|
claim_name = "roles"
|
||||||
|
multivalued = true
|
||||||
|
add_to_id_token = true
|
||||||
|
add_to_access_token = true
|
||||||
|
}
|
||||||
|
|
||||||
output "oidc_issuer" {
|
output "oidc_issuer" {
|
||||||
value = "http://keycloak:8080/auth/realms/$${keycloak_realm.localai.realm}"
|
value = "http://keycloak:8080/realms/$${keycloak_realm.localai.realm}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -222,7 +281,7 @@ configs:
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -e
|
set -e
|
||||||
echo "Waiting for Keycloak..."
|
echo "Waiting for Keycloak..."
|
||||||
until wget -qO- http://keycloak:8080/auth/realms/master > /dev/null 2>&1; do
|
until wget -qO- http://keycloak:8080/realms/master > /dev/null 2>&1; do
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
echo "Keycloak ready."
|
echo "Keycloak ready."
|
||||||
@@ -275,9 +334,8 @@ services:
|
|||||||
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
|
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
|
||||||
KC_DB_USERNAME: keycloak
|
KC_DB_USERNAME: keycloak
|
||||||
KC_DB_PASSWORD: ${POSTGRES_PASSWORD:-keycloak_secret}
|
KC_DB_PASSWORD: ${POSTGRES_PASSWORD:-keycloak_secret}
|
||||||
KC_HOSTNAME: https://${DOMAIN:-localhost}/auth
|
KC_HOSTNAME: https://${DOMAIN_AUTH:-localhost}
|
||||||
KC_HTTP_RELATIVE_PATH: /auth
|
KC_PROXY_HEADERS: xforwarded
|
||||||
KC_PROXY_HEADERS: xforwarded
|
|
||||||
KC_HTTP_ENABLED: "true"
|
KC_HTTP_ENABLED: "true"
|
||||||
volumes:
|
volumes:
|
||||||
- ./volumes/keycloak/data:/opt/keycloak/data
|
- ./volumes/keycloak/data:/opt/keycloak/data
|
||||||
@@ -288,7 +346,7 @@ services:
|
|||||||
postgres:
|
postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "exec 3<>/dev/tcp/localhost/8080 && echo -e 'GET /auth/realms/master HTTP/1.0\\r\\nHost: localhost\\r\\n\\r\\n' >&3 && grep -q '200 OK' <(cat <&3)"]
|
test: ["CMD-SHELL", "exec 3<>/dev/tcp/localhost/8080 && echo -e 'GET /realms/master HTTP/1.0\\r\\nHost: localhost\\r\\n\\r\\n' >&3 && grep -q '200 OK' <(cat <&3)"]
|
||||||
interval: 15s
|
interval: 15s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 15
|
retries: 15
|
||||||
@@ -303,10 +361,12 @@ services:
|
|||||||
restart: "no"
|
restart: "no"
|
||||||
entrypoint: ["sh", "/entrypoint.sh"]
|
entrypoint: ["sh", "/entrypoint.sh"]
|
||||||
environment:
|
environment:
|
||||||
TF_VAR_keycloak_admin_user: ${KEYCLOAK_ADMIN_USER:-admin}
|
TF_VAR_keycloak_admin_user: ${KEYCLOAK_ADMIN_USER:-admin}
|
||||||
TF_VAR_keycloak_admin_password: ${KEYCLOAK_ADMIN_PASSWORD:-admin_secret}
|
TF_VAR_keycloak_admin_password: ${KEYCLOAK_ADMIN_PASSWORD:-admin_secret}
|
||||||
TF_VAR_localai_client_secret: ${LOCALAI_OIDC_CLIENT_SECRET:-localai_oidc_secret}
|
TF_VAR_localai_client_secret: ${LOCALAI_OIDC_CLIENT_SECRET:-localai_oidc_secret}
|
||||||
TF_VAR_localai_base_url: https://${DOMAIN:-localhost}
|
TF_VAR_localai_base_url: https://${DOMAIN_LOCALAI:-localhost}
|
||||||
|
TF_VAR_openwebui_client_secret: ${OPENWEBUI_OIDC_CLIENT_SECRET:-openwebui_oidc_secret}
|
||||||
|
TF_VAR_openwebui_base_url: https://${DOMAIN_WEBUI:-localhost}
|
||||||
volumes:
|
volumes:
|
||||||
- ./volumes/terraform/tf:/tf
|
- ./volumes/terraform/tf:/tf
|
||||||
configs:
|
configs:
|
||||||
@@ -341,10 +401,10 @@ services:
|
|||||||
capabilities: [gpu]
|
capabilities: [gpu]
|
||||||
environment:
|
environment:
|
||||||
LOCALAI_AUTH: "true"
|
LOCALAI_AUTH: "true"
|
||||||
LOCALAI_OIDC_ISSUER: https://${DOMAIN:-localhost}/auth/realms/localai
|
LOCALAI_OIDC_ISSUER: https://${DOMAIN_AUTH:-localhost}/realms/localai
|
||||||
LOCALAI_OIDC_CLIENT_ID: localai
|
LOCALAI_OIDC_CLIENT_ID: localai
|
||||||
LOCALAI_OIDC_CLIENT_SECRET: ${LOCALAI_OIDC_CLIENT_SECRET:-localai_oidc_secret}
|
LOCALAI_OIDC_CLIENT_SECRET: ${LOCALAI_OIDC_CLIENT_SECRET:-localai_oidc_secret}
|
||||||
LOCALAI_BASE_URL: https://${DOMAIN:-localhost}
|
LOCALAI_BASE_URL: https://${DOMAIN_LOCALAI:-localhost}
|
||||||
LOCALAI_ADMIN_EMAIL: ${LOCALAI_ADMIN_EMAIL:-admin@example.com}
|
LOCALAI_ADMIN_EMAIL: ${LOCALAI_ADMIN_EMAIL:-admin@example.com}
|
||||||
LOCALAI_API_KEY: ${LOCALAI_API_KEY:-}
|
LOCALAI_API_KEY: ${LOCALAI_API_KEY:-}
|
||||||
LOCALAI_REGISTRATION_MODE: invite
|
LOCALAI_REGISTRATION_MODE: invite
|
||||||
@@ -370,7 +430,45 @@ services:
|
|||||||
start_period: 30s
|
start_period: 30s
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# 5. nginx — reverse proxy
|
# 5. Open WebUI — chat frontend
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
openwebui:
|
||||||
|
image: ghcr.io/open-webui/open-webui:main
|
||||||
|
container_name: localai-openwebui
|
||||||
|
<<: *restart
|
||||||
|
environment:
|
||||||
|
WEBUI_URL: https://${DOMAIN_WEBUI:-localhost}
|
||||||
|
WEBUI_SECRET_KEY: ${OPENWEBUI_SECRET_KEY:-change_me_webui_secret}
|
||||||
|
OPENAI_API_BASE_URL: http://localai:8080/v1
|
||||||
|
OPENAI_API_KEY: ${LOCALAI_API_KEY:-}
|
||||||
|
OPENID_PROVIDER_URL: https://${DOMAIN_AUTH:-localhost}/realms/localai/.well-known/openid-configuration
|
||||||
|
OAUTH_CLIENT_ID: openwebui
|
||||||
|
OAUTH_CLIENT_SECRET: ${OPENWEBUI_OIDC_CLIENT_SECRET:-openwebui_oidc_secret}
|
||||||
|
OAUTH_PROVIDER_NAME: Keycloak
|
||||||
|
OAUTH_SCOPES: openid email profile
|
||||||
|
OAUTH_ROLES_CLAIM: roles
|
||||||
|
OAUTH_ALLOWED_ROLES: localai-user,localai-admin
|
||||||
|
OAUTH_ADMIN_ROLES: localai-admin
|
||||||
|
ENABLE_OAUTH_SIGNUP: "true"
|
||||||
|
ENABLE_LOGIN_FORM: "false"
|
||||||
|
volumes:
|
||||||
|
- ./volumes/openwebui/data:/app/backend/data
|
||||||
|
networks:
|
||||||
|
- localai
|
||||||
|
depends_on:
|
||||||
|
localai:
|
||||||
|
condition: service_healthy
|
||||||
|
keycloak:
|
||||||
|
condition: service_healthy
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "curl -sf http://localhost:8080/health || exit 1"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 5
|
||||||
|
start_period: 30s
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# 6. nginx — reverse proxy
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
nginx:
|
nginx:
|
||||||
image: nginx:alpine
|
image: nginx:alpine
|
||||||
|
|||||||
Reference in New Issue
Block a user