From f0c1ba00c140bf1c7506e4fb60a5515072fa4a79 Mon Sep 17 00:00:00 2001 From: wm Date: Sun, 18 Jan 2026 23:11:54 +0100 Subject: [PATCH] feat: Add Flowise LXC installer --- FLOWISE_SETUP.md | 189 ++++++++++++++++++++ install_flowise.sh | 419 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 608 insertions(+) create mode 100644 FLOWISE_SETUP.md create mode 100644 install_flowise.sh diff --git a/FLOWISE_SETUP.md b/FLOWISE_SETUP.md new file mode 100644 index 0000000..83ef84a --- /dev/null +++ b/FLOWISE_SETUP.md @@ -0,0 +1,189 @@ +# Flowise LXC Installer + +Dieses Script erstellt einen LXC-Container mit Docker, PostgreSQL (mit pgvector) und Flowise. + +## Was ist Flowise? + +[Flowise](https://flowiseai.com/) ist ein Open-Source Low-Code Tool zum Erstellen von LLM-Flows und AI-Agenten. Es bietet eine visuelle Drag-and-Drop-Oberfläche zum Erstellen von: + +- Chatbots +- RAG (Retrieval Augmented Generation) Pipelines +- AI-Agenten mit Tools +- LangChain-basierte Workflows + +## Voraussetzungen + +- Proxmox VE mit LXC-Unterstützung +- Debian 12 Template +- Netzwerk-Bridge (default: vmbr0) +- Storage (default: local-zfs) + +## Installation + +```bash +# Minimale Konfiguration +bash install_flowise.sh + +# Mit Debug-Ausgabe +bash install_flowise.sh --debug + +# Mit benutzerdefinierten Credentials +bash install_flowise.sh \ + --flowise-user admin \ + --flowise-pass "MeinSicheresPasswort1" + +# Mit allen Optionen +bash install_flowise.sh \ + --cores 4 \ + --memory 4096 \ + --disk 50 \ + --base-domain userman.de \ + --flowise-user admin \ + --debug +``` + +## Parameter + +### Core-Optionen + +| Parameter | Beschreibung | Standard | +|-----------|--------------|----------| +| `--ctid ` | Container ID (optional, wird automatisch generiert) | Auto | +| `--cores ` | CPU-Kerne | 4 | +| `--memory ` | RAM in MB | 4096 | +| `--swap ` | Swap in MB | 512 | +| `--disk ` | Disk in GB | 50 | +| `--bridge ` | Netzwerk-Bridge | vmbr0 | +| `--storage ` | Proxmox Storage | local-zfs | +| `--ip ` | IP-Konfiguration | dhcp | +| `--vlan ` | VLAN-Tag | 90 | +| `--privileged` | Privilegierter Container | unprivileged | +| `--apt-proxy ` | APT-Proxy URL | - | + +### Flowise-Optionen + +| Parameter | Beschreibung | Standard | +|-----------|--------------|----------| +| `--base-domain ` | Basis-Domain für FQDN | userman.de | +| `--flowise-user ` | Flowise Admin-Benutzername | admin | +| `--flowise-pass ` | Flowise Admin-Passwort | Auto-generiert | +| `--debug` | Debug-Modus aktivieren | Aus | + +## Ausgabe + +### Normalmodus (ohne --debug) + +Das Script gibt nur JSON auf stdout aus: + +```json +{ + "ctid": 768736637, + "hostname": "fw-1768736637", + "fqdn": "fw-1768736637.userman.de", + "ip": "192.168.45.136", + "vlan": 90, + "urls": { + "flowise_internal": "http://192.168.45.136:3000/", + "flowise_external": "https://fw-1768736637.userman.de" + }, + "postgres": { + "host": "postgres", + "port": 5432, + "db": "flowise", + "user": "flowise", + "password": "GeneratedPassword1" + }, + "flowise": { + "username": "admin", + "password": "GeneratedPassword2", + "secret_key": "64-char-hex-key" + }, + "log_file": "/root/customer-installer/logs/fw-1768736637.log" +} +``` + +### Debug-Modus (mit --debug) + +Zusätzlich werden Logs auf stderr ausgegeben. + +## Erstellte Komponenten + +### Docker-Container + +1. **flowise-postgres** - PostgreSQL 16 mit pgvector Extension +2. **flowise** - Flowise AI Flow Builder + +### Verzeichnisstruktur im Container + +``` +/opt/flowise-stack/ +├── .env # Umgebungsvariablen +├── docker-compose.yml # Docker Compose Konfiguration +├── sql/ +│ └── init_pgvector.sql # PostgreSQL Initialisierung +└── volumes/ + ├── postgres/data/ # PostgreSQL Daten + └── flowise-data/ # Flowise Daten (Flows, Credentials, etc.) +``` + +## Ports + +| Service | Interner Port | Externer Port | +|---------|---------------|---------------| +| Flowise | 3000 | 3000 | +| PostgreSQL | 5432 | - (nur intern) | + +## NGINX Reverse Proxy + +Nach der Installation kann ein NGINX Reverse Proxy auf OPNsense eingerichtet werden: + +```bash +bash setup_nginx_proxy.sh \ + --ctid \ + --hostname fw- \ + --fqdn fw-.userman.de \ + --backend-ip \ + --backend-port 3000 +``` + +## Unterschiede zu n8n-Installer + +| Aspekt | n8n (install.sh) | Flowise (install_flowise.sh) | +|--------|------------------|------------------------------| +| Hostname-Präfix | `sb-` | `fw-` | +| Standard-Port | 5678 | 3000 | +| Authentifizierung | Email + Passwort | Username + Passwort | +| Container-Name | n8n | flowise | +| Datenverzeichnis | /opt/customer-stack | /opt/flowise-stack | + +## Fehlerbehebung + +### Container startet nicht + +```bash +# Logs prüfen +pct exec -- docker compose -f /opt/flowise-stack/docker-compose.yml logs +``` + +### Flowise nicht erreichbar + +```bash +# Container-Status prüfen +pct exec -- docker compose -f /opt/flowise-stack/docker-compose.yml ps + +# Flowise-Logs prüfen +pct exec -- docker logs flowise +``` + +### Datenbank-Verbindungsfehler + +```bash +# PostgreSQL-Status prüfen +pct exec -- docker logs flowise-postgres +``` + +## Versionsverlauf + +| Version | Änderungen | +|---------|------------| +| 1.0.0 | Initiale Version | diff --git a/install_flowise.sh b/install_flowise.sh new file mode 100644 index 0000000..2b05e23 --- /dev/null +++ b/install_flowise.sh @@ -0,0 +1,419 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +# ============================================================================= +# Flowise LXC Installer +# ============================================================================= +# Erstellt einen LXC-Container mit Docker + Flowise + PostgreSQL +# ============================================================================= + +SCRIPT_VERSION="1.0.0" + +# Debug mode: 0 = nur JSON, 1 = Logs auf stderr +DEBUG="${DEBUG:-0}" +export DEBUG + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Log-Verzeichnis +LOG_DIR="${SCRIPT_DIR}/logs" +mkdir -p "${LOG_DIR}" + +# Temporäre Log-Datei (wird später umbenannt nach Container-Hostname) +TEMP_LOG="${LOG_DIR}/install_flowise_$$.log" +FINAL_LOG="" + +# Funktion zum Aufräumen bei Exit +cleanup_log() { + # Wenn FINAL_LOG gesetzt ist, umbenennen + if [[ -n "${FINAL_LOG}" && -f "${TEMP_LOG}" ]]; then + mv "${TEMP_LOG}" "${FINAL_LOG}" + fi +} +trap cleanup_log EXIT + +# Alle Ausgaben in Log-Datei umleiten +# Bei DEBUG=1: auch auf stderr ausgeben (tee) +# Bei DEBUG=0: nur in Datei +if [[ "$DEBUG" == "1" ]]; then + # Debug-Modus: Ausgabe auf stderr UND in Datei + exec > >(tee -a "${TEMP_LOG}") 2>&1 +else + # Normal-Modus: Nur in Datei, stdout bleibt für JSON frei + exec 3>&1 # stdout (fd 3) für JSON reservieren + exec > "${TEMP_LOG}" 2>&1 +fi + +source "${SCRIPT_DIR}/libsupabase.sh" +setup_traps + +usage() { + cat >&2 <<'EOF' +Usage: + bash install_flowise.sh [options] + +Core options: + --ctid Force CT ID (optional). If omitted, a customer-safe CTID is generated. + --cores (default: 4) + --memory (default: 4096) + --swap (default: 512) + --disk (default: 50) + --bridge (default: vmbr0) + --storage (default: local-zfs) + --ip (default: dhcp) + --vlan VLAN tag for net0 (default: 90; set 0 to disable) + --privileged Create privileged CT (default: unprivileged) + --apt-proxy Optional: APT proxy (e.g. http://192.168.45.2:3142) for Apt-Cacher NG + +Domain / Flowise options: + --base-domain (default: userman.de) -> FQDN becomes fw-.domain + --flowise-user (default: admin) + --flowise-pass Optional. If omitted, generated (policy compliant). + --debug Enable debug mode (show logs on stderr) + --help Show help + +Notes: +- This script creates a Debian 12 LXC and provisions Docker + Flowise stack (Postgres + Flowise). +- At the end it prints a JSON with credentials and URLs. +EOF +} + +# Defaults +DOCKER_REGISTRY_MIRROR="http://192.168.45.2:5000" +APT_PROXY="" +CTID="" +CORES="4" +MEMORY="4096" +SWAP="512" +DISK="50" +BRIDGE="vmbr0" +STORAGE="local-zfs" +IPCFG="dhcp" +VLAN="90" +UNPRIV="1" + +BASE_DOMAIN="userman.de" +FLOWISE_USER="admin" +FLOWISE_PASS="" + +# --------------------------- +# Arg parsing +# --------------------------- +while [[ $# -gt 0 ]]; do + case "$1" in + --ctid) CTID="${2:-}"; shift 2 ;; + --apt-proxy) APT_PROXY="${2:-}"; shift 2 ;; + --cores) CORES="${2:-}"; shift 2 ;; + --memory) MEMORY="${2:-}"; shift 2 ;; + --swap) SWAP="${2:-}"; shift 2 ;; + --disk) DISK="${2:-}"; shift 2 ;; + --bridge) BRIDGE="${2:-}"; shift 2 ;; + --storage) STORAGE="${2:-}"; shift 2 ;; + --ip) IPCFG="${2:-}"; shift 2 ;; + --vlan) VLAN="${2:-}"; shift 2 ;; + --privileged) UNPRIV="0"; shift 1 ;; + --base-domain) BASE_DOMAIN="${2:-}"; shift 2 ;; + --flowise-user) FLOWISE_USER="${2:-}"; shift 2 ;; + --flowise-pass) FLOWISE_PASS="${2:-}"; shift 2 ;; + --debug) DEBUG="1"; export DEBUG; shift 1 ;; + --help|-h) usage; exit 0 ;; + *) die "Unknown option: $1 (use --help)" ;; + esac +done + +# --------------------------- +# Validation +# --------------------------- +[[ "$CORES" =~ ^[0-9]+$ ]] || die "--cores must be integer" +[[ "$MEMORY" =~ ^[0-9]+$ ]] || die "--memory must be integer" +[[ "$SWAP" =~ ^[0-9]+$ ]] || die "--swap must be integer" +[[ "$DISK" =~ ^[0-9]+$ ]] || die "--disk must be integer" +[[ "$UNPRIV" == "0" || "$UNPRIV" == "1" ]] || die "internal: UNPRIV invalid" +[[ "$VLAN" =~ ^[0-9]+$ ]] || die "--vlan must be integer (0 disables tagging)" +[[ -n "$BASE_DOMAIN" ]] || die "--base-domain must not be empty" + +if [[ "$IPCFG" != "dhcp" ]]; then + [[ "$IPCFG" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}$ ]] || die "--ip must be dhcp or CIDR (e.g. 192.168.45.171/24)" +fi + +if [[ -n "${APT_PROXY}" ]]; then + [[ "${APT_PROXY}" =~ ^http://[^/]+:[0-9]+$ ]] || die "--apt-proxy must look like http://IP:PORT (example: http://192.168.45.2:3142)" +fi + +info "Script Version: ${SCRIPT_VERSION}" +info "Argument-Parsing OK" + +if [[ -n "${APT_PROXY}" ]]; then + info "APT proxy enabled: ${APT_PROXY}" +else + info "APT proxy disabled" +fi + +# --------------------------- +# Preflight Proxmox +# --------------------------- +need_cmd pct pvesm pveam pvesh grep date awk sed cut tr head + +pve_storage_exists "$STORAGE" || die "Storage not found: $STORAGE" +pve_bridge_exists "$BRIDGE" || die "Bridge not found: $BRIDGE" + +TEMPLATE="$(pve_template_ensure_debian12 "$STORAGE")" +info "Template OK: ${TEMPLATE}" + +# Hostname / FQDN based on unix time (fw- prefix for Flowise) +UNIXTS="$(date +%s)" +CT_HOSTNAME="fw-${UNIXTS}" +FQDN="${CT_HOSTNAME}.${BASE_DOMAIN}" + +# Log-Datei nach Container-Hostname benennen +FINAL_LOG="${LOG_DIR}/${CT_HOSTNAME}.log" + +# CTID selection +if [[ -n "$CTID" ]]; then + [[ "$CTID" =~ ^[0-9]+$ ]] || die "--ctid must be integer" + if pve_vmid_exists_cluster "$CTID"; then + die "Forced CTID=${CTID} already exists in cluster" + fi +else + # unix time - 1000000000 (safe until 2038) + CTID="$(pve_ctid_from_unixtime "$UNIXTS")" + if pve_vmid_exists_cluster "$CTID"; then + die "Generated CTID=${CTID} already exists in cluster (unexpected). Try again in 1s." + fi +fi + +# Flowise credentials defaults +if [[ -z "$FLOWISE_PASS" ]]; then + FLOWISE_PASS="$(gen_password_policy)" +else + password_policy_check "$FLOWISE_PASS" || die "--flowise-pass does not meet policy: 8+ chars, 1 number, 1 uppercase" +fi + +info "CTID selected: ${CTID}" +info "SCRIPT_DIR=${SCRIPT_DIR}" +info "CT_HOSTNAME=${CT_HOSTNAME}" +info "FQDN=${FQDN}" +info "cores=${CORES} memory=${MEMORY}MB swap=${SWAP}MB disk=${DISK}GB" +info "bridge=${BRIDGE} storage=${STORAGE} ip=${IPCFG} vlan=${VLAN} unprivileged=${UNPRIV}" + +# --------------------------- +# Step 1: Create CT +# --------------------------- +NET0="$(pve_build_net0 "$BRIDGE" "$IPCFG" "$VLAN")" +ROOTFS="${STORAGE}:${DISK}" +FEATURES="nesting=1,keyctl=1,fuse=1" + +info "Step 1: Create CT" +info "Creating CT ${CTID} (${CT_HOSTNAME}) from ${TEMPLATE}" +pct create "${CTID}" "${TEMPLATE}" \ + --hostname "${CT_HOSTNAME}" \ + --cores "${CORES}" \ + --memory "${MEMORY}" \ + --swap "${SWAP}" \ + --net0 "${NET0}" \ + --rootfs "${ROOTFS}" \ + --unprivileged "${UNPRIV}" \ + --features "${FEATURES}" \ + --start 0 \ + --onboot yes + +info "CT created (not started). Next step: start CT + wait for IP" +info "Starting CT ${CTID}" +pct start "${CTID}" + +CT_IP="$(pct_wait_for_ip "${CTID}" || true)" +[[ -n "${CT_IP}" ]] || die "Could not determine CT IP after start" + +info "Step 1 OK: LXC erstellt + IP ermittelt" +info "CT_HOSTNAME=${CT_HOSTNAME}" +info "CT_IP=${CT_IP}" + +# --------------------------- +# Step 2: Provision inside CT (Docker + Locales + Base) +# --------------------------- +info "Step 2: Provisioning im CT (Docker + Locales + Base)" + +# Optional: APT proxy (Apt-Cacher NG) +if [[ -n "${APT_PROXY}" ]]; then + pct_exec "${CTID}" "cat > /etc/apt/apt.conf.d/00aptproxy <<'EOF' +Acquire::http::Proxy \"${APT_PROXY}\"; +Acquire::https::Proxy \"${APT_PROXY}\"; +EOF" + pct_exec "$CTID" "apt-config dump | grep -i proxy || true" +fi + +# Minimal base packages +pct_exec "${CTID}" "export DEBIAN_FRONTEND=noninteractive; apt-get update -y" +pct_exec "${CTID}" "export DEBIAN_FRONTEND=noninteractive; apt-get install -y ca-certificates curl gnupg lsb-release" + +# Locales (avoid perl warnings + consistent system) +pct_exec "${CTID}" "export DEBIAN_FRONTEND=noninteractive; apt-get install -y locales" +pct_exec "${CTID}" "sed -i 's/^# *de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/; s/^# *en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen || true" +pct_exec "${CTID}" "locale-gen >/dev/null || true" +pct_exec "${CTID}" "update-locale LANG=de_DE.UTF-8 LC_ALL=de_DE.UTF-8 || true" + +# Docker official repo (Debian 12 / bookworm) +pct_exec "${CTID}" "install -m 0755 -d /etc/apt/keyrings" +pct_exec "${CTID}" "curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg" +pct_exec "${CTID}" "chmod a+r /etc/apt/keyrings/docker.gpg" +pct_exec "${CTID}" "echo \"deb [arch=\$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \$(. /etc/os-release && echo \$VERSION_CODENAME) stable\" > /etc/apt/sources.list.d/docker.list" +pct_exec "${CTID}" "export DEBIAN_FRONTEND=noninteractive; apt-get update -y" +pct_exec "${CTID}" "export DEBIAN_FRONTEND=noninteractive; apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin" + +# Create stack directories +pct_exec "${CTID}" "mkdir -p /opt/flowise-stack/volumes/postgres/data /opt/flowise-stack/volumes/flowise-data /opt/flowise-stack/sql" + +info "Step 2 OK: Docker + Compose Plugin installiert, Locales gesetzt, Basis-Verzeichnisse erstellt" + +# --------------------------- +# Step 3: Stack finalisieren + Secrets + Up + Checks +# --------------------------- +info "Step 3: Stack finalisieren + Secrets + Up + Checks" + +# Secrets +PG_DB="flowise" +PG_USER="flowise" +PG_PASSWORD="$(gen_password_policy)" +FLOWISE_SECRETKEY="$(gen_hex_64)" + +# Flowise configuration +FLOWISE_PORT="3000" +FLOWISE_HOST="${CT_IP}" +FLOWISE_EXTERNAL_URL="https://${FQDN}" + +# Write .env into CT +pct_push_text "${CTID}" "/opt/flowise-stack/.env" "$(cat < /etc/docker/daemon.json </dev/null || echo "$JSON_OUTPUT" +else + # Normal-Modus: JSON auf ursprüngliches stdout (fd 3) - kompakt + echo "$JSON_OUTPUT" >&3 +fi