Moving hosts sounds scary and is mostly rsync, DNS and patience. The trick is two passes: a slow one while the old server still runs, and a fast final one that takes seconds.
Order a Buran VPS, install the same OS version as the old server, and do the basics: SSH keys and firewall. Install the same services (nginx, PostgreSQL, Docker) at the same versions — but do not start them yet.
From the new server, pull the data. This pass can take as long as it wants; nobody notices it.
rsync -avz --delete \
--exclude=/proc --exclude=/sys --exclude=/dev --exclude=/tmp \
--exclude=/var/lib/postgresql \
root@OLD_SERVER_IP:/etc /etc
rsync -avz --delete root@OLD_SERVER_IP:/var/www /var/www
rsync -avz --delete root@OLD_SERVER_IP:/root /root
Database data directories are excluded on purpose — a live PostgreSQL or MySQL dir copied file-by-file is broken. Databases move as dumps.
On the old server:
pg_dumpall -U postgres > /root/all-databases.sql
# or per database, compressed:
pg_dump -Fc -U postgres appdb > /root/appdb.dump
Pull the dumps to the new server and import them:
rsync -avz root@OLD_SERVER_IP:/root/all-databases.sql /root/
sudo -u postgres psql < /root/all-databases.sql
Put the app in maintenance mode, run the final sync and start services:
# on the old server
pg_dumpall -U postgres > /root/final.sql
# on the new server
rsync -avz --delete root@OLD_SERVER_IP:/var/www /var/www
rsync -avz root@OLD_SERVER_IP:/root/final.sql /root/
sudo -u postgres psql < /root/final.sql
systemctl enable --now nginx postgresql myapp
Test locally first — before touching DNS:
curl -H "Host: example.com" http://127.0.0.1
Change the A record to the new IP and lower the TTL to 300 seconds a day before — the old value expires quickly. Within minutes most visitors are on the new server; stragglers arrive over the next hours.
Certificates: run certbot --nginx on the new server after DNS resolves there. If you use Cloudflare proxy, flip the record and re-issue as usual — the commands are in the Nginx guide.
Check from several places: website, API, mail, cron jobs, backups. Watch the old server's logs for an hour — any traffic left there means something still points at the old IP.
tail -f /var/log/nginx/access.log
crontab -l
systemctl list-timers
Keep the old server for a week after the switch. Then cancel it — no drama, and an easy rollback if you missed something.
With the two-pass rsync method, downtime is only the final sync plus DNS propagation — typically 2 to 10 minutes. A maintenance page on the old server makes it invisible.
Any hardcoded old IP has to change: nginx upstreams, app configs, firewall allowlists. Search the configs with grep for the old IP before the final sync.
Provisioning is fully automatic, and the panel gives you console and reinstall access; migration is a standard rsync job you can run yourself in half an hour. If something does not fit, [email protected] answers within 30 minutes.