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>
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
- Transfer — rsync files + database dump from the old server to the new VM
- Build staging — minimal Apache + PHP + DB stack to run the upgrade chain
- Upgrade — sequential major-version upgrades (e.g. v30 → v31 → v32 → v33)
- Install AIO — Docker + AIO mastercontainer; guided wizard
- 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/configaliases 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
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:
# 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 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:
./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 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:
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:
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:
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:
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.