VPNSmith
cloud-privacyINFO

AWS to Contabo migration: 2026 cost optimization guide

Step-by-step procedure to migrate an EC2 + RDS + S3 stack to Contabo VPS + self-hosted Postgres + S3-compatible storage. Measured ROI: 78% savings over 12 months.

By Eric Gerard · Fondateur · VPNSmith — Spécialiste self-host VPN & VPS GDPR9 min readPhoto: Luke Chesser — Unsplash

Your end-of-month AWS bill makes you grind your teeth. €187/mo for a Node.js + Postgres 50 GB + 200 GB of static objects stack, of which 60% goes to RDS and NAT Gateway. You know there's something cheaper, but you hesitate to abandon the comfort of EC2 and the magic of S3. This guide is the honest write-up of a migration we ran internally in April 2026: from AWS to a single Contabo VPS at €9.99/month, 78% savings over 12 months, with no significant feature loss for our use case.

Why leave AWS in 2026

Three cumulative reasons, not one:

  • Cost. AWS scales brutally with egress traffic ($0.09/GB above 100 GB), NAT Gateways ($45/mo just to exist), and RDS snapshots. A project that starts at $30/mo routinely ends up at $200-400/mo within 18 months without a single new feature.
  • GDPR & sovereignty. Even in eu-central-1 (Frankfurt), AWS is a US entity bound by the CLOUD Act: a US federal judge can compel access to data stored in Europe. For EU customer data, that's a real legal risk, formalized by the EDPB's 2020 recommendations (post-Schrems II).
  • Technical lock-in. IAM, KMS, VPC, ALB, Lambda — every AWS service ties you in a bit more. After two years, "just moving" takes three weeks. The longer you wait, the more you pay, and the more expensive leaving becomes.

Contabo isn't magic: it's a low-end German VPS provider that hands you an Ubuntu box and lets you do the rest. But for 80% of SMB and solo SaaS workloads, it's more than enough — and 5 to 10× cheaper.

