From 844f71a343046df49b861d6b18b82841980a7a84 Mon Sep 17 00:00:00 2001 From: jessikitty Date: Wed, 27 May 2026 10:58:42 +1000 Subject: [PATCH] feat: Guacamole LXC setup script with Docker Compose stack --- setup-guacamole-lxc.sh | 208 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 setup-guacamole-lxc.sh diff --git a/setup-guacamole-lxc.sh b/setup-guacamole-lxc.sh new file mode 100644 index 0000000..112cfc1 --- /dev/null +++ b/setup-guacamole-lxc.sh @@ -0,0 +1,208 @@ +#!/bin/bash +# ===================================================================== +# Apache Guacamole LXC Setup for Proxmox (Docker-based) +# ===================================================================== +# Migrates Guacamole from a Home Assistant add-on to a dedicated +# LXC container on Proxmox. Guacamole was using 25% CPU and 9% RAM +# inside the HAOS VM — this frees those resources. +# +# Uses Docker Compose for clean deployment of: +# - guacamole (web frontend) +# - guacd (connection daemon) +# - postgres (user/connection database) +# +# Run this script on the Proxmox host (HAL-HOST) as root. +# +# Network assumptions: +# - Guacamole LXC: 10.0.0.52 (new - adjust if taken) +# - Gateway: 10.0.0.254 +# - NPM: 10.0.0.54 (for reverse proxy) +# ===================================================================== + +set -euo pipefail + +# --- Configuration --- +CT_ID="${1:-121}" +CT_NAME="guacamole" +CT_IP="10.0.0.52/24" +CT_GW="10.0.0.254" +CT_STORAGE="local-lvm" +CT_TEMPLATE="local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst" +CT_MEMORY=1024 +CT_SWAP=256 +CT_CORES=2 +CT_DISK="8" +BRIDGE="vmbr0" + +GUAC_DB_PASSWORD="$(openssl rand -hex 16 2>/dev/null || echo "ChangeMe_$(date +%s)")" + +echo "============================================" +echo " Apache Guacamole LXC Setup" +echo " Container ID: ${CT_ID}" +echo " IP Address: ${CT_IP}" +echo "============================================" + +# --- Check if template exists --- +if ! pveam list local | grep -q "debian-12-standard"; then + echo "[1/8] Downloading Debian 12 template..." + pveam download local debian-12-standard_12.7-1_amd64.tar.zst +else + echo "[1/8] Debian 12 template already available" +fi + +# --- Create the container --- +echo "[2/8] Creating LXC container ${CT_ID}..." +pct create "${CT_ID}" "${CT_TEMPLATE}" \ + --hostname "${CT_NAME}" \ + --memory "${CT_MEMORY}" \ + --swap "${CT_SWAP}" \ + --cores "${CT_CORES}" \ + --rootfs "${CT_STORAGE}:${CT_DISK}" \ + --net0 "name=eth0,bridge=${BRIDGE},ip=${CT_IP},gw=${CT_GW},firewall=0" \ + --nameserver "1.1.1.1" \ + --onboot 1 \ + --start 1 \ + --unprivileged 1 \ + --features "nesting=1,keyctl=1" \ + --startup "order=2,up=15" + +echo "[3/8] Waiting for container to start..." +sleep 5 + +# --- Install Docker inside the container --- +echo "[4/8] Installing Docker..." +pct exec "${CT_ID}" -- bash -c ' + apt-get update -qq + apt-get install -y -qq ca-certificates curl gnupg + install -m 0755 -d /etc/apt/keyrings + curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg + chmod a+r /etc/apt/keyrings/docker.gpg + 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 + apt-get update -qq + apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-compose-plugin + systemctl enable docker + systemctl start docker +' + +# --- Create Docker Compose config --- +echo "[5/8] Creating Guacamole Docker Compose configuration..." +pct exec "${CT_ID}" -- bash -c " + mkdir -p /opt/guacamole + cat > /opt/guacamole/docker-compose.yml << DCEOF +services: + guacd: + image: guacamole/guacd:latest + container_name: guacd + restart: unless-stopped + networks: + - guac-net + + postgres: + image: postgres:15-alpine + container_name: guac-postgres + restart: unless-stopped + environment: + POSTGRES_DB: guacamole_db + POSTGRES_USER: guacamole_user + POSTGRES_PASSWORD: ${GUAC_DB_PASSWORD} + volumes: + - postgres-data:/var/lib/postgresql/data + - /opt/guacamole/initdb:/docker-entrypoint-initdb.d + networks: + - guac-net + + guacamole: + image: guacamole/guacamole:latest + container_name: guacamole + restart: unless-stopped + depends_on: + - guacd + - postgres + environment: + GUACD_HOSTNAME: guacd + POSTGRESQL_HOSTNAME: postgres + POSTGRESQL_DATABASE: guacamole_db + POSTGRESQL_USER: guacamole_user + POSTGRESQL_PASSWORD: ${GUAC_DB_PASSWORD} + ports: + - '8080:8080' + networks: + - guac-net + +networks: + guac-net: + driver: bridge + +volumes: + postgres-data: +DCEOF +" + +# --- Generate the database init script --- +echo "[6/8] Generating database initialisation schema..." +pct exec "${CT_ID}" -- bash -c ' + mkdir -p /opt/guacamole/initdb + docker pull guacamole/guacamole:latest -q + docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --postgresql > /opt/guacamole/initdb/001-init.sql + echo "Database schema extracted successfully" +' + +# --- Start the stack --- +echo "[7/8] Starting Guacamole stack..." +pct exec "${CT_ID}" -- bash -c ' + cd /opt/guacamole + docker compose up -d + echo "Waiting for services to initialise..." + sleep 15 + docker compose ps +' + +# --- Create systemd service for auto-start --- +echo "[8/8] Creating systemd service for auto-start..." +pct exec "${CT_ID}" -- bash -c ' + cat > /etc/systemd/system/guacamole.service << "SVCEOF" +[Unit] +Description=Apache Guacamole Docker Stack +Requires=docker.service +After=docker.service + +[Service] +Type=oneshot +RemainAfterExit=yes +WorkingDirectory=/opt/guacamole +ExecStart=/usr/bin/docker compose up -d +ExecStop=/usr/bin/docker compose down +TimeoutStartSec=120 + +[Install] +WantedBy=multi-user.target +SVCEOF + + systemctl daemon-reload + systemctl enable guacamole.service +' + +CT_IP_CLEAN=$(echo "${CT_IP}" | cut -d'/' -f1) + +echo "" +echo "============================================" +echo " Apache Guacamole LXC setup complete!" +echo "============================================" +echo "" +echo " Web UI: http://${CT_IP_CLEAN}:8080/guacamole/" +echo " Default: guacadmin / guacadmin (CHANGE IMMEDIATELY)" +echo " DB Pass: ${GUAC_DB_PASSWORD}" +echo "" +echo " MIGRATION STEPS:" +echo " 1. Login at http://${CT_IP_CLEAN}:8080/guacamole/" +echo " 2. Change admin password immediately" +echo " 3. Re-create RDP connections (Settings > Connections)" +echo " 4. Set up NPM proxy: guac.hideawaygaming.com.au" +echo " Forward: http://${CT_IP_CLEAN}:8080 (enable WebSocket!)" +echo " 5. Test all RDP connections" +echo " 6. Stop HA Guacamole add-on" +echo "" +echo " Docker management:" +echo " pct exec ${CT_ID} -- docker compose -f /opt/guacamole/docker-compose.yml logs -f" +echo " pct exec ${CT_ID} -- docker compose -f /opt/guacamole/docker-compose.yml restart" +echo "============================================"