Most agencies write blogs about the work they do for clients. This one is about work we're doing on ourselves, because we think the honest version of this story is more useful than the polished one.
The starting point
Like a lot of agencies that grew organically, Nectra's hosting grew organically too. We had one workhorse of a server running a large number of client applications side by side. Laravel apps, integrations, cron jobs, databases, WordPress sites, queue workers, all living on the same box. Her name is mary, and she has been very good to us.
The problem with a setup like that is not that it doesn't work. It works fine, right up until the day it doesn't. As we started taking on bigger clients with more serious operational dependencies, the question stopped being "is this working?" and became "would I be comfortable explaining this architecture to a client whose warehouse stops shipping if this box goes down?"
The honest answer was no. So we did something about it.
Step one: audit before opinions
It's tempting to jump straight to solutions. New servers, new provider, containers everywhere. We deliberately didn't.
Instead we ran a full structured audit of the existing server before making a single decision. We used Claude Code to work through the box systematically: system baseline, every running service, every scheduled job, the web layer, the databases, a full application inventory, users and access, firewall configuration, and a sweep for security red flags. The output was a proper written audit document, not a vibe.
This is the same principle we apply to client integration work. You cannot plan a migration for a system you haven't inventoried. Every "quick" migration that goes wrong goes wrong because of the cron job nobody knew about or the two apps that secretly share a database.
Step two: face what the audit tells you
The audit found things we didn't enjoy reading. A backup agent that had silently stopped working a long time ago. A database port that was more exposed than it should have been. Debug settings left on where they should have been off.
None of it had caused an incident. All of it could have. And this is the part worth being honest about publicly: this server was built over years, by busy people, under deadline pressure, and it accumulated risk the way every long-lived server does. If you run your business on a box that has been up for years and has never had a proper independent audit, we would gently suggest that yours has a similar list waiting to be found.
The critical items were fixed the same day, starting with off-host database dumps before anything else was touched. Rule one of any migration: get real backups working before you begin, not after.
Step three: design the target, not the patch
With a full inventory in hand, the architecture decision became straightforward. We rejected the "one bigger shared server" option and went with a tiered approach.
Revenue-critical and data-sensitive clients get their own dedicated server. If their business depends on the application, it should not share a failure domain, a database engine, or a noisy neighbour with anyone else. Smaller workloads consolidate onto clean, Docker-separated shared infrastructure.
Each new box follows the same standard definition. Every application is deployed as Docker Compose, so an app is a directory, a compose file, and an env file, and moving it between servers is trivial. Provisioning is scripted with cloud-init, so a new server comes up pre-hardened with everything installed. DNS lives in Cloudflare, independent of any host, so a migration is a TTL drop and a record change. Central uptime monitoring watches every box.
The result is that "spin up a new client server" goes from an afternoon of manual setup to a ten-minute, repeatable job. That's the capability we were actually after. The migration is just the excuse to build it.
Step four: sequence by risk
The migration order was decided by the audit, not by preference. Lowest-risk workloads move first, which proves the provisioning process on something forgiving. Applications that share infrastructure with each other move together and move last, because splitting coupled systems mid-migration is how you create outages.
We also chose to consolidate providers rather than add a shiny new one. We already had accounts with several UK hosts we trusted, and one of them offered the things the new workflow needs: a proper API, Terraform support, cloud-init, and UK datacentres. Consolidating with a provider you already know beats a marginally better dashboard from a stranger. And because DNS and provisioning are provider-independent by design, if that choice ever disappoints, moving is a weekend job rather than a rebuild.
Why we're telling you this
Because this is exactly the conversation we have with clients about their systems, and it lands differently when we can say we did it to ourselves first.
The pattern is always the same. Audit before deciding. Fix the critical risks immediately. Design a standard, repeatable target rather than patching in place. Migrate in risk order. Keep the old system running until the new one has proven itself.
If your business runs on a server that was set up years ago, has grown by accretion, and has never had an independent audit, the uncomfortable truth is that you probably have a version of our list too. The good news is that finding it is a day's work, and fixing it is a plan, not a panic.
We build and run systems for UK ecommerce, fulfilment, and trade supply businesses, and infrastructure like this sits underneath all of it. If you'd like a second pair of eyes on yours, get in touch.


