cd ../blog

23 Oct 2026 · 4 min read · Ravi Sanchala

One server to four: what happened when we split a crashing VM

A fintech platform kept crashing on a single machine. Splitting it into four small, isolated servers fixed stability and security at the same time.

architecturesecurityaws

Most products start on one server. That’s not a mistake. When you’re validating an idea, one machine running the app, the database, the cache and a few internal tools is cheap and fast to set up.

The mistake is staying there after the product starts working.

I recently worked with a fintech client in exactly this spot. Their Go application, PostgreSQL, a cache and some internal tools all ran on one VM. At 80 to 100 transactions a day, the server hit high CPU, crashed, and customers saw timeouts. Today the same platform handles more than 1,000 transactions a day without drama. The fix wasn’t a bigger machine. It was more, smaller machines with one job each.

Why one big server fails in a specific way

When everything shares one machine, everything shares one failure.

  • Resource fights. A slow query eats CPU, and the app stops answering. A burst of traffic fills memory, and the database gets killed. You can’t tell which part is the real problem, because they all degrade together.
  • One door into everything. If the server is reachable from the internet, so is the database, the cache and the internal tools. A single misconfigured port exposes all of them.
  • You can’t size anything properly. The database wants memory. The app wants CPU. The cache wants a bit of both. One instance type is a compromise for all of them.

Upgrading to a bigger instance buys time, but it keeps all three problems.

The four-server layout

Here’s the shape we moved to:

ServerJobWho can reach it
GatewayReverse proxy (Caddy), TLSThe internet
AppThe Go binary, managed by systemdOnly the gateway
DatabasePostgreSQLOnly the app
CacheValkeyOnly the app

Each layer accepts traffic only from the one in front of it. The gateway is the only machine with a public IP. Everything else lives on a private subnet.

What changed, piece by piece

The gateway became the only door. One machine faces the internet, so there’s one place to harden, one place to watch, and one place where TLS terminates. If you ever move clouds, you point DNS at a new gateway and nothing behind it needs to change.

The app got its own restricted user. The binary runs as a dedicated system user that can manage its own systemd service and nothing else. If the app is ever compromised, the blast radius is that one service, not the whole machine.

The database got split permissions. Separate users for reading and writing. Reporting tools and background jobs that only read get a read-only user. A bug in a read path can’t corrupt data.

The cache took load off the database. Rate limiting, user lookups and auth token checks moved to Valkey. Those are small, frequent reads that the database was doing thousands of times a day for no reason.

Each server got sized for its own job. Only the database runs on a larger instance. The gateway, app and cache run on small ones. You pay for what each part actually needs.

“Isn’t four servers more expensive?”

Sometimes, yes. Four small instances can cost more than one medium one, depending on the provider’s prices.

I don’t sell this as a cost cut, and you should be suspicious of anyone who does without showing you the bill. What you’re buying is:

  • A crash in one part that doesn’t take down the others
  • A database that isn’t reachable from the internet
  • The ability to scale the one part that’s actually under pressure
  • Clear logs and metrics per role, so debugging is faster

For a platform that handles money, that’s usually an easy trade.

How to know you’ve outgrown one server

You probably need to split if:

  1. You’ve already upgraded the instance once “to fix performance”
  2. You can’t tell whether a slowdown is the app or the database
  3. Your database port is reachable from anywhere other than your app
  4. A deploy or restart means everything goes down together
  5. You’re nervous every time traffic spikes

If three or more of those sound familiar, the split is worth planning now, before the next crash plans it for you.

Do it as code, not by hand

The last piece matters as much as the architecture: build the new layout with infrastructure as code. Servers, networks and firewall rules defined in files, reviewed before they’re applied. That way the new setup is documented by default, and you can rebuild any of the four servers without guessing how it was configured.

Boring architecture. Boring results. That’s the goal.

related case study From one overloaded server to an isolated, secure fintech platform read case study →

$ ./book-call.sh

Dealing with something like this?

Let's talk it through. 30 minutes, free, and you'll leave with a clear picture of what to fix first.

Book a free 30-min callOr take the free 3-minute scorecard

next post

Right-sizing without breaking production Shrinking servers saves money until it causes an outage. Here's the careful way: measure first, change one thing at a time, and keep a way back. Read post →