Tuesday, August 19, 2025

Step-by-Step Guide to Migrating Your Website to a VPS in Germany

 Here’s a clear, production‑ready, step‑by‑step guide to migrating your website to a VPS in Germany. It’s written for busy teams and solo builders alike, with copy‑paste commands, zero‑downtime tactics, and post‑cutover checks. (If you still need a German VPS, you can use your preferred provider—many readers choose 99RDP for Frankfurt‑based instances.)



0) What you’ll need (checklist)

  • Domain registrar access (to update DNS A/AAAA/CNAME).

  • SSH or RDP access to your current host.

  • A fresh German VPS (Ubuntu 22.04 LTS or Debian 12 recommended; Windows Server if you use IIS/.NET).

  • Application stack info: web server (Nginx/Apache/IIS), language/runtime (PHP/Node/Python), database (MySQL/MariaDB/PostgreSQL/MongoDB), background jobs (cron/queue), storage (local/NFS/S3/CDN).

  • A rollback plan: a snapshot of the old server or a full backup you can restore quickly.

1) Plan for zero surprises

  1. Inventory everything

    • Site files, env variables/secrets, SSL certs, database(s), scheduled tasks, queue workers, geo‑blocked IP rules, CDN settings, email sending (SMTP/API), third‑party callbacks (webhooks), and payment IP allowlists.

  2. Pick the German location

    • Frankfurt is a popular hub (low latency to EU via DE‑CIX). If your audience is DACH/EU, you’ll usually see faster TTFB.

  3. Lower DNS TTL

    • 24 hours before cutover, set your domain’s A/AAAA/CNAME TTL to 300 seconds. This speeds up propagation during the move.

  4. Freeze the write path (near cutover)

    • Put the site in maintenance or read‑only mode just before final sync to prevent data drift (especially carts, comments, or dashboards).

2) Provision and harden the German VPS

Linux (Ubuntu/Debian)

# Update base system
sudo apt update && sudo apt -y upgrade

# Create a non-root sudo user
sudo adduser deploy
sudo usermod -aG sudo deploy

# Harden SSH
sudo -s
mkdir -p /home/deploy/.ssh
nano /home/deploy/.ssh/authorized_keys   # paste your public key
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys

# Optional: change SSH port and disable password login
nano /etc/ssh/sshd_config
# Port 2222 (example)
# PasswordAuthentication no
systemctl restart ssh

# Basic firewall
sudo apt -y install ufw fail2ban
sudo ufw allow 2222/tcp   # or your SSH port
sudo ufw allow http
sudo ufw allow https
sudo ufw enable

# (Optional) swap if RAM is tight
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Windows Server (IIS)

  • Create an Administrator alt user, enable RDP, update OS.

  • Install IIS + URL Rewrite + ARR if needed, and Web Deploy for app import.

  • Set Windows Firewall rules for RDP (3389), HTTP (80), HTTPS (443).

3) Install your runtime stack

Choose what you use; here are common recipes.

LEMP (Nginx + PHP + MySQL/MariaDB)

sudo apt -y install nginx
sudo apt -y install mariadb-server  # or mysql-server
sudo apt -y install php-fpm php-mysql php-cli php-xml php-curl php-zip php-gd

LAMP (Apache + PHP)

sudo apt -y install apache2
sudo apt -y install mariadb-server
sudo apt -y install php libapache2-mod-php php-mysql php-xml php-curl php-zip php-gd

Node.js

sudo apt -y install curl
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt -y install nodejs

Create a systemd service (example):

sudo nano /etc/systemd/system/myapp.service
# -----------------------------------------
[Unit]
Description=My Node App
After=network.target

[Service]
User=deploy
WorkingDirectory=/var/www/myapp
ExecStart=/usr/bin/node server.js
Restart=always
Environment=NODE_ENV=production
# -----------------------------------------
sudo systemctl daemon-reload
sudo systemctl enable --now myapp

Python (Gunicorn + Nginx)

sudo apt -y install python3-venv python3-pip
python3 -m venv /var/www/myapp/venv
source /var/www/myapp/venv/bin/activate
pip install gunicorn yourframework

Docker (if you containerize)

sudo apt -y install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu $(. /etc/os-release; echo "$VERSION_CODENAME") stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update && sudo apt -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin

4) Stage the site files on the VPS

Option A: rsync (fast, incremental)

# from OLD server -> NEW VPS
rsync -avz --progress -e "ssh -p 2222" /var/www/your_site/ deploy@NEW_VPS_IP:/var/www/your_site/

Option B: scp

scp -P 2222 -r /var/www/your_site/ deploy@NEW_VPS_IP:/var/www/your_site/

Option C: Dockerized

# Save and move your images if needed
docker save your-image:tag | gzip > image.tar.gz
scp -P 2222 image.tar.gz deploy@NEW_VPS_IP:~
ssh -p 2222 deploy@NEW_VPS_IP "gunzip -c ~/image.tar.gz | docker load"