When migration pays off (and when it doesn't)

Be honest with yourself. AWS → Contabo makes sense if:

  • You have one or two services to host (API + DB + objects), not a 30-container microservice architecture.
  • Your traffic is predictable (no 100× baseline spikes). Contabo has no auto-scaling.
  • You accept becoming the admin: apt, systemctl, ufw, manual backups.
  • Your data doesn't tolerate the CLOUD Act, or your AWS bill is past €100/mo.

Conversely, stay on AWS if:

  • You heavily use Lambda, Cognito, SageMaker, managed SQS. Migration cost > AWS cost.
  • You have a customer SLA requiring 99.99% (Contabo is 99.9%, i.e. ~8h downtime/year).
  • You handle tens of TB and your outbound traffic exceeds Contabo's quota (32 TB/mo).

Our case at VPNSmith: a single Node.js backend + Postgres + static objects. Every box checked. Decision made in an hour.

Audit current AWS cost (Cost Explorer method)

Before migrating, measure. Without a baseline, there's no ROI.

  1. Go to AWS Cost Explorer → ReportsCost & Usage Reports.
  2. Filter the last 3 months, monthly granularity, grouped by Service.
  3. Export as CSV. Open in a spreadsheet. You typically get:
AWS ServiceAvg monthly cost
EC2 (1× t3.medium)€32
RDS (db.t3.small Postgres)€38
S3 (200 GB + requests)€12
Data Transfer Out€24
NAT Gateway€41
CloudFront€18
Route 53 + misc€6
Total€171 / mo

Annualized: €2,052. Note the detail: on this profile, NAT Gateway + Data Transfer = €65/mo, or 38% of the bill just to push bytes in and out. That's the classic blind spot.

Set up the target Contabo VPS

For this stack, we pick a Cloud VPS 10 from Contabo: 6 vCPU, 16 GB RAM, 400 GB NVMe, 1 Gbps, 32 TB traffic/month. €9.99/mo on a 24-month commitment.

Provisioning:

# Once the VPS is delivered (Contabo email with IP + root password)
ssh root@YOUR_IP

# Minimal hardening
adduser ericg
usermod -aG sudo ericg
mkdir -p /home/ericg/.ssh
nano /home/ericg/.ssh/authorized_keys   # paste your SSH key
chmod 700 /home/ericg/.ssh && chmod 600 /home/ericg/.ssh/authorized_keys
chown -R ericg:ericg /home/ericg/.ssh

sed -i 's/^PermitRootLogin .*/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/^#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart ssh

apt update && apt upgrade -y
apt install -y ufw fail2ban
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw --force enable
systemctl enable --now fail2ban

Full hardening details (Lynis, Contabo snapshots, journald) are in the WireGuard self-host guide. Same foundations apply here.

Postgres RDS → self-hosted Postgres migration (pg_dump step by step)

This is the most critical piece. Battle-tested procedure:

Step 1 — Install Postgres 15 on Contabo

sudo apt install -y postgresql-15 postgresql-contrib-15
sudo systemctl enable --now postgresql

# Create app user and DB
sudo -u postgres psql <<EOF
CREATE USER appuser WITH PASSWORD 'PASTE_A_STRONG_PASSWORD';
CREATE DATABASE appdb OWNER appuser;
GRANT ALL PRIVILEGES ON DATABASE appdb TO appuser;
EOF

Enable SSL and allow remote connections only from your app (or local-only if Postgres runs on the same machine as the API — recommended):

sudo nano /etc/postgresql/15/main/postgresql.conf
# ssl = on
# listen_addresses = 'localhost'  (or '*' if app lives on another VPS)

sudo nano /etc/postgresql/15/main/pg_hba.conf
# Add: hostssl appdb appuser YOUR_APP_IP/32 scram-sha-256

sudo systemctl restart postgresql

Step 2 — Dump from RDS

From your workstation, with RDS access:

pg_dump \
  -h your-rds.eu-central-1.rds.amazonaws.com \
  -U masteruser \
  -d appdb \
  -Fc \
  -f appdb.dump

# Custom format (-Fc) = compressed + parallelizable on restore

For a 50 GB database, expect 10-25 min depending on RDS class and bandwidth.

Step 3 — Transfer and restore

scp appdb.dump ericg@YOUR_CONTABO_IP:/tmp/
ssh ericg@YOUR_CONTABO_IP

sudo -u postgres pg_restore \
  -d appdb \
  -j 4 \
  --no-owner \
  --role=appuser \
  /tmp/appdb.dump

# Verify
sudo -u postgres psql -d appdb -c "SELECT count(*) FROM users;"

Check integrity by comparing count(*) of large tables between RDS and Contabo. Difference = 0.

Step 4 — Automated backups post-migration

You replace RDS automated backups with a simple cron:

sudo nano /usr/local/bin/pg-backup.sh
#!/bin/bash
DATE=$(date +%Y%m%d-%H%M)
sudo -u postgres pg_dump -Fc appdb > /var/backups/postgres/appdb-$DATE.dump
find /var/backups/postgres -name "appdb-*.dump" -mtime +14 -delete
# Push to MinIO or external S3 for off-site
rclone copy /var/backups/postgres/appdb-$DATE.dump remote:backups/postgres/

Daily cron at 3 AM: 0 3 * * * /usr/local/bin/pg-backup.sh.

S3 → MinIO migration (rclone, aws-cli compatibility)

MinIO is an open-source, Go-based object store that's 100% S3 API compatible. Direct install:

wget https://dl.min.io/server/minio/release/linux-amd64/minio
chmod +x minio
sudo mv minio /usr/local/bin/

sudo mkdir -p /data/minio
sudo useradd -r minio-user -s /sbin/nologin
sudo chown minio-user:minio-user /data/minio

sudo nano /etc/default/minio
MINIO_VOLUMES="/data/minio"
MINIO_OPTS="--console-address :9001 --address :9000"
MINIO_ROOT_USER=admin
MINIO_ROOT_PASSWORD=PASTE_A_STRONG_32_CHAR_PASSWORD

systemd unit: grab the official .service (MinIO docs) and systemctl enable --now minio.

Migrate objects from S3 using rclone:

sudo apt install -y rclone

rclone config
# n) New remote → name: aws / s3 / AWS / paste access_key + secret_key
# n) New remote → name: minio / s3 / Other / endpoint http://localhost:9000 / paste admin + password

# Bucket-to-bucket
rclone copy aws:my-prod-bucket minio:my-prod-bucket --transfers=8 --progress

For 200 GB: budget 2-5 hours depending on AWS egress bandwidth (which will cost you ~€18 in final transfer-out — that's the exit toll).

On the application side, no code change: your aws-sdk-js keeps working, you just point at the MinIO endpoint:

const s3 = new S3Client({
  endpoint: 'https://storage.yourdomain.com',
  region: 'us-east-1',           // arbitrary required value
  credentials: { accessKeyId, secretAccessKey },
  forcePathStyle: true,          // important for MinIO
});

Zero-downtime DNS cutover

The clean method, planned over 10 days:

  • D-10: deploy the full stack on Contabo, run internal smoke-tests via /etc/hosts override.
  • D-7: lower the TTL of A records in Route 53 from 3600 → 60 seconds. Let it propagate 48h.
  • D-3: feature freeze, last incremental pg_dump, last rclone sync of objects.
  • D-1: cut over at off-peak time (typically 3 AM UTC for an EU audience). Change the A record: old AWS IP → new Contabo IP. Propagation max 60s.
  • D+0 → D+2: aggressive monitoring (latency, 5xx errors, DB metrics). Keep AWS running "just in case".
  • D+7: clean up AWS (terminate EC2, delete RDS after final snapshot exported, delete S3 bucket after off-site backup).

Zero perceptible user downtime if Postgres is sync'd (a 5 min read-only freeze is enough to ship the final delta).

Want a Contabo VPS to kick off your migration? Contabo Cloud VPS 10, 24-month term — €9.99/mo

Measured ROI (before/after cost table over 12 months)

Our internal migration, measured:

Line itemAWS (before)Contabo (after)
Compute (EC2 t3.medium / VPS Cloud 10)€32€9.99
Database (RDS / self-hosted Postgres)€38€0 (included)
Object storage (S3 200 GB / MinIO)€12€0 (included)
Data transfer out€24€0 (32 TB/mo included)
NAT Gateway€41€0 (not needed)
CloudFront CDN€18€12 (external BunnyCDN)
DNS Route 53€6€0.40 (free Cloudflare + 1 domain)
Off-site backup (Wasabi 50 GB)€0€3
Monitoring (UptimeRobot pro)€0€4
Monthly total€171€29.39
Annual cost€2,052€352.68

Saving: €1,699.32/yr, or 83%. On our real case, slightly heavier (€187/mo on AWS), that's 78% savings, or €1,752/yr. Payback is instant: no significant migration cost (one day of work).

What you lose vs AWS (managed services)

No marketing, let's be clear about the losses:

  • RDS Multi-AZ auto-failover: on AWS, if the primary dies, the secondary takes over in 60-120s. Self-hosted on Contabo, you'd need a second VPS + streaming replication + Patroni. Doable but adds ops time.
  • S3's 11 nines of durability: Amazon guarantees 99.999999999% durability per object (3-AZ internal replication). MinIO on a single disk = the durability of your NVMe disk. Fix: regular backups to Wasabi or Backblaze B2 (€2-6/mo for 200 GB off-site).
  • Fine-grained IAM: replaced by Linux users + sudoers + MinIO policies. Less granular, simpler to manage.
  • Unified CloudWatch: replace with Prometheus + Grafana, or Netdata (15 min setup), or an external SaaS (Better Stack, Sentry).
  • Enterprise 24/7 support: Contabo replies by email within 24-48h. For critical ops, plan a runbook + a second admin on call.

Budget 3 to 5 hours of ops per month in steady state: Ubuntu updates, backup checks, monitoring alerts. That's the real hidden cost — not insurmountable, but real.

Article published 2026-06-02. ROI measured on VPNSmith's internal migration in April 2026. Affiliate disclosure: if you pick up a Contabo VPS via the links in this article, we earn a commission that funds the ongoing testing of our guides. The price you pay is identical. We only recommend what we run in production.

★ Datacenter Nuremberg GDPR · ✓ IPv4 dédiée incluse · 200+ Mbps garantis

Get Contabo30 jours satisfait ou remboursé