People imagine a migration as a single dramatic moment where they pull a plug here and plug something in over there, and hope. It doesn’t have to feel like that. A move goes smoothly when the new server is fully ready and tested before you touch anything that users depend on, and when DNS has been prepared so that the switch propagates in seconds rather than hours. The actual cutover then becomes a few minutes of careful work instead of an outage.
This guide walks through moving a typical web application to a Cybeward VDS in Santiago. The same plan applies whether you’re coming from another provider or another datacenter.
Before you start, write down exactly what's running on the old server: services, open ports, cron jobs, TLS certificates and where data lives. A migration is only as clean as your inventory of what you're migrating.
1. Provision the target VDS with matching resources
Order a server in Santiago that matches or exceeds the source: same CPU and RAM class, at least as much disk, and the same OS major version. Matching the OS version matters more than people expect — moving from Debian 11 to Debian 12 mid-migration adds variables you don’t want while you’re also moving data.
Note the new server’s public IP. You’ll keep both machines running side by side for the entire process, so there’s no rush and no risk to the live site yet.
2. Prepare and harden the new server
Before any application data lands on it, bring the new machine up to a sane baseline: SSH keys instead of passwords, a non-root sudo user, a firewall that allows only what you need, and automatic security updates. We covered this in detail in our first 15 minutes security checklist — do that pass now, while the server is empty and a mistake costs nothing.
Then install the runtime your app needs (web server, language runtime, database engine) at the same major versions as the source. Don’t import data yet. The goal here is a clean, secured, correctly-configured shell waiting to receive content.
3. Initial data sync while the old server stays live
With both servers running, copy data across with rsync. Because the source is still serving traffic, this first pass can take as long as it needs — nobody is waiting on it.
# pull application files from the old server $ rsync -aHAX --info=progress2 \ root@203.0.113.10:/var/www/ /var/www/ # pull uploads / user content $ rsync -aHAX --info=progress2 \ root@203.0.113.10:/srv/data/ /srv/data/
For databases, take a consistent dump on the source and restore it on the target so the engine rebuilds its own files correctly:
# on the OLD server: consistent dump $ mysqldump --single-transaction --routines --triggers \ appdb | gzip > /tmp/appdb.sql.gz # on the NEW server: import it $ gunzip < appdb.sql.gz | mysql appdb
Now bring the application up on the new server and test it directly by IP (or a temporary hostname). Walk through real flows: log in, submit a form, upload a file. Fix configuration issues here, where there are no consequences.
The migration succeeds or fails in the rehearsal, not in the cutover. If the app works perfectly by IP on the new box, the switch is just paperwork.
4. Lower your DNS TTL a day ahead
This is the step that turns a multi-hour outage window into a couple of minutes, and it’s the one most people skip. Your DNS records have a TTL — how long resolvers cache them. If it’s set to 3600 or higher, visitors can keep hitting the old IP for an hour after you change it.
At least a full day before the cutover, drop the TTL on the records you’ll change:
; before: app.example.com. 3600 IN A 203.0.113.10 app.example.com. 300 IN A 203.0.113.10
A 300-second TTL means that once you change the record, the world catches up within five minutes. Set it a day ahead so every cached copy of the old, longer TTL has expired by cutover time.
Note. Lowering the TTL is harmless and reversible — but only takes effect after the old TTL has aged out of caches. Do it early. Raise it back to a normal value a day or two after the migration is confirmed stable.
5. The cutover: brief pause, final delta sync, switch DNS
Now the only short window in the whole plan. Put the old application into a brief maintenance state so no new writes happen, then run a final rsync — it only copies what changed since the first pass, so it finishes quickly:
# on the new server: catch the last changes $ rsync -aHAX --delete --info=progress2 \ root@203.0.113.10:/var/www/ /var/www/ $ rsync -aHAX --delete --info=progress2 \ root@203.0.113.10:/srv/data/ /srv/data/
Re-run the database dump-and-import for the final delta, start the app on the new server, then flip the A record to the Santiago IP. Because the TTL is already 300, propagation is near-immediate.
6. Verify before you celebrate
Confirm the world is actually seeing the new server, not your local cache:
# what IP is the record resolving to now? $ dig +short app.example.com @1.1.1.1 # is the app healthy over HTTPS end to end? $ curl -sS -o /dev/null -w "%{http_code}\n" https://app.example.com/health # watch the new server's logs for live traffic $ tail -f /var/log/nginx/access.log
Watch real requests arrive in the new server’s logs, check error logs are quiet, and click through the same flows you rehearsed in step 3. Lift the maintenance state only once you’ve confirmed traffic is landing correctly.
7. Keep the old server as a rollback
Don’t decommission the source immediately. Leave it running, untouched, for a few days. If something subtle surfaces, you can point DNS back in five minutes — exactly because you lowered the TTL. Once you’ve gone a few days with clean logs and no surprises, raise the TTL back to normal and retire the old machine.
If any of this feels uncertain for your particular stack, talk to Cybeward support before you begin. We do migrations every week and can advise on the safest sequence for your case — and during the cutover there’s a human on the other end of the line, not a ticket queue.
- New Santiago VDS provisioned with matching CPU, RAM, disk and OS version
- New server hardened and runtimes installed before any data lands
- Initial
rsyncand database import done while the old server stays live - App tested directly by IP on the new server — real login, upload, form flows
- DNS TTL lowered to
300at least a day before cutover - Maintenance pause, final delta
rsync, then A record switched to the new IP - Verified with
dig,curland live logs that traffic hits Santiago - Old server kept untouched as a rollback for a few days, then TTL raised back