Set correct permissions:

sudo chown -R www-data:www-data /var/www/your_site
sudo find /var/www/your_site -type d -exec chmod 755 {} \;
sudo find /var/www/your_site -type f -exec chmod 644 {} \;

5) Migrate the database safely

MySQL/MariaDB

# On OLD server
mysqldump -u root -p --single-transaction --routines --triggers yourdb > yourdb.sql

# Transfer & import on NEW
scp -P 2222 yourdb.sql deploy@NEW_VPS_IP:~
ssh -p 2222 deploy@NEW_VPS_IP
mysql -u root -p -e "CREATE DATABASE yourdb /*\!40100 DEFAULT CHARACTER SET utf8mb4 */;"
mysql -u root -p yourdb < ~/yourdb.sql

PostgreSQL

# On OLD server
pg_dump -U postgres -Fc yourdb > yourdb.dump

# Transfer & restore
scp -P 2222 yourdb.dump deploy@NEW_VPS_IP:~
ssh -p 2222 deploy@NEW_VPS_IP
createdb -U postgres yourdb
pg_restore -U postgres -d yourdb ~/yourdb.dump

MongoDB

mongodump --db yourdb --out dumpdir
scp -P 2222 -r dumpdir deploy@NEW_VPS_IP:~
mongorestore --db yourdb ~/dumpdir/yourdb

Update app config (env file) to point to the new local DB socket/host, credentials, and any changed ports.

6) Configure the web server & SSL

Nginx server block (PHP‑FPM example):

sudo nano /etc/nginx/sites-available/your_site
# ------------------------------------------------
server {
    server_name yourdomain.com www.yourdomain.com;
    root /var/www/your_site/public;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.1-fpm.sock;  # adjust version
    }

    access_log /var/log/nginx/your_site.access.log;
    error_log  /var/log/nginx/your_site.error.log;
}
# ------------------------------------------------
sudo ln -s /etc/nginx/sites-available/your_site /etc/nginx/sites-enabled/your_site
sudo nginx -t && sudo systemctl reload nginx

Let’s Encrypt (HTTPS)

sudo apt -y install certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com --redirect --agree-tos -m you@example.com

Apache vhost (snippet)

sudo a2enmod rewrite
sudo nano /etc/apache2/sites-available/your_site.conf
# ------------------------------------------------
<VirtualHost *:80>
    ServerName yourdomain.com
    ServerAlias www.yourdomain.com
    DocumentRoot /var/www/your_site/public
    <Directory /var/www/your_site/public>
        AllowOverride All
        Require all granted
    </Directory>
    ErrorLog ${APACHE_LOG_DIR}/your_site.error.log
    CustomLog ${APACHE_LOG_DIR}/your_site.access.log combined
</VirtualHost>
# ------------------------------------------------
sudo a2ensite your_site && sudo systemctl reload apache2
sudo apt -y install certbot python3-certbot-apache
sudo certbot --apache -d yourdomain.com -d www.yourdomain.com

