diff --git a/PrivateAI/LocalAGI/Dockerfile.realtimesst b/PrivateAI/LocalAGI/Dockerfile.realtimesst new file mode 100644 index 0000000..142bb3e --- /dev/null +++ b/PrivateAI/LocalAGI/Dockerfile.realtimesst @@ -0,0 +1,12 @@ +# python +FROM python:3.14-slim + +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get install -y python3-dev portaudio19-dev ffmpeg build-essential + +RUN pip install RealtimeSTT + +#COPY ./example/realtimesst /app +# https://github.com/KoljaB/RealtimeSTT/blob/master/RealtimeSTT_server/README.md#server-usage +ENTRYPOINT ["stt-server"] +#ENTRYPOINT [ "/app/main.py" ] diff --git a/PrivateAI/LocalAGI/Dockerfile.sshbox b/PrivateAI/LocalAGI/Dockerfile.sshbox new file mode 100644 index 0000000..0055a14 --- /dev/null +++ b/PrivateAI/LocalAGI/Dockerfile.sshbox @@ -0,0 +1,46 @@ +# Final stage +FROM ubuntu:24.04 + +ENV DEBIAN_FRONTEND=noninteractive + +# Install runtime dependencies +RUN apt-get update && apt-get install -y \ + ca-certificates \ + tzdata \ + docker.io \ + bash \ + wget \ + curl \ + openssh-server \ + sudo + +# Configure SSH +RUN mkdir /var/run/sshd +RUN echo 'PasswordAuthentication yes' >> /etc/ssh/sshd_config + +# Create startup script +RUN echo '#!/bin/bash\n\ +if [ -n "$SSH_USER" ]; then\n\ + if [ "$SSH_USER" = "root" ]; then\n\ + echo "PermitRootLogin yes" >> /etc/ssh/sshd_config\n\ + if [ -n "$SSH_PASSWORD" ]; then\n\ + echo "root:$SSH_PASSWORD" | chpasswd\n\ + fi\n\ + else\n\ + echo "PermitRootLogin no" >> /etc/ssh/sshd_config\n\ + useradd -m -s /bin/bash $SSH_USER\n\ + if [ -n "$SSH_PASSWORD" ]; then\n\ + echo "$SSH_USER:$SSH_PASSWORD" | chpasswd\n\ + fi\n\ + if [ -n "$SUDO_ACCESS" ] && [ "$SUDO_ACCESS" = "true" ]; then\n\ + echo "$SSH_USER ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$SSH_USER\n\ + fi\n\ + fi\n\ +fi\n\ +/usr/sbin/sshd -D' > /start.sh + +RUN chmod +x /start.sh + +EXPOSE 22 + +CMD ["/start.sh"] diff --git a/PrivateAI/LocalAGI/Dockerfile.webui b/PrivateAI/LocalAGI/Dockerfile.webui new file mode 100644 index 0000000..a0ec440 --- /dev/null +++ b/PrivateAI/LocalAGI/Dockerfile.webui @@ -0,0 +1,82 @@ +# Use Bun container for building the React UI +FROM oven/bun:1 AS ui-builder +ARG HTTP_PROXY +ARG HTTPS_PROXY +ARG NO_PROXY +ENV http_proxy=$HTTP_PROXY +ENV https_proxy=$HTTPS_PROXY +ENV no_proxy=$NO_PROXY + +# Set the working directory for the React UI +WORKDIR /app + +# Copy package.json and bun.lockb (if exists) +COPY webui/react-ui/package.json webui/react-ui/bun.lockb* ./ + +# Install dependencies +RUN bun install --frozen-lockfile + +# Copy the rest of the React UI source code +COPY webui/react-ui/ ./ + +# Build the React UI +RUN bun run build + +# Use a temporary build image based on Golang 1.24-alpine +FROM golang:1.24-alpine AS builder +ARG HTTP_PROXY +ARG HTTPS_PROXY +ARG NO_PROXY +ENV http_proxy=$HTTP_PROXY +ENV https_proxy=$HTTPS_PROXY +ENV no_proxy=$NO_PROXY + +# Define argument for linker flags +ARG LDFLAGS="-s -w" + +# Install git +RUN apk add --no-cache git +RUN rm -rf /tmp/* /var/cache/apk/* + +# Set the working directory +WORKDIR /work + +# Copy go.mod and go.sum files first to leverage Docker cache +COPY go.mod go.sum ./ + +# Download dependencies - this layer will be cached as long as go.mod and go.sum don't change +RUN go mod download + +# Now copy the rest of the source code +COPY . . + +# Copy the built React UI from the ui-builder stage +COPY --from=ui-builder /app/dist /work/webui/react-ui/dist + +# Build the application +RUN CGO_ENABLED=0 go build -ldflags="$LDFLAGS" -o localagi ./ + +FROM ubuntu:24.04 +ARG HTTP_PROXY +ARG HTTPS_PROXY +ARG NO_PROXY +ENV http_proxy=$HTTP_PROXY +ENV https_proxy=$HTTPS_PROXY +ENV no_proxy=$NO_PROXY + +ENV DEBIAN_FRONTEND=noninteractive + +# Install runtime dependencies +RUN apt-get update && apt-get install -y \ + ca-certificates \ + tzdata \ + docker.io \ + bash \ + wget \ + curl + +# Copy the webui binary from the builder stage to the final image +COPY --from=builder /work/localagi /localagi + +# Define the command that will be run when the container is started +ENTRYPOINT ["/localagi"] diff --git a/PrivateAI/LocalAGI/docker-compose.local.yaml b/PrivateAI/LocalAGI/docker-compose.local.yaml new file mode 100644 index 0000000..62359c3 --- /dev/null +++ b/PrivateAI/LocalAGI/docker-compose.local.yaml @@ -0,0 +1,199 @@ +services: + ################################################################# + # LocalAI – add proxy, API key, GPU hint, healthcheck, no ports # + ################################################################# + localai: + image: localai/localai:master-gpu-nvidia-cuda-12 + environment: + # Keep core behaviour + - LOCALAI_SINGLE_ACTIVE_BACKEND=true + - DEBUG=true + + # Local site config + #- LOCALAI_API_KEY=${LOCALAI_API_KEY} + + # <<< NEW: allow UI/GET endpoints without API key, but still require it for API calls + #- LOCALAI_DISABLE_API_KEY_REQUIREMENT_FOR_HTTP_GET=true + + # Outbound proxy for model/gallery downloads + - HTTP_PROXY=${HTTP_PROXY} + - HTTPS_PROXY=${HTTPS_PROXY} + + # Don't proxy internal Docker traffic + - NO_PROXY=localhost,127.0.0.1,::1,localai,localagi,localrecall,localrecall-healthcheck,nginx + + # Non-swarm GPU hint (deploy.resources from nvidia file still stays) + gpus: all + + # Ensure this service is *only* on the internal network + ports: [] + expose: + - "8080" + networks: + - internal + + # Make sure Deakin proxy host resolves inside the container + extra_hosts: + - "proxy1.it.deakin.edu.au:10.137.0.162" + + healthcheck: + test: [ + "CMD-SHELL", + "curl -fsS -H \"Authorization: Bearer $LOCALAI_API_KEY\" http://localhost:8080/v1/models > /dev/null || exit 1" + ] + interval: 30s + timeout: 10s + retries: 10 + start_period: 60s + + + ####################################### + # dind – add proxy, internal-only # + ####################################### + dind: + environment: + - HTTP_PROXY=${HTTP_PROXY} + - HTTPS_PROXY=${HTTPS_PROXY} + - NO_PROXY=localhost,127.0.0.1,::1,localai,localagi,localrecall,localrecall-healthcheck,nginx + ports: [] + networks: + - internal + + + ########################################################## + # LocalRecall – RAG settings + proxy + internal-only # + ########################################################## + localrecall: + environment: + - COLLECTION_DB_PATH=/db + - EMBEDDING_MODEL=granite-embedding-107m-multilingual + - FILE_ASSETS=/assets + - LOCALRECALL_CHUNK_SIZE=256 + - LOCALRECALL_CHUNK_OVERLAP=20 + + # Tell LocalRecall to talk to LocalAI using its API key + - OPENAI_API_KEY=${LOCALAI_API_KEY} + - OPENAI_BASE_URL=http://localai:8080 + + # Proxy behaviour + - HTTP_PROXY=${HTTP_PROXY} + - HTTPS_PROXY=${HTTPS_PROXY} + - NO_PROXY=localhost,127.0.0.1,::1,localai,localagi,localrecall,localrecall-healthcheck,nginx + + ports: [] + expose: + - "8080" + networks: + - internal + + extra_hosts: + - "proxy1.it.deakin.edu.au:10.137.0.162" + + + ########################################################## + # LocalRecall healthcheck – internal-only, no proxy out # + ########################################################## + localrecall-healthcheck: + environment: + - NO_PROXY=localhost,127.0.0.1,::1,localai,localagi,localrecall,localrecall-healthcheck,nginx + ports: [] + networks: + - internal + + + ####################################################### + # LocalAGI – build with proxy, connect to LocalAI/RAG # + ####################################################### + localagi: + # Override build to inject proxy at build time + build: + context: . + dockerfile: Dockerfile.webui + # Build-time proxy (bun/go) is fine + args: + HTTP_PROXY: ${HTTP_PROXY} + HTTPS_PROXY: ${HTTPS_PROXY} + NO_PROXY: ${NO_PROXY} + + environment: + # Tell LocalAGI where LocalAI is (OpenAI-compatible API) + - LOCALAGI_LLM_API_URL=http://localai:8080 + - LOCALAGI_LLM_API_KEY=${LOCALAI_API_KEY} + + # Tell LocalAGI where LocalRecall is (NOTE: /api is IMPORTANT) + - LOCALAGI_LOCALRAG_URL=http://localrecall:8080/api + + # Runtime: don't force HTTP(S)_PROXY, just no-proxy for internal services + - NO_PROXY=localhost,127.0.0.1,::1,localai,localagi,localrecall,localrecall-healthcheck,nginx + + ports: [] + expose: + - "3000" + networks: + - internal + + + ###################################### + # Nginx – public entrypoint/proxy # + ###################################### + nginx: + image: nginx:latest + container_name: localagi-proxy + restart: unless-stopped + depends_on: + - localagi + - localai + - localrecall + + # ONLY public-facing ports + ports: + - "9081:9081" # HTTP – now exposed on host port 9081 instead of 80 + - "9443:9443" # TLS – now exposed on host port 9443 instead of 443 + - "9000:9000" # LocalAGI Web UI (if you want a dedicated port) + - "9080:9080" # LocalRecall (if you want a dedicated port) + environment: + # Let nginx see your API key for external /v1 protection + - LOCALAI_API_KEY=${LOCALAI_API_KEY} + volumes: + #- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro + - ./nginx/conf.d:/etc/nginx/conf.d:ro + - ./nginx/.htpasswd:/etc/nginx/.htpasswd:ro + # - ./certs:/etc/letsencrypt:ro # optional if using HTTPS + + networks: + - internal + - public + + +############################################################## + # SSHBOX – Ubuntu container with SSH + tools (needs proxy) # + ############################################################## + sshbox: + build: + context: . + dockerfile: Dockerfile.sshbox + args: + HTTP_PROXY: ${HTTP_PROXY} + HTTPS_PROXY: ${HTTPS_PROXY} + NO_PROXY: ${NO_PROXY} + + environment: + - HTTP_PROXY=${HTTP_PROXY} + - HTTPS_PROXY=${HTTPS_PROXY} + - NO_PROXY=localhost,127.0.0.1,::1,localai,localagi,localrecall,localrecall-healthcheck,nginx + + networks: + - internal + + # Optional: expose SSH if you want external access + # ports: + # - "2222:22" + +##################### +# Network overrides # +##################### +networks: + internal: + driver: bridge + public: + driver: bridge diff --git a/PrivateAI/LocalAGI/localai-composefile.md b/PrivateAI/LocalAGI/localai-composefile.md new file mode 100644 index 0000000..ac33415 --- /dev/null +++ b/PrivateAI/LocalAGI/localai-composefile.md @@ -0,0 +1,209 @@ +# docker-compose.local.yaml — Local customisations + +This document describes the *site‑local* overrides applied to the LocalAI stack via `docker-compose.local.yaml`. +It is intended to be checked into GitHub alongside the Compose files. + +The main goals of this file are: + +- Proxy awareness for restricted networks (e.g. Deakin) +- Strict internal‑only networking for core services +- A single, controlled public entrypoint via Nginx +- Clear wiring between LocalAI (LLM), LocalRecall (RAG), and LocalAGI (UI) + +--- + +## Services + +### `localai` — LocalAI runtime (GPU + proxy + internal‑only) + +**Purpose:** +Runs the LocalAI server (OpenAI‑compatible API) with NVIDIA CUDA 12 GPU support. +It is accessible *only* to other containers on the internal network. + +**Key configuration:** + +- **Image** + - `localai/localai:master-gpu-nvidia-cuda-12` + - GPU‑enabled LocalAI image built for CUDA 12. + +- **Core behaviour** + - `LOCALAI_SINGLE_ACTIVE_BACKEND=true` + Ensures only one backend is active at a time. + - `DEBUG=true` + Enables verbose logging. + +- **API key handling (optional)** + - `LOCALAI_API_KEY` *(commented)* + Enables API key protection. + - `LOCALAI_DISABLE_API_KEY_REQUIREMENT_FOR_HTTP_GET` *(commented)* + Allows unauthenticated GET endpoints while still protecting API calls. + +- **Proxy configuration** + - `HTTP_PROXY`, `HTTPS_PROXY` + Required for outbound downloads (models, galleries). + - `NO_PROXY` + Prevents internal Docker traffic from going via the proxy. + +- **GPU access** + - `gpus: all` + Non‑swarm GPU hint to allow access to all NVIDIA GPUs. + +- **Networking** + - No published ports (`ports: []`). + - `expose: 8080` for internal container access. + - Attached only to the `internal` network. + +- **Host resolution** + - `extra_hosts` maps the Deakin proxy hostname to a fixed IP. + +- **Healthcheck** + - Calls `/v1/models` using the API key. + - Confirms LocalAI is responding correctly before marking healthy. + +--- + +### `dind` — Docker‑in‑Docker helper (proxy + internal‑only) + +**Purpose:** +Helper container that requires proxy access, typically used for build or Docker tooling tasks. + +**Key configuration:** + +- Proxy variables (`HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`) +- No exposed ports +- Attached only to the `internal` network + +--- + +### `localrecall` — LocalRecall RAG service (proxy + internal‑only) + +**Purpose:** +Provides document ingestion and retrieval (RAG), using LocalAI as its embedding/LLM backend. + +**Key configuration:** + +- **Storage and RAG behaviour** + - `COLLECTION_DB_PATH=/db` + - `FILE_ASSETS=/assets` + - `LOCALRECALL_CHUNK_SIZE=256` + - `LOCALRECALL_CHUNK_OVERLAP=20` + +- **Embedding model** + - `EMBEDDING_MODEL=granite-embedding-107m-multilingual` + +- **LocalAI integration** + - `OPENAI_API_KEY=${LOCALAI_API_KEY}` + - `OPENAI_BASE_URL=http://localai:8080` + +- **Proxy configuration** + - Outbound proxy enabled + - Internal traffic excluded via `NO_PROXY` + +- **Networking** + - No published ports + - `expose: 8080` + - Attached only to the `internal` network + +- **Host resolution** + - Deakin proxy hostname mapped via `extra_hosts` + +--- + +### `localrecall-healthcheck` — Internal healthcheck helper + +**Purpose:** +Runs health checks against LocalRecall without requiring outbound proxy access. + +**Key configuration:** + +- Only `NO_PROXY` is set +- No exposed ports +- Internal network only + +--- + +### `localagi` — LocalAGI Web UI (proxy‑aware build) + +**Purpose:** +Builds and runs the LocalAGI web UI, connecting it to LocalAI for LLM calls and LocalRecall for RAG. + +**Key configuration:** + +- **Build‑time proxy** + - Proxy variables passed as build args so dependencies can be fetched during image build. + +- **Runtime integration** + - `LOCALAGI_LLM_API_URL=http://localai:8080` + - `LOCALAGI_LLM_API_KEY=${LOCALAI_API_KEY}` + - `LOCALAGI_LOCALRAG_URL=http://localrecall:8080/api` + *(The `/api` path is required.)* + +- **Networking** + - No published ports + - `expose: 3000` + - Internal network only + +--- + +### `nginx` — Public entrypoint and reverse proxy + +**Purpose:** +Acts as the **only** public‑facing service. +Routes external traffic to LocalAI, LocalAGI, and LocalRecall while enforcing access controls. + +**Key configuration:** + +- **Dependencies** + - Starts after `localai`, `localagi`, and `localrecall`. + +- **Published ports** + - `9081` — HTTP + - `9443` — HTTPS + - `9000` — Optional dedicated LocalAGI UI + - `9080` — Optional dedicated LocalRecall endpoint + +- **Security** + - Receives `LOCALAI_API_KEY` for protecting `/v1` API routes. + - Optional Basic Auth via `.htpasswd`. + +- **Configuration** + - Nginx site configs mounted from `./nginx/conf.d` + - Optional TLS certificates supported. + +- **Networking** + - Connected to both `internal` and `public` networks. + +--- + +### `sshbox` — Utility container (SSH + tools) + +**Purpose:** +A general‑purpose Ubuntu container for debugging, testing, and maintenance. + +**Key configuration:** + +- Proxy‑aware at build and runtime +- Internal network only +- Optional SSH port exposure if needed + +--- + +## Networks + +### `internal` +Private bridge network used for all service‑to‑service communication. +Most containers attach **only** to this network. + +### `public` +Bridge network used by Nginx to expose selected services to the host. + +--- + +## Summary + +This Compose override ensures: + +- Core services remain internal and isolated +- Proxy requirements are handled consistently +- All LLM and RAG traffic flows over Docker DNS +- Nginx is the single, auditable boundary to the outside world diff --git a/PrivateAI/LocalAGI/readme.md b/PrivateAI/LocalAGI/readme.md new file mode 100644 index 0000000..a56eb0e --- /dev/null +++ b/PrivateAI/LocalAGI/readme.md @@ -0,0 +1,210 @@ +# LocalAGI (LocalAI) + +LocalAGI is a self-hosted AI runtime provided by **LocalAI** that enables you to run large language models (LLMs), embeddings, speech, vision, and tool-calling locally on your own infrastructure. It exposes an OpenAI-compatible API and is designed to run efficiently on CPUs and GPUs using containerised deployments. + +This document describes how to **clone the LocalAI repository locally** and **run LocalAGI using Docker**. + +--- + +## Prerequisites + +### Required +- Linux, macOS, or Windows +- Git +- Docker 24+ +- Docker Compose v2 + +### Optional (GPU support) +- NVIDIA GPU +- CUDA 11.8+ or 12.x +- NVIDIA Container Toolkit + +Verify GPU support: +```bash +docker run --rm --gpus all nvidia/cuda:12.3.0-base nvidia-smi +``` + +--- + +## Clone the Repository + +Clone the official LocalAI repository: + +```bash +git clone https://github.com/go-skynet/LocalAI.git +cd LocalAI +``` + +The repository contains: +- Dockerfiles for multiple backends +- Example docker-compose configurations +- Model configuration templates +- Documentation and scripts + +--- + +## Directory Layout (Recommended) + +Create a directory for models outside the container: + +```bash +mkdir -p models +``` + +This directory will be mounted into the container so models persist across restarts. + +--- + +## Running LocalAGI with Docker Compose + +### CPU-only Deployment + +From the root of the cloned repository: + +```bash +docker compose up -d +``` + +By default, this will: +- Build or pull the LocalAI image +- Start the LocalAGI API server +- Expose the API on port 8080 + +--- + +### GPU Deployment (NVIDIA) + +Ensure the NVIDIA Container Toolkit is installed, then run: + +```bash +docker compose up -d +``` + +If your environment requires explicit GPU configuration, confirm that the compose file includes: + +```yaml +deploy: + resources: + reservations: + devices: + - capabilities: [gpu] +``` + +--- + +## Accessing the API + +Once running, LocalAGI will be available at: + +``` +http://localhost:8080 +``` + +Health check: + +```bash +curl http://localhost:8080/health +``` + +--- + +## Installing Models + +Models are stored in the mounted models directory and configured via YAML files. + +### Example: GGUF Model + +```bash +mkdir -p models/llama3 +``` + +Download a model file into that directory, then create a configuration file: + +```yaml +# models/llama3/model.yaml +name: llama3 +backend: llama-cpp +model: model.gguf +context_size: 8192 +threads: 8 +gpu_layers: 40 +``` + +Restart the container to load the model: + +```bash +docker compose restart +``` + +--- + +## Testing a Chat Completion + +LocalAGI exposes an OpenAI-compatible API. + +```bash +curl http://localhost:8080/v1/chat/completions -H "Content-Type: application/json" -d '{ + "model": "llama3", + "messages": [ + {"role": "user", "content": "Hello from LocalAGI"} + ] + }' +``` + +--- + +## Configuration Notes + +Common environment variables: + +| Variable | Description | +|--------|-------------| +| MODELS_PATH | Path to mounted models directory | +| DEBUG | Enable verbose logging | +| THREADS | CPU threads | +| CONTEXT_SIZE | Default context size | +| CUDA_VISIBLE_DEVICES | Select GPUs | + +Model-specific settings should be placed in each model’s YAML configuration. + +--- + +## Logs and Troubleshooting + +View logs: + +```bash +docker logs localai +``` + +Common issues: +- Models not appearing: check model YAML and restart +- Out-of-memory errors: reduce context size or GPU layers +- Slow inference: adjust threads or use GPU acceleration + +--- + +## Updating the Repository + +Pull the latest changes and rebuild: + +```bash +git pull +docker compose down +docker compose up -d --build +``` + +--- + +## Documentation and Resources + +- https://localai.io +- https://localai.io/docs +- https://github.com/go-skynet/LocalAI + +--- + +## License + +LocalAI / LocalAGI is released under the MIT License. +Individual models may be distributed under separate licenses. diff --git a/PrivateAI/gpu-cuda-install/images/img01.png b/PrivateAI/gpu-cuda-install/images/img01.png new file mode 100644 index 0000000..916ebb8 Binary files /dev/null and b/PrivateAI/gpu-cuda-install/images/img01.png differ diff --git a/PrivateAI/gpu-cuda-install/images/img02.png b/PrivateAI/gpu-cuda-install/images/img02.png new file mode 100644 index 0000000..30343a7 Binary files /dev/null and b/PrivateAI/gpu-cuda-install/images/img02.png differ diff --git a/PrivateAI/gpu-cuda-install/readme.md b/PrivateAI/gpu-cuda-install/readme.md new file mode 100644 index 0000000..dae4976 --- /dev/null +++ b/PrivateAI/gpu-cuda-install/readme.md @@ -0,0 +1,618 @@ +# GPU Drivers, CUDA Toolkit & LocalAGI Setup + +> Converted from `GPU Drivers CUDA tool kit LocalAGI.docx` + + + +GPU Drivers and CUDA tool kit + + +Repaired drivers and installed CUDA 13 using the following outline process + + + +![Image](images/img01.png) + + +Did the following so that the cuda-tools are available to users when they login + +![Image](images/img02.png) + + +Additional software installed + +```bash +apt-get install nvtop (shows GPU usage, graphically, nice and useful tool) +``` + + +Docker install + +Followed the official guide as per the following + + + +```bash +Once installed if you get the following error you need to be added to the docker group in /etc/group. Once added you need to log out and log back in. +``` + + +```bash +richard@capstone-gpu1:~$ docker ps +permission denied while trying to connect to the docker API at unix:///var/run/docker.sock +``` + + +```bash +added the docker proxy config per the document “docker with proxy” (in markup link to the document) +``` + + +then installed the nvidia-container toolkit per the instructins from Nvidia. + + +# Add the NVIDIA container toolkit repo + +distribution=$(. /etc/os-release; echo $ID$VERSION_ID) + + +```bash +curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \ +``` + +| sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg + + +```bash +curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list \ +``` + +| sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#' \ + +| sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list + + +```bash +sudo apt-get update +sudo apt-get install -y nvidia-container-toolkit +``` + + +```bash +Then configure docker to use it +sudo nvidia-ctk runtime configure --runtime=docker +sudo systemctl restart docker +``` + + +localAGI Install + + +```bash +git clone +``` + + +added a + +```bash +docker-compose.local.yaml +services: +``` + +localagi: + +image: localai/localagi:latest + +container_name: localagi + +restart: unless-stopped + +# Internal only — not exposed to host + +expose: + +- "8080" + +environment: + +## - Tz=Utc + +# optional volumes: + +# volumes: + +# - ./models:/app/models + +networks: + +- internal + +build: + +context: . + +```bash +dockerfile: Dockerfile.webui +``` + +args: + +## Http_Proxy: ${Http_Proxy} + +## Https_Proxy: ${Https_Proxy} + +## No_Proxy: ${No_Proxy} + + +nginx: + +image: nginx:latest + +container_name: localagi-proxy + +restart: unless-stopped + +depends_on: + +- localagi + +ports: + +- "80:80" + +- "443:443" + +volumes: + +- ./nginx/conf.d:/etc/nginx/conf.d:ro + +- ./nginx/.htpasswd:/etc/nginx/.htpasswd:ro + +# - ./certs:/etc/letsencrypt:ro # optional if using HTTPS + +networks: + +- internal + +- public + + +networks: + +internal: + +internal: true + +public: + +driver: bridge + + +nginx config + +In the LocalAGI folder that was created with the git clone create the following hierarchy. + +./nginix + +./nginix/conf.d + + +put the following file localagi.conf in ./nginx/conf.d/ + + +localagi.conf + +############################## + +## # Upstream Definitions # + +############################## + + +upstream localagi_upstream { + +server localagi:3000; + +} + + +upstream localai_upstream { + +server localai:8080; + +} + + +upstream localrecall_upstream { + +server localrecall:8080; + +} + + +############################################### + +# 9000 — LocalAGI WEB UI (REQUIRE BASIC AUTH) # + +############################################### + +server { + +listen 9000; + +server_name _; + + +auth_basic "LocalAGI Web UI"; + +auth_basic_user_file /etc/nginx/.htpasswd; + + +location / { + +proxy_pass http://localagi_upstream; + +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 $scheme; + +proxy_buffering off; + +} + +} + + +############################################### + +# 9001 — Localrecall (REQUIRE BASIC AUTH) # + +############################################### + +server { + +listen 9080; + +server_name _; + + +auth_basic "Localrecall Web UI"; + +auth_basic_user_file /etc/nginx/.htpasswd; + + +location / { + +proxy_pass http://localrecall_upstream; + +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 $scheme; + +proxy_buffering off; + +} + +} + + +############################################################### + +# 80 — LocalAI API + UI # + +# BASIC AUTH for WEB UI ONLY # + +# NO BASIC AUTH for /v1/* (OpenAI API — token required) # + +############################################################### + +server { + +listen 80; + +server_name _; + + +############################################################### + +# SECTION 1 — OpenAI API (/v1/*) — TOKEN ONLY, NO BASIC AUTH # + +############################################################### + +location /v1/ { + +# NO basic auth here — scripts authenticate via Bearer token + +proxy_pass http://localai_upstream; + + +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 $scheme; + +proxy_buffering off; + +} + + +##################################################### + +# SECTION 2 — LocalAI WEB CONSOLE — BASIC AUTH REQ # + +##################################################### + +location / { + +auth_basic "LocalAI Web Console"; + +auth_basic_user_file /etc/nginx/.htpasswd; + + +proxy_pass http://localai_upstream; + + +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 $scheme; + +proxy_buffering off; + +} + +} + +htpasswd file + +The purpose of the .htpasswd file is to secure the administrative portals of the following applications + +Localai + +Localrecall + +localagi. + + +And in ./nginix create admin users in the .htpasswd file. These are users who need to have permission to create/modify the configuration of the services. Use the following command to add a user + + +htpasswd .htpasswd username + + +make sure that the file has permissions 644 + +LocalAGI Configuration + +```bash +Due to the nature of the deakin environment there are a number of configuration steps required to setup LocalAGI so that it works properly and can reach various external sites for docker images, models and docker builds. +``` + +Docker.webui + +This file needs to be updated to support the Deakin Proxy configuration. + +------------ + +# Use Bun container for building the React UI + +```dockerfile +FROM oven/bun:1 AS ui-builder +``` + +## Arg Http_Proxy + +## Arg Https_Proxy + +## Arg No_Proxy + +```bash +ENV http_proxy=$HTTP_PROXY +ENV https_proxy=$HTTPS_PROXY +ENV no_proxy=$NO_PROXY +``` + + +# Set the working directory for the React UI + +WORKDIR /app + + +# Copy package.json and bun.lockb (if exists) + +COPY webui/react-ui/package.json webui/react-ui/bun.lockb* ./ + + +# Install dependencies + +```bash +RUN bun install --frozen-lockfile +``` + + +# Copy the rest of the React UI source code + +COPY webui/react-ui/ ./ + + +# Build the React UI + +```bash +RUN bun run build +``` + + +# Use a temporary build image based on Golang 1.24-alpine + +```dockerfile +FROM golang:1.24-alpine AS builder +``` + +## Arg Http_Proxy + +## Arg Https_Proxy + +## Arg No_Proxy + +```bash +ENV http_proxy=$HTTP_PROXY +ENV https_proxy=$HTTPS_PROXY +ENV no_proxy=$NO_PROXY +``` + + +# Define argument for linker flags + +ARG LDFLAGS="-s -w" + + +# Install git + +```bash +RUN apk add --no-cache git +RUN rm -rf /tmp/* /var/cache/apk/* +``` + + +# Set the working directory + +WORKDIR /work + + +# Copy go.mod and go.sum files first to leverage Docker cache + +COPY go.mod go.sum ./ + + +# Download dependencies - this layer will be cached as long as go.mod and go.sum don't change + +```bash +RUN go mod download +``` + + +# Now copy the rest of the source code + +## Copy . . + + +# Copy the built React UI from the ui-builder stage + +COPY --from=ui-builder /app/dist /work/webui/react-ui/dist + + +# Build the application + +```bash +RUN CGO_ENABLED=0 go build -ldflags="$LDFLAGS" -o localagi ./ +``` + + +```dockerfile +FROM ubuntu:24.04 +``` + +## Arg Http_Proxy + +## Arg Https_Proxy + +## Arg No_Proxy + +```bash +ENV http_proxy=$HTTP_PROXY +ENV https_proxy=$HTTPS_PROXY +ENV no_proxy=$NO_PROXY +``` + + +```bash +ENV DEBIAN_FRONTEND=noninteractive +``` + + +# Install runtime dependencies + +```bash +RUN apt-get update && apt-get install -y \ +``` + +ca-certificates \ + +tzdata \ + +```bash +docker.io \ +``` + +bash \ + +wget \ + +curl + + +# Copy the webui binary from the builder stage to the final image + +COPY --from=builder /work/localagi /localagi + + +# Define the command that will be run when the container is started + +ENTRYPOINT ["/localagi"] + +Docker-compose.nvidia.yaml + +.env + +HTTP_PROXY=http://proxy1.it.deakin.edu.au:3128 + +HTTPS_PROXY=http://proxy1.it.deakin.edu.au:3128 + +NO_PROXY=localhost,127.0.0.1 + + +Added /etc/profile.d/proxy.sh + +export HTTP_PROXY=http://proxy1.it.deakin.edu.au:3128 + +export HTTPS_PROXY=http://proxy1.it.deakin.edu.au:3128 + +export NO_PROXY="localhost,127.0.0.1,::1" + + + +Setting up so that you can connect to the OpenAI API via Token Auth but still have basic auth for the admin pannels + + +Generate an API_TOKEN + + + +```bash +openssl rand -hex 32 +``` + + +sk-a07de3d7880e0b602068b3eb58fb784b808b724278aa775bac66953c11b3c4ff + + + + + + + diff --git a/PrivateAI/localagi-redback-rag/images/img01.png b/PrivateAI/localagi-redback-rag/images/img01.png new file mode 100644 index 0000000..4f05464 Binary files /dev/null and b/PrivateAI/localagi-redback-rag/images/img01.png differ diff --git a/PrivateAI/localagi-redback-rag/images/img02.png b/PrivateAI/localagi-redback-rag/images/img02.png new file mode 100644 index 0000000..ee57771 Binary files /dev/null and b/PrivateAI/localagi-redback-rag/images/img02.png differ diff --git a/PrivateAI/localagi-redback-rag/images/img03.png b/PrivateAI/localagi-redback-rag/images/img03.png new file mode 100644 index 0000000..543a011 Binary files /dev/null and b/PrivateAI/localagi-redback-rag/images/img03.png differ diff --git a/PrivateAI/localagi-redback-rag/images/img04.png b/PrivateAI/localagi-redback-rag/images/img04.png new file mode 100644 index 0000000..5eeaf74 Binary files /dev/null and b/PrivateAI/localagi-redback-rag/images/img04.png differ diff --git a/PrivateAI/localagi-redback-rag/images/img05.png b/PrivateAI/localagi-redback-rag/images/img05.png new file mode 100644 index 0000000..649cfae Binary files /dev/null and b/PrivateAI/localagi-redback-rag/images/img05.png differ diff --git a/PrivateAI/localagi-redback-rag/images/img06.png b/PrivateAI/localagi-redback-rag/images/img06.png new file mode 100644 index 0000000..1f9949d Binary files /dev/null and b/PrivateAI/localagi-redback-rag/images/img06.png differ diff --git a/PrivateAI/localagi-redback-rag/images/img07.png b/PrivateAI/localagi-redback-rag/images/img07.png new file mode 100644 index 0000000..22caa80 Binary files /dev/null and b/PrivateAI/localagi-redback-rag/images/img07.png differ diff --git a/PrivateAI/localagi-redback-rag/images/img08.png b/PrivateAI/localagi-redback-rag/images/img08.png new file mode 100644 index 0000000..274802a Binary files /dev/null and b/PrivateAI/localagi-redback-rag/images/img08.png differ diff --git a/PrivateAI/localagi-redback-rag/images/img09.png b/PrivateAI/localagi-redback-rag/images/img09.png new file mode 100644 index 0000000..6a9f0c2 Binary files /dev/null and b/PrivateAI/localagi-redback-rag/images/img09.png differ diff --git a/PrivateAI/localagi-redback-rag/readme.md b/PrivateAI/localagi-redback-rag/readme.md new file mode 100644 index 0000000..3dadfa1 --- /dev/null +++ b/PrivateAI/localagi-redback-rag/readme.md @@ -0,0 +1,72 @@ +# LocalAGI Agent – RedBack Query + +> Converted from `LocalAGI Agent RedBack Query.docx` + +The following is a proof of concept configuration of a LocalAGI Agent to facilitate the ability to ask questions about the redback onboarding document. + + +Agent Configuration for Redback Chat + + +Connect to + + +Select Agent List + +![Image](images/img01.png) + + +And then Create agent + +![Image](images/img02.png) + + +Complete details as follows + + +![Image](images/img03.png) + + +![Image](images/img04.png) + + +For the API keys use the API key that was created for LocalAI. In the original install it was done as follows: + + +```bash +openssl rand -hex 32 +``` + + +```bash +sk-a07de3d7880e0b602068b3eb58fb784b808b724278aa775bac66953c11b3c4ff +``` + + + +![Image](images/img05.png) + +This enables the use of localrecall for RAG. + + +![Image](images/img06.png) + + +The following shows the Localrecall setup + + +You can connect to Localrecall via + + +![Image](images/img07.png) + + +It is now possible to chat with the agent per the following + + +![Image](images/img08.png) + + +![Image](images/img09.png) + + diff --git a/PrivateAI/mcphub/docker-compose.yaml b/PrivateAI/mcphub/docker-compose.yaml new file mode 100644 index 0000000..828e916 --- /dev/null +++ b/PrivateAI/mcphub/docker-compose.yaml @@ -0,0 +1,18 @@ +services: + mcphub: + image: samanhappy/mcphub + ports: + - "3003:3000" + volumes: + - ./mcp_settings.json:/app/mcp_settings.json:ro + - ./entrypoint-proxy.sh:/app/entrypoint-proxy.sh:ro + - ./proxychains.conf:/etc/proxychains.conf:ro + environment: + - HTTP_PROXY=${HTTP_PROXY} + - HTTPS_PROXY=${HTTPS_PROXY} + - NO_PROXY=localhost,127.0.0.1,::1,mcphub,proxy1.it.deakin.edu.au,10.137.0.162,api.mcprouter.to + restart: unless-stopped + extra_hosts: + - "proxy1.it.deakin.edu.au:10.137.0.162" + entrypoint: ["/app/entrypoint-proxy.sh"] + command: ["pnpm","start"] diff --git a/PrivateAI/mcphub/entrypoint-proxy.sh b/PrivateAI/mcphub/entrypoint-proxy.sh new file mode 100755 index 0000000..5fa3b47 --- /dev/null +++ b/PrivateAI/mcphub/entrypoint-proxy.sh @@ -0,0 +1,62 @@ +#!/bin/sh +set -eu + +# Ensure apt and other tools see proxy envs (many tools expect lowercase) +if [ -n "${HTTP_PROXY:-}" ] && [ -z "${http_proxy:-}" ]; then export http_proxy="$HTTP_PROXY"; fi +if [ -n "${HTTPS_PROXY:-}" ] && [ -z "${https_proxy:-}" ]; then export https_proxy="$HTTPS_PROXY"; fi +if [ -n "${NO_PROXY:-}" ] && [ -z "${no_proxy:-}" ]; then export no_proxy="$NO_PROXY"; fi + +# If we're on Debian/Ubuntu, also configure apt to use the proxy explicitly +if command -v apt-get >/dev/null 2>&1; then + mkdir -p /etc/apt/apt.conf.d + # Prefer HTTPS proxy if set, otherwise HTTP proxy + APT_PROXY="${https_proxy:-${http_proxy:-}}" + if [ -n "$APT_PROXY" ]; then + cat > /etc/apt/apt.conf.d/99proxy </dev/null 2>&1; then + if command -v apk >/dev/null 2>&1; then + apk add --no-cache proxychains-ng + elif command -v apt-get >/dev/null 2>&1; then + apt-get update + # Try common package names + apt-get install -y proxychains4 || apt-get install -y proxychains-ng + else + echo "No supported package manager found to install proxychains." >&2 + exit 1 + fi +fi + +# Generate a proxychains config if none provided +CONF="/etc/proxychains.conf" +if [ ! -f "$CONF" ]; then + PROXY_URL="${https_proxy:-${http_proxy:-}}" + if [ -z "$PROXY_URL" ]; then + echo "HTTP_PROXY/HTTPS_PROXY not set and no $CONF provided." >&2 + exit 1 + fi + + HOSTPORT="$(echo "$PROXY_URL" | sed -E 's#^[a-zA-Z]+://##' | sed -E 's#/.*$##' | sed -E 's#^[^@]*@##')" + HOST="$(echo "$HOSTPORT" | cut -d: -f1)" + PORT="$(echo "$HOSTPORT" | cut -d: -f2)" + + cat > "$CONF" < **Security note:** The provided configs include placeholders and/or example secrets (API keys, bearer tokens, hashed admin password). +> Treat them as **defaults** and rotate/replace before exposing the service beyond a trusted network. + +--- + +## Contents + +After extracting `mcphub.tar`, you should have: + +```text +mcphub/ +├── docker-compose.yaml +├── entrypoint-proxy.sh +├── proxychains.conf +└── mcp_settings.json +``` + +--- + +## Quick install + +### 1) Extract + +```bash +tar -xf mcphub.tar +cd mcphub +``` + +### 2) Create an `.env` file + +Create `mcphub/.env` (recommended) with your proxy settings: + +```env +# Outbound proxy (optional but required in restricted networks) +HTTP_PROXY=http://proxy1.it.deakin.edu.au:3128 +HTTPS_PROXY=http://proxy1.it.deakin.edu.au:3128 + +# Internal destinations that must NOT be proxied +NO_PROXY=localhost,127.0.0.1,::1,mcphub,proxy1.it.deakin.edu.au,10.137.0.162,api.mcprouter.to +``` + +If you’re not behind a proxy, you can omit `HTTP_PROXY` / `HTTPS_PROXY` and rely on direct outbound access. + +### 3) Start MCPHub + +```bash +docker compose up -d +``` + +### 4) Verify + +The Compose file maps container port **3000** to host port **3003**: + +- MCPHub UI/API: `http://:3003` + +Check logs: + +```bash +docker compose logs -f --tail=200 +``` + +--- + +## Configuration files + +## `docker-compose.yaml` + +**Purpose:** Runs the `samahappy/mcphub` image with local configuration injected via bind mounts, plus proxy environment variables. + +Key sections: + +- **`image: samanhappy/mcphub`** + Uses a prebuilt MCPHub container image. + +- **`ports: "3003:3000"`** + Exposes MCPHub on **host port 3003**. + +- **`volumes:`** + Mounts your configuration into the container: + - `./mcp_settings.json` → `/app/mcp_settings.json` *(read-only)* + Main MCPHub configuration (servers, users, routing, providers). + - `./entrypoint-proxy.sh` → `/app/entrypoint-proxy.sh` *(read-only)* + Wrapper entrypoint to ensure proxy support works inside container. + - `./proxychains.conf` → `/etc/proxychains.conf` *(read-only)* + Proxychains config (forces outbound TCP via your proxy). + +- **`environment:`** + - `HTTP_PROXY`, `HTTPS_PROXY` are passed through from `.env` + - `NO_PROXY` ensures internal calls (including Docker DNS names) are not proxied + +- **`extra_hosts:`** + - `"proxy1.it.deakin.edu.au:10.137.0.162"` + Forces resolution of the proxy hostname inside the container (useful if DNS can’t resolve it). + +- **`entrypoint:` / `command:`** + - Entry is overridden to run `/app/entrypoint-proxy.sh` + - Then runs MCPHub via `pnpm start` + +--- + +## `entrypoint-proxy.sh` + +**Purpose:** Makes proxy behaviour reliable inside the container by: + +1. Normalising proxy env vars (`HTTP_PROXY` → `http_proxy`, etc.) +2. Configuring `apt` to use the proxy (if `apt-get` exists) +3. Installing `proxychains4` (or `proxychains-ng`) if missing +4. Ensuring a proxychains config exists (uses `/etc/proxychains.conf` or generates one from proxy env vars) +5. Running the container’s original entrypoint under proxychains: + +```sh +exec proxychains4 -q /usr/local/bin/entrypoint.sh "$@" +``` + +**Why this matters:** Some tools ignore `HTTP_PROXY`/`HTTPS_PROXY` for certain network calls. +Proxychains forces TCP connections through the proxy when needed. + +--- + +## `proxychains.conf` + +**Purpose:** Defines how proxychains routes traffic. + +Notable directives: + +- `strict_chain` + Use the proxies in the listed order. +- `proxy_dns` + Resolve DNS through proxychains (helps in locked-down DNS scenarios). +- Timeouts: + - `tcp_read_time_out 15000` + - `tcp_connect_time_out 8000` + +Local network bypasses (important): + +- `localnet 10.137.0.162/32` + Prevents proxying traffic *to the proxy itself* (avoids recursion). +- Also bypasses: + - `127.0.0.0/8` + - `10.0.0.0/8` + - `172.16.0.0/12` + - `192.168.0.0/16` + +Proxy list: + +- `http 10.137.0.162 3128` + +If your proxy changes, update this file (or rely on auto-generation from env vars by removing the mounted file). + +--- + +## `mcp_settings.json` + +**Purpose:** The main MCPHub configuration file. + +It contains several top-level sections: + +### `mcpServers` +Defines MCP servers MCPHub can launch and route to. This file includes examples such as: + +- `playwright` / `playwright-mcp` (Playwright MCP server) +- `fetch` / `fetch-mcp` (fetch MCP server) +- `time` / `time-mcp` (time MCP server) +- `slack` (Slack MCP server; requires tokens) +- `sequential-thinking` (reasoning helper server) +- `mindmap` (mindmap server) +- `amap` (Amap maps server; requires API key) + +Each server entry generally looks like: + +```json +{ + "command": "npx", + "args": ["-y", "@some/package"], + "env": { "SOME_KEY": "your-value" } +} +``` + +**What to edit:** +- Replace placeholder API keys (e.g. `SLACK_BOT_TOKEN`, `AMAP_MAPS_API_KEY`) +- Remove servers you don’t want MCPHub to expose +- Pin versions if you need reproducible deployments + +### `users` +Defines MCPHub users. The sample includes an `admin` user with a **bcrypt hashed password**. + +**What to edit:** +- Replace the default password hash with your own +- Consider disabling password auth if you are using bearer/OAuth only (depends on your deployment model) + +### `systemConfig` +Controls platform-wide behaviour. Notable subsections include: + +- **`routing`** + - `enableGlobalRoute`: global routing on/off + - `enableGroupNameRoute`: group-based routing on/off + - `enableBearerAuth`: bearer auth on/off + - `bearerAuthKey`: bearer token key (rotate before public exposure) + +- **`install`** + - `baseUrl`: base URL used by MCPHub (ensure it matches your deployment) + - `pythonIndexUrl` / `npmRegistry`: optional private registries + +- **`oauthServer`** + Enables an embedded OAuth server and controls lifetimes and registration behaviour. + If you don’t need OAuth, set `enabled` to `false`. + +- **`mcpRouter`** + Contains settings for the upstream routing API (including API key, base URL, referer/title). + Treat API keys here as secrets. + +### `providers` +Defines LLM providers MCPHub can talk to. The sample includes a LocalAI provider entry (OpenAI-compatible): +- `base_url`: your LocalAI endpoint +- `models`: list of model IDs you want available through this provider + +Update this to match your LocalAI host and model list. + +### `groups` +Defines groups and which servers/tools are available to each group. + +### `bearerKeys` +Defines bearer tokens and access scoping: +- `accessType: all` allows everything (tighten if needed) +- `allowedGroups` / `allowedServers` can restrict access + +--- + +## Recommended hardening (if exposing beyond LAN) + +- Put MCPHub behind a reverse proxy (Nginx/Caddy/Traefik) with TLS +- Rotate/replace: + - bearer auth token(s) + - any `mcpRouter.apiKey` + - admin password hash + - any third-party API tokens (Slack, Amap, etc.) +- Restrict allowed servers/tools to the minimum needed +- Consider network policies/firewall rules to limit who can reach port 3003 + +--- + +## Common changes + +### Change the host port +Edit `docker-compose.yaml`: + +```yaml +ports: + - "3003:3000" +``` + +For example, to run on 8088: + +```yaml +ports: + - "8088:3000" +``` + +### Change the proxy target +Update `proxychains.conf` and/or `.env`, plus `extra_hosts` if required. + +--- + +## Troubleshooting + +### Proxy loops / “connection refused” to proxy +Make sure `proxychains.conf` includes a `localnet` rule for the proxy IP itself (it already does for `10.137.0.162/32`). + +### NPM/Python installs fail +- Confirm `HTTP_PROXY`/`HTTPS_PROXY` are correct +- If you use private registries, set `systemConfig.install.npmRegistry` / `pythonIndexUrl` + +### MCP server packages change unexpectedly +Pin versions in `mcpServers` (avoid `@latest` where reproducibility matters). + +--- + +## License / Attribution + +This repository contains **deployment configuration and documentation**. +MCPHub and MCP servers remain under their respective upstream licenses. diff --git a/PrivateAI/openwebui/caddy/Caddyfile b/PrivateAI/openwebui/caddy/Caddyfile new file mode 100644 index 0000000..6dea1e9 --- /dev/null +++ b/PrivateAI/openwebui/caddy/Caddyfile @@ -0,0 +1,16 @@ +{ + # Turn off auto HTTPS completely + auto_https off +} + +# HTTP → redirect to HTTPS +:80 { + redir https://10.137.17.254{uri} +} + +# HTTPS with our self-signed cert +:443 { + tls /etc/caddy/certs/local.crt /etc/caddy/certs/local.key + + reverse_proxy http://openwebui:8080 +} diff --git a/PrivateAI/openwebui/caddy/Caddyfile.orig b/PrivateAI/openwebui/caddy/Caddyfile.orig new file mode 100644 index 0000000..10003b6 --- /dev/null +++ b/PrivateAI/openwebui/caddy/Caddyfile.orig @@ -0,0 +1,3 @@ +10.137.17.254 { + reverse_proxy openwebui:3000 +} diff --git a/PrivateAI/openwebui/caddy/caddy_config/caddy/autosave.json b/PrivateAI/openwebui/caddy/caddy_config/caddy/autosave.json new file mode 100644 index 0000000..bd155e9 --- /dev/null +++ b/PrivateAI/openwebui/caddy/caddy_config/caddy/autosave.json @@ -0,0 +1 @@ +{"apps":{"http":{"servers":{"srv0":{"automatic_https":{"disable":true},"listen":[":443"],"routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"openwebui:8080"}]}]}],"tls_connection_policies":[{"certificate_selection":{"any_tag":["cert0"]}}]},"srv1":{"automatic_https":{"disable":true},"listen":[":80"],"routes":[{"handle":[{"handler":"static_response","headers":{"Location":["https://10.137.17.254{http.request.uri}"]},"status_code":302}]}]}}},"tls":{"certificates":{"load_files":[{"certificate":"/etc/caddy/certs/local.crt","key":"/etc/caddy/certs/local.key","tags":["cert0"]}]}}}} \ No newline at end of file diff --git a/PrivateAI/openwebui/caddy/caddy_data/caddy/instance.uuid b/PrivateAI/openwebui/caddy/caddy_data/caddy/instance.uuid new file mode 100644 index 0000000..ef9eade --- /dev/null +++ b/PrivateAI/openwebui/caddy/caddy_data/caddy/instance.uuid @@ -0,0 +1 @@ +2a8c158e-bd37-4c58-a81b-8dee66267377 \ No newline at end of file diff --git a/PrivateAI/openwebui/caddy/caddy_data/caddy/last_clean.json b/PrivateAI/openwebui/caddy/caddy_data/caddy/last_clean.json new file mode 100644 index 0000000..8fb76d8 --- /dev/null +++ b/PrivateAI/openwebui/caddy/caddy_data/caddy/last_clean.json @@ -0,0 +1 @@ +{"tls":{"timestamp":"2026-01-29T23:59:16.675342759Z","instance_id":"2a8c158e-bd37-4c58-a81b-8dee66267377"}} \ No newline at end of file diff --git a/PrivateAI/openwebui/caddy/certs/local.crt b/PrivateAI/openwebui/caddy/certs/local.crt new file mode 100644 index 0000000..8ac896b --- /dev/null +++ b/PrivateAI/openwebui/caddy/certs/local.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDETCCAfmgAwIBAgIUcmLthbydWk0jTdqODawaCTUIOSswDQYJKoZIhvcNAQEL +BQAwGDEWMBQGA1UEAwwNMTAuMTM3LjE3LjI1NDAeFw0yNTEyMDEwNjA5MzBaFw0z +NTExMjkwNjA5MzBaMBgxFjAUBgNVBAMMDTEwLjEzNy4xNy4yNTQwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDpHqfhlt/KExEDjKyphPuX+Zrpxg4BSdJ+ +h8cBsBqUyRHtpzYjWOIGogCG9lGhKTJCuadahHzDMGgBSpDYVSX7Gj0Mpmz/yPqd +em79qhAt+gJUQ307xLjMkgOckCu9rhSyFwcefGybT/0wecvkxQmDILhweVmqhqc5 +CUo9JJ6AENsaEPP4Yv01YyW3CKcU/aW3CyJl4ILB879qnV1+6BCvNS+lLjJnuu1c +cB4ODOuEHmkEA4l6kugQpNX0dCT3DZzLFQ+4PxXa9qdllRT3+vXEiZfgn9SC+HMz +OPhPfUL3vCMpNjpwy8EXAAIrj4cKUrmOQDpZxA4G5QUEvbYA+qhdAgMBAAGjUzBR +MB0GA1UdDgQWBBTy6B3+IS68wVeXrtbtmDALg8nBWTAfBgNVHSMEGDAWgBTy6B3+ +IS68wVeXrtbtmDALg8nBWTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA +A4IBAQAcx9d4t8NmXiIeF02IXNhubfhQPMpsEtdbfqooGlyR3zfS+7R/JlMwVP1w +C2rZfXw3zx+eXK0DzQazUEHpVDLqdrxW7YlzIbOR539V8hOayGgFzQkKG3BC3F/F +4Ygldl8ZZQWMMyc/+Nb/iN+rgQul7VYvW4KK5PORUGuvVWFg3RYhpusgf+8Fk8NG +kGup0miEXKGTCCh86fMElV9GjGdD8ZuQ0McV18dwUIsyC9MDrsDVPcxcGcCAHMb4 +nsyBQB/CUurPf5yFRUJL4T3G3y5FKGM4hku44fKdFHcH9AyEhFYG2JPp/ElVTIl0 +cbN3TkJRWtWIgMaBYe4qUkKmsKRj +-----END CERTIFICATE----- diff --git a/PrivateAI/openwebui/caddy/certs/local.key b/PrivateAI/openwebui/caddy/certs/local.key new file mode 100644 index 0000000..90f6f0c --- /dev/null +++ b/PrivateAI/openwebui/caddy/certs/local.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDpHqfhlt/KExED +jKyphPuX+Zrpxg4BSdJ+h8cBsBqUyRHtpzYjWOIGogCG9lGhKTJCuadahHzDMGgB +SpDYVSX7Gj0Mpmz/yPqdem79qhAt+gJUQ307xLjMkgOckCu9rhSyFwcefGybT/0w +ecvkxQmDILhweVmqhqc5CUo9JJ6AENsaEPP4Yv01YyW3CKcU/aW3CyJl4ILB879q +nV1+6BCvNS+lLjJnuu1ccB4ODOuEHmkEA4l6kugQpNX0dCT3DZzLFQ+4PxXa9qdl +lRT3+vXEiZfgn9SC+HMzOPhPfUL3vCMpNjpwy8EXAAIrj4cKUrmOQDpZxA4G5QUE +vbYA+qhdAgMBAAECggEAARc7aknfXFSeFEMZ4koHEnrlSeCWklSLBjwbsDH59dz4 ++7d4ErxozS/bk8YVamiOJtzF8lRn8C4mTUmH0K694a5lGt/VVN8Ny2yxlhxmzx8e +s9AWdLSi3G9SLbgkZomWn6FEqubrtSvB/7uRA+BeI6tJKshqAH148YuXFR7e0Gnc +6xhsNRV6+Be+rYV9BL4Sq0KNKDE2AE7/E2VOyfMEAPUdhq53jrdbJvu8TgoXYYd/ +yQJarj5GG3dtnR897zw2m+nnBbgpP9Okf8dDLEOWFzwrMQXgwIJcW77Z7NBCjGgv +Y6fBHDWpQkr4Qs4Zxv+s9kos07o+DSy9qhy/g/V++wKBgQDtRGVEtfbzHImgWebV +7LKjUXCOgpjkmPeBrb2rvhoRFUOiFzS2dWTBIYF+/wXv6w0EtF1AZcAg4CgK5a5/ +zEjgrLaT4EZ0re8mL0QEMyqFzUAXrk3IRh3cfIce5Ml/viklYzZ1xidbMO9fuQsy +mn6c1WABDIgwtatLY+hRqDH+vwKBgQD7hm7nyPlSqvLCBpYva/VkZHc5wmndLL5/ +1yZDhIBHEBgmBjLFFNEBT1w5CZF0fY7z5d2Ga76/S9Q0zYkw2B1Mj3s4W5rLhlQ3 +sT0CnS5cFCu/AgUw8ij++xiw99Db5HaZAmfXx2WSe25UwYaG6/ZBIGbVvO0YqR4S +IBn7OMB74wKBgQCjK1wxaqpP+pozKmBzUfpwEnvDpdCbtQ7RobhEudGXWfZPLIJV +0Fnf77jsq1lb61vill9jABanBUDEbbwZq1WbHWvaOmx5pXxH2E2ATee6aLLhFj/r +sTyr+v+5oUFplk8ZpSc4y3MZZYfZXppyzIiyNpN1ZTbruKP6jtSgA3mOZQKBgAsL +pkcrfjdxJmP64hGHDimwd8Pjk76QvnTiv91rLi7wt/7DeutItLz3/TbMAsU41lRD +nezPQnsoG1OOSx4H/5FjI6gf7bZOWdhwQhuhR23nvNwQfKXfnIlGAZmT6GofqE2j +22eQbBd4sCmsrfmy1weZIqr0Nv1EP/vPyRRNM7a9AoGALuJALLb1MMTf2g/OHBLV +69uGu6Lywx6q0P65/jxvyBYteqcFN92/GJ59Qo7I29gUC+43AUHDssE7goewxN0s +blZOZWDGhatKz901GxM8zuYem4IcelRO98k8xCfAQRFsWyv9uhrWrDs63gcdsL/h +7mrruuqPhQCn9qPE6NzL98M= +-----END PRIVATE KEY----- diff --git a/PrivateAI/openwebui/docker-compose-entra.yaml b/PrivateAI/openwebui/docker-compose-entra.yaml new file mode 100644 index 0000000..511a5a6 --- /dev/null +++ b/PrivateAI/openwebui/docker-compose-entra.yaml @@ -0,0 +1,88 @@ +version: "3.9" + +services: + openwebui: + image: ghcr.io/open-webui/open-webui:main + container_name: openwebui + expose: + - "8080" # expose instead of ports (Caddy will proxy) + volumes: + - ./data:/app/backend/data + #- ./caddy/certs/local.crt:/etc/ssl/certs/ca-certificates.crt:ro + environment: + - WEBUI_AUTH=true + - SAFE_MODE=true + - ENABLE_COMMUNITY_SHARING=false + - OPENAI_API_BASE_URL=http://10.137.17.254:9443/v1 + - OPENAI_API_KEY=$LOCALAI_API_KEY + - HTTP_PROXY=${HTTP_PROXY} + - HTTPS_PROXY=${HTTPS_PROXY} + - NO_PROXY=localhost,127.0.0.1,::1,10.137.17.254 + - ENABLE_LOGIN_FORM=true + - ENABLE_SIGNPUT=true + - ENABLE_OIDC=true + - ENABLE_LDAP=false + #- REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt + #- SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt + + # Proxy + session behaviour + - TRUST_PROXY_HEADERS=true + - COOKIE_SECURE=true # HTTPS is now enabled via Caddy + - SESSION_COOKIE_SAMESITE=Lax + + # Public URL of OpenWebUI + - WEBUI_URL=https://10.137.17.254/ + + # OAuth / Microsoft Entra + - ENABLE_OAUTH_SIGNUP=true + - ENABLE_OAUTH_PERSISTENT_CONFIG=false + - OAUTH_MERGE_ACCOUNTS_BY_EMAIL=true + - OAUTH_UPDATE_PICTURE_ON_LOGIN=true + - OAUTH_MICROSOFT_ENABLED=true + - OAUTH_SCOPES=["openid", "profile","email"] + - MICROSOFT_CLIENT_ID=${MICROSOFT_CLIENT_ID} + - MICROSOFT_CLIENT_SECRET=${MICROSOFT_CLIENT_SECRET} + - MICROSOFT_CLIENT_TENANT_ID=${MICROSOFT_CLIENT_TENANT_ID} + - MICROSOFT_REDIRECT_URI=https://10.137.17.254/oauth/microsoft/callback + - OPENID_PROVIDER_URL=https://login.microsoftonline.com/secret/v2.0 # required for logout + #- OPENID_PROVIDER_URL=https://login.microsoftonline.com/${MICROSOFT_CLIENT_TENANT_ID}/v2.0 + - ENABLE_OAUTH_WITHOUT_EMAIL=true #this is a work around and breaks things like password reset and trusts that microsoft sub is stable which it normally isn't + - OAUTH_EMAIL_CLAIM=preferred_username + - OAUTH_PICTURE_CLAIM=picture + + extra_hosts: + - "host.docker.internal:host-gateway" + - "proxy1.it.deakin.edu.au:10.137.0.162" + networks: + - web + restart: unless-stopped + + caddy: + image: caddy:latest + container_name: caddy + ports: + - "3000:443" + - "80:80" + - "443:443" + volumes: + - ./caddy/Caddyfile:/etc/caddy/Caddyfile + - ./caddy/caddy_data:/data + - ./caddy/caddy_config:/config + - ./caddy/certs:/etc/caddy/certs:ro # <— add this + environment: + #- HTTP_PROXY=${HTTP_PROXY} + #- HTTPS_PROXY=${HTTPS_PROXY} + - NO_PROXY=localhost,127.0.0.1,::1,10.137.17.254,openwebui + networks: + - web + restart: unless-stopped + extra_hosts: + - "host.docker.internal:host-gateway" + - "proxy1.it.deakin.edu.au:10.137.0.162" +networks: + web: + +volumes: + caddy_data: + caddy_config: + data: diff --git a/PrivateAI/openwebui/readme.md b/PrivateAI/openwebui/readme.md new file mode 100644 index 0000000..990391e --- /dev/null +++ b/PrivateAI/openwebui/readme.md @@ -0,0 +1,247 @@ +# OpenWebUI (Docker Compose + Caddy + Microsoft Entra ID) + +This bundle runs **OpenWebUI** behind a **Caddy** reverse proxy with **HTTPS** (self‑signed cert) and **Microsoft Entra ID (OAuth/OIDC)** login enabled. +It is also pre-wired to talk to an **OpenAI-compatible API** (e.g. LocalAI) via `OPENAI_API_BASE_URL`. + +> **Security note:** The included `dot.env.example` contains placeholder/example values. +> Treat any secrets as **compromised** if they were ever committed or shared—rotate them in Microsoft Entra and your model backend. + +--- + +## What’s in this tarball + +``` +openwebui/ + docker-compose-entra.yaml + dot.env.example + caddy/ + Caddyfile + Caddyfile.orig + certs/ + local.crt + local.key + caddy_data/... + caddy_config/... +``` + +### File-by-file: what each configuration does + +#### `docker-compose-entra.yaml` +Defines **two services** on the same Docker network: + +- **`openwebui`** + - Image: `ghcr.io/open-webui/open-webui:main` + - Exposes port `8080` **only to the internal Docker network** (`expose:`) — not published to the host. + - Persists OpenWebUI state in `./data` (mounted to `/app/backend/data`). + - Enables: + - local login form (`ENABLE_LOGIN_FORM=true`) + - OAuth/OIDC (`ENABLE_OIDC=true`, `OAUTH_MICROSOFT_ENABLED=true`) + - auth (`WEBUI_AUTH=true`) + - safe mode (`SAFE_MODE=true`) + - Routes model calls to an OpenAI-compatible endpoint: + - `OPENAI_API_BASE_URL=http://10.137.17.254:9443/v1` + - `OPENAI_API_KEY=$LOCALAI_API_KEY` (read from `.env`) + - Supports proxies via `HTTP_PROXY` / `HTTPS_PROXY` from `.env` and a `NO_PROXY` list. + +- **`caddy`** + - Image: `caddy:latest` + - Publishes ports: + - `80:80` (HTTP redirect to HTTPS) + - `443:443` (HTTPS) + - `3000:443` (optional alternate access to the same HTTPS listener) + - Mounts: + - `./caddy/Caddyfile` to `/etc/caddy/Caddyfile` + - `./caddy/certs` to `/etc/caddy/certs` (read-only) for TLS cert/key + - `./caddy_data` and `./caddy_config` for Caddy runtime state + +> ⚠️ **Potential typo:** the compose includes `ENABLE_SIGNPUT=true`. +> OpenWebUI uses `ENABLE_SIGNUP`. If you have issues with signup, change it to `ENABLE_SIGNUP=true`. + +--- + +#### `dot.env.example` +An example environment file you copy to `.env` and edit. It provides: + +- `HTTP_PROXY`, `HTTPS_PROXY` – outbound proxy settings (optional) +- `MICROSOFT_CLIENT_ID` – Entra app registration client ID +- `MICROSOFT_CLIENT_SECRET` – Entra app registration client secret +- `MICROSOFT_CLIENT_TENANT_ID` – Entra tenant ID (or `common`/`organizations` depending on your setup) +- `LOCALAI_API_KEY` – API key for your OpenAI-compatible backend (LocalAI, etc.) + +> ⚠️ The comments in this example file are slightly mismatched (tenant vs secret). +> Use the variable names as the source of truth. + +--- + +#### `caddy/Caddyfile` +Caddy reverse proxy + TLS configuration: + +- Disables Caddy auto-HTTPS (`auto_https off`) so it **only** uses the provided cert. +- HTTP listener `:80` **redirects** to `https://10.137.17.254{uri}`. +- HTTPS listener `:443`: + - Uses the self-signed TLS cert: + - cert: `/etc/caddy/certs/local.crt` + - key: `/etc/caddy/certs/local.key` + - Proxies traffic to OpenWebUI at `http://openwebui:8080`. + +> ⚠️ The redirect + public URL are hard-coded to `10.137.17.254`. +> If your host IP/domain differs, update: +> - `caddy/Caddyfile` (redirect target) +> - `WEBUI_URL` and `MICROSOFT_REDIRECT_URI` in the compose + +--- + +#### `caddy/Caddyfile.orig` +A prior/original version of the Caddyfile kept for reference. + +--- + +#### `caddy/certs/local.crt` and `caddy/certs/local.key` +A **self-signed** TLS certificate and private key used by Caddy for HTTPS. + +- Browsers will show a certificate warning unless you **trust** the certificate on your machine. +- For a production deployment, replace these with a proper certificate (e.g., Let’s Encrypt with a real domain). + +--- + +#### `caddy/caddy_data/*` and `caddy/caddy_config/*` +Caddy’s persisted runtime state: + +- `caddy_data` – instance UUID, lock files, last-clean metadata, etc. +- `caddy_config/caddy/autosave.json` – Caddy’s autosaved config snapshot (generated/maintained by Caddy) + +You normally **do not edit** these manually. + +--- + +## Prerequisites + +- Docker + Docker Compose plugin (`docker compose version`) +- Ports **80** and **443** available on the host (and optionally **3000**) +- If you’ll use Entra login: + - A Microsoft Entra App Registration with a redirect URI matching your deployment URL. + +--- + +## Quick start + +### 1) Extract the tarball +From the directory containing the tar: + +```bash +tar -xf openwebui.tar +cd openwebui +``` + +### 2) Create your `.env` +Copy the example and edit values: + +```bash +cp dot.env.example .env +nano .env +``` + +At minimum, set: + +- `LOCALAI_API_KEY=...` +- `MICROSOFT_CLIENT_ID=...` +- `MICROSOFT_CLIENT_SECRET=...` +- `MICROSOFT_CLIENT_TENANT_ID=...` + +Optionally set proxy variables (or delete them if not needed). + +### 3) Update host/IP references (recommended) +This bundle is hardcoded to `10.137.17.254`. + +Search & replace in: + +- `caddy/Caddyfile` (redirect line) +- `docker-compose-entra.yaml`: + - `WEBUI_URL` + - `MICROSOFT_REDIRECT_URI` + - (optionally) `OPENAI_API_BASE_URL` if your model endpoint differs + +### 4) Start the stack +Run: + +```bash +docker compose --env-file .env -f docker-compose-entra.yaml up -d +``` + +Check logs: + +```bash +docker compose -f docker-compose-entra.yaml logs -f --tail=200 +``` + +Stop: + +```bash +docker compose -f docker-compose-entra.yaml down +``` + +--- + +## Accessing OpenWebUI + +- Primary (standard HTTPS): `https:///` +- Optional alternate mapping: `https://:3000/` + +Because the certificate is self-signed, your browser will warn unless you trust `caddy/certs/local.crt`. + +### Trusting the self-signed cert (quick guidance) + +- **macOS:** Keychain Access → System (or Login) → Certificates → Import `local.crt` → set to “Always Trust”. +- **Windows:** `certmgr.msc` → Trusted Root Certification Authorities → Certificates → Import `local.crt`. +- **Linux:** depends on distro; typically copy to `/usr/local/share/ca-certificates/` and run `update-ca-certificates`. + +--- + +## Microsoft Entra ID (OAuth/OIDC) notes + +In Entra App Registration: + +- Add a **Redirect URI** matching: + - `https:///oauth/microsoft/callback` +- Ensure the app is configured for the correct tenant type: + - Single-tenant: use your tenant ID + - Multi-tenant/personal: you may need `common` and adjust scopes/claims + +This compose sets: +- `OAUTH_SCOPES=["openid","profile","email"]` +- `OAUTH_EMAIL_CLAIM=preferred_username` +- `OAUTH_MERGE_ACCOUNTS_BY_EMAIL=true` + +> The compose includes `ENABLE_OAUTH_WITHOUT_EMAIL=true` (marked as a workaround). +> If you don’t need it, consider disabling it for cleaner account semantics. + +--- + +## Troubleshooting + +### Port 80/443 already in use +- Another service (nginx, Traefik, etc.) may be listening. +- Either stop the conflicting service or change the published ports in the `caddy` service. + +### Redirect goes to the wrong IP +Update the `redir` target in `caddy/Caddyfile`. + +### OAuth login loops or fails +- Confirm the redirect URI matches **exactly** (scheme/host/path). +- Confirm the tenant setting and the `MICROSOFT_CLIENT_*` values in `.env`. +- Check OpenWebUI logs for OAuth errors. + +### OpenWebUI can’t reach the model backend +- Confirm `OPENAI_API_BASE_URL` is reachable **from inside Docker**. +- If the backend runs on the Docker host, `host.docker.internal` is available due to `extra_hosts`. + +--- + +## Data persistence + +- OpenWebUI data is stored in `./data` (in the `openwebui/` folder). +- Caddy state is stored in `./caddy/caddy_data` and `./caddy/caddy_config`. + +Back up those directories if you want to preserve state. + +---