From ded9030edeb1c158754f4e9ee8358baa1d90d961 Mon Sep 17 00:00:00 2001 From: LD-Reborn Date: Fri, 31 Jul 2026 16:03:49 +0200 Subject: [PATCH] feat(deploy): adds uninstaller, docs: fixes wording and adds llama.cpp installation examples --- README.md | 16 +++++-- deploy/uninstall-client.ps1 | 42 ++++++++++++++++ deploy/uninstall-client.sh | 95 +++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+), 4 deletions(-) create mode 100644 deploy/uninstall-client.ps1 create mode 100755 deploy/uninstall-client.sh 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)"