For AI agents: a documentation index is available at /llms.txt. A markdown version of this page is available at /guide/self-hosted/operate/migration.md.

Self-hostedOperate

Migrate to a new server

Restore a full backup onto fresh infrastructure with data intact, and verify before cutting over.

This is the restore procedure, written as a server move. The same steps recover an instance after a failure — the only difference is whether the old server is still around.

Everything here runs on the NEW server

Unless a step says otherwise. Start from a complete backup — see Backup.

#1. Prepare the new server

RequirementInstallMinimum
Docker Enginecurl -fsSL https://get.docker.com | sh24.x
Docker Compose pluginapt install docker-compose-plugin2.x
curlapt install curlany
rsync / scpapt install rsync openssh-clientany
bash
docker --version
docker compose version

Meet the prerequisites too — migrating onto an undersized box just moves the problem.

#2. Extract the backup

bash
cd /home/user
tar -xzf orangescrum-backup-YYYY-MM-DD.tar.gz

ls -lh backup/YYYY-MM-DD/

Confirm all ten files are present before going further.

#3. Restore host application data

bash
mkdir -p /data
tar -xzf backup/YYYY-MM-DD/app-data.tar.gz -C /
ls -lh /data

#4. Prepare the project directory

bash
mkdir -p /opt/orangescrum
cd /opt/orangescrum

cp /home/user/backup/YYYY-MM-DD/docker-compose.yml .
cp /home/user/backup/YYYY-MM-DD/osreports.Dockerfile .   # if present

# Secrets
tar -xzf /home/user/backup/YYYY-MM-DD/secrets.tar.gz -C /opt/orangescrum/
ls secrets/

Verify every .txt file is present — a missing secret shows up later as a container that restarts forever.

#5. Create the volumes and restore into them

Create each volume first, then populate it.

bash
docker volume create orangescrum-ee_orangescrum-app-files
docker volume create orangescrum-ee_orangescrum-app-config
docker volume create orangescrum-ee_orangescrum-postgres-data
docker volume create orangescrum-ee_orangescrum-reports-data

for v in app-files app-config postgres-data reports-data; do
  docker run --rm \
    -v orangescrum-ee_orangescrum-$v:/data \
    -v /home/user/backup/YYYY-MM-DD:/backup \
    alpine tar -xzf /backup/$v.tar.gz -C /data
done

Volume names must match the compose project

If the prefix differs from the source server, the stack creates its own empty volumes and starts with no data. Confirm with docker volume ls before starting.

#6. Start the stack

bash
cd /opt/orangescrum

docker compose pull
docker compose up -d

docker compose ps
docker compose logs -f --tail=50

Allow one to two minutes for health checks. The reports service waits for its database to be healthy before it starts.

#7. If the database did not come back — restore from the dumps

The volume restore is the fast path; the SQL dumps are the reliable fallback.

bash
docker compose ps orangescrum-postgresdb   # wait for healthy

docker exec -i orangescrum-ee-orangescrum-postgresdb-1 \
  psql -U orangescrum postgres \
  < /home/user/backup/YYYY-MM-DD/main-db.sql

docker exec -i orangescrum-ee-orangescrum-reports-db-1 \
  psql -U postgres superset \
  < /home/user/backup/YYYY-MM-DD/reports-db.sql

#8. Verify before you cut over

bash
docker compose ps

curl -f http://localhost:8080     # application
curl -f http://localhost:8088     # reports

docker compose logs orangescrum-app --tail=30
docker compose logs orangescrum-postgresdb --tail=30

Then confirm the data really arrived:

bash
docker exec -it orangescrum-ee-orangescrum-postgresdb-1 \
  psql -U orangescrum postgres -c '\dt'

docker exec -it orangescrum-ee-orangescrum-postgresdb-1 \
  psql -U orangescrum postgres -c 'SELECT count(*) FROM users;'

#Verification checklist

Work through every item before switching DNS
  • All four containers report healthy
  • Application answers on 8080
  • Reports answer on 8088
  • You can log in with existing credentials
  • Projects, tasks and users are visible
  • A file attachment downloads — a database-only restore looks perfect until someone clicks a file
  • The reports dashboard loads existing dashboards
  • /data on the host is intact
  • Scheduled jobs (digests, reminders) are present in cron

#9. Cut over

  1. Update DNS or the load balancer

    Point at the new server's address.

  2. Reissue or move TLS certificates

    A migration with a stale certificate presents as a total outage.

  3. Keep the source server running

    Until verification is fully complete. It is your rollback.

  4. Re-check background jobs

    Cron lives outside Docker and is the thing most often lost in a move.

#Troubleshooting

SymptomResolution
Container keeps restartingdocker compose logs <service> — usually a wrong password in a secrets file
Database connection refusedEnsure the database container is healthy before the app starts
Port not accessibleufw allow 8080/tcp, ufw allow 8088/tcp, or fix the proxy
Volume looks empty after restoreThe tar restore failed or the prefix was wrong: docker run --rm -v <volume>:/data alpine ls /data
Permission denied on /dataRe-apply ownership: chown -R www-data:www-data /data
Reports service will not startIt waits on its database — give it ~60s, then check its logs
⬆️Upgrading

Moving to a newer Orangescrum version.