Files
OPENBUREAU/cms/proxmox/create-openbureau-lxc.sh
T
karim 60e5ef6844 cms: headless CMS vor Hugo (Supabase + Node-API + React-Admin)
All-in-One docker-compose-Stack (Muster von RAPPORT-SERVER gespiegelt):
db/auth/rest/kong + cms-Service (Node-API + Hugo-Binary 0.161.1 + Admin-SPA).

- DB-backed: posts-Tabelle kanonisch, MD ist generiertes Artefakt
- echte Hugo-Vorschau via draft:true + --buildDrafts → /_preview
- Publish: DB → content/library/<section>/<slug>.md → hugo build → live
- Bild-Upload nach static/images/, Supabase-Auth schützt /api/*
- Proxmox-LXC-Script: legt Container an, generiert Secrets, startet Stack

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 00:21:04 +02:00

168 lines
5.7 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# OPENBUREAU — All-in-One LXC für Proxmox VE (Supabase-Kern + CMS).
#
# AUSFÜHREN AUF DEM PROXMOX-HOST (nicht im Container), als root:
# bash create-openbureau-lxc.sh
#
# Legt einen unprivileged Debian-12-LXC an (Docker-fähig: nesting + keyctl),
# installiert Docker, zieht das Repo, generiert alle Secrets (POSTGRES_PASSWORD,
# JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY) und befüllt die .env. Optional baut
# und startet es den Stack direkt.
set -euo pipefail
############################ CONFIG ############################
CTID="${CTID:-$(pvesh get /cluster/nextid)}"
HOSTNAME="openbureau"
# Storage
TEMPLATE_STORAGE="local"
ROOTFS_STORAGE="local-lvm"
DISK_GB="20" # Supabase + CMS
# Ressourcen
RAM_MB="4096"
SWAP_MB="1024"
CORES="2"
# Netzwerk
BRIDGE="vmbr0"
IP="dhcp" # "dhcp" ODER statisch z.B. "192.168.1.50/24"
GATEWAY="" # nur bei statischer IP
# Zugang
SSH_PUBKEY_FILE="${SSH_PUBKEY_FILE:-$HOME/.ssh/id_ed25519.pub}"
ROOT_PASSWORD=""
# Repo (privates Gitea!). Für den Clone im frischen LXC ein Deploy-Token setzen:
GIT_TOKEN="${GIT_TOKEN:-}" # z.B. "tokenname:tokenwert"
REPO_HOST="git.kgva.ch/karim/OPENBUREAU.git"
APP_DIR="/opt/openbureau"
# Stack nach dem Setup direkt bauen + starten?
COMPOSE_UP="true"
##################################################################
say() { echo -e "\n\033[1;36m▸ $*\033[0m"; }
# --- 1. Template sicherstellen -------------------------------------------
say "Suche aktuelles Debian-12-Template…"
pveam update >/dev/null || true
TEMPLATE="$(pveam available --section system \
| awk '/debian-12-standard/{print $2}' | sort -V | tail -1)"
[ -n "$TEMPLATE" ] || { echo "Kein debian-12-Template gefunden."; exit 1; }
if ! pveam list "$TEMPLATE_STORAGE" | grep -q "$TEMPLATE"; then
say "Lade Template $TEMPLATE"
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE"
fi
TEMPLATE_REF="${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}"
# --- 2. Netzwerk ----------------------------------------------------------
if [ "$IP" = "dhcp" ]; then
NET="name=eth0,bridge=${BRIDGE},ip=dhcp"
else
[ -n "$GATEWAY" ] || { echo "Statische IP, aber GATEWAY leer."; exit 1; }
NET="name=eth0,bridge=${BRIDGE},ip=${IP},gw=${GATEWAY}"
fi
# --- 3. Container erstellen ----------------------------------------------
say "Erstelle LXC $CTID ($HOSTNAME)…"
CREATE_ARGS=(
"$CTID" "$TEMPLATE_REF"
--hostname "$HOSTNAME"
--cores "$CORES" --memory "$RAM_MB" --swap "$SWAP_MB"
--rootfs "${ROOTFS_STORAGE}:${DISK_GB}"
--net0 "$NET"
--unprivileged 1
--features "nesting=1,keyctl=1"
--onboot 1
)
[ -n "$ROOT_PASSWORD" ] && CREATE_ARGS+=(--password "$ROOT_PASSWORD")
[ -f "$SSH_PUBKEY_FILE" ] && CREATE_ARGS+=(--ssh-public-keys "$SSH_PUBKEY_FILE")
pct create "${CREATE_ARGS[@]}"
say "Starte Container…"
pct start "$CTID"
sleep 5
# Clone-URL (mit Token, falls gesetzt)
if [ -n "$GIT_TOKEN" ]; then
REPO_URL="https://${GIT_TOKEN}@${REPO_HOST}"
else
REPO_URL="https://${REPO_HOST}"
fi
# --- 4. Provisionierung im Container -------------------------------------
say "Installiere Docker + Git, ziehe Repo, generiere Secrets…"
pct exec "$CTID" -- bash -euo pipefail -c "
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y -qq ca-certificates curl git openssl >/dev/null
curl -fsSL https://get.docker.com | sh >/dev/null
systemctl enable --now docker
if [ ! -d '${APP_DIR}/.git' ]; then
git clone --quiet '${REPO_URL}' '${APP_DIR}' || {
echo 'WARN: Clone fehlgeschlagen (Token nötig?). Setup hier gestoppt.'; exit 0; }
fi
cd '${APP_DIR}/cms'
if [ ! -f .env ]; then
cp .env.example .env
# Secrets generieren
PW=\$(openssl rand -hex 32)
JWT=\$(openssl rand -hex 32)
sed -i \"s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=\${PW}|\" .env
sed -i \"s|^JWT_SECRET=.*|JWT_SECRET=\${JWT}|\" .env
# ANON_KEY + SERVICE_ROLE_KEY via Wegwerf-Node-Container ableiten
KEYS=\$(docker run --rm -v \"\$PWD\":/w -w /w node:20-alpine \
node scripts/generate-keys.mjs \"\$JWT\" 2>/dev/null)
ANON=\$(echo \"\$KEYS\" | sed -n 's/^ANON_KEY=//p')
SVC=\$(echo \"\$KEYS\" | sed -n 's/^SERVICE_ROLE_KEY=//p')
sed -i \"s|^ANON_KEY=.*|ANON_KEY=\${ANON}|\" .env
sed -i \"s|^SERVICE_ROLE_KEY=.*|SERVICE_ROLE_KEY=\${SVC}|\" .env
# URLs auf die Container-IP setzen
HOSTIP=\$(hostname -I | awk '{print \$1}')
sed -i \"s|^SITE_URL=.*|SITE_URL=http://\${HOSTIP}:8080|\" .env
sed -i \"s|^API_EXTERNAL_URL=.*|API_EXTERNAL_URL=http://\${HOSTIP}:8000|\" .env
echo 'OK: .env generiert.'
fi
if [ '${COMPOSE_UP}' = 'true' ]; then
echo '→ Baue + starte Stack (dauert beim ersten Mal ein paar Minuten)…'
docker compose up -d --build
fi
"
# --- 5. Abschluss --------------------------------------------------------
IPADDR="$(pct exec "$CTID" -- hostname -I 2>/dev/null | awk '{print $1}')"
say "Fertig. LXC $CTID läuft${IPADDR:+ unter $IPADDR}."
cat <<EOF
Admin: http://${IPADDR:-<ip>}:8080/admin/
Live: http://${IPADDR:-<ip>}:8080/
Supabase: http://${IPADDR:-<ip>}:8000
Login-User anlegen (im Container, nach dem Start):
pct enter ${CTID}
cd ${APP_DIR}/cms
source .env
curl -s -X POST "http://localhost:8000/auth/v1/admin/users" \\
-H "apikey: \$SERVICE_ROLE_KEY" \\
-H "Authorization: Bearer \$SERVICE_ROLE_KEY" \\
-H "Content-Type: application/json" \\
-d '{"email":"karim@gabrielevarano.ch","password":"DEIN-PASSWORT","email_confirm":true}'
Hinweise:
• Privates Repo: GIT_TOKEN oben setzen (Format "tokenname:tokenwert"),
sonst schlägt der Clone fehl.
• Für Domain/HTTPS: SITE_URL + API_EXTERNAL_URL in .env auf die
öffentliche Adresse setzen und 'docker compose up -d --build' neu.
• Logs: pct enter ${CTID}; cd ${APP_DIR}/cms; docker compose logs -f
EOF