Loading...
Home
Explore
Contact
Sign in
Cloud Migrations & Setup

Migrate Off AWS to Hetzner Bare-Metal Linux and Cut Costs

Unpredictable AWS bills? A practical Australia-focused guide to migrating workloads to Hetzner bare-metal Linux—inventory, cutover steps, common failures, and when Fixwebnode should handle the move.

Fixwebnode Support
Fixwebnode Support
10 min read 20 views
Migrate Off AWS to Hetzner Bare-Metal Linux and Cut Costs

If your AWS invoice keeps swinging month to month and you want stable bare-metal Linux costs instead, this guide walks Australian site owners and small businesses through a practical Hetzner migration path.

Unpredictable egress, managed database add-ons, idle instances left running, and multi-AZ “just in case” spend are the usual culprits. Moving selected workloads to Hetzner dedicated or cloud Linux servers can cut hosting spend dramatically when you right-size CPU, RAM, and disk and stop paying for every managed convenience you no longer need. Fixwebnode provides remote Linux server support for planning, cutover, and post-move hardening across Australia—not a freelance board, a direct specialist team you book for this exact job.

Why unpredictable AWS bills push teams toward Hetzner bare metal

AWS is excellent for bursty elasticity. It is expensive when your traffic is steady, your architecture grew organically, and nobody owns a weekly cost review. Bare-metal or simple VPS Linux on Hetzner gives you fixed monthly hardware pricing, full root access, and fewer surprise line items—if you migrate carefully.

This post stays on that path: inventory what you run on AWS, stand up equivalent Linux on Hetzner, move data and DNS with minimal downtime, and fix the failure modes Australian operators hit most often (latency to EU/DE/FI regions, TLS and mail after cutover, and half-migrated databases).

How do you migrate AWS workloads to Hetzner Linux from Australia without downtime?

You inventory services and data on AWS, provision matching Ubuntu or Debian hosts on Hetzner, replicate databases and object storage, switch DNS with a short TTL, then decommission AWS only after health checks pass. Most small stacks can cut over in a maintenance window if you rehearse restore and reverse-proxy cutover first.

SymptomQuick check / fixCall Fixwebnode when
Bill spikes with steady trafficMap egress, NAT, idle RDS/EC2; plan fixed Hetzner sizingMulti-account sprawl or unknown spend drivers
App slow after move to EU/DEMeasure RTT; enable CDN/cache; pick closer Hetzner DCYou need architecture redesign for AU users
Cutover breaks TLS, mail, or DBVerify certs, SPF/DKIM, replica lag before DNS flipProduction data risk or no rollback plan

Common issues when leaving AWS for Hetzner bare-metal Linux

These problems show up repeatedly for Australian businesses doing the move themselves. Each has a different root cause.

1. Surprise AWS cost drivers you never inventory

Symptoms: invoice jumps 30–200% with little traffic change; Cost Explorer shows data transfer, NAT Gateway, gp3 IOPS, idle load balancers, or forgotten snapshots. You cannot size Hetzner until you know what actually costs money.

2. High latency for Australian users after landing on EU or Finnish hardware

Symptoms: TTFB climbs, admin panels feel sluggish, API timeouts increase after DNS points at Falkenstein, Nuremberg, or Helsinki. The app is “up” but UX is worse than Sydney-region AWS.

3. Half-migrated data and broken cutover (DB lag, object storage, secrets)

Symptoms: 500 errors after DNS flip, missing images, login failures, or writes going to the old RDS while the new MySQL/Postgres is stale. Secrets still reference AWS Parameter Store or IAM roles the bare-metal box cannot use.

4. TLS, email deliverability, and firewall gaps on fresh bare metal

Symptoms: browser cert warnings, mail landing in spam, SSH open to the world, or fail2ban/ufw never configured because “security groups used to do that.”

Issue 1 — Map AWS spend and decide what moves to Hetzner

Without a clean inventory you will either oversize Hetzner or leave expensive AWS remnants running for months.

Step 1 — Export a service and cost snapshot

In AWS Cost Explorer, filter last 90 days by service. On any bastion or laptop with AWS CLI configured:

aws ce get-cost-and-usage \
 --time-period Start=2025-01-01,End=2025-02-01 \
 --granularity MONTHLY \
 --metrics UnblendedCost \
 --group-by Type=DIMENSION,Key=SERVICE

