proxmox: Selbsthosting-Set (Dialog-Suite + Einzelskripte) + 2 Artikel
Geführter Installer proxmox/install.sh: erst Vorhaben wählen (Komplettes Büro / 365+Synology ersetzen / nur Website / einzeln), dann werden die nötigen LXCs der Reihe nach gebaut. Jeder Dienst ist auch als eigenständiges, einzeln curlbares Skript verfügbar: - proxmox/nextcloud-lxc.sh Nextcloud AIO (ersetzt 365/Synology) - proxmox/empty-lxc.sh leerer Docker-LXC als Geruest - proxmox/git-compose-lxc.sh beliebiges Git-Repo (RAPPORT/DOSSIER) - (OPENBUREAU: bestehendes cms/proxmox/create-openbureau-lxc.sh) Gemeinsames Muster: unprivilegierter Debian-12-LXC mit nesting+keyctl, Docker via get.docker.com, Dienst als Container/Compose. proxmox/README.md dokumentiert beide Wege. Dazu zwei Bibliotheksbeitraege (Hochparterre-Ton): - server-im-eigenen-haus.md — das Warum/Ziel - proxmox-schritt-fuer-schritt.md — die Anleitung mit curl-Befehlen Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
# OPENBUREAU — Proxmox-Selbsthosting-Set
|
||||
|
||||
Skripte, um die Dienste eines Architekturbüros auf einem Proxmox-VE-Host
|
||||
aufzusetzen — jeder Dienst in seinem eigenen, unprivilegierten, Docker-tauglichen
|
||||
LXC. Alle Skripte werden **auf dem Proxmox-Host als `root`** ausgeführt.
|
||||
|
||||
## Zwei Wege
|
||||
|
||||
**1. Suite mit Dialog** — fragt, was man will, und installiert einen LXC nach dem
|
||||
anderen:
|
||||
|
||||
```bash
|
||||
bash <(curl -fsSL https://git.kgva.ch/karim/OPENBUREAU/raw/branch/main/proxmox/install.sh)
|
||||
```
|
||||
|
||||
**2. Einzelskripte** (für Fortgeschrittene) — direkt, ohne Menü. Jedes ist in sich
|
||||
geschlossen:
|
||||
|
||||
```bash
|
||||
# Website + CMS (eigenes Skript, erzeugt alle Supabase-Secrets)
|
||||
bash <(curl -fsSL …/cms/proxmox/create-openbureau-lxc.sh)
|
||||
|
||||
# Nextcloud (Dateien/Kalender/Kontakte/Office — ersetzt 365 + Synology)
|
||||
bash <(curl -fsSL …/proxmox/nextcloud-lxc.sh) [disk_gb] [ram_mb]
|
||||
|
||||
# Leerer Docker-LXC als Gerüst
|
||||
bash <(curl -fsSL …/proxmox/empty-lxc.sh) [name] [disk_gb] [ram_mb]
|
||||
|
||||
# Beliebiger Dienst aus einem Git-Repo mit docker-compose (RAPPORT, DOSSIER …)
|
||||
bash <(curl -fsSL …/proxmox/git-compose-lxc.sh) <repo-url> [name] [disk_gb] [ram_mb]
|
||||
```
|
||||
|
||||
`install.sh` akzeptiert dieselben Dienste auch direkt als Argument
|
||||
(`install.sh nextcloud`, `install.sh git <repo> …`).
|
||||
|
||||
## Gemeinsames Muster
|
||||
|
||||
Jedes Skript macht dasselbe: aktuelles Debian-12-Template sicherstellen,
|
||||
unprivilegierten LXC mit `nesting=1,keyctl=1` anlegen (damit Docker darin läuft),
|
||||
Docker installieren, den Dienst als Container/Compose-Stack starten. Storage, Netz
|
||||
und SSH-Key lassen sich per Umgebungsvariable überschreiben:
|
||||
|
||||
| Variable | Default |
|
||||
|--------------------|--------------------------|
|
||||
| `ROOTFS_STORAGE` | `local-lvm` |
|
||||
| `TEMPLATE_STORAGE` | `local` |
|
||||
| `BRIDGE` | `vmbr0` |
|
||||
| `SSH_PUBKEY_FILE` | `~/.ssh/id_ed25519.pub` |
|
||||
|
||||
## Hintergrund
|
||||
|
||||
Warum und wie — die zwei Artikel in der Bibliothek:
|
||||
[Server im eigenen Haus](https://openbureau.ch/library/software/server-im-eigenen-haus/)
|
||||
und [Proxmox, Schritt für Schritt](https://openbureau.ch/library/software/proxmox-schritt-fuer-schritt/).
|
||||
Executable
+74
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Leerer, Docker-tauglicher LXC für Proxmox VE — das Gerüst für eigene Dienste.
|
||||
#
|
||||
# AUF DEM PROXMOX-HOST, als root:
|
||||
# bash <(curl -fsSL https://git.kgva.ch/karim/OPENBUREAU/raw/branch/main/proxmox/empty-lxc.sh) [name] [disk_gb] [ram_mb]
|
||||
#
|
||||
# Beispiel: … empty-lxc.sh dateien 200 8192
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
############################# gemeinsamer Kopf #############################
|
||||
SSH_PUBKEY_FILE="${SSH_PUBKEY_FILE:-$HOME/.ssh/id_ed25519.pub}"
|
||||
ROOTFS_STORAGE="${ROOTFS_STORAGE:-local-lvm}"
|
||||
TEMPLATE_STORAGE="${TEMPLATE_STORAGE:-local}"
|
||||
BRIDGE="${BRIDGE:-vmbr0}"
|
||||
|
||||
say() { echo -e "\n\033[1;36m▸ $*\033[0m"; }
|
||||
ok() { echo -e "\033[1;32m✓ $*\033[0m"; }
|
||||
warn() { echo -e "\033[1;33m! $*\033[0m" >&2; }
|
||||
die() { echo -e "\033[1;31m✗ $*\033[0m" >&2; exit 1; }
|
||||
|
||||
[ "$(id -u)" -eq 0 ] || die "Bitte als root auf dem Proxmox-Host ausführen."
|
||||
command -v pct >/dev/null || die "pct nicht gefunden — läuft das wirklich auf Proxmox VE?"
|
||||
|
||||
ensure_template() {
|
||||
[ -n "${TEMPLATE_REF:-}" ] && return 0
|
||||
pveam update >/dev/null 2>&1 || true
|
||||
local tpl
|
||||
tpl="$(pveam available --section system | awk '/debian-12-standard/{print $2}' | sort -V | tail -1)"
|
||||
[ -n "$tpl" ] || die "Kein debian-12-Template verfügbar."
|
||||
pveam list "$TEMPLATE_STORAGE" | grep -q "$tpl" || { say "Lade Template $tpl…"; pveam download "$TEMPLATE_STORAGE" "$tpl" >/dev/null; }
|
||||
TEMPLATE_REF="${TEMPLATE_STORAGE}:vztmpl/${tpl}"
|
||||
}
|
||||
|
||||
# create_lxc <name> <disk_gb> <ram_mb> [cores] — setzt $CTID
|
||||
create_lxc() {
|
||||
local name="$1" disk="$2" ram="$3" cores="${4:-2}" ctid
|
||||
ensure_template
|
||||
ctid="$(pvesh get /cluster/nextid)"
|
||||
local args=(
|
||||
"$ctid" "$TEMPLATE_REF" --hostname "$name"
|
||||
--cores "$cores" --memory "$ram" --swap 1024
|
||||
--rootfs "${ROOTFS_STORAGE}:${disk}"
|
||||
--net0 "name=eth0,bridge=${BRIDGE},ip=dhcp"
|
||||
--unprivileged 1 --features "nesting=1,keyctl=1" --onboot 1
|
||||
)
|
||||
[ -f "$SSH_PUBKEY_FILE" ] && args+=(--ssh-public-keys "$SSH_PUBKEY_FILE")
|
||||
say "Erstelle LXC $ctid ($name) — ${cores} Kerne, ${ram} MB RAM, ${disk} GB…"
|
||||
pct create "${args[@]}" >/dev/null
|
||||
pct start "$ctid"; sleep 5
|
||||
CTID="$ctid"
|
||||
}
|
||||
|
||||
install_docker() {
|
||||
say "Installiere Docker in $1…"
|
||||
pct exec "$1" -- 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
|
||||
'
|
||||
}
|
||||
|
||||
ip_of() { pct exec "$1" -- hostname -I 2>/dev/null | awk '{print $1}'; }
|
||||
|
||||
################################# Dienst #################################
|
||||
NAME="${1:-docker}"; DISK="${2:-20}"; RAM="${3:-4096}"
|
||||
|
||||
create_lxc "$NAME" "$DISK" "$RAM"
|
||||
install_docker "$CTID"
|
||||
ok "Leerer Docker-LXC $CTID ($NAME) läuft unter $(ip_of "$CTID")."
|
||||
echo " Hinein: pct enter $CTID"
|
||||
Executable
+93
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Beliebiger self-hosted Dienst aus einem Git-Repo mit docker-compose, als
|
||||
# eigener LXC für Proxmox VE. Folgt demselben Muster wie OPENBUREAU — passend
|
||||
# für eigene Werkzeuge wie RAPPORT oder DOSSIER.
|
||||
#
|
||||
# AUF DEM PROXMOX-HOST, als root:
|
||||
# bash <(curl -fsSL https://git.kgva.ch/karim/OPENBUREAU/raw/branch/main/proxmox/git-compose-lxc.sh) <repo-url> [name] [disk_gb] [ram_mb]
|
||||
#
|
||||
# Beispiel: … git-compose-lxc.sh git.kgva.ch/karim/RAPPORT-SERVER.git rapport
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
############################# gemeinsamer Kopf #############################
|
||||
SSH_PUBKEY_FILE="${SSH_PUBKEY_FILE:-$HOME/.ssh/id_ed25519.pub}"
|
||||
ROOTFS_STORAGE="${ROOTFS_STORAGE:-local-lvm}"
|
||||
TEMPLATE_STORAGE="${TEMPLATE_STORAGE:-local}"
|
||||
BRIDGE="${BRIDGE:-vmbr0}"
|
||||
|
||||
say() { echo -e "\n\033[1;36m▸ $*\033[0m"; }
|
||||
ok() { echo -e "\033[1;32m✓ $*\033[0m"; }
|
||||
warn() { echo -e "\033[1;33m! $*\033[0m" >&2; }
|
||||
die() { echo -e "\033[1;31m✗ $*\033[0m" >&2; exit 1; }
|
||||
|
||||
[ "$(id -u)" -eq 0 ] || die "Bitte als root auf dem Proxmox-Host ausführen."
|
||||
command -v pct >/dev/null || die "pct nicht gefunden — läuft das wirklich auf Proxmox VE?"
|
||||
|
||||
ensure_template() {
|
||||
[ -n "${TEMPLATE_REF:-}" ] && return 0
|
||||
pveam update >/dev/null 2>&1 || true
|
||||
local tpl
|
||||
tpl="$(pveam available --section system | awk '/debian-12-standard/{print $2}' | sort -V | tail -1)"
|
||||
[ -n "$tpl" ] || die "Kein debian-12-Template verfügbar."
|
||||
pveam list "$TEMPLATE_STORAGE" | grep -q "$tpl" || { say "Lade Template $tpl…"; pveam download "$TEMPLATE_STORAGE" "$tpl" >/dev/null; }
|
||||
TEMPLATE_REF="${TEMPLATE_STORAGE}:vztmpl/${tpl}"
|
||||
}
|
||||
|
||||
create_lxc() {
|
||||
local name="$1" disk="$2" ram="$3" cores="${4:-2}" ctid
|
||||
ensure_template
|
||||
ctid="$(pvesh get /cluster/nextid)"
|
||||
local args=(
|
||||
"$ctid" "$TEMPLATE_REF" --hostname "$name"
|
||||
--cores "$cores" --memory "$ram" --swap 1024
|
||||
--rootfs "${ROOTFS_STORAGE}:${disk}"
|
||||
--net0 "name=eth0,bridge=${BRIDGE},ip=dhcp"
|
||||
--unprivileged 1 --features "nesting=1,keyctl=1" --onboot 1
|
||||
)
|
||||
[ -f "$SSH_PUBKEY_FILE" ] && args+=(--ssh-public-keys "$SSH_PUBKEY_FILE")
|
||||
say "Erstelle LXC $ctid ($name) — ${cores} Kerne, ${ram} MB RAM, ${disk} GB…"
|
||||
pct create "${args[@]}" >/dev/null
|
||||
pct start "$ctid"; sleep 5
|
||||
CTID="$ctid"
|
||||
}
|
||||
|
||||
install_docker() {
|
||||
say "Installiere Docker in $1…"
|
||||
pct exec "$1" -- 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
|
||||
'
|
||||
}
|
||||
|
||||
ip_of() { pct exec "$1" -- hostname -I 2>/dev/null | awk '{print $1}'; }
|
||||
|
||||
################################# Dienst #################################
|
||||
REPO="${1:-}"; NAME="${2:-}"; DISK="${3:-20}"; RAM="${4:-4096}"
|
||||
[ -n "$REPO" ] || die "Bitte eine Repo-URL angeben (Arg 1)."
|
||||
[ -n "$NAME" ] || NAME="$(basename "${REPO%.git}" | tr '[:upper:]' '[:lower:]')"
|
||||
case "$REPO" in http*://*) : ;; *) REPO="https://$REPO" ;; esac
|
||||
|
||||
create_lxc "$NAME" "$DISK" "$RAM"
|
||||
install_docker "$CTID"
|
||||
|
||||
say "Klone $REPO und starte den Stack…"
|
||||
pct exec "$CTID" -- bash -euo pipefail -c "
|
||||
git clone --quiet '$REPO' '/opt/$NAME' || { echo 'Clone fehlgeschlagen.'; exit 1; }
|
||||
cd '/opt/$NAME'
|
||||
CF=\$(ls docker-compose.y*ml compose.y*ml */docker-compose.y*ml */compose.y*ml 2>/dev/null | head -1)
|
||||
[ -n \"\$CF\" ] || { echo 'Keine docker-compose-Datei gefunden.'; exit 1; }
|
||||
cd \"\$(dirname \"\$CF\")\"
|
||||
if [ ! -f .env ] && [ -f .env.example ]; then
|
||||
cp .env.example .env
|
||||
echo 'HINWEIS: .env aus .env.example kopiert — Secrets ggf. anpassen.'
|
||||
fi
|
||||
docker compose up -d --build
|
||||
"
|
||||
|
||||
ok "$NAME (LXC $CTID) läuft unter $(ip_of "$CTID")."
|
||||
warn "App-spezifische Secrets (.env) ggf. prüfen: pct enter $CTID"
|
||||
Executable
+133
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# OPENBUREAU-Suite — der Dialog-Installer für das Selbsthosting-Set auf Proxmox.
|
||||
#
|
||||
# Fragt im Dialog, welche Dienste man will, und installiert dann einen LXC nach
|
||||
# dem anderen — jeder über sein eigenes, eigenständiges Skript (proxmox/*-lxc.sh).
|
||||
# Fortgeschrittene können diese Einzelskripte auch direkt curlen, ohne die Suite.
|
||||
#
|
||||
# AUF DEM PROXMOX-HOST (nicht im Container), als root:
|
||||
# bash <(curl -fsSL https://git.kgva.ch/karim/OPENBUREAU/raw/branch/main/proxmox/install.sh)
|
||||
#
|
||||
# Direkt, ohne Dialog:
|
||||
# … install.sh openbureau
|
||||
# … install.sh nextcloud [disk_gb] [ram_mb]
|
||||
# … install.sh empty [name] [disk_gb] [ram_mb]
|
||||
# … install.sh git <repo-url> [name] [disk_gb] [ram_mb]
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
RAW="https://git.kgva.ch/karim/OPENBUREAU/raw/branch/main"
|
||||
|
||||
say() { echo -e "\n\033[1;36m▸ $*\033[0m"; }
|
||||
die() { echo -e "\033[1;31m✗ $*\033[0m" >&2; exit 1; }
|
||||
|
||||
[ "$(id -u)" -eq 0 ] || die "Bitte als root auf dem Proxmox-Host ausführen."
|
||||
command -v pct >/dev/null || die "pct nicht gefunden — läuft das wirklich auf Proxmox VE?"
|
||||
|
||||
# Jeder Dienst = ein eigenständiges Skript. Die Suite ruft sie nur auf.
|
||||
run_service() {
|
||||
local svc="$1"; shift || true
|
||||
case "$svc" in
|
||||
openbureau) say "OPENBUREAU — Website + CMS…"; bash <(curl -fsSL "$RAW/cms/proxmox/create-openbureau-lxc.sh") ;;
|
||||
nextcloud) say "Nextcloud…"; bash <(curl -fsSL "$RAW/proxmox/nextcloud-lxc.sh") "$@" ;;
|
||||
empty) say "Leerer Docker-LXC…"; bash <(curl -fsSL "$RAW/proxmox/empty-lxc.sh") "$@" ;;
|
||||
git) say "Git-Compose-Dienst…"; bash <(curl -fsSL "$RAW/proxmox/git-compose-lxc.sh") "$@" ;;
|
||||
*) die "Unbekannter Dienst: $svc" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Stufe 1: Vorhaben. schlüssel | Beschreibung | Liste der Dienste
|
||||
# (Sonderfall "custom" → Einzelauswahl, siehe service_checklist.)
|
||||
PROFILES=(
|
||||
"buero|Komplettes Büro einrichten — Website/CMS + Nextcloud|openbureau nextcloud"
|
||||
"cloud|Office 365 + Synology ersetzen — nur Nextcloud|nextcloud"
|
||||
"web|Nur die öffentliche Website + CMS|openbureau"
|
||||
"custom|Einzeln auswählen … (für Fortgeschrittene)|custom"
|
||||
)
|
||||
|
||||
# Stufe 2 (custom): einzelne Dienste. schlüssel | Beschreibung
|
||||
SERVICES=(
|
||||
"openbureau|OPENBUREAU — Website + CMS (Hugo + Supabase)"
|
||||
"nextcloud|Nextcloud — Dateien, Kalender, Kontakte, Office (ersetzt 365/Synology)"
|
||||
"empty|Leerer Docker-LXC — Gerüst für eigene Dienste"
|
||||
"git|Git-Compose-Dienst — eigenes Repo (z. B. RAPPORT / DOSSIER)"
|
||||
)
|
||||
|
||||
# Holt für die interaktive Auswahl die Zusatzangaben (Repo-URL, Name) nach.
|
||||
run_from_menu() {
|
||||
case "$1" in
|
||||
git)
|
||||
local repo name
|
||||
read -rp " Repo-URL (z. B. git.kgva.ch/karim/RAPPORT-SERVER.git): " repo
|
||||
[ -n "$repo" ] || { echo " übersprungen (keine URL)."; return 0; }
|
||||
read -rp " Name [auto]: " name
|
||||
run_service git "$repo" "$name" ;;
|
||||
empty)
|
||||
local name
|
||||
read -rp " Name des Containers [docker]: " name
|
||||
run_service empty "${name:-docker}" ;;
|
||||
*) run_service "$1" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Stufe 2: Einzelauswahl der Dienste (Checkliste).
|
||||
service_checklist() {
|
||||
local choices=()
|
||||
if command -v whiptail >/dev/null && [ -t 0 ]; then
|
||||
local items=()
|
||||
for s in "${SERVICES[@]}"; do items+=("${s%%|*}" "${s#*|}" OFF); done
|
||||
local sel
|
||||
sel="$(whiptail --title "OPENBUREAU — Dienste auswählen" \
|
||||
--checklist "Mit der Leertaste auswählen, Enter bestätigt:" 20 78 ${#SERVICES[@]} \
|
||||
"${items[@]}" 3>&1 1>&2 2>&3)" || { echo "Abgebrochen."; exit 0; }
|
||||
eval "choices=($sel)" # whiptail liefert die Tags in Anführungszeichen
|
||||
else
|
||||
echo "Welche Dienste installieren? (Nummern mit Komma/Leerzeichen, Enter = nichts)"
|
||||
local i=1
|
||||
for s in "${SERVICES[@]}"; do printf " %d) %s\n" "$i" "${s#*|}"; i=$((i+1)); done
|
||||
read -rp "Auswahl: " line
|
||||
for n in ${line//,/ }; do
|
||||
[ "$n" -ge 1 ] 2>/dev/null && [ "$n" -le "${#SERVICES[@]}" ] && choices+=("${SERVICES[$((n-1))]%%|*}")
|
||||
done
|
||||
fi
|
||||
[ "${#choices[@]}" -gt 0 ] || { echo "Nichts ausgewählt."; exit 0; }
|
||||
for c in "${choices[@]}"; do run_from_menu "$c"; done
|
||||
}
|
||||
|
||||
# Stufe 1: Vorhaben wählen, dann das passende Bündel installieren.
|
||||
choose_profile() {
|
||||
local key=""
|
||||
if command -v whiptail >/dev/null && [ -t 0 ]; then
|
||||
local items=() first=ON
|
||||
for p in "${PROFILES[@]}"; do items+=("${p%%|*}" "$(echo "$p" | cut -d'|' -f2)" "$first"); first=OFF; done
|
||||
key="$(whiptail --title "OPENBUREAU — Was hast du vor?" \
|
||||
--radiolist "Vorhaben wählen (Leertaste markiert, Enter bestätigt):" 20 78 ${#PROFILES[@]} \
|
||||
"${items[@]}" 3>&1 1>&2 2>&3)" || { echo "Abgebrochen."; exit 0; }
|
||||
else
|
||||
echo "Was hast du vor? (eine Nummer)"
|
||||
local i=1
|
||||
for p in "${PROFILES[@]}"; do printf " %d) %s\n" "$i" "$(echo "$p" | cut -d'|' -f2)"; i=$((i+1)); done
|
||||
read -rp "Auswahl [1]: " n; n="${n:-1}"
|
||||
[ "$n" -ge 1 ] 2>/dev/null && [ "$n" -le "${#PROFILES[@]}" ] || die "Ungültige Auswahl."
|
||||
key="${PROFILES[$((n-1))]%%|*}"
|
||||
fi
|
||||
|
||||
if [ "$key" = "custom" ]; then
|
||||
service_checklist
|
||||
else
|
||||
local svcs=""
|
||||
for p in "${PROFILES[@]}"; do [ "${p%%|*}" = "$key" ] && svcs="${p##*|}"; done
|
||||
say "Vorhaben '$key': installiere -> $svcs"
|
||||
for s in $svcs; do run_service "$s"; done
|
||||
fi
|
||||
}
|
||||
|
||||
################################# Einstieg #################################
|
||||
if [ "$#" -gt 0 ]; then
|
||||
run_service "$@" # direkt, ohne Dialog
|
||||
else
|
||||
choose_profile # geführter Dialog: erst Vorhaben, dann Dienste
|
||||
fi
|
||||
say "Fertig. Alle ausgewählten Dienste sind durch."
|
||||
Executable
+93
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Nextcloud (All-in-One) als eigener LXC für Proxmox VE.
|
||||
# Dateien, Kalender, Kontakte, Office in einem verwalteten Container —
|
||||
# ersetzt OneDrive / Synology-Drive + Office 365.
|
||||
#
|
||||
# AUF DEM PROXMOX-HOST, als root:
|
||||
# bash <(curl -fsSL https://git.kgva.ch/karim/OPENBUREAU/raw/branch/main/proxmox/nextcloud-lxc.sh) [disk_gb] [ram_mb]
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
############################# gemeinsamer Kopf #############################
|
||||
SSH_PUBKEY_FILE="${SSH_PUBKEY_FILE:-$HOME/.ssh/id_ed25519.pub}"
|
||||
ROOTFS_STORAGE="${ROOTFS_STORAGE:-local-lvm}"
|
||||
TEMPLATE_STORAGE="${TEMPLATE_STORAGE:-local}"
|
||||
BRIDGE="${BRIDGE:-vmbr0}"
|
||||
|
||||
say() { echo -e "\n\033[1;36m▸ $*\033[0m"; }
|
||||
ok() { echo -e "\033[1;32m✓ $*\033[0m"; }
|
||||
warn() { echo -e "\033[1;33m! $*\033[0m" >&2; }
|
||||
die() { echo -e "\033[1;31m✗ $*\033[0m" >&2; exit 1; }
|
||||
|
||||
[ "$(id -u)" -eq 0 ] || die "Bitte als root auf dem Proxmox-Host ausführen."
|
||||
command -v pct >/dev/null || die "pct nicht gefunden — läuft das wirklich auf Proxmox VE?"
|
||||
|
||||
ensure_template() {
|
||||
[ -n "${TEMPLATE_REF:-}" ] && return 0
|
||||
pveam update >/dev/null 2>&1 || true
|
||||
local tpl
|
||||
tpl="$(pveam available --section system | awk '/debian-12-standard/{print $2}' | sort -V | tail -1)"
|
||||
[ -n "$tpl" ] || die "Kein debian-12-Template verfügbar."
|
||||
pveam list "$TEMPLATE_STORAGE" | grep -q "$tpl" || { say "Lade Template $tpl…"; pveam download "$TEMPLATE_STORAGE" "$tpl" >/dev/null; }
|
||||
TEMPLATE_REF="${TEMPLATE_STORAGE}:vztmpl/${tpl}"
|
||||
}
|
||||
|
||||
create_lxc() {
|
||||
local name="$1" disk="$2" ram="$3" cores="${4:-2}" ctid
|
||||
ensure_template
|
||||
ctid="$(pvesh get /cluster/nextid)"
|
||||
local args=(
|
||||
"$ctid" "$TEMPLATE_REF" --hostname "$name"
|
||||
--cores "$cores" --memory "$ram" --swap 1024
|
||||
--rootfs "${ROOTFS_STORAGE}:${disk}"
|
||||
--net0 "name=eth0,bridge=${BRIDGE},ip=dhcp"
|
||||
--unprivileged 1 --features "nesting=1,keyctl=1" --onboot 1
|
||||
)
|
||||
[ -f "$SSH_PUBKEY_FILE" ] && args+=(--ssh-public-keys "$SSH_PUBKEY_FILE")
|
||||
say "Erstelle LXC $ctid ($name) — ${cores} Kerne, ${ram} MB RAM, ${disk} GB…"
|
||||
pct create "${args[@]}" >/dev/null
|
||||
pct start "$ctid"; sleep 5
|
||||
CTID="$ctid"
|
||||
}
|
||||
|
||||
install_docker() {
|
||||
say "Installiere Docker in $1…"
|
||||
pct exec "$1" -- 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
|
||||
'
|
||||
}
|
||||
|
||||
ip_of() { pct exec "$1" -- hostname -I 2>/dev/null | awk '{print $1}'; }
|
||||
|
||||
################################# Dienst #################################
|
||||
# Grosszügig dimensioniert — hier leben die Bürodaten.
|
||||
DISK="${1:-500}"; RAM="${2:-8192}"
|
||||
|
||||
create_lxc nextcloud "$DISK" "$RAM"
|
||||
install_docker "$CTID"
|
||||
|
||||
say "Starte Nextcloud All-in-One (mastercontainer)…"
|
||||
pct exec "$CTID" -- bash -euo pipefail -c '
|
||||
docker run -d --name nextcloud-aio-mastercontainer --restart always \
|
||||
-p 8080:8080 -e APACHE_PORT=11000 \
|
||||
-v nextcloud_aio_mastercontainer:/mnt/docker-aio-config \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock:ro \
|
||||
nextcloud/all-in-one:latest >/dev/null
|
||||
'
|
||||
|
||||
IP="$(ip_of "$CTID")"
|
||||
ok "Nextcloud-LXC $CTID läuft."
|
||||
cat <<EOF
|
||||
|
||||
Einrichtung im Browser: https://${IP}:8080
|
||||
Dort Admin-Passwort + Domain setzen — Nextcloud startet dann die übrigen
|
||||
Container (Datenbank, Office, Talk …) selbst.
|
||||
|
||||
Ohne eigene Domain ist das vorerst nur im LAN erreichbar. Für den Zugriff
|
||||
von aussen einen Reverse-Proxy davorsetzen.
|
||||
EOF
|
||||
Reference in New Issue
Block a user