Migrating a VPS Without Downtime — Replication, Cutover, Rollback
A cutover pattern that keeps the old server serving while the new one catches up: rsync replication, DNS/database switchover and a tested rollback path.

A cutover pattern that keeps the old server serving while the new one catches up: rsync replication, DNS/database switchover and a tested rollback path.
The pattern
Run old and new in parallel, replicate forward, switch reads and writes at the data layer, then retire the old box. Downtime lives only in the seconds between the final sync and the write switchover — not in a move-the-disk weekend.
Business $24/mo (6 vCPU / 16 GB DDR5) is the production size. Crypto invoice, no KYC.
Launch nowSteps
- Provision the target in the destination location; harden it with the same checklist.
- Replicate data continuously (rsync over SSH, database replication, or application-level sync) until the delta is seconds.
- Lower DNS TTLs to 60–300 seconds a day ahead.
- Cutover: stop writes on old → final sync → point writes at new → smoke-test → let DNS converge.
- Keep the old VPS alive for a rollback window; snapshot it before decommission.
Where BitCloudVPS fits
Snapshots on VPS/Storage plans make the sync-and-cutover pattern cheap: clone, verify, switch. Same no-KYC checkout on both sides of a migration — including moves from providers that want a passport scan for the destination.
Prerequisites: the inventory that decides whether zero downtime is possible
Zero downtime is a property of your application's state, not of the transfer tool. Before any command runs, inventory the four state classes; a workload with only class 1 and 2 migrates with a two-second interruption at worst, while class 4 decides the whole project.
| State class | Examples | Migration method |
|---|---|---|
| Static files and code | Web roots, media, configs | Iterated rsync -a; trivially re-syncable |
| Packages and services | Installed software, unit files, cron | Reinstall from a manifest, not a copy: dpkg --get-selections or the compose file |
| Secrets and certificates | SSH keys, TLS certs, API tokens, /etc/letsencrypt | Copy once, verify fingerprints match on both ends |
| Live mutable state | Databases, queues, user sessions | Replication or a write-freeze cutover window measured in seconds |
Two numbers from the inventory set your budget: total data size (decides rsync stages) and DNS TTL (decides how long stragglers hit the old IP). Measure both before you book anything: du -sh /var/lib and dig +noall +answer example.com for the current TTL.
The rsync stage loop: exact commands and what each flag buys
The transfer core is rsync run three times, not once. The first pass moves the bulk while the old server still serves traffic; the second catches the delta; the third, seconds before cutover, makes the gap almost nil.
- Provision the target with the same OS major version to avoid glibc and systemd surprises.
- First pass, throttled so it never competes with production:
rsync -aHAX --info=progress2 --exclude={"/dev","/proc","/sys","/tmp","/run","/var/lib/mysql"} root@old:/ /- the excludes keep pseudo-filesystems and the database out of the file pass, since each needs its own handling. - Second pass once the first settles: same command, now cheap - only changed blocks move.
- Database: either configure replication old→new and wait for zero lag, or plan a freeze window: stop writes, final dump
mysqldump --single-transaction --master-data=2(orpg_dump -Fc), restore on target, measure the window. Record the number; it is your real downtime. - Final rsync pass after the write freeze: same command again plus the now-included
/var/lib/mysqlif you chose freeze over replication. - Copy secrets and verify:
sha256sum /etc/ssh/ssh_host_*_key.pubon both ends must match if you want hosts keys preserved (clients will not re-prompt), and the TLS chain must validate on the new box before DNS moves.
The -HAX flags are the difference between a working system and a mystery: hardlinks (package managers use them), ACLs and extended attributes (web servers and containers rely on them).
DNS and TTL mechanics, verified against how resolvers actually behave
DNS is where migrations leak downtime that the data transfer eliminated. Three mechanics matter, and each has a number you control.
- Lower TTL 24-48 hours ahead. Set it to 60 seconds on every A/AAAA record in play. The TTL that matters is the one currently published, not the new one: resolvers cache the old value until it expires, so a 3600-second TTL means up to an hour of stragglers no matter what you do on cutover day.
- Announce before you depend on it. Flip the records while both servers answer. Traffic drains from old to new over one old-TTL period; watch both access logs and wait for old-box requests to approach zero.
- Verify propagation, do not assume it.
dig +short example.com @1.1.1.1,@8.8.8.8and a couple of ISP resolvers; expect the new IP within the old TTL and treat anything longer as a stuck record - usually a second A record or an old wildcard nobody remembered.
Services that pin IPs outside DNS - mobile apps with hardcoded endpoints, outbound webhooks registered to an IP, email sending from a fixed address with rDNS - are the real long-tail. Grep your configs for the old IP (grep -r "203.0.113.10" /etc /opt /srv) and update rDNS and SPF before cutover, not after the first bounce.
Cutovers beyond the database: queues, sessions and cron
Files and databases get all the attention; the migrations that fail at 02:00 fail on background state instead. Three systems cover most of it.
- Queues and workers. If jobs live in Redis or a broker, decide: replicate the broker (preferred - mirror and fail over) or drain-and-switch (stop producers, wait for
LLENon every queue to hit zero, move consumers). Never start the new workers while old ones still consume - each job must have exactly one potential owner. - Sessions. Cookie-signed sessions survive a move transparently; server-side sessions stored in files or a local memcached do not. Either externalize sessions to the migrated store before the move, or accept that users log in again once - and say so in the maintenance notice.
- Cron and timers. Overlap means double execution. Export (
crontab -lfor each user, plussystemctl list-timers --all), disable on the old box before enabling on the new, and add a flock guard to idempotency-unsafe jobs:* * * * * flock -n /tmp/job.lock /usr/local/bin/job.sh.
The audit trick that catches stragglers: on the old box, journalctl --since "cutover time" and grep for anything still writing. Any process still touching disk after cutover is a component you forgot to plan.
How to verify the migration worked, before you cancel anything
Verification is a checklist, not a feeling, and every item runs from outside the new box:
- Service probes: HTTP status and content hash on a set of representative URLs (
curl -s https://example.com | sha256sumcompared against the old box's output), TLS expiry and chain (openssl s_client -connect example.com:443 -brief), database connection from the application's own config. - Write path: perform one real write (a test order, a test post) and confirm it appears, persists across a service restart, and lands in the new backups.
- Background systems: confirm cron fired on the new box at the expected minute, queues are draining, and mail exits with correct rDNS (
dig -x <new-ip>). - Observables: error rates in logs for 24 hours (
journalctl -p err --since today) and latency from your audience region - a new rack can be geographically different enough to change p95 even when everything works.
Only when all four have been quiet for a full billing-relevant day do you cancel the old server. Keep its last backups for at least one full backup cycle beyond cancellation.
Troubleshooting a live migration: symptom, cause, fix
| Symptom | Likely cause | Fix |
|---|---|---|
| Some users still hit the old box hours after cutover | High TTL cached before you lowered it, or pinned DNS (mobile app, hardcoded webhook) | Keep the old box serving read-only until stragglers drain; for pins, proxy from the old IP to the new one at the load-balancer level |
| Database replication lag grows instead of shrinking | Bulk rsync competing with the replication stream for uplink | Throttle the final rsync with --bwlimit=20000 or pause it; let replication reach zero before the freeze |
| SSH warns about changed host key after the move | Host keys not copied, or copied without the private halves | Copy /etc/ssh/ssh_host_* including private keys, or accept the new fingerprint and tell users once |
| Cron jobs ran twice during the overlap | Both boxes enabled during the drain window | Disable old crons before enabling new ones next time; for now, dedupe the produced artifacts and add the flock guard |
| Everything works but mail bounces | rDNS, SPF or the sending IP changed with the rack | Set rDNS for the new IP, update SPF, and warm the new IP gradually rather than switching full volume at once |
Every row above is cheaper to prevent than to fix, which is why the pre-migration checklist and this table read as pairs - each symptom names the checklist item that would have caught it.
Rehearse on the target before the real cutover
A migration you have never run is a migration you are debugging live. The staged pattern exists precisely so you can rehearse it: deploy the target box a week early, run the full rsync-plus-replication sequence against it during off-hours, cut a staging hostname over, and keep the rehearsal artifacts - the manifest, the timings, the freeze-window length. On cutover day, the only new thing is the date.
The rehearsal week is also where the direction of travel gets decided in practice: moves into BitCloudVPS racks use the identical procedure as moves between two of our locations - deploy the target in the chosen datacenter, sync, replicate, freeze for the measured window, cut. Total cost of the pattern is one extra server for one to two weeks; on a Starter box that is under $20 for the overlap, and the monthly term exists exactly for this kind of temporary capacity.
BitCloudVPS Starter · deploy the migration target · $8.50/mo, monthly term
Deploy in 60 secondsPre-migration checklist: measure before you move
Zero-downtime migrations fail on unknowns, so the week before the move is for measurement, not copying. Inventory what actually serves traffic: open ports, cron jobs, timers, certificates and their renewal hooks, reverse-proxy configs, and anything stateful from queues to uploaded files that rsync instinct alone will miss. Measure real resource use over several days - sustained CPU, peak RAM, disk growth per week - because the target plan is chosen from that, not from the old provider's marketing sheet. On the BitCloudVPS side the sheet is concrete: Starter 2 vCPU/4 GB ECC/60 GB NVMe at $8.50, Business 6 vCPU/16 GB/240 GB NVMe at $30 list ($24/mo billed yearly), storage line 1-5 TB when the dataset is the point. Lower DNS TTLs to 60-300 seconds a day ahead of cutover. And decide the rollback criterion in advance: a migration without a written 'abort if X' line tends to become a weekend of improvisation. Provisioning the target takes about 60 seconds, which removes any excuse for starting the checklist without a destination ready.
Database cutovers: the hard part of zero downtime
Files replicate with rsync; databases need a promotion story. The general pattern: configure the target as a replica of the source, let it catch up, then switch writes at a moment you choose rather than when the copy happens to finish. For PostgreSQL that is streaming replication with a final promote; for MySQL, a replica promoted after the write freeze; for SQLite-sized workloads, a brief write lock plus a file copy is honest and fast. Sequence the cutover: stop writes on the old primary, confirm the replica is at or past the last transaction, promote, point the application at the new primary, then re-enable writes. Two failure modes deserve rehearsal: clock skew between boxes breaking replication assumptions, and applications that cache connection strings and need a restart, not a config reload - know which yours is before the window. Keep replication running in reverse after cutover if you want a near-instant rollback path: the old box becomes the replica of the new primary, and an abort is a promotion in the other direction. That reverse replica is also your safety net during the first week, when obscure background jobs surface one by one.
Rollback planning: when to abort, and how
A migration without a pre-agreed abort condition always runs long. Decide the criteria in writing before cutover: which smoke tests must pass within how many minutes - login works, a write lands, a checkout completes - and define the abort as a reversible action, not a mood. The mechanics are simple if you prepared: DNS back to the old IP with the already-lowered TTL, writes re-enabled on the old primary (or promoted from the reverse replica), application configs pointed back. Keep the old VPS alive and unchanged for a rollback window - two weeks covers most latent surprises like monthly cron jobs and quarter-end reports; snapshot it before decommission so the final teardown is one click. Budget the overlap honestly: running two servers means two invoices for those weeks, so a $3-$8.50/mo old Nano alongside the new Business is a cheap insurance policy, while overlapping dedicated servers at $79.50-$449.50/mo make the window a real cost to minimize. The last step is boring and non-negotiable: verify backups run on the new box before you cancel the old one, because a migration that ends with no tested restore path has only moved the risk.
Read enough? Provision the target and rehearse
Migrations reward rehearsal: provision the target now, run the replication and cutover once against a test domain, then do it for real. Deploy takes about 60 seconds in any of 21 locations, plans from $3/mo effective, paid in any of 19 crypto assets with no KYC - including moves away from providers that wanted a passport scan. Get the $24 Business plan
Cost and time budgeting: what the staged window actually takes
The direct answer: a staged zero-downtime move costs you the second server for the overlap period plus one focused maintenance hour; on this catalog that means the cheapest viable target — Nano at $5.49/mo for a front-end rehearsal, Starter at $8.50 (2 vCPU, 4 GB ECC, 60 GB NVMe) once real state is involved — paid monthly, because the annual term's 20% discount is wasted on a box you plan to delete in three weeks.
Time budget by phase, for a typical single-service box. Provision and baseline the target: under an hour, since deploy takes about a minute and the hardening steps are scripted from your runbook. First rsync pass: however long the data takes at line rate — with unmetered 1-10 Gbps ports and short rack-to-rack RTT (Amsterdam to Frankfurt is ~8 ms, Amsterdam to Reykjavik ~18 ms), most datasets of tens of gigabytes move in well under an hour; the pass runs while the source is live, so it costs no downtime at all. Delta passes: minutes each, and you can run several. The cutover itself — final delta, brief write-freeze, DNS flip, verify — is the one phase where users might notice, and with a pre-lowered TTL it is measured in seconds to a couple of minutes. Keep the source running for a full TTL-plus-a-day afterwards as the instant rollback path; then decommission it.
That makes the honest total: one small monthly bill plus an evening, with the risky window being minutes long. How to verify the budget holds: rehearse the whole sequence against the target before the real cutover — the rehearsal costs nothing extra since the target already exists, and it converts 'about an hour' from an estimate into a measurement.
BitCloudVPS Starter · rehearse the move on real hardware · $8.50/mo
Deploy in 60 secondsWhere the limits are (October 2026)
Keep the threat model precise. Anonymous-adjacent hosting removes the host-side identity trail: token-only signup, optional email, no KYC review, crypto invoices that record a txid rather than a name. It does not blind the host to traffic it must carry, it does not make a logged-in panel session anonymous, and it does not protect workloads that identify themselves — an admin login from your home IP defeats the whole design. Exact limits of no-KYC anonymity. OPSEC guide. Full checklist. Payment-side note: chain analysis happens on public blockchains, not at the host. Coin choice and network choice are your OPSEC knobs, and the checkout keeps 19 of them open.
Can BitCloudVPS migrate my server for me?
No managed migration service — you get root and this playbook. Remote hands on dedicated tiers assist with hardware-level work.
How do I move without changing my IP?
You cannot take an IP across providers — plan DNS cutovers and short TTLs; use a proxy or VPN endpoint if IP continuity is critical.
Which direction is most common?
Into no-KYC locations from mainstream clouds — the replication pattern is identical either way.
How long does the write-freeze window need to be?
<p>For a database under a few GB with the final rsync pre-warmed, tens of seconds: dump or final sync, restore or catch up, verify service start. Measure it in rehearsal; the measured number, not hope, is what you publish to users.</p>
Can I migrate a running Docker Compose stack with this pattern?
<p>Yes - migrate the compose file, volumes and images as state: rsync bind-mounted volumes in the loop, <code>docker save</code>/<code>load</code> or re-pull images, then bring the stack up before the DNS drain. Named volumes must be rsynced separately from the filesystem pass.</p>
What should I do about the old server's IP-reputation history?
<p>Plan the identity layer deliberately: set rDNS on the new IP on day one, update SPF/DKIM, and warm email volume over a week rather than switching at once. Do not attempt to "transfer" reputation - it does not move between IPs.</p>
Is annual billing wrong while my setup is still changing?
<p>Yes, for migrating boxes: stay monthly during the overlap and rehearsal, then take the -20% annual term on the target only after a full billing month of verified stability. The quarterly -10% term covers the in-between case.</p>
How low should DNS TTLs be before a cutover?
Set 60-300 seconds about a day ahead, then verify with a DNS lookup that authoritative servers actually serve the short TTL. Long TTLs cached by resolvers are the usual reason a 'finished' migration still sends traffic to the old box for hours.
Can I migrate between two BitCloudVPS locations with this pattern?
Yes - the pattern is identical for any direction, including between two of the 21 locations here. Deploy the target, replicate over SSH, switch at the data layer. IPs do not travel between locations, so plan DNS and TLS exactly as for a cross-provider move.
How do I benchmark disk and network on the target before moving a database?
Run the same fio profile your database actually produces (a mix of random 4k writes and sequential reads is typical) and an iperf3 test from the source to the target, both while the target is idle. Compare against the same tests on the source; if the target wins on both, the move is safe to schedule, and you have your expected sync time for the budget.
What does the second, target box cost during a staged migration?
A throwaway target for rsync rehearsal can be as cheap as the Nano at $5.49/mo list or $36/yr flat, while the real target usually mirrors your current tier — Starter at $8.50 is the common match. Quarter billing takes 10% off, so a one-to-two-month overlap stays inexpensive.
What does the host actually know about me?
Whatever you hand over: a signup token, an optional email address, the invoice you paid and the service traffic. No ID documents, no phone number, no KYC step exists to hand anything else over.
What won't an anonymous VPS protect against?
Self-inflicted links: personal logins from a home IP, leaked cookies, services that publish your address, and on-chain patterns that tie wallets together. The server removes one identifier; it does not fix operational mistakes.
Ready to launch?
Configure a VPS or dedicated server, set a password, then pay the invoice.
Network
Edge RTT
Uptime · 36h
Complaints · 36h