DEV Community

Cover image for Ransomware wiped a client's entire server. I rebuilt it solo in 2 months.
Victor Minbeom Joo
Victor Minbeom Joo

Posted on

Ransomware wiped a client's entire server. I rebuilt it solo in 2 months.

It started with a phone call.

One afternoon I picked up a referral call. The founder of a small company — call them Company B — was on the line, and his voice was tight. Their whole service had been wiped overnight. Ransomware.

Company B ran a gym membership and community platform: gyms checked members in, members logged workouts and joined contests inside the app. It was a hybrid app — native shell with a WebView — and the backend ran on PHP/Laravel. They were on shared web hosting, and an attacker rode a vulnerability in that hosting straight into their directory and encrypted everything. Source code, uploads, config. All of it locked.

And the service was live. Gyms depended on it daily. Every hour it stayed down, real businesses couldn't operate.

I took the job — on the condition that I'd work it solo.

The backups existed, and that made it worse

The first thing I checked wasn't the code. It was the backup situation.

  • Source code: no backup. A developer might have an old local copy, but it would be far behind production.
  • Database: there was a backup — but it was taken long before the infection. Restoring it meant the last several months of members, attendance records, and points were simply gone.

Here's the trap: having an old backup is harder to reason about than having none. With nothing, your only option is "rewrite." With a stale backup, you have an asset that looks usable but isn't — close enough to tempt you, wrong enough to burn you.

We didn't pay — and I proposed one more thing

Two decisions had to be made.

1. Pay the ransom? No. There's no guarantee the decryption key even works, and paying once puts you on the list for the next attack. The rebuild was achievable at this scale, so paying made no sense.

2. Scope of the rewrite. Here I made a proposal: convert the video player from WebView to a native module. The app streamed workout videos through a WebView player that handled background playback, screen-lock, and quality poorly — and video was the core content. It was something they'd need to fix eventually anyway. Since we were rewriting the source from scratch, I argued, this was the cheapest moment to also fix it. It was out of "recovery" scope and meant extra cost, but the founder agreed: the moment you're rebuilding from rubble is, paradoxically, the best moment to change structure.

The project's shape was set: rewrite + upgrade, 2 months.

I started with consulting, not code

For the first two weeks I barely wrote any code.

Instead I spent the time understanding how the business actually ran: what role the app played on the gym floor, when members logged in most, what each feature did and why. I talked with the founder repeatedly and documented every feature's current behavior and what he wanted to improve while we were at it.

If the old code had survived, this phase would have been much shorter. But with the source gone, the founder's memory and the operators' experience were the only design sources. Every screen flow, every notification trigger, had to be reconstructed and redefined.

I also took the chance to re-architect. Rather than faithfully recreating the old structure, I cleaned it up for the current requirements. That paid off later in maintenance and iteration speed. Those two "slow" weeks ended up saving time — I got almost no "wait, why is it like this?" rework, because everything was built for present requirements from the start.

Two months, five features

The work list:

Rewrite: push notifications, attendance, contests, points system.
Upgrade (my add-on proposal): video player → native module.

Priorities were clear:

  1. Push + attendance. These are what get members opening the app daily. If they're broken, reopening doesn't rebuild the habit.
  2. Contests + points. Re-engagement levers for the gyms — natural to add once tier 1 was stable.
  3. Native video. Playback already worked via WebView, so this was last.

Because the service was already live, "wait until everything is done" was not an option. I shipped sequentially — finish a feature, test, deploy, move on — so gyms could get back to at least minimal functionality fast.

The data couldn't be undone

The hardest part wasn't technical. It was the missing data.

Recent signups, recent attendance, contest history, accumulated points — all blank. Not a clean slate, just an unreliable one.

This wasn't mine to communicate. Company B served many gyms, and the gyms had the direct relationship with members. The founder handled loss disclosure and compensation with each gym directly. My job was to draw a precise technical line: "restorable up to backup point A; everything after is unrecoverable." If that line is fuzzy, the client sets wrong expectations with their customers, and that becomes a bigger conflict later.

Stating technical facts clearly, and making business decisions on top of them, are two different jobs. The first was mine. The second was the client's.

Why solo actually helped

Looking back, working alone was an advantage in this specific case:

  • Decision speed. When every hour mattered, there was no "team alignment" step. One layer between the founder and me. Ask, decide, ship.
  • Design coherence. I designed all five features, so the seams were smooth — how points tie into attendance, how contest entry triggers a push. Split across people, those joints are where friction lives.
  • Clear ownership. If it broke, it was on me; if it worked, that was on me too. That was steadying, not stressful.

The limit is just as real: five features in two months solo only works at that scale. Knowing that boundary before taking the job mattered.

Rehosting and a real backup system

When the service was fully back, one task remained. Staying on the same shared host was not an option. I migrated hosting and rebuilt the whole backup discipline — scheduled backups, off-site copies, and recovery drills.

Most small companies only build this after their first disaster. Company B was no different — the cost of backups only felt real once recovery was behind them. I finished that migration too. It wasn't in the recovery quote, but we agreed: stop here and it happens again.

What stuck with me afterward

The lasting takeaway was about what recovery is.

Recovery isn't restoring the original state. Often there is no original state to restore to — the code is gone, the data is a stale backup, the history in between is permanently blank. The actual work is deciding what to rebuild, what to abandon, and what to make better while you're in there.

So a recovery project always starts by figuring out what is truly necessary — together with the client. Skip that and go straight to code, and a month later you get "why do we even need this?" By then it's too late.

When I took that first call, my opening line wasn't "how fast can I fix it." It was: "Let's first sort out what to bring back, and what to make better while we're at it." That frame steadied the entire project.


Have you ever had to rebuild something with no usable backup? I'm curious how others drew the "restorable vs. gone" line with clients.

Top comments (0)