enekui
SMB tech  ·  7 min

Lift-and-shift to ECS Fargate: 6-week migration of a Java monolith for an industrial SMB

An industrial SMB with a 12-year-old Java monolith moved to AWS ECS Fargate in six weeks without rewriting code. We document the cost impact, downtime, and what we'd do differently next time.


This case study comes from a real Enekui engagement in Q1 2024. The client: a €9M revenue industrial distributor in northern Spain, running a custom Java 11 monolith on two bare-metal servers (one production, one staging). The ask: move to AWS with minimal disruption, no budget for a rewrite, and a hard deadline of six weeks to free up the on-premise rack space.

We chose ECS Fargate over EC2 or Lambda. This post explains why, what the migration looked like in practice, and the cost/performance outcome.

The starting point

Stack before migration: - Java 11 Spring Boot monolith (~80k LoC). - PostgreSQL 12 on the same bare-metal server. - Nginx reverse proxy. - Manual deployments via SSH + shell scripts. - No CI/CD. No infrastructure as code. - ~200 concurrent users during business hours (8am-6pm CET). - Average response time: 180ms (p95: 450ms).

Constraints: - Budget: €12k for migration + first 3 months of AWS spend. - Timeline: 6 weeks from kickoff to production cutover. - Downtime tolerance: 2 hours maximum for final cutover. - No code changes allowed (business logic frozen for regulatory audit).

Why ECS Fargate over alternatives

We evaluated three paths:

  1. EC2 instances (t3.medium): Closest to the existing setup. Rejected because it still requires OS patching, SSH access management, and doesn't solve the "infrastructure as cattle" problem. The client wanted to stop thinking about servers.

  2. Lambda + API Gateway: Attractive for cost (pay-per-request), but the monolith has 4-second cold starts and some endpoints run 15+ seconds. Lambda's 15-minute timeout would work, but cold starts would kill user experience. Refactoring to split the monolith wasn't in scope.

  3. ECS Fargate: Container orchestration without managing EC2. We can lift the existing JAR into a Docker image, point it at RDS PostgreSQL, and scale horizontally if needed. Winner.

Decision: ECS Fargate with Application Load Balancer, RDS PostgreSQL (db.t3.medium), and Terraform for all infrastructure.

Migration steps (week by week)

Week 1: Containerisation + local testing

Week 2: Terraform infrastructure

Week 3-4: Data migration + parallel run

Week 5: Load testing + cutover prep

Week 6: Production cutover

No rollback needed. First business day (Monday) ran without incidents.

Cost comparison: before vs after

Before (on-premise, monthly): - Server lease: €320/month (2 servers). - Electricity + cooling: ~€80/month. - Sysadmin time (10% FTE): ~€600/month. - Total: ~€1,000/month.

After (AWS, monthly average over 3 months): - ECS Fargate (2 tasks 24/7, 4 tasks during business hours): €145/month. - RDS db.t3.medium Multi-AZ: €180/month. - ALB: €25/month. - Data transfer + CloudWatch logs: €18/month. - Total: €368/month.

Saving: €632/month (63% reduction). The client also freed up rack space worth €200/month in colocation fees, bringing the real saving to €832/month.

Break-even on the €12k migration cost: 14 months.

What this means for your SMB

If you're running a monolith on bare-metal or a single VM, this migration pattern works when: - Your app is already stateless (or can be made stateless by externalising sessions to Redis/DynamoDB). - You don't need sub-50ms response times (Fargate cold starts are ~2 seconds, but with 2+ tasks always warm, users don't hit cold starts). - Your database fits in RDS (up to a few hundred GB; beyond that, you'd look at Aurora or self-managed on EC2).

The key win isn't just cost. It's operational simplicity: no SSH access, no OS patching, no "the server is down" calls at 3am. ECS handles task health checks and restarts. RDS handles backups and minor version upgrades.

The gotcha: you need to externalise everything. If your app writes logs to /var/log or stores uploads in /tmp, you'll need to refactor to CloudWatch Logs and S3. This client's app was already stateless (uploads went to an external FTP, logs to syslog), so we had no blockers.

How we'd apply it at Enekui

For a similar engagement today, we'd make two changes:

  1. Use Terraform modules from day one. We wrote raw Terraform for this project; now we'd use our internal ECS module (standardises task definitions, ALB rules, auto-scaling policies). Saves ~30% of infrastructure code.

  2. Add a staging slot in production. ECS supports blue/green deployments via CodeDeploy. We'd set this up so the client can deploy to a "staging" task set in production, run smoke tests, then shift traffic. Zero-downtime deploys.

We'd keep the same stack: ECS Fargate, RDS, ALB, Terraform. It's the right tool for monoliths that aren't ready (or don't need) to become microservices.


Want help with a similar migration? We offer a 2-week cloud readiness diagnosis (€2,900) that includes containerisation feasibility, cost projection, and a migration runbook. Get in touch.

Fuentes