aws ec2 describe-instances --query 'Reservations[].Instances[].[InstanceId,InstanceType,State.Name,Tags]' --output table
aws rds describe-db-instances --query 'DBInstances[].[DBInstanceIdentifier,Engine,DBInstanceClass,Endpoint.Address]' --output table
aws s3api list-buckets --query 'Buckets[].Name' --output text

Record instance sizes, RDS engines/versions, S3 bucket sizes, and monthly transfer. Note anything that must stay on AWS temporarily (e.g. SES, specific managed AI APIs).

Step 2 — Right-size the Hetzner target

Match vCPU/RAM to steady load, not peak AWS “burst” marketing. Prefer one solid dedicated or CX/CPX cloud server over many tiny boxes unless you truly need isolation. Plan disk: NVMe for DB, separate volume or Box/Storage Box for backups.

Step 3 — Freeze change and lower DNS TTL

# At your DNS host, set A/AAAA TTL to 300 before migration week
# Verify current records
dig +noall +answer yourdomain.com.au A
dig +noall +answer yourdomain.com.au AAAA

When to call Fixwebnode: multi-account organisations, shared VPCs, or no single owner of Cost Explorer—book a remote discovery so the Hetzner bill target is real, not a guess.

Issue 2 — Fix Australia-to-Europe latency after the move

Hetzner’s strongest price/performance is often in Germany or Finland. From Australia that adds RTT. You either pick the best available location, cache aggressively, or keep latency-sensitive tiers closer.

Step 1 — Measure before and after

# From an AU workstation or jump host
ping -c 20 <hetzner-server-ip>
curl -o /dev/null -s -w 'DNS %{time_namelookup} TLS %{time_appconnect} TTFB %{time_starttransfer} total %{time_total}\n' https://yourdomain.com.au/
mtr -rwzc 50 <hetzner-server-ip>

Step 2 — Application-level mitigation on Ubuntu/Debian

sudo apt update
sudo apt install -y nginx redis-server
# Enable gzip/brotli and long cache for static assets in Nginx
sudo nano /etc/nginx/sites-available/app

Serve static assets with long Cache-Control, put Redis in front of session/query hot paths, and terminate TLS on Nginx. For WordPress or similar, offload media to a CDN edge that reaches AU well; keep origin on Hetzner.

Step 3 — Verify perceived speed

curl -I https://yourdomain.com.au/
# Confirm cache headers and HTTP/2
nginx -t && sudo systemctl reload nginx

When to call Fixwebnode: if core transactional APIs must stay sub-100ms for AU users, you may need a hybrid design (AU edge or selective AWS retention). That is architecture work, not a weekend DNS flip.

Issue 3 — Complete data cutover without a split brain

Most failed migrations are database and object-storage problems, not “Linux install” problems.

Step 1 — Provision Hetzner Linux and baseline hardening

# On new Ubuntu 22.04/24.04 Hetzner host
sudo apt update && sudo apt -y upgrade
sudo adduser deploy
sudo usermod -aG sudo deploy
sudo apt install -y ufw fail2ban unattended-upgrades curl git
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo systemctl enable --now fail2ban

Step 2 — Install runtime stack (example: Nginx + PHP-FPM + MariaDB)

sudo apt install -y nginx mariadb-server redis-server \
 php-fpm php-mysql php-xml php-curl php-mbstring php-zip
sudo systemctl enable --now nginx php8.3-fpm mariadb redis-server
# Adjust phpX.Y-fpm to the version Ubuntu installed
php -v
sudo mysql_secure_installation

Step 3 — Replicate the database (MySQL/MariaDB example)

# On AWS source (dump during low traffic; prefer replica if available)
mysqldump -h YOUR_RDS_ENDPOINT -u migrate -p \
 --single-transaction --routines --triggers --events \
 --databases appdb | gzip -c > appdb.sql.gz

scp appdb.sql.gz deploy@HETZNER_IP:/tmp/
# On Hetzner
gunzip -c /tmp/appdb.sql.gz | sudo mysql
sudo mysql -e "CREATE USER 'app'@'localhost' IDENTIFIED BY 'STRONG_PASSWORD'; GRANT ALL ON appdb.* TO 'app'@'localhost'; FLUSH PRIVILEGES;"

For Postgres, use pg_dump -Fc / pg_restore the same way. For a final cutover, take a short write lock or put the app in maintenance, dump again, import, then flip DNS.

Step 4 — Move object storage and rewrite secrets