7) Test privately before going live

  1. Edit local hosts file to point the domain to the new VPS IP so only you see the new server:

    • macOS/Linux: /etc/hosts

    • Windows: C:\Windows\System32\drivers\etc\hosts

    NEW_VPS_IP yourdomain.com www.yourdomain.com
    
  2. Browse the site. Check:

    • Pages, logins, forms, checkout flow

    • File uploads/downloads

    • Admin panel actions

    • Background jobs/queues

    • Webhooks (temporarily repoint a test webhook to staging if possible)

    • Error logs: /var/log/nginx/*.log or /var/log/apache2/*.log

8) Final sync & cutover

  1. Enable maintenance mode on the old server (or freeze writes).

  2. Final rsync + DB dump (fast delta copy):

    # files
    rsync -avz --delete -e "ssh -p 2222" /var/www/your_site/ deploy@NEW_VPS_IP:/var/www/your_site/
    
    # database - repeat the dump/import quickly
    # (MySQL example)
    mysqldump -u root -p --single-transaction yourdb > final.sql
    scp -P 2222 final.sql deploy@NEW_VPS_IP:~
    ssh -p 2222 deploy@NEW_VPS_IP "mysql -u root -p yourdb < ~/final.sql"
    
  3. Switch DNS

    • Update A (and AAAA if using IPv6) records to the German VPS IP.

    • Thanks to low TTL (300s), most users will hit the new server within minutes.

  4. Keep the old server online for 24–48 hours (serving the maintenance page) in case of stragglers due to caching.

9) Post‑migration checks (the “first hour”)

  • HTTPS: no mixed content; HSTS if you used it before.

  • SEO: 200/301/404 status codes behave as before; robots.txt and sitemaps load; canonical tags correct; redirect www/non‑www and HTTP→HTTPS.

  • Performance: verify TTFB and core pages; enable opcache (PHP), gzip/brotli, HTTP/2/3 if supported.

  • Queues/cron:

    crontab -e    # install your cron jobs
    # or systemd timers / supervisor as previously
    
  • Email: SMTP creds on the new host; SPF/DKIM/DMARC unchanged at DNS.

  • Webhooks (Stripe/PayPal/etc.): confirm the new public IP is allowed if you used allowlists.

10) Hardening, backups, and monitoring

Security basics

# Unattended security updates
sudo apt -y install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

# Fail2ban jail (default works for SSH/Nginx/Apache)
sudo systemctl enable --now fail2ban

Backups

  • Files: nightly rsync to another volume or object storage.

  • DB: nightly dumps with retention. Example MySQL backup script:

sudo nano /usr/local/bin/db_backup.sh
# -----------------------------------------
#!/bin/bash
set -e
STAMP=$(date +%F_%H%M)
mysqldump -u root -p'yourpass' --single-transaction yourdb | gzip > /backup/yourdb_$STAMP.sql.gz
find /backup -type f -mtime +7 -delete
# -----------------------------------------
sudo chmod +x /usr/local/bin/db_backup.sh
(crontab -l 2>/dev/null; echo "15 2 * * * /usr/local/bin/db_backup.sh") | crontab -

Monitoring

  • Install metrics/log shipping (Netdata/Prometheus agent/Elastic agent) and set uptime checks from multiple regions (EU/US/Asia).

11) Troubleshooting quick fixes

  • 502/504 (Nginx ↔ upstream)

    • App not running or wrong socket/port. Check service: systemctl status php8.1-fpm or your app service. Verify fastcgi_pass/proxy_pass.

  • 403/404 after move

    • File permissions/owners. Ensure:

      sudo chown -R www-data:www-data /var/www/your_site
      
    • Apache: AllowOverride All for .htaccess rewrites.

  • PHP uploads failing

    • Increase limits:

      php.ini: upload_max_filesize, post_max_size, memory_limit
      Nginx: client_max_body_size 50M;
      
  • Database connection refused

    • Service listening locally? Confirm sockets/ports. Recheck env variables and credentials.

  • Mixed content

    • Update app/site URL to https:// in CMS settings; run a safe search‑replace if needed.

  • Email not sending

    • New server’s IP may be blocked by a provider’s policy; double‑check SMTP host, port, TLS; ensure PTR (reverse DNS) is configured by your provider if sending mail directly.

12) If you use a CMS or framework

  • WordPress

    • Update WP_HOME and WP_SITEURL in wp-config.php or in DB.

    • Regenerate .htaccess via Permalinks.

    • Cache/OPcache/WAF rules as before; image/CDN endpoints intact.

  • Laravel / Symfony / Django / Rails / Next.js

    • Recreate .env with production values (keys, DB, mail).

    • Run migrations/build:

      composer install --no-dev --optimize-autoloader
      php artisan migrate --force
      npm ci && npm run build   # if applicable
      
    • For Python: pip install -r requirements.txt, run collectstatic if Django.

13) Zero‑downtime pattern (summary)

  1. Lower TTL to 300s (T‑24h).

  2. Full initial sync (files + DB) to German VPS.

  3. Private testing via hosts file.

  4. Maintenance/read‑only on old server.

  5. Final delta sync (fast).

  6. DNS switch to German VPS.

  7. Keep old server as warm standby for 24–48h.

  8. Monitor, then decommission.

14) Notes specific to a German VPS

  • Latency: users in DE/AT/CH and much of EU will see improved latency; peering in Frankfurt is excellent.

  • Data locality & compliance: hosting in Germany helps keep EU resident data in the EU, which many teams prefer for regulatory/contract reasons. (Always validate your own compliance needs.)

  • IPv6: enable AAAA records if your provider offers native IPv6—many EU networks do.

15) Optional: IIS / Windows quick path

  • Export site via Web Deploy on the old host, import on the new Windows Server in Germany.

  • Bindings: set hostnames on port 80/443 in IIS Manager.

  • SSL: import existing cert (PFX) or issue via your preferred CA; complete the HTTPS binding.

  • Update web.config rewrites and test via hosts file before DNS cutover.

16) Decommission the old server (only when ready)

  • Take a final snapshot, keep backups for the retention period you need.

  • Remove secrets/keys, revoke any old API tokens bound to the old IP.

  • Update runbooks/docs with the new host’s details.

Quick CTA

If you need a ready‑to‑go VPS in Germany, many teams use providers like 99RDP—pick a Frankfurt location, attach IPv6 if available, and follow the checklist above for a smooth cutover.


No comments:

Post a Comment

Admin RDP vs Traditional Remote Desktop Software: Pros and Cons

In the digital age, remote access has become a necessity for businesses, IT professionals, and individuals who need to manage systems, perfo...