Initial commit: Nextcloud bare/Hansson → AIO migration toolkit
Scripts 01-05 voor sequentiële migratie: transfer, staging, upgrade-keten, AIO-install en DB-import. PostgreSQL + MySQL/MariaDB bronnen ondersteund. Proxmox/OPNSense VM-builder optioneel in proxmox/. README met 12 gotchas. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
# Lokale config met echte IP's, wachtwoorden en domeinen — nooit committen
|
||||
config.local.sh
|
||||
*.local.sh
|
||||
|
||||
# Logs en tijdelijke bestanden
|
||||
*.log
|
||||
.DS_Store
|
||||
Executable
+89
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env bash
|
||||
# 01-transfer.sh — Rsync bestanden + database-dump van bronserver naar doelserver.
|
||||
#
|
||||
# Wat het doet:
|
||||
# 1. Genereert SSH-key op doel en voegt die toe aan bron (authorized_keys)
|
||||
# 2. Rsynct NC-app, configs, crontabs → /root/staging/
|
||||
# 3. Maakt een database-dump op de bron (PostgreSQL of MySQL/MariaDB)
|
||||
# 4. Rsynct ncdata → TARGET_DATA_PATH (herstart-veilig via --partial)
|
||||
#
|
||||
# Herstart-veilig: rsync --partial; dit script is idempotent (delta op re-run).
|
||||
# Voortgang volgen: ssh <doel> 'tail -f /var/log/pull-source.log'
|
||||
|
||||
set -euo pipefail
|
||||
source "$(dirname "$0")/config.sh"
|
||||
log() { echo "[$(date '+%H:%M:%S')] $*"; }
|
||||
|
||||
# ── STAP 1: SSH-key op doel → bron ───────────────────────────────────────────
|
||||
log "SSH-key genereren op doel (indien nodig)..."
|
||||
ssh "${TARGET_SSH}" "test -f /root/.ssh/id_ed25519 || \
|
||||
ssh-keygen -t ed25519 -N '' -f /root/.ssh/id_ed25519 -C nc-migration-pull"
|
||||
|
||||
TARGETKEY=$(ssh "${TARGET_SSH}" "cat /root/.ssh/id_ed25519.pub")
|
||||
|
||||
log "Key toevoegen aan bron authorized_keys (indien nodig)..."
|
||||
ssh "${SOURCE_USER}@${SOURCE_HOST}" \
|
||||
"grep -qF '${TARGETKEY}' /root/.ssh/authorized_keys 2>/dev/null || \
|
||||
echo '${TARGETKEY}' >> /root/.ssh/authorized_keys"
|
||||
|
||||
log "Hostkey accepteren + verbinding testen van doel naar bron..."
|
||||
ssh "${TARGET_SSH}" "
|
||||
ssh-keyscan -H ${SOURCE_HOST} >> /root/.ssh/known_hosts 2>/dev/null
|
||||
ssh -o ConnectTimeout=10 ${SOURCE_USER}@${SOURCE_HOST} hostname
|
||||
"
|
||||
|
||||
# ── DB-dump commando samenstellen ────────────────────────────────────────────
|
||||
# AIO gebruikt PostgreSQL; als de bron MySQL/MariaDB is, wordt de DB later
|
||||
# geconverteerd via 'occ db:convert-type pgsql' (na de upgrade-keten, voor AIO-import).
|
||||
if [[ "${SOURCE_DB_TYPE}" == "mysql" ]]; then
|
||||
# Wachtwoord op de command line is niet ideaal maar werkt voor eenmalige migratie.
|
||||
# Alternatief: zet een .my.cnf op de bronserver met [mysqldump] credentials.
|
||||
DUMP_CMD="mysqldump -u '${SOURCE_DB_USER}' -p'${SOURCE_DB_PASS}' '${SOURCE_DB}' | gzip"
|
||||
else
|
||||
DUMP_CMD="sudo -u postgres pg_dump '${SOURCE_DB}' | gzip"
|
||||
fi
|
||||
|
||||
# ── STAP 2: Pull-script op doel plaatsen en starten ──────────────────────────
|
||||
log "pull-source.sh plaatsen op doel..."
|
||||
ssh "${TARGET_SSH}" "cat > /root/pull-source.sh" << EOF
|
||||
#!/bin/bash
|
||||
# Draait op doel. Log: /var/log/pull-source.log
|
||||
set -uo pipefail
|
||||
SRC="${SOURCE_USER}@${SOURCE_HOST}"
|
||||
{
|
||||
echo "===== START \$(date) ====="
|
||||
mkdir -p /root/staging/etc
|
||||
|
||||
echo "== 1/4 NC-app =="
|
||||
rsync -aHAX --numeric-ids --partial \
|
||||
\${SRC}:${SOURCE_NC_PATH}/ /root/staging/nextcloud-app/
|
||||
|
||||
echo "== 2/4 configs =="
|
||||
rsync -aH --numeric-ids \${SRC}:/etc/apache2/ /root/staging/etc/apache2/ 2>/dev/null || true
|
||||
rsync -aH --numeric-ids \${SRC}:/etc/php/ /root/staging/etc/php/ 2>/dev/null || true
|
||||
rsync -aH --numeric-ids \${SRC}:/etc/letsencrypt/ /root/staging/etc/letsencrypt/ 2>/dev/null || true
|
||||
rsync -aH --numeric-ids \${SRC}:/var/scripts/ /root/staging/var-scripts/ 2>/dev/null || true
|
||||
ssh \${SRC} 'crontab -l' > /root/staging/crontab-root.txt 2>/dev/null || true
|
||||
ssh \${SRC} 'crontab -u www-data -l' > /root/staging/crontab-www-data.txt 2>/dev/null || true
|
||||
|
||||
echo "== 3/4 database dump (${SOURCE_DB_TYPE}: ${SOURCE_DB}) =="
|
||||
ssh \${SRC} '${DUMP_CMD}' > /root/staging/${SOURCE_DB}-\$(date +%F).sql.gz
|
||||
ls -lh /root/staging/${SOURCE_DB}-*.sql.gz | tail -1
|
||||
|
||||
echo "== 4/4 ncdata =="
|
||||
rsync -aHAX --numeric-ids --partial --info=stats1 \
|
||||
\${SRC}:${SOURCE_DATA_PATH}/ ${TARGET_DATA_PATH}/
|
||||
|
||||
echo "===== KLAAR \$(date) ====="
|
||||
df -h ${TARGET_DATA_PATH}
|
||||
} >> /var/log/pull-source.log 2>&1
|
||||
EOF
|
||||
ssh "${TARGET_SSH}" "chmod +x /root/pull-source.sh"
|
||||
|
||||
# ── STAP 3: Starten met nohup ────────────────────────────────────────────────
|
||||
log "Transfer starten (nohup, herstart-veilig)..."
|
||||
ssh "${TARGET_SSH}" "nohup /root/pull-source.sh > /dev/null 2>&1 & echo PID: \$!"
|
||||
|
||||
log "✓ Transfer draait op de achtergrond."
|
||||
log " Voortgang: ssh <doel> 'tail -f /var/log/pull-source.log'"
|
||||
log " Schijfruimte: ssh <doel> 'df -h ${TARGET_DATA_PATH}'"
|
||||
Executable
+215
@@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env bash
|
||||
# 02-build-staging.sh — Bouwt de staging NC-stack op de doelserver.
|
||||
#
|
||||
# Doel: exact genoeg om 'occ upgrade' te kunnen draaien richting AIO-doelversie.
|
||||
# Apache luistert alleen op :80 intern; geen SSL.
|
||||
# Na geslaagde AIO-import: apt purge apache2 php8.3* postgresql mariadb-server
|
||||
#
|
||||
# Ondersteunt PostgreSQL en MySQL/MariaDB als brontype (SOURCE_DB_TYPE in config.sh).
|
||||
# AIO gebruikt altijd PostgreSQL. Bij MySQL-bron: na de upgrade-keten converteren
|
||||
# met 'occ db:convert-type pgsql' vóór 05-import.sh.
|
||||
#
|
||||
# Log op doel: /var/log/build-staging.log
|
||||
|
||||
set -euo pipefail
|
||||
source "$(dirname "$0")/config.sh"
|
||||
log() { echo "[$(date '+%H:%M:%S')] $*"; }
|
||||
|
||||
log "Staging stack bouwen op ${TARGET_SSH}..."
|
||||
|
||||
ssh "${TARGET_SSH}" bash -s << REMOTE
|
||||
set -euo pipefail
|
||||
log() { echo "[\$(date '+%H:%M:%S')] \$*"; }
|
||||
|
||||
# Config-variabelen (expanded door lokale shell)
|
||||
STAGING_DB="${STAGING_DB}"
|
||||
STAGING_DB_USER="${STAGING_DB_USER}"
|
||||
STAGING_DB_PASS="${STAGING_DB_PASS}"
|
||||
DB_TYPE="${SOURCE_DB_TYPE}"
|
||||
TARGET_DATA="${TARGET_DATA_PATH}"
|
||||
SOURCE_DB_NAME="${SOURCE_DB}"
|
||||
|
||||
{
|
||||
# ── 1. PHP 8.3 repo + pakketten ───────────────────────────────────────────────
|
||||
log "1/7 Pakketten installeren..."
|
||||
# Debian 13 levert PHP 8.4; NC v30 vereist max PHP 8.3 → sury.org repo.
|
||||
# Pas dit aan als je start vanaf NC v32+ (dan werkt PHP 8.4 wel).
|
||||
apt-get update -qq
|
||||
apt-get install -y curl ca-certificates lsb-release gnupg2 2>&1 | tail -1
|
||||
curl -fsSL https://packages.sury.org/php/apt.gpg \
|
||||
-o /etc/apt/keyrings/sury-php.gpg
|
||||
echo "deb [signed-by=/etc/apt/keyrings/sury-php.gpg] https://packages.sury.org/php/ \$(lsb_release -sc) main" \
|
||||
> /etc/apt/sources.list.d/sury-php.list
|
||||
apt-get update -qq
|
||||
|
||||
# PHP-extensies gemeenschappelijk
|
||||
PHP_COMMON="php8.3-fpm php8.3-cli php8.3-gd php8.3-curl php8.3-xml php8.3-zip
|
||||
php8.3-mbstring php8.3-intl php8.3-bcmath php8.3-gmp
|
||||
php8.3-imagick php8.3-redis php8.3-apcu php8.3-ldap php8.3-bz2"
|
||||
|
||||
if [[ "\$DB_TYPE" == "mysql" ]]; then
|
||||
apt-get install -y apache2 libapache2-mod-fcgid \
|
||||
mariadb-server \
|
||||
php8.3-mysql \
|
||||
\$PHP_COMMON redis-server 2>&1 | tail -3
|
||||
else
|
||||
apt-get install -y apache2 libapache2-mod-fcgid \
|
||||
postgresql \
|
||||
php8.3-pgsql \
|
||||
\$PHP_COMMON redis-server 2>&1 | tail -3
|
||||
fi
|
||||
|
||||
# ── 2. NC-app op zijn plek ────────────────────────────────────────────────────
|
||||
log "2/7 NC-app kopiëren naar /var/www/nextcloud..."
|
||||
rsync -a --delete /root/staging/nextcloud-app/ /var/www/nextcloud/
|
||||
chown -R www-data:www-data /var/www/nextcloud
|
||||
chmod -R 750 /var/www/nextcloud
|
||||
chown -R www-data:www-data "\$TARGET_DATA"
|
||||
|
||||
# ── 3. Database: aanmaken + dump restoren ────────────────────────────────────
|
||||
log "3/7 Database inrichten (\$DB_TYPE)..."
|
||||
|
||||
DUMP_FILE=\$(ls -t /root/staging/\${SOURCE_DB_NAME}-*.sql.gz 2>/dev/null | head -1)
|
||||
[ -z "\$DUMP_FILE" ] && { echo "FOUT: geen dump gevonden in /root/staging/"; exit 1; }
|
||||
log "Dump: \$DUMP_FILE (\$(du -sh "\$DUMP_FILE" | cut -f1))"
|
||||
|
||||
if [[ "\$DB_TYPE" == "mysql" ]]; then
|
||||
systemctl enable --now mariadb
|
||||
mysql -e "CREATE USER IF NOT EXISTS '\${STAGING_DB_USER}'@'localhost' IDENTIFIED BY '\${STAGING_DB_PASS}';" 2>/dev/null || true
|
||||
mysql -e "CREATE DATABASE IF NOT EXISTS \${STAGING_DB} CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;" 2>/dev/null || true
|
||||
mysql -e "GRANT ALL PRIVILEGES ON \${STAGING_DB}.* TO '\${STAGING_DB_USER}'@'localhost'; FLUSH PRIVILEGES;"
|
||||
log "Dump restoren naar MariaDB..."
|
||||
zcat "\$DUMP_FILE" | mysql -u "\$STAGING_DB_USER" -p"\$STAGING_DB_PASS" "\$STAGING_DB"
|
||||
else
|
||||
systemctl enable --now postgresql
|
||||
sudo -u postgres psql -tc "SELECT 1 FROM pg_roles WHERE rolname='\$STAGING_DB_USER'" | grep -q 1 || \
|
||||
sudo -u postgres psql -c "CREATE USER \${STAGING_DB_USER} WITH PASSWORD '\${STAGING_DB_PASS}';"
|
||||
sudo -u postgres psql -tc "SELECT 1 FROM pg_database WHERE datname='\$STAGING_DB'" | grep -q 1 || \
|
||||
sudo -u postgres createdb -O "\$STAGING_DB_USER" "\$STAGING_DB"
|
||||
log "Dump restoren naar PostgreSQL..."
|
||||
# Restore als de DB-user zodat tabeleigenaarschap direct klopt
|
||||
PGPASSWORD="\$STAGING_DB_PASS" zcat "\$DUMP_FILE" | \
|
||||
sudo -u postgres psql -U "\$STAGING_DB_USER" "\$STAGING_DB"
|
||||
fi
|
||||
|
||||
# ── 4. PHP-FPM pool ──────────────────────────────────────────────────────────
|
||||
log "4/7 PHP-FPM pool configureren..."
|
||||
cat > /etc/php/8.3/fpm/pool.d/nextcloud.conf << 'EOF'
|
||||
[nextcloud]
|
||||
user = www-data
|
||||
group = www-data
|
||||
listen = /run/php/php8.3-fpm.nextcloud.sock
|
||||
listen.owner = www-data
|
||||
listen.group = www-data
|
||||
listen.mode = 0660
|
||||
pm = dynamic
|
||||
pm.max_children = 20
|
||||
pm.start_servers = 3
|
||||
pm.min_spare_servers = 2
|
||||
pm.max_spare_servers = 10
|
||||
php_admin_value[memory_limit] = 512M
|
||||
php_admin_value[upload_max_filesize] = 10G
|
||||
php_admin_value[post_max_size] = 10G
|
||||
php_admin_value[max_execution_time] = 3600
|
||||
EOF
|
||||
rm -f /etc/php/8.3/fpm/pool.d/www.conf
|
||||
sed -i 's/^memory_limit.*/memory_limit = 512M/' /etc/php/8.3/cli/php.ini
|
||||
# apc.enable_cli=1 is vereist voor occ; zonder dit falen APCu-afhankelijke commando's stil
|
||||
grep -q "apc.enable_cli" /etc/php/8.3/cli/php.ini || echo "apc.enable_cli=1" >> /etc/php/8.3/cli/php.ini
|
||||
systemctl enable --now php8.3-fpm
|
||||
|
||||
# ── 5. Apache vhost (HTTP-only, intern) ──────────────────────────────────────
|
||||
log "5/7 Apache vhost configureren..."
|
||||
a2enmod proxy_fcgi setenvif rewrite headers env dir mime authz_core 2>/dev/null || true
|
||||
a2enconf php8.3-fpm 2>/dev/null || true
|
||||
cat > /etc/apache2/sites-available/nextcloud.conf << 'EOF'
|
||||
<VirtualHost *:80>
|
||||
ServerName _default_
|
||||
DocumentRoot /var/www/nextcloud
|
||||
|
||||
<Directory /var/www/nextcloud>
|
||||
Options +FollowSymlinks
|
||||
AllowOverride All
|
||||
Require all granted
|
||||
<IfModule mod_dav.c>
|
||||
Dav off
|
||||
</IfModule>
|
||||
</Directory>
|
||||
|
||||
<FilesMatch \.php$>
|
||||
SetHandler "proxy:unix:/run/php/php8.3-fpm.nextcloud.sock|fcgi://localhost"
|
||||
</FilesMatch>
|
||||
|
||||
ErrorLog \${APACHE_LOG_DIR}/nextcloud-error.log
|
||||
CustomLog \${APACHE_LOG_DIR}/nextcloud-access.log combined
|
||||
</VirtualHost>
|
||||
EOF
|
||||
a2dissite 000-default 2>/dev/null || true
|
||||
a2ensite nextcloud
|
||||
systemctl enable --now apache2
|
||||
apache2ctl configtest
|
||||
|
||||
# ── 6. config.php patchen voor staging ───────────────────────────────────────
|
||||
log "6/7 config.php patchen voor staging (geen SSL, intern)..."
|
||||
# config.php definieert \$CONFIG maar returnt het niet; gebruik require (niet include).
|
||||
if [[ "\$DB_TYPE" == "mysql" ]]; then
|
||||
DB_HOST="localhost"
|
||||
DB_PORT="3306"
|
||||
else
|
||||
DB_HOST="localhost"
|
||||
DB_PORT="5432"
|
||||
fi
|
||||
TARGET_IP=\$(hostname -I | awk '{print \$1}')
|
||||
|
||||
php8.3 -r "
|
||||
require '/var/www/nextcloud/config/config.php';
|
||||
\\\$CONFIG['trusted_domains'] = ['\$TARGET_IP', 'localhost'];
|
||||
\\\$CONFIG['overwrite.cli.url'] = 'http://\$TARGET_IP';
|
||||
\\\$CONFIG['overwriteprotocol'] = 'http';
|
||||
\\\$CONFIG['maintenance'] = false;
|
||||
\\\$CONFIG['dbhost'] = '\$DB_HOST';
|
||||
\\\$CONFIG['dbport'] = '\$DB_PORT';
|
||||
\\\$CONFIG['dbpassword'] = '\$STAGING_DB_PASS';
|
||||
\\\$CONFIG['datadirectory'] = '\$TARGET_DATA';
|
||||
\\\$CONFIG['redis'] = ['host' => '127.0.0.1', 'port' => 6379];
|
||||
\\\$CONFIG['memcache.local'] = '\\\\OC\\\\Memcache\\\\APCu';
|
||||
\\\$CONFIG['memcache.locking'] = '\\\\OC\\\\Memcache\\\\Redis';
|
||||
\\\$out = \"<?php\n\\\\\\\$CONFIG = \" . var_export(\\\$CONFIG, true) . \";\n\";
|
||||
file_put_contents('/var/www/nextcloud/config/config.php', \\\$out);
|
||||
echo 'config.php geschreven' . PHP_EOL;
|
||||
"
|
||||
chown www-data:www-data /var/www/nextcloud/config/config.php
|
||||
|
||||
# ── 7. Cron + verificatie ─────────────────────────────────────────────────────
|
||||
log "7/7 Cron instellen + occ status controleren..."
|
||||
cat > /etc/systemd/system/nextcloud-cron.service << 'EOF'
|
||||
[Unit]
|
||||
Description=Nextcloud cron
|
||||
|
||||
[Service]
|
||||
User=www-data
|
||||
ExecStart=/usr/bin/php -f /var/www/nextcloud/cron.php
|
||||
EOF
|
||||
cat > /etc/systemd/system/nextcloud-cron.timer << 'EOF'
|
||||
[Unit]
|
||||
Description=Nextcloud cron timer
|
||||
|
||||
[Timer]
|
||||
OnBootSec=5min
|
||||
OnUnitActiveSec=5min
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
EOF
|
||||
systemctl enable --now nextcloud-cron.timer
|
||||
|
||||
sudo -u www-data php8.3 /var/www/nextcloud/occ status
|
||||
|
||||
log "✓ Staging stack klaar."
|
||||
log " occ: sudo -u www-data php8.3 /var/www/nextcloud/occ <commando>"
|
||||
log " Logs: /var/log/apache2/nextcloud-error.log"
|
||||
|
||||
} 2>&1 | tee /var/log/build-staging.log
|
||||
REMOTE
|
||||
|
||||
log "✓ Script klaar. Voortgang: ssh <doel> 'tail -f /var/log/build-staging.log'"
|
||||
Executable
+183
@@ -0,0 +1,183 @@
|
||||
#!/usr/bin/env bash
|
||||
# 03-upgrade.sh — NC upgrade-keten op de doelserver.
|
||||
#
|
||||
# Draait sequentieel door NC_UPGRADE_VERSIONS uit config.sh.
|
||||
# NC vereist één major per stap: v30 → v31 → v32 → v33.
|
||||
# Na elke major: optioneel een Proxmox-snapshot als terugkeerput.
|
||||
#
|
||||
# Bij MySQL-bron: voeg NA de laatste upgrade-stap het commando toe:
|
||||
# occ db:convert-type --all-apps pgsql <user> <pass> <db>
|
||||
# zodat de DB PostgreSQL is voor AIO-import (05-import.sh).
|
||||
#
|
||||
# Terugzetten naar snapshot: ssh <pve> 'qm rollback <vmid> <naam>' (VM offline)
|
||||
# Log: elke stap print naar stdout; draai met 'tee upgrade.log' om op te slaan.
|
||||
|
||||
set -euo pipefail
|
||||
source "$(dirname "$0")/config.sh"
|
||||
log() { echo "[$(date '+%H:%M:%S')] $*"; }
|
||||
|
||||
OCC="sudo -u www-data php8.3 /var/www/nextcloud/occ"
|
||||
|
||||
# ── Apps uitschakelen die niet draaien op staging ────────────────────────────
|
||||
# AIO vervangt deze later; staging heeft geen Docker/HPB.
|
||||
log "Apps uitschakelen die afhankelijk zijn van Docker/HPB..."
|
||||
ssh "${TARGET_SSH}" "
|
||||
for app in fulltextsearch fulltextsearch_elasticsearch recognize spreed \
|
||||
whiteboard talk_matterbridge notify_push app_api; do
|
||||
${OCC} app:disable \"\$app\" 2>/dev/null && echo \" disabled: \$app\" || true
|
||||
done
|
||||
"
|
||||
|
||||
# ── Upgrade-functie ───────────────────────────────────────────────────────────
|
||||
upgrade_to() {
|
||||
local VERSION="$1"
|
||||
local MAJOR="${VERSION%%.*}"
|
||||
local ARCHIVE="nextcloud-${VERSION}.tar.bz2"
|
||||
local URL="https://download.nextcloud.com/server/releases/${ARCHIVE}"
|
||||
local SNAPSHOT="upgrade-v${MAJOR}-done"
|
||||
|
||||
log "══ NC ${VERSION} ══════════════════════════════════════"
|
||||
|
||||
ssh "${TARGET_SSH}" "${OCC} maintenance:mode --on"
|
||||
|
||||
# Download + bestanden vervangen op de doelserver
|
||||
ssh "${TARGET_SSH}" bash -s << VMEOF
|
||||
set -euo pipefail
|
||||
log() { echo "[\$(date '+%H:%M:%S')] \$*"; }
|
||||
|
||||
cd /tmp
|
||||
if [ ! -f "${ARCHIVE}" ]; then
|
||||
log "Downloaden ${ARCHIVE}..."
|
||||
wget -q --show-progress -O "${ARCHIVE}" "${URL}" 2>&1 | tail -3
|
||||
else
|
||||
log "Archief al aanwezig, overgeslagen."
|
||||
fi
|
||||
|
||||
log "Bestanden vervangen..."
|
||||
rm -rf /tmp/nc-new && mkdir /tmp/nc-new
|
||||
tar -xjf "${ARCHIVE}" -C /tmp/nc-new
|
||||
|
||||
cp -a /var/www/nextcloud/config /tmp/nc-config-bak
|
||||
|
||||
# --exclude='/config/' geankerd op root van de bron: raakt geen config/-mappen in apps.
|
||||
# Zonder leading slash zou rsync ook app/*/config/ verwijderen (bug).
|
||||
rsync -a --delete \
|
||||
--exclude='/config/' \
|
||||
--exclude='/data' \
|
||||
/tmp/nc-new/nextcloud/ /var/www/nextcloud/ || true
|
||||
|
||||
# config/ herstellen als rsync die geraakt heeft
|
||||
[ -f /var/www/nextcloud/config/config.php ] || \
|
||||
cp -a /tmp/nc-config-bak/. /var/www/nextcloud/config/
|
||||
|
||||
# Apps zonder appinfo/info.xml crashen occ upgrade — verwijder ze
|
||||
for dir in /var/www/nextcloud/apps/*/; do
|
||||
app=\$(basename "\$dir")
|
||||
[ -f "\$dir/appinfo/info.xml" ] || { rm -rf "\$dir"; echo " opgeruimd (geen info.xml): \$app"; }
|
||||
done
|
||||
|
||||
chown -R www-data:www-data /var/www/nextcloud
|
||||
rm -rf /tmp/nc-new /tmp/nc-config-bak
|
||||
log "Bestanden klaar."
|
||||
VMEOF
|
||||
|
||||
log "occ upgrade..."
|
||||
ssh "${TARGET_SSH}" "${OCC} upgrade 2>&1"
|
||||
|
||||
log "App-updates..."
|
||||
ssh "${TARGET_SSH}" "${OCC} app:update --all 2>&1 || true"
|
||||
|
||||
ssh "${TARGET_SSH}" "${OCC} status"
|
||||
ssh "${TARGET_SSH}" "${OCC} maintenance:mode --off"
|
||||
|
||||
if [[ "${USE_PROXMOX}" == "true" ]]; then
|
||||
log "Snapshot '${SNAPSHOT}' aanmaken..."
|
||||
ssh "${PROXMOX_HOST}" \
|
||||
"qm snapshot ${PROXMOX_VMID} '${SNAPSHOT}' \
|
||||
--description 'NC ${VERSION} upgrade klaar' 2>&1"
|
||||
log "✓ Snapshot klaar."
|
||||
fi
|
||||
|
||||
log "✓ NC ${VERSION} klaar."
|
||||
}
|
||||
|
||||
# ── Upgrade-keten ─────────────────────────────────────────────────────────────
|
||||
log "Start versie:"
|
||||
ssh "${TARGET_SSH}" "${OCC} status | grep versionstring"
|
||||
|
||||
# App-inventarisatie vóór de keten
|
||||
log "App-inventarisatie opslaan (voor vergelijking achteraf)..."
|
||||
ssh "${TARGET_SSH}" "
|
||||
${OCC} app:list --output=json 2>/dev/null | python3 -c \"
|
||||
import json, sys
|
||||
d = json.load(sys.stdin)
|
||||
for app in sorted(d.get('enabled', {}).keys()):
|
||||
print(app)
|
||||
\" > /tmp/nc-apps-before.txt
|
||||
echo \" \$(wc -l < /tmp/nc-apps-before.txt) apps enabled voor upgrade\"
|
||||
"
|
||||
|
||||
for VERSION in "${NC_UPGRADE_VERSIONS[@]}"; do
|
||||
upgrade_to "${VERSION}"
|
||||
done
|
||||
|
||||
# ── App-rapport na de keten ───────────────────────────────────────────────────
|
||||
log "══════════════════════════════════════════"
|
||||
log "Upgrade-keten klaar. Eindversie:"
|
||||
ssh "${TARGET_SSH}" "${OCC} status"
|
||||
log ""
|
||||
log "App-rapport (vergelijking voor/na upgrade-keten):"
|
||||
|
||||
ssh "${TARGET_SSH}" "
|
||||
${OCC} app:list --output=json 2>/dev/null | python3 -c \"
|
||||
import json, sys
|
||||
d = json.load(sys.stdin)
|
||||
for app in sorted(d.get('enabled', {}).keys()):
|
||||
print(app)
|
||||
\" > /tmp/nc-apps-after.txt
|
||||
|
||||
# Apps die verdwenen of uitgeschakeld zijn na de keten
|
||||
LOST=\$(comm -23 \
|
||||
<(sort /tmp/nc-apps-before.txt) \
|
||||
<(sort /tmp/nc-apps-after.txt))
|
||||
|
||||
# Apps die door AIO vervangen worden (geen actie nodig)
|
||||
AIO_REPLACES='fulltextsearch fulltextsearch_elasticsearch notify_push
|
||||
spreed whiteboard recognize files_antivirus'
|
||||
|
||||
echo ''
|
||||
echo '── Nog steeds enabled ────────────────────────────'
|
||||
comm -12 <(sort /tmp/nc-apps-before.txt) <(sort /tmp/nc-apps-after.txt)
|
||||
|
||||
echo ''
|
||||
echo '── Uitgeschakeld/verdwenen na upgrade ────────────'
|
||||
if [ -z \"\$LOST\" ]; then
|
||||
echo ' (geen)'
|
||||
else
|
||||
for app in \$LOST; do
|
||||
if echo \"\$AIO_REPLACES\" | grep -qw \"\$app\"; then
|
||||
echo \" [AIO-native] \$app ← vervangen door AIO-container\"
|
||||
else
|
||||
echo \" [ACTIE NODIG] \$app ← handmatig herinstalleren na AIO-import\"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo ''
|
||||
echo '── Nieuw disabled in NC app store (incompatibel) ─'
|
||||
${OCC} app:list --output=json 2>/dev/null | python3 -c \"
|
||||
import json, sys
|
||||
d = json.load(sys.stdin)
|
||||
for app in sorted(d.get('disabled', {}).keys()):
|
||||
print(' ' + app)
|
||||
\"
|
||||
"
|
||||
|
||||
if [[ "${SOURCE_DB_TYPE}" == "mysql" ]]; then
|
||||
log "VOLGENDE STAP (MySQL-bron): converteer de DB naar PostgreSQL vóór 05-import.sh:"
|
||||
log " ssh <doel> 'sudo -u www-data php8.3 /var/www/nextcloud/occ \\"
|
||||
log " db:convert-type --all-apps pgsql ${STAGING_DB_USER} ${STAGING_DB_PASS} ${STAGING_DB}'"
|
||||
log " Daarna een verse pg_dump maken en opslaan als /tmp/nc_v33_aio.sql"
|
||||
else
|
||||
log "VOLGENDE STAP: 04-install-aio.sh production"
|
||||
fi
|
||||
Executable
+145
@@ -0,0 +1,145 @@
|
||||
#!/usr/bin/env bash
|
||||
# 04-install-aio.sh — AIO mastercontainer installeren op de doelserver.
|
||||
#
|
||||
# Gebruik:
|
||||
# ./04-install-aio.sh test → NC_STAGING_DOMAIN, poort 11000, skip LE
|
||||
# ./04-install-aio.sh production → NC_DOMAIN, poort 443, Let's Encrypt cert
|
||||
#
|
||||
# Na dit script: handmatige stappen in de AIO-wizard (zie output).
|
||||
# Wacht tot alle containers groen zijn → dan 05-import.sh draaien.
|
||||
#
|
||||
# BELANGRIJK: de mastercontainer bindt poort 443/80/3478 NIET zelf.
|
||||
# AIO's apache-subcontainer beheert die poorten. Als je die poorten wél aan de
|
||||
# mastercontainer geeft, faalt de domeincheck omdat beide containers op 443 luisteren.
|
||||
|
||||
set -euo pipefail
|
||||
source "$(dirname "$0")/config.sh"
|
||||
MODE="${1:-test}"
|
||||
log() { echo "[$(date '+%H:%M:%S')] $*"; }
|
||||
|
||||
if [[ "$MODE" == "production" ]]; then
|
||||
DOMAIN="${NC_DOMAIN}"
|
||||
APACHE_PORT=443
|
||||
SKIP_VALIDATION=""
|
||||
else
|
||||
DOMAIN="${NC_STAGING_DOMAIN}"
|
||||
APACHE_PORT=11000
|
||||
SKIP_VALIDATION="-e SKIP_DOMAIN_VALIDATION=true"
|
||||
fi
|
||||
|
||||
log "Modus: ${MODE} — domein: ${DOMAIN} — apache-poort: ${APACHE_PORT}"
|
||||
|
||||
# ── Snapshot vóór AIO ────────────────────────────────────────────────────────
|
||||
if [[ "${USE_PROXMOX}" == "true" ]]; then
|
||||
SNAPSHOT="pre-aio-import-${MODE}"
|
||||
log "Snapshot '${SNAPSHOT}' aanmaken..."
|
||||
ssh "${PROXMOX_HOST}" \
|
||||
"qm snapshot ${PROXMOX_VMID} '${SNAPSHOT}' \
|
||||
--description 'Voor AIO start (${MODE})' 2>&1"
|
||||
log "✓ Snapshot klaar."
|
||||
fi
|
||||
|
||||
# ── Staging NC stoppen ───────────────────────────────────────────────────────
|
||||
log "Staging stack stoppen (indien actief)..."
|
||||
ssh "${TARGET_SSH}" "
|
||||
sudo -u www-data php8.3 /var/www/nextcloud/occ maintenance:mode --on 2>/dev/null || true
|
||||
systemctl stop apache2 php8.3-fpm nextcloud-cron.timer 2>/dev/null || true
|
||||
echo 'Staging gestopt.'
|
||||
"
|
||||
|
||||
# ── Docker installeren ───────────────────────────────────────────────────────
|
||||
log "Docker controleren / installeren..."
|
||||
ssh "${TARGET_SSH}" bash -s << 'REMOTE'
|
||||
if command -v docker &>/dev/null; then
|
||||
echo "Docker al aanwezig: $(docker --version)"
|
||||
exit 0
|
||||
fi
|
||||
apt-get update -qq
|
||||
apt-get install -y ca-certificates curl gnupg lsb-release 2>&1 | tail -1
|
||||
install -m 0755 -d /etc/apt/keyrings
|
||||
curl -fsSL https://download.docker.com/linux/debian/gpg \
|
||||
-o /etc/apt/keyrings/docker.asc
|
||||
chmod a+r /etc/apt/keyrings/docker.asc
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
|
||||
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 docker-ce docker-ce-cli containerd.io docker-compose-plugin 2>&1 | tail -3
|
||||
systemctl enable --now docker
|
||||
echo "Docker geïnstalleerd: $(docker --version)"
|
||||
REMOTE
|
||||
|
||||
# ── AIO mastercontainer starten ──────────────────────────────────────────────
|
||||
log "AIO mastercontainer starten..."
|
||||
ssh "${TARGET_SSH}" bash -s << REMOTE
|
||||
set -e
|
||||
docker rm -f nextcloud-aio-mastercontainer 2>/dev/null || true
|
||||
|
||||
docker run -d \
|
||||
--name nextcloud-aio-mastercontainer \
|
||||
--restart always \
|
||||
-p 8080:8080 \
|
||||
-e APACHE_PORT=${APACHE_PORT} \
|
||||
-e APACHE_IP_BINDING=0.0.0.0 \
|
||||
-e NEXTCLOUD_DATADIR=${TARGET_DATA_PATH} \
|
||||
${SKIP_VALIDATION} \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock:ro \
|
||||
-v nextcloud_aio_mastercontainer:/mnt/docker-aio-config \
|
||||
nextcloud/all-in-one:latest
|
||||
|
||||
echo ""
|
||||
echo "Wachten op AIO start (~15s)..."
|
||||
sleep 15
|
||||
|
||||
echo ""
|
||||
echo "══ AIO PASSPHRASE ══════════════════════════════"
|
||||
docker logs nextcloud-aio-mastercontainer 2>&1 \
|
||||
| grep -i "passphrase\|initial passphrase" | tail -3 \
|
||||
|| docker logs nextcloud-aio-mastercontainer 2>&1 | tail -15
|
||||
echo "════════════════════════════════════════════════"
|
||||
REMOTE
|
||||
|
||||
# ── App-rapport uit stap 03 printen ─────────────────────────────────────────
|
||||
log ""
|
||||
log "Apps die na AIO-import handmatig herinstalleerd moeten worden:"
|
||||
ssh "${TARGET_SSH}" "
|
||||
if [ -f /tmp/nc-apps-before.txt ] && [ -f /tmp/nc-apps-after.txt ]; then
|
||||
AIO_REPLACES='fulltextsearch fulltextsearch_elasticsearch notify_push
|
||||
spreed whiteboard recognize files_antivirus'
|
||||
comm -23 \
|
||||
<(sort /tmp/nc-apps-before.txt) \
|
||||
<(sort /tmp/nc-apps-after.txt) | while read app; do
|
||||
echo \"\$AIO_REPLACES\" | grep -qw \"\$app\" || echo \" occ app:install \$app\"
|
||||
done
|
||||
else
|
||||
echo ' (voer eerst 03-upgrade.sh uit voor een volledige lijst)'
|
||||
fi
|
||||
" 2>/dev/null || true
|
||||
|
||||
# ── Instructies ──────────────────────────────────────────────────────────────
|
||||
TARGET_IP=$(ssh "${TARGET_SSH}" "hostname -I | awk '{print \$1}'" 2>/dev/null || echo "<doel-ip>")
|
||||
|
||||
echo ""
|
||||
log "══════════════════════════════════════════════════════════════"
|
||||
log "AIO mastercontainer draait. Handmatige stappen in de browser:"
|
||||
log ""
|
||||
log " 1. Open: https://${TARGET_IP}:8080"
|
||||
log " (self-signed cert → klik door de waarschuwing)"
|
||||
log " 2. Voer de passphrase in (zie output hierboven)"
|
||||
log " 3. Stel domein in: ${DOMAIN}"
|
||||
if [[ "$MODE" == "test" ]]; then
|
||||
log " 4. 'Skip domain validation' is al geconfigureerd"
|
||||
fi
|
||||
log " 5. Selecteer optionele containers:"
|
||||
log " Minimaal (test): Imaginary"
|
||||
log " Volledig (prod): Talk, Imaginary, ClamAV, Fulltextsearch, Whiteboard"
|
||||
log " Office-suite: kies één — Collabora, OnlyOffice, Euro-Office, of geen"
|
||||
log " 6. Klik 'Save and start containers'"
|
||||
log " 7. Wacht tot ALLE containers groen zijn (~5-15 min)"
|
||||
log " Let op: eerste start na import geeft zware CPU-piek door"
|
||||
log " Elasticsearch-indexering + ClamAV DB-update + Recognize."
|
||||
log " Plan dit buiten kantooruren."
|
||||
log ""
|
||||
log " Daarna: ./05-import.sh"
|
||||
log "══════════════════════════════════════════════════════════════"
|
||||
Executable
+154
@@ -0,0 +1,154 @@
|
||||
#!/usr/bin/env bash
|
||||
# 05-import.sh — Bestaande NC-database + data importeren in AIO.
|
||||
#
|
||||
# Vereiste: AIO-wizard afgerond, alle containers groen (via https://<doel>:8080).
|
||||
# Draait op de doelserver zelf (gesourcet via SSH).
|
||||
#
|
||||
# Wat het doet:
|
||||
# 1. Dump van de staging-postgres (NC-versie gelijk aan AIO-doelversie)
|
||||
# 2. NC + notify-push stoppen (DB-verbindingen verbreken)
|
||||
# 3. AIO-database vervangen door de staging-dump
|
||||
# 4. NC starten + instanceid/passwordsalt/secret overnemen van staging
|
||||
# 5. maintenance:repair + maintenance:mode --off
|
||||
# 6. groupfolders herinstalleren (AIO start kaal)
|
||||
#
|
||||
# AIO v13+ containernamen (wijken af van oudere docs):
|
||||
# DB-container : nextcloud-aio-database
|
||||
# Database : nextcloud_database
|
||||
# NC-user : oc_nextcloud
|
||||
# Superuser : nextcloud
|
||||
#
|
||||
# Log: /var/log/aio-import.log op de doelserver
|
||||
|
||||
set -euo pipefail
|
||||
source "$(dirname "$0")/config.sh"
|
||||
log() { echo "[$(date '+%H:%M:%S')] $*"; }
|
||||
|
||||
log "05-import.sh starten op ${TARGET_SSH}..."
|
||||
|
||||
ssh "${TARGET_SSH}" bash -s << REMOTE
|
||||
set -euo pipefail
|
||||
log() { echo "[\$(date '+%H:%M:%S')] \$*"; }
|
||||
|
||||
STAGING_DB="${STAGING_DB}"
|
||||
STAGING_DB_USER="${STAGING_DB_USER}"
|
||||
STAGING_DB_PASS="${STAGING_DB_PASS}"
|
||||
TARGET_DATA="${TARGET_DATA_PATH}"
|
||||
|
||||
NC_CONTAINER=nextcloud-aio-nextcloud
|
||||
DB_CONTAINER=nextcloud-aio-database
|
||||
AIO_DB=nextcloud_database
|
||||
AIO_SUPER=nextcloud
|
||||
AIO_NCUSER=oc_nextcloud
|
||||
DUMP=/tmp/nc_aio_import.sql
|
||||
|
||||
{
|
||||
log "═══ AIO import start ═══"
|
||||
|
||||
# ── Sanity checks ────────────────────────────────────────────────────────────
|
||||
for c in "\$NC_CONTAINER" "\$DB_CONTAINER"; do
|
||||
docker ps --format '{{.Names}}' | grep -q "^\${c}$" || {
|
||||
log "FOUT: container \${c} niet actief."
|
||||
log "Zorg dat alle AIO-containers groen zijn in de wizard (https://<doel>:8080)."
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
|
||||
# ── Staging-waarden uitlezen ─────────────────────────────────────────────────
|
||||
# Deze drie waarden koppelen de NC-sessies aan de database.
|
||||
# Ze MOETEN overeenkomen met de waarden in de te importeren DB.
|
||||
OCC_STAGING="sudo -u www-data php8.3 /var/www/nextcloud/occ"
|
||||
if command -v php8.3 &>/dev/null && [ -f /var/www/nextcloud/occ ]; then
|
||||
INSTANCEID=\$(\$OCC_STAGING config:system:get instanceid 2>/dev/null)
|
||||
PASSWORDSALT=\$(\$OCC_STAGING config:system:get passwordsalt 2>/dev/null)
|
||||
SECRET=\$(\$OCC_STAGING config:system:get secret 2>/dev/null)
|
||||
log "instanceid/passwordsalt/secret uitgelezen uit staging-stack."
|
||||
else
|
||||
log "FOUT: staging-stack (php8.3 / occ) niet beschikbaar."
|
||||
log "Zet INSTANCEID, PASSWORDSALT en SECRET handmatig bovenaan dit script,"
|
||||
log "of herstart 02-build-staging.sh zodat de staging-stack aanwezig is."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# AIO DB-wachtwoord voor oc_nextcloud (staat in AIO's config.php)
|
||||
NCPASS=\$(docker exec "\$NC_CONTAINER" \
|
||||
php /var/www/html/occ config:system:get dbpassword 2>/dev/null || true)
|
||||
[ -z "\$NCPASS" ] && { log "FOUT: kon dbpassword niet uitlezen uit AIO-container."; exit 1; }
|
||||
log "AIO dbpassword aanwezig."
|
||||
|
||||
# ── 1. Staging-postgres dumpen ───────────────────────────────────────────────
|
||||
log "1/6 Staging-postgres dumpen (--no-owner --no-acl)..."
|
||||
sudo -u postgres pg_dump --no-owner --no-acl -Fp "\$STAGING_DB" > "\$DUMP"
|
||||
log "Dump klaar: \$(du -sh \$DUMP | cut -f1)"
|
||||
|
||||
# ── 2. NC + notify-push stoppen ──────────────────────────────────────────────
|
||||
log "2/6 NC + notify-push stoppen..."
|
||||
docker stop "\$NC_CONTAINER" nextcloud-aio-notify-push 2>/dev/null || true
|
||||
docker exec "\$DB_CONTAINER" psql -U "\$AIO_SUPER" -d postgres \
|
||||
-c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity
|
||||
WHERE datname = '\$AIO_DB';" 2>/dev/null || true
|
||||
log "Containers gestopt."
|
||||
|
||||
# ── 3. AIO-database vervangen ────────────────────────────────────────────────
|
||||
log "3/6 AIO DB droppen en opnieuw aanmaken..."
|
||||
docker exec "\$DB_CONTAINER" psql -U "\$AIO_SUPER" -d postgres \
|
||||
-c "DROP DATABASE IF EXISTS \${AIO_DB};"
|
||||
docker exec "\$DB_CONTAINER" psql -U "\$AIO_SUPER" -d postgres \
|
||||
-c "CREATE DATABASE \${AIO_DB} OWNER \${AIO_NCUSER}
|
||||
ENCODING 'UTF8'
|
||||
LC_COLLATE='en_US.utf8' LC_CTYPE='en_US.utf8'
|
||||
TEMPLATE template0;"
|
||||
|
||||
log "4/6 Dump restoren als \$AIO_NCUSER..."
|
||||
docker exec -e PGPASSWORD="\$NCPASS" -i "\$DB_CONTAINER" \
|
||||
psql -U "\$AIO_NCUSER" "\$AIO_DB" < "\$DUMP"
|
||||
|
||||
# Verifieer eigenaarschap — alle tabellen moeten van oc_nextcloud zijn
|
||||
OWNERS=\$(docker exec "\$DB_CONTAINER" psql -U "\$AIO_SUPER" "\$AIO_DB" \
|
||||
-tAc "SELECT tableowner, count(*) FROM pg_tables
|
||||
WHERE schemaname='public' GROUP BY tableowner;")
|
||||
log "Tabeleigenaarschap na restore: \$OWNERS"
|
||||
|
||||
# ── 5. NC starten + config bijwerken ────────────────────────────────────────
|
||||
log "5/6 NC starten + instanceid/passwordsalt/secret bijwerken..."
|
||||
docker start "\$NC_CONTAINER"
|
||||
for i in \$(seq 1 30); do
|
||||
docker exec "\$NC_CONTAINER" php /var/www/html/occ status &>/dev/null && break || true
|
||||
sleep 3
|
||||
done
|
||||
|
||||
docker exec "\$NC_CONTAINER" php /var/www/html/occ \
|
||||
config:system:set instanceid --value="\$INSTANCEID"
|
||||
docker exec "\$NC_CONTAINER" php /var/www/html/occ \
|
||||
config:system:set passwordsalt --value="\$PASSWORDSALT"
|
||||
docker exec "\$NC_CONTAINER" php /var/www/html/occ \
|
||||
config:system:set secret --value="\$SECRET"
|
||||
docker exec "\$NC_CONTAINER" php /var/www/html/occ \
|
||||
config:system:set datadirectory --value="/mnt/ncdata"
|
||||
log "config.php bijgewerkt."
|
||||
|
||||
# ── 6. Repair + maintenance uit ─────────────────────────────────────────────
|
||||
log "6/6 maintenance:repair + maintenance:mode --off..."
|
||||
docker exec "\$NC_CONTAINER" php /var/www/html/occ \
|
||||
maintenance:repair --include-expensive 2>&1 | tail -20
|
||||
docker exec "\$NC_CONTAINER" php /var/www/html/occ maintenance:mode --off
|
||||
|
||||
# groupfolders herinstalleren (AIO start kaal, app zit in de DB maar niet in de container)
|
||||
log "groupfolders installeren..."
|
||||
docker exec "\$NC_CONTAINER" php /var/www/html/occ app:install groupfolders 2>&1 | tail -2 || \
|
||||
docker exec "\$NC_CONTAINER" php /var/www/html/occ app:enable groupfolders 2>&1 | tail -2
|
||||
|
||||
docker exec "\$NC_CONTAINER" php /var/www/html/occ status
|
||||
|
||||
log "═══ AIO import klaar ═══"
|
||||
log ""
|
||||
log "Controleer NC via: https://${NC_DOMAIN}"
|
||||
log ""
|
||||
log "Volgende stappen:"
|
||||
log " • Snapshot aanmaken: ssh <pve> 'qm snapshot <vmid> aio-import-ok'"
|
||||
log " • Apps herinstalleren (zie output van 03-upgrade.sh / 04-install-aio.sh)"
|
||||
log " • DNS-cutover naar productie-IP (als dat nog niet gebeurd is)"
|
||||
log " • Contabo / bron uit maintenance halen na verificatie"
|
||||
|
||||
} 2>&1 | tee /var/log/aio-import.log
|
||||
REMOTE
|
||||
@@ -0,0 +1,252 @@
|
||||
# nextcloud-to-aio
|
||||
|
||||
Migration toolkit: Nextcloud bare/Hansson install → Nextcloud All-in-One (AIO).
|
||||
|
||||
Tested path: NC v30 (Debian 12, Apache + PHP-FPM + PostgreSQL) → AIO v13 (NC v33) on Debian 13.
|
||||
Works for any NC version that can be upgraded sequentially to the AIO target version.
|
||||
|
||||
---
|
||||
|
||||
## What it does
|
||||
|
||||
1. **Transfer** — rsync files + database dump from the old server to the new VM
|
||||
2. **Build staging** — minimal Apache + PHP + DB stack to run the upgrade chain
|
||||
3. **Upgrade** — sequential major-version upgrades (e.g. v30 → v31 → v32 → v33)
|
||||
4. **Install AIO** — Docker + AIO mastercontainer; guided wizard
|
||||
5. **Import** — restore the upgraded DB into AIO, carry over instanceid/passwordsalt/secret
|
||||
|
||||
The data directory (`/mnt/ncdata`) is rsynced once upfront and delta-synced at cutover.
|
||||
Downtime window is only the final delta-sync + DNS cutover — typically under an hour.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- New VM with Debian 12/13, SSH root access, enough disk for data
|
||||
- Old server accessible via SSH from the new VM (key-based)
|
||||
- DNS control for your NC domain
|
||||
- `~/.ssh/config` aliases set up for all hosts
|
||||
|
||||
Optional:
|
||||
- Proxmox for live snapshots between upgrade steps (`USE_PROXMOX=true`)
|
||||
- OPNSense with public VIP routing (`proxmox/build-vm.sh`)
|
||||
|
||||
---
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
cp config.sh config.local.sh # never commit this file
|
||||
# edit config.local.sh — fill in all variables
|
||||
source config.local.sh
|
||||
|
||||
./01-transfer.sh # start background rsync (can take hours)
|
||||
./02-build-staging.sh # build Apache+PHP+DB on target
|
||||
./03-upgrade.sh # sequential NC upgrade chain
|
||||
./04-install-aio.sh test # AIO on staging domain first
|
||||
# → complete wizard in browser at https://<target>:8080
|
||||
./05-import.sh # import DB + data into AIO
|
||||
|
||||
# After verification:
|
||||
./04-install-aio.sh production # switch to production domain + LE cert
|
||||
./05-import.sh # re-run import on production AIO
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration reference (`config.sh`)
|
||||
|
||||
| Variable | Description |
|
||||
|---|---|
|
||||
| `SOURCE_HOST` | IP/hostname of the existing NC server |
|
||||
| `SOURCE_NC_PATH` | Path to NC app directory (default `/var/www/nextcloud`) |
|
||||
| `SOURCE_DATA_PATH` | Path to ncdata (default `/mnt/ncdata`) |
|
||||
| `SOURCE_DB` | Database name on source |
|
||||
| `SOURCE_DB_TYPE` | `postgres` or `mysql` |
|
||||
| `SOURCE_DB_PASS` | DB password — only needed for MySQL |
|
||||
| `TARGET_SSH` | SSH target for new VM (`root@10.x.x.x` or alias) |
|
||||
| `TARGET_DATA_PATH` | Where ncdata lives on target |
|
||||
| `NC_DOMAIN` | Production domain for AIO + Let's Encrypt |
|
||||
| `NC_STAGING_DOMAIN` | Staging domain (HTTP only, internal) |
|
||||
| `STAGING_DB_PASS` | Password for staging DB (created in step 02) |
|
||||
| `NC_UPGRADE_VERSIONS` | Array of NC versions to upgrade through |
|
||||
| `USE_PROXMOX` | `true`/`false` — enable snapshot after each upgrade step |
|
||||
| `PROXMOX_HOST` | SSH alias for PVE node |
|
||||
| `PROXMOX_VMID` | VM ID for snapshots |
|
||||
|
||||
---
|
||||
|
||||
## MySQL → PostgreSQL
|
||||
|
||||
AIO uses PostgreSQL exclusively. If your source uses MySQL/MariaDB, you need one
|
||||
extra step after the upgrade chain and before `05-import.sh`:
|
||||
|
||||
```bash
|
||||
# On the target VM, after 03-upgrade.sh completes:
|
||||
sudo -u www-data php8.3 /var/www/nextcloud/occ \
|
||||
db:convert-type --all-apps pgsql \
|
||||
<staging_db_user> <staging_db_pass> <staging_db_name>
|
||||
```
|
||||
|
||||
This converts the staging MariaDB to PostgreSQL in-place. After conversion,
|
||||
`05-import.sh` takes a `pg_dump` of that PostgreSQL DB and imports it into AIO.
|
||||
|
||||
---
|
||||
|
||||
## Upgrade path
|
||||
|
||||
NC requires sequential major-version upgrades — you cannot skip a major.
|
||||
Set `NC_UPGRADE_VERSIONS` in `config.sh` based on your source version:
|
||||
|
||||
| Source | Example path |
|
||||
|---|---|
|
||||
| v28/v29 | `("29.0.x" "30.0.x" "31.0.x" "32.0.x" "33.0.x")` |
|
||||
| v30 | `("31.0.14" "32.0.12" "33.0.6")` |
|
||||
| v32 | `("33.0.6")` |
|
||||
|
||||
Check the [NC release archive](https://nextcloud.com/changelog/) for the latest patch version per major.
|
||||
AIO ships a specific NC version — check the AIO release notes to know which final version to target.
|
||||
|
||||
---
|
||||
|
||||
## Proxmox: creating the VM
|
||||
|
||||
If you use Proxmox, `proxmox/build-vm.sh` creates the target VM automatically:
|
||||
Debian 13 cloud image, separate LVM data disk, loopback VIP (optional), OPNSense routing (optional).
|
||||
|
||||
Fill in the `Proxmox VM` section of `config.sh`, then:
|
||||
|
||||
```bash
|
||||
./proxmox/build-vm.sh
|
||||
```
|
||||
|
||||
After the VM is up, set `TARGET_SSH` to match `VM_PRIVATE_IP` and continue with `01-transfer.sh`.
|
||||
|
||||
---
|
||||
|
||||
## Known issues & gotchas
|
||||
|
||||
These caused real failures during development. Read before running.
|
||||
|
||||
### PHP version
|
||||
|
||||
Debian 13 ships PHP 8.4. NC v30 requires PHP ≤ 8.3.
|
||||
`02-build-staging.sh` adds the [sury.org](https://packages.sury.org) repo for PHP 8.3 automatically.
|
||||
If your source is NC v32+, you can remove the sury.org step and use the system PHP.
|
||||
|
||||
### `rsync --exclude` anchoring
|
||||
|
||||
`--exclude='config/'` matches **any** directory named `config` in the tree,
|
||||
including `apps/someapp/config/`. Use `--exclude='/config/'` (leading slash) to
|
||||
anchor it to the root of the source — this is what the scripts use.
|
||||
|
||||
### `apc.enable_cli`
|
||||
|
||||
APCu is disabled in CLI by default (`apc.enable_cli=0`). `occ` commands that touch
|
||||
APCu caches silently fail or produce wrong results. `02-build-staging.sh` sets
|
||||
`apc.enable_cli=1` in `/etc/php/8.3/cli/php.ini` automatically.
|
||||
|
||||
### `require` vs `include` for config.php
|
||||
|
||||
NC's `config.php` defines `$CONFIG` but does not `return` it.
|
||||
`include('/path/to/config.php')` returns `1` (bool), not the config array.
|
||||
Use `require` instead — the scripts do this.
|
||||
|
||||
### Apps without `appinfo/info.xml`
|
||||
|
||||
Third-party apps that are present in `/var/www/nextcloud/apps/` but lack
|
||||
`appinfo/info.xml` (abandoned, partially deleted, or leftover) cause `occ upgrade`
|
||||
to crash. `03-upgrade.sh` removes them automatically before each upgrade step.
|
||||
|
||||
### AIO mastercontainer port binding
|
||||
|
||||
The AIO mastercontainer must **not** bind ports 80, 443, or 3478.
|
||||
AIO's apache sub-container manages those ports itself.
|
||||
Binding them on the mastercontainer causes the domain check to fail with a
|
||||
conflict — two processes listening on port 443.
|
||||
`04-install-aio.sh` does not bind those ports.
|
||||
|
||||
### AIO container names (v13+)
|
||||
|
||||
Older AIO docs refer to `nextcloud-aio-postgresql` — this was renamed.
|
||||
Current names used by `05-import.sh`:
|
||||
|
||||
| Role | Container/resource name |
|
||||
|---|---|
|
||||
| DB container | `nextcloud-aio-database` |
|
||||
| Database | `nextcloud_database` |
|
||||
| NC DB user | `oc_nextcloud` |
|
||||
| DB superuser | `nextcloud` |
|
||||
|
||||
### CPU spike on first AIO start after migration
|
||||
|
||||
When AIO starts for the first time with existing data, Elasticsearch indexes all
|
||||
files, ClamAV downloads its virus database, and Recognize scans all photos.
|
||||
On a large installation (500K+ files) this can take 1–2 hours at high CPU load.
|
||||
|
||||
**Plan this for late evening** — do not run the first AIO start during business
|
||||
hours or when the server is serving other workloads.
|
||||
|
||||
### instanceid / passwordsalt / secret
|
||||
|
||||
These three values in `config.php` are the identity of the NC instance. They must
|
||||
match what is in the database. `05-import.sh` reads them from the staging stack
|
||||
and writes them into the AIO container's config. If the staging stack has been
|
||||
removed before running `05-import.sh`, note these values from the source
|
||||
`config.php` and set them manually.
|
||||
|
||||
### systemd-resolved blocking DNS
|
||||
|
||||
On Debian 12/13, `systemd-resolved` can intercept DNS and cause resolution
|
||||
failures inside Docker containers. If containers cannot resolve hostnames:
|
||||
|
||||
```bash
|
||||
systemctl disable --now systemd-resolved
|
||||
echo "nameserver 1.1.1.1" > /etc/resolv.conf
|
||||
```
|
||||
|
||||
### Docker DNS cache after IP change
|
||||
|
||||
Docker caches the upstream DNS from `/etc/resolv.conf` at daemon start.
|
||||
After a VM IP change or network reconfiguration, containers may get DNS
|
||||
timeouts even though the host resolves correctly. Fix:
|
||||
|
||||
```bash
|
||||
systemctl restart docker
|
||||
docker start $(docker ps -aq)
|
||||
```
|
||||
|
||||
### notify-push after import
|
||||
|
||||
`05-import.sh` stops `nextcloud-aio-notify-push` to release DB connections.
|
||||
After import, restart it via the AIO admin UI or:
|
||||
|
||||
```bash
|
||||
docker start nextcloud-aio-notify-push
|
||||
```
|
||||
|
||||
### OPNSense: fw01 root shell is csh
|
||||
|
||||
If you use OPNSense, its root shell is `csh`. Shell redirects like `2>/dev/null`
|
||||
are interpreted differently by csh and can corrupt commands.
|
||||
Always wrap non-trivial commands in `sh -c '...'` when SSHing to OPNSense.
|
||||
`proxmox/build-vm.sh` does this for all fw01 commands.
|
||||
|
||||
---
|
||||
|
||||
## After import: apps to reinstall
|
||||
|
||||
`03-upgrade.sh` prints a list of apps that need manual reinstall after AIO import.
|
||||
These are apps that were enabled in your source but are not included in AIO.
|
||||
Common examples:
|
||||
|
||||
```bash
|
||||
docker exec nextcloud-aio-nextcloud php /var/www/html/occ app:install occweb
|
||||
docker exec nextcloud-aio-nextcloud php /var/www/html/occ app:install drawio
|
||||
docker exec nextcloud-aio-nextcloud php /var/www/html/occ app:install maps
|
||||
docker exec nextcloud-aio-nextcloud php /var/www/html/occ app:install extract
|
||||
docker exec nextcloud-aio-nextcloud php /var/www/html/occ app:enable notes
|
||||
```
|
||||
|
||||
AIO includes natively (no action needed): fulltextsearch, notify_push, Talk/spreed,
|
||||
whiteboard, recognize, files_antivirus (ClamAV), imaginary.
|
||||
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env bash
|
||||
# config.sh — Vul dit in voordat je de scripts draait.
|
||||
# Wordt gesourcet door alle andere scripts: source "$(dirname "$0")/config.sh"
|
||||
|
||||
# ── Bronserver (bestaande Nextcloud-installatie) ──────────────────────────────
|
||||
SOURCE_HOST="192.0.2.10" # IP van de oude NC-server
|
||||
SOURCE_USER="root" # SSH-gebruiker (key-based, passwordless)
|
||||
SOURCE_NC_PATH="/var/www/nextcloud"
|
||||
SOURCE_DATA_PATH="/mnt/ncdata"
|
||||
SOURCE_DB="nextcloud_db"
|
||||
SOURCE_DB_USER="nextcloud_db_user"
|
||||
SOURCE_DB_PASS="" # alleen nodig voor MySQL/MariaDB; leeglaten voor PostgreSQL
|
||||
SOURCE_DB_TYPE="postgres" # "postgres" of "mysql"
|
||||
|
||||
# ── Doelserver (nieuwe VM waar AIO komt te draaien) ───────────────────────────
|
||||
TARGET_SSH="root@10.0.0.10" # SSH naar doel (of ~/.ssh/config alias)
|
||||
TARGET_DATA_PATH="/mnt/ncdata" # pad waar ncdata gemount is
|
||||
|
||||
# ── Domeinen ──────────────────────────────────────────────────────────────────
|
||||
NC_DOMAIN="next.example.com" # productiedomein (voor AIO + LE-cert)
|
||||
NC_STAGING_DOMAIN="nc.internal" # staging-domein (HTTP-only, intern)
|
||||
|
||||
# ── Staging PostgreSQL ────────────────────────────────────────────────────────
|
||||
# Wachtwoord voor de staging-DB (wordt aangemaakt in 02-build-staging.sh)
|
||||
STAGING_DB="nextcloud_db"
|
||||
STAGING_DB_USER="nextcloud_db_user"
|
||||
STAGING_DB_PASS="changeme-strong-password"
|
||||
|
||||
# ── NC upgrade-pad ────────────────────────────────────────────────────────────
|
||||
# Pas aan op basis van je bronversie. NC vereist sequentiële upgrades per major.
|
||||
# Eindversie moet overeenkomen met de AIO-versie die je installeert (zie stap 4).
|
||||
# Voorbeeld: bron = v30, AIO target = v33
|
||||
NC_UPGRADE_VERSIONS=("31.0.14" "32.0.12" "33.0.6")
|
||||
|
||||
# ── Proxmox snapshots (optioneel) ─────────────────────────────────────────────
|
||||
# Zet op false als je geen Proxmox hebt of geen snapshots wil maken.
|
||||
USE_PROXMOX=true
|
||||
PROXMOX_HOST="pve01" # SSH-alias voor de PVE-node
|
||||
PROXMOX_VMID=100 # VM ID van de doel-VM
|
||||
|
||||
# ── Proxmox VM aanmaken (alleen voor proxmox/build-vm.sh) ─────────────────────
|
||||
# Sla deze sectie over als je de VM handmatig aanmaakt.
|
||||
VM_NAME="nc-aio"
|
||||
VM_CORES=4
|
||||
VM_MEMORY=8192 # MB
|
||||
VM_DISK_SIZE=50 # GB systeemdisk
|
||||
VM_DATA_SIZE=500 # GB datadisk (/mnt/ncdata)
|
||||
VM_VLAN=50 # VLAN-tag; leeglaten voor untagged
|
||||
VM_BRIDGE=vmbr20
|
||||
VM_PRIVATE_IP=10.0.0.10 # moet overeenkomen met TARGET_SSH
|
||||
VM_PRIVATE_GW=10.0.0.1
|
||||
VM_PRIVATE_PREFIX=24
|
||||
VM_PUBLIC_IP="" # publiek VIP op loopback; leeglaten indien niet van toepassing
|
||||
VM_DNS=10.0.0.1
|
||||
VM_SEARCH_DOMAIN=example.com
|
||||
CLOUD_IMAGE="/var/lib/vz/template/iso/debian-13-genericcloud-amd64.qcow2"
|
||||
Executable
+210
@@ -0,0 +1,210 @@
|
||||
#!/usr/bin/env bash
|
||||
# proxmox/build-vm.sh — Maakt de doel-VM aan op een Proxmox-node.
|
||||
#
|
||||
# Optioneel script: sla dit over als je de VM handmatig aanmaakt of een
|
||||
# andere hypervisor gebruikt. De overige scripts (01–05) werken op elke
|
||||
# Linux-VM met SSH-toegang.
|
||||
#
|
||||
# Wat het doet:
|
||||
# - VM aanmaken (Debian 13 cloud image, qcow2)
|
||||
# - Systeemdisk + aparte datadisk (LVM, ext4, /mnt/ncdata)
|
||||
# - Netplan vervangen door /etc/network/interfaces
|
||||
# - Loopback VIP (publiek IP) via systemd oneshot (indien VM_PUBLIC_IP gezet)
|
||||
# - OPNSense: gateway + static route voor het publieke VIP (indien VM_PUBLIC_IP gezet)
|
||||
#
|
||||
# Vereisten:
|
||||
# - SSH-alias voor PROXMOX_HOST en (indien VIP) fw01 werken
|
||||
# - Debian 13 genericcloud qcow2 beschikbaar op de PVE-node (zie CLOUD_IMAGE)
|
||||
# - config.sh ingevuld
|
||||
|
||||
set -euo pipefail
|
||||
source "$(dirname "$0")/../config.sh"
|
||||
log() { echo "[$(date '+%H:%M:%S')] $*"; }
|
||||
SCRATCHDIR=$(mktemp -d)
|
||||
trap 'rm -rf "$SCRATCHDIR"' EXIT
|
||||
|
||||
# ── STAP 1: VM aanmaken ───────────────────────────────────────────────────────
|
||||
log "VM ${PROXMOX_VMID} (${VM_NAME}) aanmaken op ${PROXMOX_HOST}..."
|
||||
ssh "${PROXMOX_HOST}" "
|
||||
qm create ${PROXMOX_VMID} \
|
||||
--name ${VM_NAME} \
|
||||
--memory ${VM_MEMORY} \
|
||||
--cores ${VM_CORES} \
|
||||
--sockets 1 \
|
||||
--cpu host \
|
||||
--net0 virtio,bridge=${VM_BRIDGE}$([ -n '${VM_VLAN}' ] && echo ',tag=${VM_VLAN}' || true) \
|
||||
--scsihw virtio-scsi-single \
|
||||
--ostype l26 \
|
||||
--serial0 socket \
|
||||
--vga serial0 \
|
||||
--agent enabled=1 \
|
||||
--onboot 1
|
||||
"
|
||||
|
||||
log "Systeemdisk importeren als qcow2..."
|
||||
ssh "${PROXMOX_HOST}" \
|
||||
"qm importdisk ${PROXMOX_VMID} ${CLOUD_IMAGE} local --format qcow2 2>&1 | tail -1"
|
||||
|
||||
PUBKEY_PVE=$(ssh "${PROXMOX_HOST}" \
|
||||
"cat /root/.ssh/id_ed25519.pub 2>/dev/null || cat /root/.ssh/id_rsa.pub")
|
||||
PUBKEY_WS=$(cat ~/.ssh/id_ed25519.pub 2>/dev/null || cat ~/.ssh/id_rsa.pub)
|
||||
|
||||
log "Disks koppelen + cloud-init configureren..."
|
||||
ssh "${PROXMOX_HOST}" "
|
||||
qm set ${PROXMOX_VMID} \
|
||||
--scsi0 local:${PROXMOX_VMID}/vm-${PROXMOX_VMID}-disk-0.qcow2,discard=on,ssd=1,iothread=1 \
|
||||
--scsi1 local:${VM_DATA_SIZE},format=qcow2,discard=on,iothread=1 \
|
||||
--boot order=scsi0 \
|
||||
--ide2 local:cloudinit \
|
||||
--ciuser root \
|
||||
--sshkeys <(printf '%s\n%s\n' '${PUBKEY_PVE}' '${PUBKEY_WS}') \
|
||||
--ipconfig0 ip=${VM_PRIVATE_IP}/${VM_PRIVATE_PREFIX},gw=${VM_PRIVATE_GW} \
|
||||
--nameserver ${VM_DNS} \
|
||||
--searchdomain ${VM_SEARCH_DOMAIN}
|
||||
qm resize ${PROXMOX_VMID} scsi0 ${VM_DISK_SIZE}G
|
||||
"
|
||||
|
||||
# ── STAP 2: VM starten en wachten op SSH ─────────────────────────────────────
|
||||
log "VM starten..."
|
||||
ssh "${PROXMOX_HOST}" "qm start ${PROXMOX_VMID}"
|
||||
log "Wachten op SSH (${VM_PRIVATE_IP})..."
|
||||
for i in $(seq 1 60); do
|
||||
ssh "${PROXMOX_HOST}" \
|
||||
"ssh -o StrictHostKeyChecking=no -o ConnectTimeout=4 \
|
||||
root@${VM_PRIVATE_IP} hostname 2>/dev/null" && break || true
|
||||
sleep 5
|
||||
done
|
||||
|
||||
# ── STAP 3: Netplan → ifupdown ───────────────────────────────────────────────
|
||||
log "Netplan vervangen door ifupdown..."
|
||||
ssh "${PROXMOX_HOST}" "ssh root@${VM_PRIVATE_IP} bash -s" << EOF
|
||||
set -e
|
||||
apt-get install -y ifupdown 2>&1 | tail -1
|
||||
cat > /etc/network/interfaces << 'IFEOF'
|
||||
source /etc/network/interfaces.d/*
|
||||
|
||||
auto lo
|
||||
iface lo inet loopback
|
||||
|
||||
auto ens18
|
||||
iface ens18 inet static
|
||||
address ${VM_PRIVATE_IP}/${VM_PRIVATE_PREFIX}
|
||||
gateway ${VM_PRIVATE_GW}
|
||||
dns-nameservers ${VM_DNS} 1.1.1.1
|
||||
dns-search ${VM_SEARCH_DOMAIN}
|
||||
IFEOF
|
||||
systemctl disable systemd-networkd systemd-networkd-wait-online 2>/dev/null || true
|
||||
mkdir -p /etc/cloud/cloud.cfg.d
|
||||
echo "network: {config: disabled}" > /etc/cloud/cloud.cfg.d/99-disable-network.cfg
|
||||
apt-get purge -y netplan.io 2>&1 | tail -1
|
||||
rm -rf /etc/netplan /usr/share/netplan
|
||||
EOF
|
||||
|
||||
# ── STAP 4: Loopback VIP (optioneel) ─────────────────────────────────────────
|
||||
if [[ -n "${VM_PUBLIC_IP}" ]]; then
|
||||
log "Loopback VIP ${VM_PUBLIC_IP} instellen..."
|
||||
ssh "${PROXMOX_HOST}" "ssh root@${VM_PRIVATE_IP} bash -s" << EOF
|
||||
set -e
|
||||
cat > /etc/systemd/system/loopback-vip.service << 'VIPEOF'
|
||||
[Unit]
|
||||
Description=Loopback VIP
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/sbin/ip addr add ${VM_PUBLIC_IP}/32 dev lo label lo:vip
|
||||
ExecStop=/sbin/ip addr del ${VM_PUBLIC_IP}/32 dev lo label lo:vip
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
VIPEOF
|
||||
systemctl enable loopback-vip.service
|
||||
EOF
|
||||
fi
|
||||
|
||||
# ── STAP 5: Datadisk — LVM + ext4 ───────────────────────────────────────────
|
||||
log "Datadisk inrichten (LVM vg_data/ncdata, ext4, /mnt/ncdata)..."
|
||||
ssh "${PROXMOX_HOST}" "ssh root@${VM_PRIVATE_IP} bash -s" << 'EOF'
|
||||
set -e
|
||||
apt-get install -y lvm2 2>&1 | tail -1
|
||||
DISK=/dev/sdb
|
||||
[ -b "$DISK" ] || { echo "FOUT: $DISK niet gevonden"; exit 1; }
|
||||
[ -z "$(lsblk -dn -o FSTYPE $DISK 2>/dev/null)" ] || { echo "FOUT: $DISK is niet leeg"; exit 1; }
|
||||
pvcreate "$DISK"
|
||||
vgcreate vg_data "$DISK"
|
||||
lvcreate -n ncdata -l 100%FREE vg_data
|
||||
mkfs.ext4 -L ncdata /dev/vg_data/ncdata
|
||||
mkdir -p /mnt/ncdata
|
||||
echo "/dev/vg_data/ncdata /mnt/ncdata ext4 defaults,noatime 0 2" >> /etc/fstab
|
||||
mount -a
|
||||
df -h /mnt/ncdata
|
||||
EOF
|
||||
|
||||
# ── STAP 6: Basis-pakketten + reboot ─────────────────────────────────────────
|
||||
log "Basis-pakketten installeren..."
|
||||
ssh "${PROXMOX_HOST}" "ssh root@${VM_PRIVATE_IP} bash -s" << 'EOF'
|
||||
set -e
|
||||
apt-get update -qq
|
||||
apt-get install -y qemu-guest-agent rsync curl ca-certificates gnupg htop 2>&1 | tail -1
|
||||
systemctl enable --now qemu-guest-agent
|
||||
EOF
|
||||
|
||||
log "Reboot..."
|
||||
ssh "${PROXMOX_HOST}" "ssh root@${VM_PRIVATE_IP} reboot" || true
|
||||
sleep 10
|
||||
log "Wachten op herstart..."
|
||||
for i in $(seq 1 60); do
|
||||
ssh "${PROXMOX_HOST}" \
|
||||
"ssh -o StrictHostKeyChecking=no -o ConnectTimeout=4 \
|
||||
root@${VM_PRIVATE_IP} hostname 2>/dev/null" && break || true
|
||||
sleep 5
|
||||
done
|
||||
|
||||
# ── STAP 7: OPNSense gateway + static route (optioneel) ──────────────────────
|
||||
if [[ -n "${VM_PUBLIC_IP}" ]]; then
|
||||
log "OPNSense: gateway + static route voor ${VM_PUBLIC_IP}..."
|
||||
GW_NAME="GW_$(echo ${VM_NAME} | tr '[:lower:]' '[:upper:]')"
|
||||
cat > "${SCRATCHDIR}/add_route.py" << PYEOF
|
||||
import xml.etree.ElementTree as ET, uuid, sys
|
||||
tree = ET.parse('/conf/config.xml')
|
||||
root = tree.getroot()
|
||||
name, gw_ip, pub_ip, iface = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]
|
||||
|
||||
gws = root.find('OPNsense/Gateways')
|
||||
for old in gws.findall('gateway_item'):
|
||||
if old.findtext('name') == name:
|
||||
gws.remove(old)
|
||||
gw = ET.SubElement(gws, 'gateway_item')
|
||||
gw.set('uuid', str(uuid.uuid4()))
|
||||
for tag, val in [
|
||||
('disabled','0'),('name',name),('descr',name),
|
||||
('interface',iface),('ipprotocol','inet'),('gateway',gw_ip),
|
||||
('defaultgw','0'),('fargw','0'),('monitor_disable','1'),
|
||||
('force_down','0'),('nosync','0'),('priority','255'),('weight','1')
|
||||
]:
|
||||
ET.SubElement(gw, tag).text = val
|
||||
|
||||
sr = root.find('staticroutes')
|
||||
for old in sr.findall('route'):
|
||||
if old.findtext('network') == pub_ip:
|
||||
sr.remove(old)
|
||||
route = ET.SubElement(sr, 'route')
|
||||
route.set('uuid', str(uuid.uuid4()))
|
||||
for tag, val in [('network',pub_ip),('gateway',name),('descr',name),('enabled','1')]:
|
||||
ET.SubElement(route, tag).text = val
|
||||
tree.write('/conf/config.xml')
|
||||
print('done')
|
||||
PYEOF
|
||||
# fw01 root shell is csh — altijd wrappen in sh -c, anders verminkt csh
|
||||
# fd-redirects (2>/dev/null) en kan een bogus 0.0.0.0/1 route aanmaken.
|
||||
scp "${SCRATCHDIR}/add_route.py" fw01:/tmp/add_route.py
|
||||
ssh fw01 "sh -c 'python3 /tmp/add_route.py \
|
||||
${GW_NAME} ${VM_PRIVATE_IP} ${VM_PUBLIC_IP}/32 opt5 \
|
||||
&& rm /tmp/add_route.py'"
|
||||
ssh fw01 "sh -c 'configctl filter reload'"
|
||||
log "✓ OPNSense route actief."
|
||||
fi
|
||||
|
||||
log "✓ VM klaar: ${VM_PRIVATE_IP}$([ -n '${VM_PUBLIC_IP}' ] && echo " / VIP ${VM_PUBLIC_IP}" || true)"
|
||||
log " Pas TARGET_SSH aan in config.sh en ga verder met 01-transfer.sh"
|
||||
Reference in New Issue
Block a user