For migrating or restoring your Ethora instance, the options generally are:
Restore the whole instance from backup
Install a new system on a clean instance using Ethora Deploy / Install system, restore MongoDB for Apps and Users state, but start with a clean MySQL / Postgres DB for chat state.
Same as 2, but restore chat DB as well so that chat rooms and chat history is also restored.
In this guide we will cover options #2 and #3 which require manual operations.
Note: all bash commands are examples, make sure to replace them with your specific file names, paths and domain names.
In our example, we are deploying copies of Prod DB to a QA server.
Export DB files from the source server
Export Mongo DB (Core apps state)
Find Mongo container
docker ps --format '{{.Names}}' | rg mongoExport dump
docker exec <mongo_container> mongodump --archive --gzip --db ethora_prod > /tmp/ethora-prod-mongo.archive.gzExport MySQL DB (Chat server state)
You'll need MySQL password for exporting. In case you don't know the password:
Find source MySQL password:
docker inspect "xmpp_ethoradev_com-mysql-1" \
--format '{{range .Config.Env}}{{println .}}{{end}}' \
| rg 'MYSQL_ROOT_PASSWORD|MYSQL_PASSWORD|MYSQL_DATABASE|MYSQL_USER'List databases:
docker exec -it "xmpp_ethoradev_com-mysql-1" \
mysql -uroot -p'PASTE_PASSWORD_HERE' -e "SHOW DATABASES;"commonly this would be ejabberd_db.
Export the DB:
docker exec "xmpp_ethoradev_com-mysql-1" \
mysqldump -uroot -p'PASTE_PASSWORD_HERE' \
--single-transaction --quick --routines --triggers \
ejabberd_db > /tmp/ejabberd_db.sqlOptional gzip before copying
gzip -f /tmp/ejabberd_db.sql
ls -lh /tmp/ejabberd_db.sql.gzRestore DB backups to the target server
Copy DB files to target server
gzip -k "ejabberd_db.sql"
scp "dev_20260403T135921Z.archive" \
"ejabberd_db.sql.gz" \
ubuntu@<QA_SERVER_IP>:/tmp/Identify expected DB names on target server
sudo rg '^MONGO_DB=' /home/ubuntu/ethora/ethora-backend/services/api/.env
sudo bash -lc 'source /home/ubuntu/ethora/deploy/.deploy.env && echo "$MYSQL_ROOT_PASSWORD"'
docker ps --format '{{.Names}}' | rg 'mongo|mysql|xmpp'Stop writers before restore
pm2 stop backend backend-jobs push push-worker sdk-playground || true
sudo bash -lc 'source /home/ubuntu/ethora/deploy/.deploy.env && docker compose -f /home/ubuntu/ethora/deploy/docker-compose.enterprise.yml stop xmpp'Backup current server DBs first (optional, skip if installing to a fresh instance)
docker exec deploy-mongo-1 mongodump --archive > /tmp/qa-before-restore-mongo.archive
sudo bash -lc 'source /home/ubuntu/ethora/deploy/.deploy.env && docker exec deploy-mysql-1 mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" --single-transaction --quick ejabberd_db > /tmp/qa-before-restore-ejabberd.sql'Deploy MongoDB (and optionally remap)
Remap example - source DB archive contains 'dev' but target expects 'ethora_prod', so we carry out a remap:
docker exec -i deploy-mongo-1 mongorestore \
--archive \
--drop \
--nsFrom='dev.*' \
--nsTo='ethora_prod.*' \
< /tmp/dev_20260403T135921Z.archiveAlternatively, if remap is not needed:
Deploying without remap:
docker exec -i deploy-mongo-1 mongorestore \
--archive \
--drop \
< /tmp/dev_20260403T135921Z.archiveRestart services and test
This is assuming MySQL (chat server state) doesn't need restoring or you want to test the system before that.
sudo bash -lc 'source /home/ubuntu/ethora/deploy/.deploy.env && docker compose -f /home/ubuntu/ethora/deploy/docker-compose.enterprise.yml start xmpp'
pm2 restart backend backend-jobs push push-worker sdk-playgroundRestoring MySQL (Chat database)
To restore plain SQL:
sudo bash -lc 'source /home/ubuntu/ethora/deploy/.deploy.env && \
docker exec -i deploy-mysql-1 mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "DROP DATABASE IF EXISTS ejabberd_db; CREATE DATABASE ejabberd_db;"'
sudo bash -lc 'source /home/ubuntu/ethora/deploy/.deploy.env && \
docker exec -i deploy-mysql-1 mysql -uroot -p"$MYSQL_ROOT_PASSWORD" ejabberd_db' < /tmp/ejabberd_db.sqlTo restore gzipped SQL:
sudo bash -lc 'source /home/ubuntu/ethora/deploy/.deploy.env && \
docker exec -i deploy-mysql-1 mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "DROP DATABASE IF EXISTS ejabberd_db; CREATE DATABASE ejabberd_db;"'
gunzip -c /tmp/ejabberd_db.sql.gz | \
sudo bash -lc 'source /home/ubuntu/ethora/deploy/.deploy.env && \
docker exec -i deploy-mysql-1 mysql -uroot -p"$MYSQL_ROOT_PASSWORD" ejabberd_db'Then restart XMPP:
sudo bash -lc 'source /home/ubuntu/ethora/deploy/.deploy.env && docker compose -f /home/ubuntu/ethora/deploy/docker-compose.enterprise.yml restart xmpp'Minio migration
To migrate Minio file storage, the cleanest option is to use mc:
mc alias set legacy http://<legacy-host>:9000 <access_key> <secret_key>
mc alias set qa http://<qa-host>:9000 <access_key> <secret_key>
mc mirror --overwrite legacy qaIf legacy MinIO is only local inside Docker, you can run mc on the legacy server against localhost:9000 .






