Skip to content
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
e338f36
feat: add open-webui module for coder-labs
mtojek Dec 3, 2025
3cb817c
fixes
mtojek Dec 3, 2025
e46cbbd
fixes 2
mtojek Dec 3, 2025
ebce587
fix: use venv instead of pip install --user
mtojek Dec 3, 2025
cfc8383
fix: remove running process check
mtojek Dec 3, 2025
749be20
fix: restore LOG_PATH and PORT variable assignments from templatefile
mtojek Dec 3, 2025
a1de7c2
fixes
mtojek Dec 3, 2025
855c545
fixes
mtojek Dec 3, 2025
631a137
Revert "fixes"
mtojek Dec 3, 2025
b4902e4
fix: rename variables to HTTP_SERVER_PORT and HTTP_SERVER_LOG_PATH
mtojek Dec 3, 2025
b6009b2
test
mtojek Dec 3, 2025
0411dfc
test
mtojek Dec 3, 2025
3015fdf
test
mtojek Dec 3, 2025
2a22690
test
mtojek Dec 3, 2025
f28e116
cleanup
mtojek Dec 3, 2025
da9fb56
Add terraform tests for open-webui module
mtojek Dec 3, 2025
0996f63
Add open_webui_version parameter (default: 0.6.40)
mtojek Dec 3, 2025
f548d3d
Show version in startup message
mtojek Dec 3, 2025
7f9854e
fix: typo
mtojek Dec 3, 2025
02cd802
Add data_dir parameter for database/vectordb storage location
mtojek Dec 3, 2025
fd0bd95
Use ~/.open-webui as default data_dir
mtojek Dec 3, 2025
12e0760
Remove unused DATA_DIR export
mtojek Dec 3, 2025
7ae3bb8
Add DATA_DIR echo before starting server
mtojek Dec 3, 2025
b2ccead
Change default data_dir from ~/.open-webui to .open-webui
mtojek Dec 3, 2025
34fa08d
Add openai_api_key parameter for OpenAI integration
mtojek Dec 4, 2025
983a83d
Export DATA_DIR as environment variable for Open WebUI
mtojek Dec 4, 2025
07a3492
screenshot
mtojek Dec 4, 2025
4db13c0
Format README.md
mtojek Dec 4, 2025
73af9e7
Fix README structure: add tf code block in h1 section
mtojek Dec 4, 2025
57289ae
Apply code review feedback
mtojek Dec 5, 2025
259f980
Merge branch 'main' into open-webui-module
DevelopmentCats Dec 8, 2025
0741b59
fix?
mtojek Dec 8, 2025
2d5dbe4
fix: use pip semver
mtojek Dec 8, 2025
0ffd694
fix?
mtojek Dec 8, 2025
60c6148
fix ?
mtojek Dec 8, 2025
4e83a73
fix ?
mtojek Dec 8, 2025
fa6b236
fix tests
mtojek Dec 8, 2025
61f6ec0
fmt
mtojek Dec 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .icons/openwebui.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added registry/coder-labs/.images/openwebui.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
64 changes: 64 additions & 0 deletions registry/coder-labs/modules/open-webui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
display_name: Open WebUI
description: A self-hosted AI chat interface supporting various LLM providers
icon: ../../../../.icons/openwebui.svg
verified: true
tags: [ai, llm, chat, web-ui, python]
---

# Open WebUI

Open WebUI is a user-friendly web interface for interacting with Large Language Models. It provides a ChatGPT-like interface that can connect to various LLM providers including OpenAI, Ollama, and more.

```tf
module "open-webui" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder-labs/open-webui/coder"
version = "1.0.0"
agent_id = coder_agent.main.id
}
```

![Open WebUI](../../.images/openwebui.png)

## Prerequisites

- **Python 3.11 or higher** must be installed in your image (with `venv` module)
- Port 7800 (default) or your custom port must be available

