diff --git a/README.md b/README.md
index 4d33d83..6d1d250 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
# Ngino
-Ngino is a small outbound HTTP tunnel for running Ollama (or vLLM, etc.) on GPU workstations while exposing the API from a server that cannot reach those workstations directly.
+Ngino is a small outbound HTTP tunnel for running Ollama, llama.cpp, vLLM, etc. on GPU workstations while exposing the API from a server that cannot reach those workstations directly.
-The client opens and maintains a WebSocket connection to the server. The server accepts normal HTTP requests and forwards them through that WebSocket to the client. The client then calls a local upstream such as `http://localhost:11434` and streams the response back.
+The client opens and maintains a WebSocket connection to the server. The server accepts normal HTTP requests from users and forwards them through that WebSocket to the client. The client then calls a local upstream such as `http://localhost:11434` and streams the response back.
@@ -15,8 +15,8 @@ The server provides
- An API with
- Authentication via user keys
- Authorization (planned)
-- Load balancing (Scale your AI strategy horizontally!)
-- (Ollama-only) Model management (install, remove, load, unload models)
+- Load balancing (Scale your AI inferencing horizontally by adding more nodes!)
+- (Ollama-based) GGUF Model management (install, remove, load, unload models)
- Client monitoring
- Who is active
- What models are running
@@ -129,6 +129,14 @@ Linux:
```bash
sudo bash deploy/install-client.sh --server http://your-server:5050 --token "change-me"
```
+or using ollama models with llama.cpp backend using ROCm:
+```bash
+sudo bash deploy/install-client.sh --server https://ai.domain.tld --token "change-me" --use-llama-cpp-via-docker --use-ollama-models-path /usr/share/ollama/.ollama/models --llama-cpp-docker-image ghcr.io/ggml-org/llama.cpp:server-rocm --llama-cpp-base-port 8081
+```
+or using ollama models with llama.cpp backend using CUDA:
+```bash
+sudo bash deploy/install-client.sh --server https://ai.domain.tld --token "change-me" --use-llama-cpp-via-docker --use-ollama-models-path /usr/share/ollama/.ollama/models --llama-cpp-docker-image ghcr.io/ggml-org/llama.cpp:server-cuda --llama-cpp-base-port 8081
+```
Options: `--server`, `--token` (required); `--client-id`, `--upstream`, `--install-dir`, `--service-name`, `--no-ollama` (optional). Missing required values are prompted interactively.
diff --git a/deploy/uninstall-client.ps1 b/deploy/uninstall-client.ps1
new file mode 100644
index 0000000..028b33f
--- /dev/null
+++ b/deploy/uninstall-client.ps1
@@ -0,0 +1,42 @@
+#Requires -Version 5.1
+#Requires -RunAsAdministrator
+
+[CmdletBinding()]
+param(
+ [string]$InstallDir = "$env:ProgramFiles\Ngino Client",
+ [string]$ServiceName = "NginoClient"
+)
+
+$ErrorActionPreference = "Stop"
+
+function Write-Info([string]$Message) { Write-Host "[INFO] $Message" -ForegroundColor Green }
+
+if ($ServiceName -notmatch '^[A-Za-z0-9_.-]+$') { throw "ServiceName contains unsupported characters." }
+
+# ── Stop and delete the Windows service ───────────────────────────────────────
+$service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
+if ($service) {
+ if ($service.Status -ne "Stopped") {
+ Write-Info "Stopping service $ServiceName..."
+ Stop-Service -Name $ServiceName -Force
+ $service.WaitForStatus("Stopped", [TimeSpan]::FromSeconds(30))
+ }
+ Write-Info "Deleting service $ServiceName..."
+ & sc.exe delete $ServiceName
+ if ($LASTEXITCODE -ne 0) { throw "Could not delete Windows service $ServiceName." }
+} else {
+ Write-Info "Service $ServiceName does not exist; skipping."
+}
+
+# ── Remove install directory ──────────────────────────────────────────────────
+if (Test-Path -LiteralPath $InstallDir) {
+ Write-Info "Removing install directory $InstallDir..."
+ Remove-Item -LiteralPath $InstallDir -Recurse -Force
+} else {
+ Write-Info "Install directory $InstallDir does not exist; skipping."
+}
+
+Write-Host ""
+Write-Info "Uninstall complete."
+Write-Host " Service: $ServiceName (stopped and deleted)"
+Write-Host " Install dir: $InstallDir (removed)"
diff --git a/deploy/uninstall-client.sh b/deploy/uninstall-client.sh
new file mode 100755
index 0000000..33f1f58
--- /dev/null
+++ b/deploy/uninstall-client.sh
@@ -0,0 +1,95 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# ── Defaults ──────────────────────────────────────────────────────────────────
+DEFAULT_INSTALL_DIR="/opt/ngino-client"
+DEFAULT_SERVICE_NAME="ngino-client"
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+INSTALL_DIR="$DEFAULT_INSTALL_DIR"
+SERVICE_NAME="$DEFAULT_SERVICE_NAME"
+
+# ── Colors ────────────────────────────────────────────────────────────────────
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[0;33m'
+NC='\033[0m'
+
+info() { echo -e "${GREEN}[INFO]${NC} $*"; }
+warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
+err() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
+die() { err "$@"; exit 1; }
+
+# ── Usage ─────────────────────────────────────────────────────────────────────
+usage() {
+ cat < Install directory; defaults to $DEFAULT_INSTALL_DIR
+ --service-name systemd service name; defaults to $DEFAULT_SERVICE_NAME
+ -h, --help Show this help message
+
+Examples:
+ $0
+ $0 --install-dir /opt/ngino-client --service-name ngino-client
+EOF
+ exit 0
+}
+
+# ── Argument parsing ──────────────────────────────────────────────────────────
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ --install-dir) INSTALL_DIR="$2"; shift 2 ;;
+ --service-name) SERVICE_NAME="$2"; shift 2 ;;
+ -h|--help) usage ;;
+ *) die "Unknown option: $1" ;;
+ esac
+done
+
+# ── Root check ────────────────────────────────────────────────────────────────
+if [[ $EUID -ne 0 ]]; then
+ die "This script must be run as root (or with sudo)."
+fi
+
+SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
+ENV_DIR="/etc/ngino-client"
+
+# ── Stop and disable the service ──────────────────────────────────────────────
+if systemctl list-unit-files "$SERVICE_NAME.service" &>/dev/null 2>&1; then
+ info "Stopping service $SERVICE_NAME..."
+ systemctl stop "$SERVICE_NAME" 2>/dev/null || true
+ info "Disabling service $SERVICE_NAME..."
+ systemctl disable "$SERVICE_NAME" 2>/dev/null || true
+fi
+
+# ── Remove service unit file ──────────────────────────────────────────────────
+if [[ -f "$SERVICE_FILE" ]]; then
+ info "Removing service unit file $SERVICE_FILE..."
+ rm -f "$SERVICE_FILE"
+fi
+
+systemctl daemon-reload
+
+# ── Remove install directory ──────────────────────────────────────────────────
+if [[ -d "$INSTALL_DIR" ]]; then
+ info "Removing install directory $INSTALL_DIR..."
+ rm -rf "$INSTALL_DIR"
+fi
+
+# ── Remove environment file ───────────────────────────────────────────────────
+if [[ -d "$ENV_DIR" ]]; then
+ info "Removing environment directory $ENV_DIR..."
+ rm -rf "$ENV_DIR"
+fi
+
+# ── Done ──────────────────────────────────────────────────────────────────────
+echo
+info "Uninstall complete."
+echo " Service: $SERVICE_NAME (stopped, disabled, unit removed)"
+echo " Install dir: $INSTALL_DIR (removed)"
+echo " Env dir: $ENV_DIR (removed)"