The $100k WSO2 Migration

Glitch-art painting of a pixelated server farm collapsing into fragments that reassemble into a single glowing API gateway endpoint

"Lift and shift" is the most dangerous phrase in the cloud

It sounds harmless. Take what runs in your data center, put it on EC2, done. The software works, the team is comfortable, and the migration report comes back green.

Except that what works on-prem often becomes a money-burning furnace in the cloud.

We recently took over a project where a client had "migrated" their API management platform to AWS. They were running WSO2, orchestrated by a self-managed stack of Consul, Nomad, and Vault. And they had not used AWS load balancers at all. They had rolled their own HAProxy clusters on EC2.

The result was a tangled web: 81 servers, enterprise licenses, and hours-long maintenance windows that nobody enjoyed.

flowchart LR classDef miamiPink fill:#ff9ec7,stroke:#333,stroke-width:2px,color:#232F3E; classDef miamiBlue fill:#99f2ff,stroke:#333,stroke-width:2px,color:#232F3E; subgraph ROUTE ["Routing Layer (4x HAProxy)"] direction LR HPP["HAProxy Pub 4x"]:::miamiBlue HPR["HAProxy Priv 4x"]:::miamiBlue end subgraph FLEET ["WSO2 Application Fleet (16x instances)"] direction LR subgraph GWS ["Gateways"] G1["Gw 6x"]:::miamiPink end subgraph MGT ["Mgmt & Traffic"] direction TB K1["KeyMgr 2x"]:::miamiPink T1["Traffic 2x"]:::miamiPink end subgraph PUBA ["Pub/Store/Analytics"] direction TB P1["PubStore 4x"]:::miamiPink A1["Analytics 2x"]:::miamiPink end end subgraph DATA ["Data & User Stores (6x instances)"] direction LR subgraph USR ["User Stores"] U1["UserStore 3x"]:::miamiBlue end subgraph DBS ["Databases"] D1["DB 3x"]:::miamiBlue end end ROUTE --> FLEET FLEET --> DATA

Figure 1: The Legacy Sprawl. A massive fleet of 81 EC2 instances was required just to run the API management platform. This included self-managed Load Balancers (HAProxy), the WSO2 suite, and a heavy orchestration stack (Consul/Nomad/Vault), all requiring manual patching and maintenance.

We replaced the entire platform with AWS API Gateway. This is the anatomy of that rescue, and the math behind the roughly $111,000 per year it saves.

The before: a private cloud inside a public cloud

The client ran three environments: Prod, PreProd, and NonProd. Because WSO2 is a heavy, modular platform, each environment needed its own fleet of EC2 instances, plus dedicated instances for routing traffic.

The bill of materials per environment looked like this:

ComponentInstances per environment
Load balancers (HAProxy)4 (2 public, 2 private)
Databases3
Analytics2
Gateways6
Key managers2
Publisher / store4
Traffic managers2
User stores3
Total27

Three environments at 27 instances each is 81 EC2 instances running 24/7, with Consul for service discovery, Nomad for orchestration, and Vault for secrets layered on top.

Consul, Nomad, and Vault are excellent tools. Running them yourself on EC2 is a completely different statement.

The cost of lift and shift

The numbers, assuming standard production sizing (m5.large or equivalent) for the Java workloads and the HAProxy nodes:

The rent. 81 servers at m5.large comes to roughly $5,900 a month in compute, plus about $400 a month in EBS. Call it $6,300 a month, or $75,600 a year, before a single license.

The tax. Running the HashiCorp stack at enterprise level for roughly 80 nodes is not cheap. Vault Enterprise for secrets compliance, Consul and Nomad Enterprise for cluster management. A conservative estimate for a fleet that size is $40,000 to $60,000 a year.

The patching tax. This was the real killer. You could not just patch a server. You had to patch the private HAProxy nodes one by one, verify Consul health, then patch the WSO2 gateways, and only then touch the public HAProxy layer, all while hoping the cluster did not lose quorum. The HAProxy configuration files were managed across 12 load balancer instances by hand or by fragile scripts, which produced a steady stream of routing errors. And the maintenance windows? They stretched for hours.

The fix: we do not need servers, we need an endpoint

When we looked at what the platform actually did, the requirement was simple: route authenticated traffic to backend APIs, with throttling, logging, and secrets. That is not a server farm. That is an API endpoint.

So we migrated the API definitions to AWS API Gateway and deleted the fleet:

  • Routing: 12 HAProxy servers replaced by native API Gateway stages.
  • Authentication: WSO2 key manager replaced by Amazon Cognito.
  • Throttling: WSO2 traffic manager replaced by native usage plans.
  • Secrets: Vault replaced by AWS Secrets Manager and SSM Parameter Store.
  • Defense: AWS WAF attached directly to the API, plus native Shield.

The math of efficiency

Infrastructure. The old stack cost about $6,300 a month. The new one: API Gateway is serverless and billed per request, and even with heavy usage it lands around $300 a month all-in with Cognito and Secrets Manager. That is roughly a 95% reduction.

Operations. Servers to patch: zero. HAProxy configs to manage: zero. OS updates: zero. HashiCorp upgrades: zero. The maintenance window for this part of the infrastructure simply does not exist anymore. We manage one artifact, the API definition itself, and AWS manages everything underneath it.

Security. The old setup required a wide range of TCP/UDP ports (8300-8600, 4646-4648) open between servers just to keep Consul and Nomad in sync, and 81 SSH entry points for engineers. Every open port is a vulnerability, and every key is a potential lateral-movement path across production. Now there are no servers to log into, DDoS protection is native, WAF blocks injection and bot traffic at the edge, and the platform carries its compliance posture out of the box.

The architecture, after

The collapse of complexity, drawn as a straight line:

flowchart LR classDef miamiPink fill:#ff9ec7,stroke:#333,stroke-width:2px,color:#232F3E; classDef miamiBlue fill:#99f2ff,stroke:#333,stroke-width:2px,color:#232F3E; classDef external fill:#fff,stroke:#333,stroke-width:2px,stroke-dasharray:5 5,color:#333; C([Client / Consumer]):::external WAF["AWS WAF"]:::miamiBlue APIGW["API Gateway (Stages + Usage Plans)"]:::miamiPink COG["Amazon Cognito"]:::miamiBlue SM["Secrets Manager + Parameter Store"]:::miamiBlue BE([Backend APIs]):::external C --> WAF WAF --> APIGW APIGW -- "Auth" --> COG APIGW -- "Secrets" --> SM APIGW --> BE

Compare that with the 81-instance fleet it replaced. The line got shorter. That is the whole project.

Stop buying servers

The client was burning over $115,000 a year on a platform whose only job was to route API traffic. The new setup costs about $3,600 a year. The APIs are faster, cheaper, safer, and the engineers stopped spending their nights on maintenance windows.

The scorecard:

Old wayNew way
Servers81 EC20
Licenses~$50k/year$0
Infra~$6.3k/month~$300/month
Total~$115,000/year~$3,600/year

The lesson is the same one behind most of the work we do: complexity is a price, and it is optional. If you kept a legacy architecture because "we used it on-prem," you are paying a lift-and-shift tax on every invoice.

We deleted the servers. We cancelled the licenses. The engineers finally sleep.


Are you paying for zombie servers?

Contact us at support@sevenseven.tech or fill out our contact form.

If your cloud bill is dominated by EC2 instances running legacy software, we can help you move to the serverless version of what you already have.