Verified results: how Gart Solutions migrated a large-scale language-learning platform from AWS to Hetzner, caught 1,464 database discrepancies before they became an incident, and brought monthly infrastructure spend down by roughly 78%, backed by real Cost Explorer data.
TL;DR
- FluentU had a verified AWS monthly baseline of $9,318.15, with $6,071.87 (65.16%) coming from RDS.
- Gart Solutions designed and executed a phased AWS-to-Hetzner migration, rebuilding the database layer, application servers, shared storage, and deployment pipeline.
- Validation exposed broad schema drift — 1,464 column-metadata diff rows and 1,179 missing target indexes. A live cutover attempt was later aborted when CDC latency and blocking table diffs remained, proving the Go/No-Go process worked.
- Result: AWS spend fell from $9,318/month to $4,690 in the first cleanup-heavy month (49.7% down), trending to $600–$630/month once legacy is retired. Hetzner is ~$2,030.80/month today with an optimization path to ~$1,429/month. Combined steady-state: $2,029–$2,059/month — ~78% lower, ~$87,100–$87,500/year saved. Both cost analyses were read-only; no infrastructure was changed.
The client
FluentU is a large e-learning platform that teaches languages through authentic video content. Its production environment isn’t a simple web app — it’s an ecosystem: a core web application, native mobile apps, a Chrome browser extension, a WordPress-powered blog, and a set of cron jobs and scheduled workers that keep personalized learning content flowing to users around the world. Every learner’s history — the videos watched, the words studied, the language they’re learning, their progress over time — lives in the database. That’s a lot of sensitive, hard-to-lose data sitting behind a platform that can’t afford extended downtime.
The challenge: AWS costs that had outgrown the business
FluentU’s infrastructure had been built up over years directly on AWS: multiple application servers behind load balancers, several RDS databases for the main platform, blog, and demo environment, ElastiCache, CloudFront, S3, NFS shares, SQS queues, and a deployment process wired tightly into AWS-specific services.
That architecture worked, but it had become expensive. The verified AWS Cost Explorer export provides this monthly baseline:

RDS accounted for $6,071.87/month — 65.16% of the AWS bill. The largest usage-type charges were the main Multi-AZ database class ($2,035.58), provisioned IOPS ($1,400), another Multi-AZ database class ($1,100.73), and PIOPS storage ($625). The client needed to cut that spend without sacrificing recoverability, validation, or rollback.
Why Hetzner, and why it wasn’t a simple lift-and-shift
Hetzner offered the raw compute and storage FluentU needed at a fraction of AWS’s price — but it doesn’t offer the same breadth of fully managed services. On AWS, spinning up a highly available, auto-backed-up RDS instance is a checkbox. On Hetzner, the team would need to build and operate that reliability themselves: provisioning database servers, configuring automated backups, and taking on operational responsibility that AWS had previously abstracted away.
Gart Solutions’ engineers made a deliberate call: keep genuinely cost-effective managed services where they still made sense, and move everything else — starting with the biggest cost centers — onto self-managed Hetzner infrastructure designed and hardened for FluentU’s specific workload.


Combined AWS + Hetzner forecast after the planned Hetzner optimization

What made this migration hard
Three things made this more than a routine “move the servers” project:
A large, sensitive, actively-written database. The main RDS footprint was substantial enough to require a 2.4-TiB retained final snapshot. It held business-critical account and learning-history data, so data loss or uncontrolled downtime during cutover would have been a serious incident, not a minor inconvenience.
A legacy architecture with more hidden dependencies than expected. As the team got deeper into migration planning, they found the existing AWS setup had accumulated more interdependencies than the initial audit suggested — a common reality in platforms that have grown organically over years. Untangling those dependencies safely took as much work as the migration itself.
Data-integrity problems discovered mid-project. Broad validation showed that the target schema was not equivalent to the source: the first wide comparison across 1,474 completed tables found 1,464 column-metadata diff rows and 1,179 missing target indexes. The exact DDL-changing command was never proven, but continuing with that target would have been unsafe — so the team introduced a hard schema gate and rebuilt.
How Gart Solutions executed the migration
The team broke the project into deliberate, testable phases rather than a single high-risk cutover:
1. Design the target environment first
Before touching production, Gart Solutions’ architects designed the new Hetzner infrastructure — server sizing, networking, and replacements for AWS-native services like managed backups and load balancing.
2. Prove it works with a test migration
A test database was stood up on Hetzner from a logical dump of the production data, purely to validate that FluentU’s application functioned correctly in the new environment before any live data was at risk.
3. Rebuild the target after finding schema drift
The team did not patch around an unverified database. It recreated the target from the source schema, repeated migration work, and added full column, index, and constraint comparisons before accepting another cutover candidate.
4. Replicate live, then freeze writers for the final sync
Using AWS Database Migration Service, the team staged the full load and ongoing change capture. At cutover, source cron jobs and background writers were stopped, the final NFS/content sync was executed, and traffic opened only after application, database, and network gates passed. Rollback remained available until the approved boundary.
5. Define strict Go/No-Go criteria — and actually use them
The first live attempt was aborted when CDC latency was still rising and blocking table diffs remained. The team restored the minimum AWS runtime, corrected the issues, repeated the evidence gates, and proceeded only after the cutover state was acceptable. That is the difference between a migration case study and an incident postmortem.
6. Reduce blast radius by migrating in stages
The WordPress blog was deliberately excluded from the core cutover and rehearsed separately. After source/target count checks, backup gates, and public smoke tests passed, six CloudFront blog behaviors were routed to the Hetzner origin. AWS blog compute was initially kept frozen for rollback and was later retired after recovery artifacts were captured and validated.
7. Communicate the maintenance window honestly
A maintenance page was enabled ahead of cutover so users saw a clear, expected message rather than a broken app. The final NFS/content sync alone took 8,937 seconds — about two and a half hours — and the team chose a longer, verified window with rollback readiness over a faster, riskier switch.
8. Resolve what only shows up in production
After traffic moved, the team repaired database routing, environment configuration, CDN/cache behavior, and PHP-FPM/Apache tuning, while expanding monitoring and backup verification. The later blog cutover reused the same green-gate pattern.