# Example: sync S3 bucket to local disk or Hetzner Storage Box via rclone
rclone sync s3:your-bucket /var/www/app/storage/uploads --progress
# Update app env — remove IAM role assumptions
sudo nano /var/www/app/.env
# e.g. DB_HOST=127.0.0.1 FILESYSTEM_DISK=local
sudo systemctl restart php8.3-fpm nginx

Step 5 — Pre-flight on the Hetzner IP before DNS

curl -k -H 'Host: yourdomain.com.au' https://HETZNER_IP/
journalctl -u nginx -n 50 --no-pager
tail -n 100 /var/log/nginx/error.log
sudo mysql -e 'SHOW DATABASES; SELECT COUNT(*) FROM appdb.users;'

Step 6 — DNS cutover and AWS soak period

Point A/AAAA to Hetzner, watch logs for 24–72 hours, keep AWS read-only or stopped but not destroyed until you confirm backups restore cleanly.

# After TTL expires
dig +short yourdomain.com.au A
curl -I https://yourdomain.com.au/

When to call Fixwebnode: multi-terabyte databases, zero-downtime requirements, or apps deeply tied to SQS, Lambda, and IAM—remote cutover planning prevents irreversible data divergence.

Issue 4 — TLS, mail, and “security groups are gone” hardening

On bare metal you own the edge. That is the point—and the risk.

Step 1 — Issue certificates with Certbot

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com.au -d www.yourdomain.com.au
sudo systemctl status certbot.timer
sudo certbot renew --dry-run

Step 2 — Rebuild mail authentication if you still send from the app

Prefer a transactional provider with clear AU deliverability rather than raw sendmail on the Hetzner box. Publish SPF, DKIM, and DMARC at your DNS host. If you must run Postfix, restrict relay and monitor blacklists—Fixwebnode usually recommends separating mail from the app server.

Step 3 — Confirm firewall and SSH posture

sudo ufw status verbose
sudo ss -tulpn
# Optional: key-only SSH
sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl reload ssh
sudo fail2ban-client status sshd

Step 4 — Automated backups (not optional after leaving AWS snapshots)

# Daily DB dump example
sudo mkdir -p /var/backups/mysql
echo '0 2 * * * root mysqldump --single-transaction --all-databases | gzip > /var/backups/mysql/all-$(date +\%F).sql.gz' | sudo tee /etc/cron.d/mysql-backup
# Sync off-box (Storage Box / remote) with rclone or rsync over SSH

When to call Fixwebnode: production PCI-ish stores, complex reverse proxies, or no one on staff who can prove restore from backup.

End-to-end migration checklist (DIY runbook)

  1. Cost and service inventory on AWS; list keep vs move.
  2. Lower DNS TTL; schedule maintenance window for AU off-peak.
  3. Provision Hetzner Ubuntu/Debian; SSH keys, ufw, fail2ban, unattended-upgrades.
  4. Install app runtime; import DB; sync files; rewrite secrets off IAM.
  5. Test via hosts-file or Host header against Hetzner IP.
  6. Certbot TLS; CDN if AU latency hurts.
  7. DNS flip; monitor logs and error rates.
  8. Keep AWS warm 48–72 hours; then snapshot final and terminate to stop bill bleed.
  9. Document new IPs, panel logins, backup jobs, and restore test date.

When DIY is enough vs when to book Fixwebnode

DIY is enough when you have one or two VMs, a single MySQL/Postgres app database under ~50GB, static or simple PHP/Node apps, and someone comfortable with SSH, Nginx, and mysqldump. Follow the numbered steps above, rehearse on a staging Hetzner box, and do not destroy AWS until restore works.

Book Fixwebnode when bills are chaotic across many accounts, the stack includes managed queues/Lambdas you must re-home, downtime must stay near zero, AU latency needs a deliberate design, or a previous cutover already left you in a split-brain state. We work remote across Australia as a direct server-support provider—see all regions on our service areas page—and we stay on the AWS-to-Hetzner path until health checks and backups are proven.

Talk through your AWS-to-Hetzner move

If unpredictable AWS invoices are the problem and fixed bare-metal Linux pricing is the goal, bring your Cost Explorer export and a rough architecture sketch. Fixwebnode will help you decide what to move, what to leave, and how to cut over without guessing. Start a conversation via our Linux server support page—practical remote migration help for Australian businesses ready to leave bill shock behind.

Share this article
Fixwebnode Support
Fixwebnode Support

Hey there!
I am your assistant for Fixwebnode. Ask about our services, quotes, packages, orders, or how to get support.
While you wait
What’s your name and best email? We’ll reply even if you leave.