#!/bin/bash # ct/mermaidjs.sh - Create and configure a self-hosted Mermaid.js editor LXC set -euo pipefail RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log() { echo -e "${GREEN}[$(date +%H:%M:%S)]${NC} $1"; } warn() { echo -e "${YELLOW}[$(date +%H:%M:%S)]${NC} $1"; } die() { echo -e "${RED}[$(date +%H:%M:%S)]${NC} $1"; exit 1; } # Ensure root on Proxmox if [[ $EUID -ne 0 ]]; then die "This script must be run as root on a Proxmox VE host" fi # Defaults LXC_HOSTNAME="mermaid" LXC_ID="" LXC_MEMORY=512 LXC_CORES=1 LXC_DISK="local-lvm" LXC_TEMPLATE="local:vztmpl/debian-12-standard_12.12-1_amd64.tar.zst" LXC_ROOT_PASSWORD="mermaid" LXC_IP="" LXC_NETMASK="24" LXC_GATEWAY="" LXC_BRIDGE="vmbr0" # Auto-increment VMID get_next_id() { local max=0 for id in $(pct list | awk 'NR>1 {print $1}'); do ((id > max)) && max=$id done echo $((max + 1)) } log "=== Mermaid.js Interactive Editor LXC Setup ===" log "This creates a self-hosted Mermaid editor with OFFLINE support." read -rp "Hostname (default: mermaid): " HOSTNAME_INPUT [[ -n "$HOSTNAME_INPUT" ]] && LXC_HOSTNAME="$HOSTNAME_INPUT" read -rp "Container ID (default: $(get_next_id)): " ID_INPUT LXC_ID=${ID_INPUT:-$(get_next_id)} read -rp "Memory (MB, default: 512): " MEM_INPUT LXC_MEMORY=${MEM_INPUT:-512} read -rp "CPU Cores (default: 1): " CORES_INPUT LXC_CORES=${CORES_INPUT:-1} read -rp "Root Password (default: mermaid): " PASS_INPUT LXC_ROOT_PASSWORD=${PASS_INPUT:-mermaid} read -rp "Disk Storage Pool (default: local-lvm): " DISK_INPUT LXC_DISK=${DISK_INPUT:-local-lvm} read -rp "Network Bridge (default: vmbr0): " BRIDGE_INPUT LXC_BRIDGE=${BRIDGE_INPUT:-vmbr0} read -rp "IP Address (e.g., 192.168.1.60; leave blank for DHCP): " IP_INPUT LXC_IP="$IP_INPUT" if [[ -n "$LXC_IP" ]]; then read -rp "Netmask (default: 24): " NETMASK_INPUT LXC_NETMASK=${NETMASK_INPUT:-24} read -rp "Gateway (blank for none): " GW_INPUT LXC_GATEWAY="$GW_INPUT" fi NET0_ARGS="name=eth0,bridge=$LXC_BRIDGE" if [[ -n "$LXC_IP" ]]; then NET0_ARGS="$NET0_ARGS,ip=$LXC_IP/$LXC_NETMASK" [[ -n "$LXC_GATEWAY" ]] && NET0_ARGS="$NET0_ARGS,gw=$LXC_GATEWAY" fi # Fail fast if bridge or disk don't exist pvesm status | grep -q "$LXC_DISK" || die "Storage pool '$LXC_BRIDGE' not found" ip link show "$LXC_BRIDGE" >/dev/null 2>&1 || die "Bridge '$LXC_BRIDGE' not found" # === 1. Create LXC Container === log "Creating LXC container $LXC_ID ($LXC_HOSTNAME)..." pct create $LXC_ID $LXC_TEMPLATE \ -hostname $LXC_HOSTNAME \ -memory $LXC_MEMORY \ -cores $LXC_CORES \ -net0 $NET0_ARGS \ -rootfs $LXC_DISK:1 \ -ostype debian \ -password $LXC_ROOT_PASSWORD \ -onboot 1 # === 2. Start & wait for boot === log "Starting container..." pct start $LXC_ID log "Waiting for container to be reachable..." for i in {1..40}; do if pct exec $LXC_ID -- sh -c "ping -c1 127.0.0.1 >/dev/null 2>&1"; then break fi sleep 1 done # === 3. Prepare install script (bundled offline Mermaid) === log "Deploying Mermaid editor + Caddy..." # Generate the install script dynamically (with bundled mermaid.min.js) pct push $LXC_ID - <<'EOF' /root/mermaid-install.sh #!/bin/bash set -euo pipefail GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log() { echo -e "${GREEN}[$(date +%H:%M:%S)]${NC} $1"; } # 1. Update & install Caddy & deps log "Updating system..." apt-get update -qq apt-get install -y -qq curl wget # 2. Download Mermaid.min.js (offline bundled) log "Downloading Mermaid v10.6.1 (offline)..." mkdir -p /var/www/mermaid wget -q https://cdn.jsdelivr.net/npm/mermaid@10.6.1/dist/mermaid.min.js -O /var/www/mermaid/mermaid.min.js # 3. Create the editor HTML (self-contained: editor + preview + Mermaid JS) log "Creating Mermaid editor interface..." cat > /var/www/mermaid/index.html <<'HTML' Self-hosted Mermaid Editor
HTML # 4. Caddy config (HTTP only — easy; HTTPS in comment) cat > /etc/caddy/Caddyfile <<'CADDY' :80 { root * /var/www/mermaid file_server log { output file /var/log/caddy/access.log } } # Uncomment below for Let's Encrypt HTTPS # mermaid.yourdomain.com { # root * /var/www/mermaid # file_server # } CADDY # 5. Start & enable Caddy rc-service caddy start rc-update add caddy # 6. Check if Caddy started sleep 5 if curl -sf http://localhost >/dev/null; then log "✅ Mermaid Editor is live!" else warn "Caddy failed — check 'rc-service caddy status' and 'journalctl -u caddy'" exit 1 fi # 7. Summary IP=$(hostname -I 2>/dev/null | cut -d' ' -f1) if [[ -z "$IP" ]]; then IP=$(ip -4 addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}') fi log "URL: ${BLUE}http://${IP}${NC}" log "Root password: ${YELLOW}$LXC_ROOT_PASSWORD${NC}" log "SSH: ssh root@${IP}" EOF # Push & run the install script inside LXC log "Installing Mermaid editor..." pct exec $LXC_ID -- bash /root/mermaid-install.sh # === 4. Final summary === IP=$(pct exec $LXC_ID -- hostname -I 2>/dev/null | cut -d' ' -f1) [[ -z "$IP" ]] && IP=$(pct exec $LXC_ID -- ip -4 addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}') log "✅ Mermaid Editor LXC ($LXC_ID) ready!" log "URL: ${BLUE}http://${IP}${NC}" log "Root password: ${YELLOW}$LXC_ROOT_PASSWORD${NC}"