For the better part of the last decade, the default answer to any infrastructure question was "put it in the cloud." AWS, GCP, Azure — pick one, provision what you need, pay by the hour. The flexibility was real, the speed to market was real, and for many teams it was the right call.
But something has been shifting. A growing number of engineering teams — including some that were early cloud adopters — are running the numbers and finding that the elasticity they are paying for is elasticity they do not actually need. Their workloads are predictable. Their traffic does not spike tenfold overnight. And the bill at the end of the month reflects none of that nuance.
We recently completed a full cloud repatriation for one of our clients: a migration from AWS to dedicated bare-metal servers hosted at Leaseweb. The result was a significant reduction in monthly spend — and, for this specific workload and team, measurable improvements in performance and operational clarity. It also came with real trade-offs that we had to plan and build for explicitly. This is that story.
Why the cloud premium stops making sense at scale
Public cloud pricing is built on a model of flexibility. You pay a significant markup over the raw cost of hardware because the provider absorbs the risk of capacity, handles physical maintenance, and gives you the ability to scale up or down at any moment. That is a genuine and valuable service.
The problem is that not every workload benefits equally from that flexibility. Once a business reaches a certain maturity — stable traffic patterns, known resource requirements, a team capable of managing infrastructure — the cloud premium stops paying for itself. You are renting flexibility you are not using.
Some concrete examples of where the math starts to work against the cloud:
- Compute-heavy workloads with predictable load — a dedicated server at €400/month delivers more raw CPU than an equivalent EC2 instance at €1,500–2,000/month. The comparison is not apples-to-apples: cloud compute includes managed SLA, hardware redundancy and provisioning flexibility that bare metal does not. But if you are not using those benefits, you are still paying for them.
- High-bandwidth applications — egress traffic on AWS is billed at €0.08–0.09 per GB; most dedicated hosting providers include several terabytes of transfer in a flat monthly fee
- Storage-intensive systems — EBS and S3 costs compound quickly at scale; raw NVMe on dedicated hardware is orders of magnitude cheaper per GB
- Databases with large datasets — RDS instances with high IOPS requirements can easily cost more than the application servers they serve
The Leaseweb migration: what we did and why
Our client was running a production platform on AWS across multiple EC2 instance types, RDS for PostgreSQL, S3 for object storage, and a set of managed services (load balancer, CloudWatch, VPC NAT gateway) that each added a line to the invoice. The total monthly bill was in the range of tens of thousands of euros.
The workload was not bursty. Traffic followed a predictable daily curve. The team had a solid understanding of their resource requirements. They were, in short, a good candidate for repatriation.
We selected Leaseweb dedicated servers for several reasons: competitive pricing on high-core-count servers, availability of NVMe storage configurations, a European data center presence that matched the client's compliance requirements, and a straightforward SLA with hardware replacement guarantees. Leaseweb is not the only provider in this space — Hetzner and OVHcloud are similarly positioned — but for this client's geography and requirements it was the right fit.
The stack we deployed on bare metal
The key decision that made the migration both feasible and safe was: do not change the application layer, only change the infrastructure layer. We achieved this by running Kubernetes on bare metal, keeping the same container images, the same Helm charts, and the same CI/CD pipelines that were already in place on AWS.
The stack on the new servers:
- Kubernetes (kubeadm-provisioned cluster, 3 control plane nodes + worker nodes) — same workload definitions, zero application changes
- Longhorn for distributed block storage across nodes, replacing EBS
- MinIO for S3-compatible object storage, replacing AWS S3 with a drop-in API-compatible layer
- PostgreSQL on dedicated nodes with streaming replication, replacing RDS
- HAProxy + Keepalived for load balancing and virtual IP failover, replacing the AWS ALB
- Prometheus + Grafana + Alertmanager for observability, replacing CloudWatch
- WireGuard for encrypted inter-node communication and secure remote access, replacing the AWS VPC and NAT gateway
Every component in this stack is open source, cloud-agnostic, and portable. If the client ever needs to move again — to a different provider, to a different data center, or back to a public cloud — the same manifests and tooling go with them.
Standardisation as a side effect of repatriation
One outcome we did not fully anticipate was how much the migration forced us to standardise things that had been left informal on AWS.
On managed cloud services, it is easy to let infrastructure drift. You click through a console, enable a managed feature, add a tag, and move on. Over time the infrastructure becomes a collection of implicit decisions that nobody fully understands. The architecture exists, in practice, inside the AWS console.
Moving to bare metal forces the opposite discipline. Everything must be declared explicitly — in Kubernetes manifests, in Ansible playbooks, in Terraform or in shell scripts checked into version control. There is no console to fall back on. If it is not in code, it does not exist.
This constraint turned out to be a significant operational improvement:
- Full infrastructure-as-code — every server configuration, every network rule, every service definition is in a Git repository. Reproducing the entire environment from scratch takes hours, not weeks
- Documented runbooks — because managed services were no longer handling things invisibly, the team had to write down how things work. This documentation became genuinely useful during incidents
- Consistent environments — development, staging and production all run the same Kubernetes distribution on the same OS. "Works on my machine" issues dropped significantly
- Portable processes — the CI/CD pipeline, the deployment process, the rollback procedure: none of these have any AWS-specific steps. They would work identically on any provider or on-premises
Troubleshooting became simpler — for this team
This is counterintuitive, and it comes with an important caveat: it is true specifically for teams with solid infrastructure expertise. If the operational knowledge is not there, bare metal adds complexity, not removes it.
For a team that is comfortable with Linux internals and systems diagnostics, however, the failure domain on bare metal is genuinely simpler. On AWS, a latency spike might originate in EC2, in the EBS volume, in the RDS instance, in the NAT gateway, in the VPC routing, or in a throttled API call to a managed service. Diagnosing it means navigating CloudWatch dashboards, correlating metrics across multiple services, and sometimes opening a support ticket to get information that is not exposed to you at all.
On bare metal, a latency spike traces back to CPU, memory, disk I/O, or network — and all of those are directly observable with standard tools (htop, iostat, iftop, perf). There are no managed service abstractions sitting between you and the signal. What you gain in visibility you give up in auto-recovery: on AWS, many failure modes are handled silently. On bare metal, you handle them yourself — which is why having runbooks, monitoring and an on-call rotation in place before cutover is not optional.
The single biggest improvement in our client's operations post-migration was not the cost saving — it was the reduction in mean time to diagnosis during incidents. What used to take hours of CloudWatch log archaeology now takes minutes of reading kernel metrics.
Performance improvements
AWS has significantly improved hypervisor isolation over the years — the Nitro system, introduced progressively since 2017, provides strong resource isolation and largely mitigates the classic "noisy neighbour" problem on modern instance types. This is not the AWS of 2015. That said, for CPU and I/O-bound workloads, dedicated hardware still eliminates a layer of indirection entirely: all physical resources belong exclusively to you, with no hypervisor overhead and no shared physical substrate.
In our client's case, the PostgreSQL workload on dedicated NVMe with direct kernel access showed measurably lower query latency compared to RDS on gp3 EBS — particularly for write-heavy operations. Part of this was the storage layer, part of it was the ability to tune PostgreSQL parameters (including shared_buffers, work_mem and max_wal_size) beyond what RDS parameter groups allow for a given instance class.
On internal network throughput: modern large EC2 instances (c6i.8xlarge and above) provide 10–25 Gbps of network bandwidth, which is competitive. The difference in our case was latency consistency rather than raw throughput — traffic between application nodes and the database on a dedicated LAN has no per-instance baseline cap and no shared physical uplink with other tenants' traffic.
What repatriation is not right for
Honesty matters here. Cloud repatriation is not the right answer for every situation, and we would be doing a disservice to frame it as a universal solution.
- Highly variable or unpredictable traffic — if your workload genuinely spikes 10x during peak events and is idle the rest of the time, cloud elasticity has real value. Provisioning bare metal for peak capacity means paying for idle hardware most of the month
- Small teams without infrastructure expertise — managing your own servers requires someone who is comfortable with Linux administration, networking, and on-call responsibilities. If that expertise does not exist in-house, a managed provider abstracts it at a cost that may be worth paying
- Early-stage products with uncertain resource requirements — when you do not yet know what your workload will look like in six months, the flexibility to over- and under-provision without commitment is genuinely valuable
- Hard regulatory requirements tied to specific cloud certifications — some compliance frameworks (FedRAMP, certain financial sector requirements) effectively mandate specific cloud providers. Bare metal may not satisfy those requirements without significant additional certification effort
The cost breakdown, honestly
The savings in our client's case were dramatic because the starting point was a poorly optimised AWS environment that had grown organically over several years. Not every repatriation will yield the same delta. That said, the structural cost advantage of dedicated hardware over equivalent cloud compute is real and well-documented across the industry.
A rough comparison for a mid-size production setup:
| Component | AWS (managed, equivalent spec) | Bare metal (Leaseweb) |
|---|---|---|
| 32-core compute node × 3 | ~€3,500–4,500/mo (c6i.8xlarge × 3, on-demand) | ~€900/mo (3 dedicated servers) |
| 10 TB NVMe storage | ~€750/mo (EBS gp3 @ €0.08/GB/mo) | Included in server cost |
| Managed PostgreSQL (db.r6g.2xlarge) | ~€800/mo | Self-managed on dedicated node, ~€0 extra |
| Object storage (10 TB + egress) | ~€500–1,000/mo (S3 + egress) | No additional line item (flat bandwidth included in server cost) |
| Load balancer + NAT + misc managed services | ~€400–600/mo | No additional managed service cost (HAProxy on existing nodes; ops time internalised) |
The figures above are illustrative approximations based on publicly available pricing as of early 2025. The exact delta depends heavily on region, reserved instance discounts, actual data transfer volumes, and the specific AWS services in use. The point is not the precise numbers — it is the structural difference in what you are paying for.
The migration process itself
A repatriation of this kind is not a weekend project, but it is also not a multi-year programme. For this client, the full migration — from initial assessment to production cutover with zero downtime — took approximately three months. The phases looked like this:
- Assessment (2 weeks) — inventory all AWS services in use, identify dependencies, map data flows, estimate target hardware requirements based on observed utilisation
- Environment build (3 weeks) — provision Leaseweb servers, install and configure the Kubernetes cluster, set up networking, storage and observability
- Parallel run (4 weeks) — deploy the application stack to bare metal alongside the existing AWS environment, run load tests, validate behaviour, tune PostgreSQL and system parameters
- Data migration (2 weeks) — establish PostgreSQL streaming replication from RDS to the bare-metal primary, sync object storage from S3 to MinIO, validate consistency
- Cutover (1 day) — DNS switch with short TTL, monitor for 24 hours, decommission AWS resources progressively over the following two weeks
The zero-downtime cutover was possible because the parallel run phase gave us confidence in the new environment before any traffic was directed to it. We did not cut over until the bare-metal stack had been running the full workload in shadow mode for several weeks.
What we had to build ourselves — and what we underestimated
No migration story is complete without the parts that did not go perfectly. In our case, the application layer migrated cleanly. The infrastructure layer required more work than initially scoped in two areas.
The first was high availability. On AWS, multi-AZ RDS failover, EBS replication, and ALB health checks are handled by the provider. On bare metal, we had to design and validate our own HA strategy: PostgreSQL streaming replication with automated failover via Patroni, Longhorn replication across nodes, and Keepalived VIP failover for the load balancer. These are all well-established tools — but each one required configuration, testing, and documented runbooks. We underestimated the time needed to test failure scenarios properly. The parallel run phase extended by one week specifically to run controlled failure drills.
The second was backup and disaster recovery. RDS automated backups and point-in-time recovery are genuinely convenient. Replacing them with a self-managed backup pipeline (pgBackRest for PostgreSQL, restic for filesystem backups, offsite replication to a secondary Leaseweb location) was not technically difficult, but it added scope to the project and added ongoing operational responsibility to the client's team. This is a recurring cost that does not appear in any monthly invoice but is real.
The honest summary: repatriation shifts costs from invoices to engineering time. In this case the shift was strongly net positive. But it requires a team that is willing and able to own that responsibility.
Cloud repatriation is not a rejection of cloud computing — it is a maturation of the conversation around it. The best infrastructure for a given workload depends on that workload's actual characteristics, not on the default assumptions of a decade ago.
For workloads that are stable and compute-intensive, managed by a team with the operational capability to own infrastructure, dedicated bare-metal hardware can offer better economics and more direct observability than equivalent managed cloud services. It is not simpler — it is differently complex, and the complexity shifts to where a capable team can see and control it.
The discipline that repatriation demands — full infrastructure-as-code, explicit HA design, self-managed backup and recovery — is discipline that pays dividends regardless of where you ultimately run your workloads. A team that has gone through this process owns their infrastructure in a way that makes them less dependent on any single provider and more resilient as an organisation. The same stack would run on Hetzner, OVHcloud, a different data centre, or back on a public cloud with minimal changes.
Whether that trade-off is right for you depends entirely on your workload characteristics, your team's capabilities, and your appetite for operational ownership. The answer is not always bare metal. But it is worth running the numbers.
Want to experiment with local AI responsibly?
We help teams and companies design local, private and governable AI environments, balancing technical freedom, security, policy and operational control.
Start the conversation