Who this is forInfrastructure managers and IT directors who own a server move, whether between data centres, from an ageing estate to a hosted platform, or from one hosting arrangement to another, and who need to know what to ask of the people doing the work.
Most migrations that go badly were lost long before the cutover. They were lost when someone accepted a server list that nobody had checked, or chose a method that needed a four-hour window for a business that could spare forty minutes. This guide follows a migration in the order the decisions actually bite: discovery, dependencies, data movement, addressing, cutover, rollback, and the hold period before you switch the old environment off.
The shape of a migration
Whatever the technology, the work divides into six stages. Naming them matters because most failures are a stage that was skipped or compressed.
- Discover. Establish what exists, what it does and who owns it.
- Map. Establish what talks to what, in both directions, including things nobody documented.
- Design and rehearse. Decide the target, the order of moves, and measure the real duration on a copy.
- Seed and replicate. Move the bulk of the data ahead of time, while the source is live.
- Cut over. Move the last difference, switch traffic, validate, and decide go or roll back.
- Hold and retire. Keep the source recoverable until the new side has survived a full business cycle.
The migration readiness planner scores your position against these stages. This article explains the reasoning behind each.
Discovery: the inventory you do not have
A server list from a spreadsheet is a claim, not a fact. Build the inventory from several independent sources and reconcile them: the hypervisor or hardware management console, monitoring, backup job lists, DNS zones, DHCP leases, and the patching or configuration tool. A server that appears in only one source is the interesting one. It is either retired and forgotten, or alive and unmanaged.
For every server record at least: hostname and addresses, role, operating system and version, owner (a named person, not a team alias), data volume, and whether it holds state. Then classify it. There are only four sensible dispositions: move as-is, rebuild on the target, replace with something else, or retire. Retiring is the cheapest migration, and the one most often skipped because nobody will sign off the decision. Make someone sign.
Dependency mapping: observe, then ask
Documentation of dependencies drifts. Observed connections do not. Take a listing of live connections from each server over a period long enough to include every scheduled job, which means at least one full business cycle and, if you have month-end processing, that too.
On a Linux server, list listening sockets and then sample established connections with the owning process:
# What is listening, and which process owns it
ss -tlnp
# What this server is currently talking to (outbound and inbound), with process names
ss -tnp state established
On Windows, the equivalent in PowerShell is:
# Established TCP connections with the owning process id
Get-NetTCPConnection -State Established |
Select-Object LocalAddress,LocalPort,RemoteAddress,RemotePort,OwningProcess |
Sort-Object RemoteAddress
Both are point-in-time snapshots, so a single run proves little. Sample them on a schedule, or use flow data from your network equipment if you have it, and aggregate by remote address and port. Then take the aggregated list to the owner of each server and ask what each peer is. The questions that surface real surprises are the ones about inbound connections: who calls this server that you did not expect? Typical answers are a reporting tool using a service account, a vendor’s monitoring probe, a script on someone’s desktop, and a printer.
Record two more things while you are here: anything addressed by a literal IP address rather than a name, and anything that depends on the server’s identity in some other way, such as licence keys bound to a host, allow-lists at third parties, and certificates issued to a specific name. These are what break when addresses change.
Design and rehearse
Settle the target architecture before moving data, because it decides what you are copying into. The architecture comparison matrix lays out the options. Then write the order of moves from the dependency map. Shared services go first: identity, name resolution, time, certificate services. Applications follow, with their databases moving at the same time rather than leaving a database in one place and its application in another across a slow link.
Then rehearse. A rehearsal on a copy is the only way an outage estimate becomes a measurement. Run the whole procedure including the validation, time each step, and write down what surprised you. A plan that has not been rehearsed is a hypothesis.
Data movement: do the arithmetic first
Moving data is where optimism is most expensive, so work the numbers before choosing a method. One gigabyte is 8 billion bits, which is 8,000 megabits. The time to copy is the data in megabits divided by the usable rate in megabits per second.
Worked example. 12 TB (12,000 GB) over a 1 Gbit/s link, assuming 70% of the line rate is usable. Usable rate: 1,000 x 0.70 = 700 Mbit/s. Data: 12,000 x 8,000 = 96,000,000 Mbit. Time: 96,000,000 / 700 = 137,143 seconds, which is 38 hours 6 minutes. The same data at 100 Mbit/s usable would take 960,000 seconds, or 11 days.
The 70% is an assumption, not a law. Encryption, protocol overhead, many small files and competing traffic all lower it. Measure with a representative sample before you rely on any figure.
Why a fast link can behave slowly
A single TCP stream cannot exceed its window size divided by the round-trip time. With a 64 KiB window and a 50 ms round trip:
65,536 bytes x 8 = 524,288 bits per round trip
524,288 bits / 0.050 s = 10,485,760 bit/s, about 10.5 Mbit/s
That is the ceiling for one stream on a gigabit link with a 64 KiB window, because the sender waits for acknowledgements. Modern operating systems scale the window automatically, and parallel streams multiply it, but a copy tool configured with one stream across a long path can still disappoint badly. If a transfer runs at a small fraction of the link, test with several parallel streams before blaming the link.
Seeding and replication
You almost never copy everything inside the outage window. The standard approach is to copy the bulk while the source is live, then repeatedly copy what changed, then freeze writes and copy the final difference. Each pass takes less time than the last, as long as the link can copy faster than the data changes.
Let R be the rate at which data changes divided by the rate at which it can be copied. If R is 1 or more, the copy never catches up. If R is below 1, each pass takes R times as long as the one before it. A worked case: an initial copy of 8,000 seconds with R = 0.5 means the next pass takes 4,000 seconds, then 2,000, then 1,000. Add the fixed overhead of scanning and snapshotting, which does not shrink with the amount of changed data, and you have your final sync estimate. The planner does this arithmetic for your own figures and shows each pass.
If the initial copy would take more than a couple of days, consider moving a base copy on encrypted drives by courier and closing the gap over the link. Account for transit and load time, encrypt the drives, and keep a record of who handled them.
Typical tools, with the cautions that matter:
# Linux: copy a directory tree preserving permissions, hard links, ACLs and extended attributes.
# --dry-run first: it shows what would be copied and changes nothing.
rsync -aHAX --numeric-ids --dry-run --info=stats2 -e ssh /srv/data/ user@newhost:/srv/data/
# Then the real run, repeatable for delta passes. Note: no --delete, so nothing is removed on the target.
rsync -aHAX --numeric-ids --info=progress2 -e ssh /srv/data/ user@newhost:/srv/data/
:: Windows: copy a tree including security, timestamps and directory attributes.
:: /E copies subdirectories; deliberately NOT /MIR, which deletes target files missing from the source.
robocopy D:\Data \\newhost\Data /E /COPY:DATSOU /DCOPY:DAT /XJ /R:2 /W:5 /MT:16 /LOG+:C:\Temp\migrate.log
The U in /COPY:DATSOU copies auditing information and needs a privilege most accounts lack, so drop it if you do not need audit settings preserved. In both tools, run the delta passes as many times as the plan calls for, and compare a sample of the result against the source before trusting it.
Databases need their own method. Copying live database files with a file-level tool produces an inconsistent copy. Use the database’s native replication or a consistent dump, then verify with row counts and an application-level check.
Trade-off accepted. Replicating continuously shortens the final outage, but it adds a second system to keep consistent for days or weeks, and a replication pair is a dependency in its own right. It is the right trade when the tolerance is tight and the data large; it is needless complexity when a quiet weekend window comfortably covers a full copy.
DNS and addressing strategy
Clients usually find servers by name, and a DNS record is cached for as long as its time to live (TTL) says. If the record has a TTL of 3,600 seconds and you change it at the moment of cutover, some clients will keep reaching the old address for up to an hour. The remedy is to lower the TTL ahead of time, by at least the old TTL, so that every cache has already picked up the short value before you make the change.
# Read the TTL as seen by a resolver (the number counts down while cached)
dig +noall +answer app.example.com A
# Ask the authoritative server directly to see the configured TTL
dig +noall +answer app.example.com A @ns1.example.com
On Windows, Resolve-DnsName app.example.com -Type A shows the remaining TTL too. The sequence is: lower the TTL to something like 300 seconds, wait at least one full old TTL (plus a margin, because some resolvers hold records longer than asked), confirm at the authoritative server that the short value is live, cut over, then restore a longer TTL once the new side is stable.
Hard-coded addresses do not follow DNS. Find them in the discovery stage, and for each decide whether to update the client, move the address with the service, or put a load balancer or reverse proxy at a stable address in front.
The cutover runbook
Write the runbook as times relative to the start of the window, so that anyone can see whether the plan is on schedule.
| Time | Step | Owner |
|---|---|---|
| T-7 days | Lower DNS TTLs; confirm at authoritative servers | DNS owner |
| T-3 days | Rehearsal result reviewed; go/no-go on proceeding | Project owner |
| T-1 hour | Final backup of source taken; communications sent | Infrastructure lead |
| T-0 | Freeze writes on the source | Application owner |
| T+15 min | Final sync begins; verify counts and checksums when it ends | Infrastructure lead |
| T+60 min | Start services on target; switch DNS or addresses | Infrastructure and DNS owners |
| T+75 min | Application owners run their smoke tests | Application owners |
| Agreed time | Go or roll back, decided by the named owner | Project owner |
Two rules keep a runbook honest. Every step has a named owner and a measured duration. And the go/no-go time is fixed in advance, because a team that has been working for six hours will always find a reason to carry on.
Rollback
Rollback is the part that is planned least and needed most. Keep the source environment intact until the hold period ends, and do not reuse its storage during that time. Write down what switching back actually involves: reverting DNS, which takes up to the TTL to reach clients, restarting services on the old side, and re-enabling anything you disabled.
The hard question is data written on the new side after cutover. Rolling back in the first few minutes is easy because nothing has changed. Rolling back after a day of writes means either copying data back, which needs reverse replication prepared before you started, or accepting a defined loss. Decide which in advance, and say so in the plan.
Validation and the hold period
Declare success on evidence. File counts and checksums for file data, row counts and a consistency check for databases, and smoke tests written by the application owners rather than the migration team. Confirm monitoring and alerting work on the new side before anyone relaxes, and confirm backups are running there and that one restore has been proven.
Then hold. Keep the source untouched and recoverable for an agreed period, long enough to include the next month-end if you have one. Decommission afterwards, not before.
How migrations fail
- A forgotten caller. A job, an integration or a client with an address typed in. Found by observing inbound connections for a full business cycle, not by asking.
- Optimistic transfer arithmetic. The line rate was used instead of the achieved rate. Found by testing a sample copy.
- No rollback. The source was repurposed in the first week.
- Licences and activation. Software bound to hardware identity refuses to start on the new side. Found by checking each licence before the window.
- Everything in one night. A large estate moved in a single window concentrates all the risk in one team on one night. Waves cost more calendar time and far less risk.
- Backups left behind. The new environment went live with no working backup, because the old backup agent was tied to the old server.
What to do next
Run your figures through the migration readiness planner to see which stage is your weakest link and what your outage estimate looks like. Read backup, high availability and disaster recovery before you finalise rollback, since the restore time of your backups is part of it. And if a supplier will do the move, the due-diligence and exit questions in managed infrastructure apply to the migration contract as much as to the hosting one.