Plan to migrate server (Version: 12.0.14) from a Mac to Linux machine

Server Version: 12.0.14; currently installed via Docker on an intel Mac Mini running Mac OS. Behavior is mostly stable, but I have to periodically reboot it for seemingly no reason and I feel putting it on a Linux bot is smarter for the future before I start thinking about updating it. I have an Orange Pi (ARM 64) device that I think will run this well.

This is my provisional battle plan. I am wondering if anyone familiar could kindly just peek at my planned order of operations and let me know if any obvious problems jump out at them or if anything is obviously missing or completely unnecessary

Export db. Shut down, bring up only the db container to avoid conflicts, dump data, then shut down again:

cd /opt/seafile
docker compose down
docker compose up -d db
docker exec seafile-mysql sh -c 'exec mysqldump --all-databases -uroot -p"$MYSQL_ROOT_PASSWORD"' > /opt/seafile/database_dump.sql
docker compose down
docker ps -a #confirm nothing's still up.

Archive Data:

sudo tar -czvf seafile-migration.tar.gz /opt/notification-data /opt/onlyoffice /opt/seafile /opt/seafile-data /opt/seafile-elasticsearch /opt/seafile-mysql /opt/shared

Extract after Transferring Data:

# Sync seafile-migration.tar.gz to new (Linux) host. 
# Extract data directly to the new root directory to recreate the /opt paths:

sudo tar -xzvf /tmp/seafile-migration.tar.gz -C /

Fix permissions, aligning host directory ownership with the internal container UIDs:

sudo chown -R root:root /opt/seafile-data /opt/notification-data /opt/shared /opt/seafile 
sudo chown -R 999:999 /opt/seafile-mysql/db
sudo chown -R 1000:1000 /opt/seafile-elasticsearch/data
sudo chown -R 109:112 /opt/onlyoffice

Spin up new containers using the exact same configuration files

cd /opt/seafile # parent dir can be owned by docker user or root

sudo sysctl -w vm.max_map_count=262144
echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.conf
docker compose up -d

Verify Database Status

Try to go live from the sql data already included in the transferred volumes

# Wait ~30 seconds, then confirm MariaDB accepted the raw Mac binaries.
# If this outputs a line ending in "ready for connections", migration is complete:

docker logs seafile-mysql | grep -i "ready for connections"
#or check `docker compose ps` for "healthy" status

Database Restore (Fallback) if above fails:

docker compose stop db
sudo rm -rf /opt/seafile-mysql/db/*
docker compose start db
# Wait ~30 seconds or until db process is healthy, then:
cat /opt/seafile/database_dump.sql | docker exec -i seafile-mysql sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD"'

Your migration plan looks good to me.

A few specific observations and recommendations for your “battle plan”:

  1. Database Migration (Intel to ARM64):
    Moving raw database binaries (/opt/seafile-mysql/db) between different CPU architectures (Intel to ARM) and operating systems is frequently problematic for MariaDB/MySQL. You should expect that your Database Restore (Fallback) via the SQL dump will be necessary.

    • Recommendation: Instead of --all-databases, it is safer to dump only the specific Seafile databases (ccnet_db, seafile_db, and seahub_db). Dumping the system mysql database from an Intel/Mac environment and restoring it into a new ARM/Linux container can cause internal permission and configuration conflicts.
  2. Permissions:
    Your chown commands are correct for standard Docker deployments on Linux (UID 999 for MariaDB and 1000 for Elasticsearch). If OnlyOffice has issues starting, you can verify the required UID by running stat on the directory inside the container.

  3. Official Reference:
    For general backup and restore procedures, you can refer to the document: Backup and Recovery - Seafile Admin Manual

Overall, the plan is solid. Having that SQL dump ready is the most important step for an architecture change.

1 Like

Thank you very much for your time and for your feedback. With this in mind I split off the SQL dump.

The actual working commands that I used for this on the old host were as follows (assuming SEAFILE_MYSQL_DB_PASSWORD is set to somepassword123 in .env):

docker exec seafile-mysql sh -c 'exec mariadb-dump -useafile -p"somepassword123" --opt ccnet_db' > /opt/seafile/ccnet_db.sql
docker exec seafile-mysql sh -c 'exec mariadb-dump -useafile -p"somepassword123" --opt seafile_db' > /opt/seafile/seafile_db.sql
docker exec seafile-mysql sh -c 'exec mariadb-dump -useafile -p"somepassword123" --opt seahub_db' > /opt/seafile/seahub_db.sql

On the new host, after extracting the tar and running chown commands, I deleted the db binaries to avoid conflicts so MariaDB could initialize on a fresh start:

sudo rm -rf /opt/seafile-mysql/db/*

I forgot the new db instance would not start without some value for INIT_SEAFILE_MYSQL_ROOT_PASSWORD, so I added that to .env; I must have had that at one point on the old install and then cleared it.

echo "INIT_SEAFILE_MYSQL_ROOT_PASSWORD=ArbitrarySecurePasswordHere" | sudo tee -a /opt/seafile/.env

Before I could import the SQL on the new host I had to create the ccnet_db, seafile_db, and seahub_db databases and also the seafile user. Following the same somepassword123 example value for SEAFILE_MYSQL_DB_PASSWORD as before:

docker exec -i seafile-mysql sh -c 'exec mariadb -uroot -p"$MYSQL_ROOT_PASSWORD"' <<'SQL'
CREATE DATABASE IF NOT EXISTS ccnet_db;
CREATE DATABASE IF NOT EXISTS seafile_db;
CREATE DATABASE IF NOT EXISTS seahub_db;
CREATE USER IF NOT EXISTS 'seafile'@'%' IDENTIFIED BY 'somepassword123';
GRANT ALL PRIVILEGES ON ccnet_db.* TO 'seafile'@'%';
GRANT ALL PRIVILEGES ON seafile_db.* TO 'seafile'@'%';
GRANT ALL PRIVILEGES ON seahub_db.* TO 'seafile'@'%';
FLUSH PRIVILEGES;
SQL

I suppose bypassing the usual initialization scripts was somehow avoidable (maybe clearing out /opt/seafile-mysql/db/* was overly cautious) but the above resolved the issue and I was able to import accordingly:

cat /opt/seafile/ccnet_db.sql | docker exec -i seafile-mysql sh -c 'exec mariadb -useafile -p"somepassword123" ccnet_db'
cat /opt/seafile/seafile_db.sql | docker exec -i seafile-mysql sh -c 'exec mariadb -useafile -p"somepassword123" seafile_db'
cat /opt/seafile/seahub_db.sql | docker exec -i seafile-mysql sh -c 'exec mariadb -useafile -p"somepassword123" seahub_db'

I was able to bring up the rest of the docker compose stack from here, updated my nginx proxy, and everything appears to have been successful. After fretting and mulling over this for a couple weeks, it really wasn’t that bad. Now it’s time to start fretting and mulling over updating it.

Thanks again for your help