Move a VPS to a New Provider Without Downtime
How to migrate a self-hosted app from one VPS provider to another with zero downtime: build the new box in parallel, sync data, and cut over DNS cleanly.
Moving a VPS to a new provider without downtime comes down to one principle: never migrate in place, always build in parallel. You stand up the new box completely, get it running the app against synced data, verify it works, and only then point traffic at it. The old box keeps serving the whole time. If anything goes wrong, you have changed nothing and you simply do not cut over. Done this way, a provider migration is calm and reversible. Done the other way, editing the live box and hoping, it is how you end up down for hours. I have moved apps across providers this way many times, and the sequence is always the same.
Why in-place migration is the trap
The instinct is to treat migration as transformation: take the running server and somehow move it. That instinct is wrong because it puts your live service on the operating table. The moment you start changing the box that serves traffic, every mistake is a live outage, and you are debugging under pressure with customers watching.
Parallel migration removes the pressure entirely. The new environment is separate, so you build it, break it, fix it, and test it with zero effect on production. The old box does not know the new one exists. This is the same philosophy behind migrating off managed cloud without downtime: the safe path is always a parallel build and a clean cutover, never surgery on the live system.
Step one: build the new box in parallel
Provision the new VPS and bring it to a full, running copy of your app, serving from its own IP, before you touch anything user-facing.
- Install the same stack: runtime, web server, reverse proxy, dependencies.
- Deploy the application, ideally through the same deploy pipeline you already control, so the new box is built the way every box is built, not by hand.
- Wire up config and secrets. This is trivial if you already manage secrets without a cloud vendor, because they are not trapped in the old provider's dashboard.
At the end of this step you can hit the new box directly by IP and see the app run. It has no live traffic and no real data yet, but it works. That is the foundation everything else sits on.
Step two: sync the data, then sync it again
Data is the part that cannot be casually copied, because it keeps changing on the live box. Handle it in two passes.
First, do a bulk copy: restore a recent backup of the database and files onto the new box. This gets you 99 percent of the way there while the old box keeps serving. For a database, this is your base restore.
Second, close the gap at cutover. Right before you switch traffic, sync only the changes since the bulk copy. For a database, replication or a final incremental catch-up brings the new box current. For files, a delta sync copies just what changed. The window of change you have to close is small because the bulk of the data moved already. This is exactly why keeping tight RPO and RTO targets and good backups makes migration easy: the tools you use to recover are the tools you use to move.
Step three: cut over DNS cleanly
With the new box running and data current, the switch is a DNS change: point your domain at the new IP. The one thing that trips people up is DNS caching. Clients hold your old record for as long as its TTL says, so if your TTL is an hour, some users keep hitting the old box for up to an hour after you change it.
Handle it in advance. Lower the TTL to a minute or two a day or so before the migration, so when you flip the record, the change propagates fast. Keep the old box running through the propagation window, serving whatever stragglers still resolve to it. Because both boxes are live and their data is in sync, users on either one get correct service. There is no moment where the app is down. There is only a window where traffic drifts from old to new, and both work.
If you front the app with Cloudflare, the cutover is even cleaner, because you change the origin at the edge and clients never see a DNS change at all. Traffic moves the instant you update the origin.
Step four: verify, then decommission
Once traffic is flowing to the new box, watch it. Confirm requests are landing, errors are flat, and the data is right. Keep the old box alive for a day or two as a fallback: if something surfaces, you can point DNS back and you have lost nothing. Only when the new box has proven itself do you tear the old one down.
This is the payoff of the parallel approach. At every step you had a working system and a way back. I run every provider migration like this across my portfolio, moving boxes on HostSSH with zero user-visible downtime. Build in parallel, sync in two passes, lower your TTL, cut over, verify, then decommission. Never operate on the live box. The calm way is also the safe way.