For Ubuntu/Debian, you can install Python 3.11 from [deadsnakes PPA](https://launchpad.net/~deadsnakes/+archive/ubuntu/ppa):

```shell
sudo add-apt-repository -y ppa:deadsnakes/ppa
sudo apt-get update
sudo apt-get install -y python3.11 python3.11-venv
```

## Examples

### With OpenAI API Key

```tf
module "open-webui" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder-labs/open-webui/coder"
version = "1.0.0"
agent_id = coder_agent.main.id

openai_api_key = var.openai_api_key
}
```

### Custom Port and Data Directory

```tf
module "open-webui" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder-labs/open-webui/coder"
version = "1.0.0"
agent_id = coder_agent.main.id

http_server_port = 8080
data_dir = "/home/coder/open-webui-data"
}
```
94 changes: 94 additions & 0 deletions registry/coder-labs/modules/open-webui/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
terraform {
required_version = ">= 1.0"

required_providers {
coder = {
source = "coder/coder"
version = ">= 2.5"
}
}
}

# Add required variables for your modules and remove any unneeded variables
variable "agent_id" {
type = string
description = "The ID of a Coder agent."
}

variable "http_server_log_path" {
type = string
description = "The path to log Open WebUI to."
default = "/tmp/open-webui.log"
}

variable "http_server_port" {
type = number
description = "The port to run Open WebUI on."
default = 7800
}

variable "open_webui_version" {
type = string
description = "The version of Open WebUI to install."
default = "0.6.40"
}

variable "data_dir" {
type = string
description = "The directory where Open WebUI stores its data (database, uploads, vector_db, cache)."
default = ".open-webui"
}

variable "openai_api_key" {
type = string
description = "OpenAI API key for accessing OpenAI models. If not provided, OpenAI integration will need to be configured manually in the UI."
default = ""
sensitive = true
}

variable "share" {
type = string
default = "owner"
validation {
condition = var.share == "owner" || var.share == "authenticated" || var.share == "public"
error_message = "Incorrect value. Please set either 'owner', 'authenticated', or 'public'."
}
}

variable "order" {
type = number
description = "The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order)."
default = null
}

variable "group" {
type = string
description = "The name of a group that this app belongs to."
default = null
}

resource "coder_script" "open-webui" {
agent_id = var.agent_id
display_name = "open-webui"
icon = "/icon/openwebui.svg"
script = templatefile("${path.module}/run.sh", {
HTTP_SERVER_LOG_PATH : var.http_server_log_path,
HTTP_SERVER_PORT : var.http_server_port,
VERSION : var.open_webui_version,
DATA_DIR : var.data_dir,
OPENAI_API_KEY : var.openai_api_key,
})
run_on_start = true
}

resource "coder_app" "open-webui" {
agent_id = var.agent_id
slug = "open-webui"
display_name = "Open WebUI"
url = "http://localhost:${var.http_server_port}"
icon = "/icon/openwebui.svg"
subdomain = true
share = var.share
order = var.order
group = var.group
}
188 changes: 188 additions & 0 deletions registry/coder-labs/modules/open-webui/main.tftest.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
mock_provider "coder" {}

run "test_defaults" {
command = plan

variables {
agent_id = "test-agent-123"
}

assert {
condition = var.http_server_port == 7800
error_message = "Default port should be 7800"
}

assert {
condition = var.http_server_log_path == "/tmp/open-webui.log"
error_message = "Default log path should be /tmp/open-webui.log"
}

assert {
condition = var.share == "owner"
error_message = "Default share should be 'owner'"
}

assert {
condition = var.open_webui_version == "0.6.40"
error_message = "Default version should be '0.6.40'"
}

assert {
condition = coder_app.open-webui.subdomain == true
error_message = "App should use subdomain"
}

assert {
condition = coder_app.open-webui.display_name == "Open WebUI"
error_message = "App display name should be 'Open WebUI'"
}
}

run "test_custom_port" {
command = plan

variables {
agent_id = "test-agent-456"
http_server_port = 9000
}

assert {
condition = var.http_server_port == 9000
error_message = "Custom port should be 9000"
}

assert {
condition = coder_app.open-webui.url == "http://localhost:9000"
error_message = "App URL should use custom port"
}
}

run "test_custom_log_path" {
command = plan

variables {
agent_id = "test-agent-789"
http_server_log_path = "/var/log/open-webui.log"
}

assert {
condition = var.http_server_log_path == "/var/log/open-webui.log"
error_message = "Custom log path should be set"
}
}

run "test_share_authenticated" {
command = plan

variables {
agent_id = "test-agent-auth"
share = "authenticated"
}

assert {
condition = coder_app.open-webui.share == "authenticated"
error_message = "Share should be 'authenticated'"
}
}

run "test_share_public" {
command = plan

variables {
agent_id = "test-agent-public"
share = "public"
}

assert {
condition = coder_app.open-webui.share == "public"
error_message = "Share should be 'public'"
}
}

run "test_order_and_group" {
command = plan

variables {
agent_id = "test-agent-order"
order = 10
group = "AI Tools"
}

assert {
condition = coder_app.open-webui.order == 10
error_message = "Order should be 10"
}

assert {
condition = coder_app.open-webui.group == "AI Tools"
error_message = "Group should be 'AI Tools'"
}
}

run "test_custom_version" {
command = plan

variables {
agent_id = "test-agent-version"
open_webui_version = "0.5.0"
}

assert {
condition = var.open_webui_version == "0.5.0"
error_message = "Custom version should be '0.5.0'"
}
}

run "test_custom_data_dir" {
command = plan

variables {
agent_id = "test-agent-data"
data_dir = "/home/coder/open-webui-data"
}

assert {
condition = var.data_dir == "/home/coder/open-webui-data"
error_message = "Custom data_dir should be set"
}
}

run "test_default_data_dir" {
command = plan

variables {
agent_id = "test-agent-data-default"
}

assert {
condition = var.data_dir == ".open-webui"
error_message = "Default data_dir should be '.open-webui'"
}
}

run "test_openai_api_key" {
command = plan

variables {
agent_id = "test-agent-openai"
openai_api_key = "sk-test-key-123"
}

assert {
condition = var.openai_api_key == "sk-test-key-123"
error_message = "OpenAI API key should be set"
}
}

run "test_default_openai_api_key" {
command = plan

variables {
agent_id = "test-agent-openai-default"
}

assert {
condition = var.openai_api_key == ""
error_message = "Default OpenAI API key should be empty"
}
}
Loading