Detailed tutorial for migrating Nextcloud from one docker instance to another (e.g. on a different server)

AIM
to transfer a running docker installation to another server (also running nextcloud in docker)

:information_source: Support > :package: Appliances (Docker, Snappy, VM, NCP, AIO) documentation docker-compose
PRECONDITIONS
the two servers shall be running the same version of nextcloud. And with the same structure (here nextcloud, mysql, redis, apache…)

TESTED WITH
Installation 1 > Docker on Synology DSM migrated to
Installation 2 > Docker on Ubuntu Server running on proxmox

TESTED WITH
Nextcloud Hub 9 (30.0.6)

First generate a working installation of nextcloud on your Installation 2
Here is an example of a working docker compose file running under ubuntu server on a proxmox

First, create the required directories on your Installation 2

cd docker 
mkdir nextcloud
cd nextcloud
mkdir config
mkdir custom_apps
mkdir data
mkdir db
mkdir html
mkdir redis

And now use this example of a docker compose (e.g. via portainer) to get the containers up and running. Setup a admin user (this will be overwritten, so just anything to have the setup completed)

---
version: '3'

services:
  nextcloud:
    image: nextcloud
    container_name: nextcloud
    restart: unless-stopped
    networks: 
      - cloud
    depends_on:
      - mariadb
      - redis
    ports:
      - 8081:80
    volumes:
      - /home/ubuntu/docker/nextcloud/html:/var/www/html
      - /home/ubuntu/docker/nextcloud/custom_apps:/var/www/html/custom_apps
      - /home/ubuntu/docker/nextcloud/config:/var/www/html/config
      - /home/ubuntu/docker/nextcloud/data:/var/www/html/data
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Zurich
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=XXXXXXXXX
      - MYSQL_HOST=nextclouddb
      - REDIS_HOST=redis

  mariadb:
    image: mariadb
    container_name: Nextclouddb
    restart: unless-stopped
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
    networks: 
      - cloud
    volumes:
      - /home/ubuntu/docker/nextcloud/db:/var/lib/mysql
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Zurich
      - MYSQL_RANDOM_ROOT_PASSWORD=true
      - MYSQL_PASSWORD=XXXXXXXXX
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      

  redis:
    image: redis:alpine
    container_name: redis
    volumes:
      - /home/ubuntu/docker/nextcloud/redis:/data  
    networks: 
      - cloud
  
  cron:
   image: nextcloud:apache
   container_name: Nextcloud-CRON
#   logging:
#      driver: none 
   restart: always
   networks: 
      - cloud
   volumes:
     - /home/ubuntu/docker/nextcloud/config:/var/www/html/config:rw
     - /home/ubuntu/docker/nextcloud/html:/var/www/html:rw
     - /home/ubuntu/docker/nextcloud/custom_apps:/var/www/html/custom_apps:rw
     - /home/ubuntu/docker/nextcloud/data:/var/www/html/data:rw
   entrypoint: /cron.sh
   depends_on:
    mariadb:
       condition: service_started
    redis:
       condition: service_started  


networks:
  cloud:
    name: cloud
    driver: bridge

Deploy docker and create a dummy admin user. Stop the nextcloud container after setting up the admin account since we will be overwriting the database.

In the meantime, create backups from Installation 1
Create dabase-backup in OLD installation using the mariadb-dump command in the console of the database docker. Stop the nextcloud container in Installation 1 so that the database will not be overwritten. The database container of Installation 1 is still running. Open a terminal in this container and create a dump of the existing database.

mariadb-dump --single-transaction -u nextcloud -pXXXXXXXXX  nextcloud > nextcloud-sqlbkp_`date +"%Y%m%d"`.bak  

Check that the .bak file is generated. This can be copied from the mountlocation “db”

The database being “done”, it is time to look at the actual user data stored in the folder “data”. From the Installation 1 download the user data as zip to your PC. In this case (Synology), go to DSM, navigate to the folder and download as zip to your PC

We are now done with Installation 1. Now starts the import and copy into the Installation 2 which is assumed to be up and running (see above)

Connect to Installation 2 Server via ssh and create a storage for old files

mkdir /home/ubuntu/old

From your PC, transfer the created backups to the Installation 2
Copy the backup and the data to the folder old

 scp .\Downloads\data.zip ubuntu@192.168.1.64:/home/ubuntu/old/
 scp .\Downloads\nextcloud-sqlbkp_20250215.bak ubuntu@192.168.1.64:/home/ubuntu/old

copy the backup into the docker database folder…we will use this file to overwrite the databse of Installation 2

sudo cp old/nextcloud-sqlbkp_20250215.bak docker/nextcloud/db/

…and correct the file ownership if needed (here changed from root to 999) as in the other files

sudo chown 999:systemd-journal nextcloud-sqlbkp_20250215.bak

Open terminal of database docker (nextclouddb) on the Installation 2

Enter the following commands at the command prompt inside the docker container Nextclouddb

# delete old database
mariadb -u nextcloud -pXXXXXXXXX -e "DROP DATABASE nextcloud"
mariadb -u nextcloud -pXXXXXXXXX -e "CREATE DATABASE nextcloud"
# import new database
cd /var/lib/mysql/
mariadb -u nextcloud -pXXXXXXXXX nextcloud < nextcloud-sqlbkp_20250215.bak

Now the database has been overwritten. The user files will be copied over. The data.zip should be already on your Installation 2 as outlined above.

Overwrite the contents of data.zip
Unzip, move and check permissions.

cd old
# unzip
sudo 7z x data.zip
# move / copy with rsync
sudo rsync -a data/ ../docker/nextcloud/data/
# change permissions of copied files to user www-data
sudo chown  www-data:www-data data -R

Note permissions of the new installation
user www-data:www-data is owner of files except of db

On the INstallation 2 open config.php and enable update via web

 'upgrade.disable-web' => true,

Now, very important - from outside docker (on ssh terminal ) execute occ upgrade as user www-data. NOTE this can not be executed from within the docker container nextcloud, it has to be external (i.e. from a terminal on the server) otherwise the users don’t match and the upgrade will not proceed.

docker exec --user www-data nextcloud php occ upgrade

Now you should be able to login to new server with all the user and data from the old server

1 Like