Stabilising an inherited Laravel platform nobody dared to restart

A half-finished Typo3-to-Laravel migration, a 15 GB repository and a production server nobody dared to reboot. Audit first — then backups, security fixes, Docker and ~500 tests.

~500 unit tests on a codebase that had none
15 GB repository slimmed down for CI/CD
0 → daily EC2 snapshots and MySQL backups

Two travel websites ran on a Laravel platform inherited from a previous vendor. The rewrite from Typo3 CMS had never been finished, and the 15 GB repository held two separate Laravel projects, CMS leftovers and years of junk files — even cloning it was a challenge.

The challenge

The audit we ran in the first two weeks read like a list of business risks rather than technical ones:

  • The server ran an outdated operating system and packages, with a pending restart nobody dared to trigger — no one knew if production would come back up.
  • There was no reliable backup strategy: a serious incident would have meant data loss and a long recovery.
  • Credentials and secrets lived inside the repository.
  • Endpoints and files that should have been private were publicly reachable — including forgotten development routes and roles that could modify data.
  • The repository was too heavy for sane CI/CD, and there were no automated tests at all.

What we did

We started the way we always start — with a written audit of what actually threatens the business (the same exercise we sell as a System Risk Check). Then we worked down the risk list:

  • Backups first, before changing anything: automated MySQL dumps and daily EC2 snapshots on the existing setup.
  • Moved secrets out of the repository into environment-based configuration.
  • The overdue server upgrade: rehearsed on a cloned server, written as a step-by-step runbook, protected by a snapshot for rollback, and executed in a low-traffic window. The restart everyone feared was a non-event — because it had already happened once, on the clone.
  • Closed the security gaps: public routes and files made private, forgotten development endpoints removed, data-changing permissions tightened, staging put behind a password. Nobody had exploited them — but with automated scanning everywhere, finding an open door is only a matter of time.
  • Slimmed the repository: media moved to Amazon S3, runtime artifacts, cached views, dead code and unneeded packages removed — from 15 GB towards a size where CI/CD is realistic.
  • Added a Docker-based local setup — any developer can launch the project with a couple of commands — plus health checks and roughly 500 unit tests on a codebase that had none, as groundwork for safe refactoring.
  • Set up CloudWatch monitoring for CPU and memory. It caught load spikes; the logs showed scanner bots probing for .env files and WordPress paths, each request spinning up PHP-FPM. We blocked them with rate limiting at the Nginx layer — before they reach PHP at all — and the load dropped.
  • Next on the plan: the instance is roughly twice as large as the workload needs, so a downgrade is scheduled once bot traffic stays low — alongside an AWS Savings Plan recommendation (~20% off for a 1-year commitment, up to ~40% for 3 years).

The outcome

The platform now has backups it never had, security doors closed before anyone walked through them, a repository a team can actually work with, and tests, Docker and runbooks that make changes boring — in the best possible sense. The scary restart, the risky upgrade, the unexplained load: all handled without a single disruption to the business.

This is what an application takeover looks like when it is done in the right order: understand the risks first, stabilise second, improve third.

More case studies

Laravel maintenance for two established travel websites

Maintenance & Support Laravel maintenance for two established travel websites

How we took ongoing technical ownership of two live Laravel travel websites — cutting a key search page from about 17 seconds to about 1 second along the way.

MySQL upgrade that cut about $10k a year in AWS costs

Modernisation & Upgrades MySQL upgrade that cut about $10k a year in AWS costs

An outdated MySQL 5.7 database was quietly adding about $900 a month in AWS Extended Support fees. We planned and ran a safe upgrade to 8.0 around a live legacy application.

SAP–Shopify sync rebuilt from legacy PHP to Symfony

Modernisation & Upgrades SAP–Shopify sync rebuilt from legacy PHP to Symfony

Six storefronts depended on a fragile black-box sync with SAP. We took it over and replaced it step by step with a Symfony middleware — without stopping the business.

Culinary events platform: years of maintenance and a UK launch

Maintenance & Support Culinary events platform: years of maintenance and a UK launch

We keep a Dutch culinary events platform stable through high-traffic ticket sales — and refactored its legacy Symfony core so the same system could launch in the UK.

300,000-SKU product catalogue: instant search and stable syncs

Maintenance & Support 300,000-SKU product catalogue: instant search and stable syncs

A custom PHP product information system struggled under 300k+ SKUs: slow searches and fragile Shopify and Shopware syncs. We modernised it in place — no rewrite.

REST API on a legacy Symfony app for a headless React frontend

Modernisation & Upgrades REST API on a legacy Symfony app for a headless React frontend

Instead of rewriting a Symfony 3.4 events platform, we exposed its existing business logic through 20+ REST endpoints — unblocking a full React migration at a fraction of rewrite cost.

From no-code prototype to a production SaaS platform

Product Development From no-code prototype to a production SaaS platform

A validated MVP built on Make, Bubble and Replit had hit its ceiling. We re-platformed it into a multi-tenant Symfony + React SaaS with a grounded AI content engine.

An AI legal-training MVP, live in about two weeks

Product Development An AI legal-training MVP, live in about two weeks

Law students practise argumentation against AI judge personas grounded in real legal documents. We designed and shipped the production-ready MVP in roughly two weeks.

Keeping a Symfony 1 / PHP 5.4 website safely in business

Maintenance & Support Keeping a Symfony 1 / PHP 5.4 website safely in business

A property website on Symfony 1 and PHP 5.4 still earned its keep. We maintain it carefully — SEO updates, feeds, cache issues — and brought production changes back under Git control.

The outage that wasn’t the application: a Route 53 DNS story

Rescue & Incident Response The outage that wasn’t the application: a Route 53 DNS story

Internal business systems stopped resolving even though the servers were healthy. We traced the outage layer by layer to incomplete Route 53 delegation and restored access.

Technical SEO cleanup for two Laravel travel websites

Maintenance & Support Technical SEO cleanup for two Laravel travel websites

After a difficult migration history, two travel websites had canonical, sitemap, redirect and indexation problems. We cleaned up the technical foundation as part of ongoing maintenance.

A real-time crypto signals SaaS on Symfony and ClickHouse

Product Development A real-time crypto signals SaaS on Symfony and ClickHouse

Tick-by-tick market data from major exchanges, analysed and delivered as trading signals in under half a second — through a web dashboard and a Telegram bot.

Monetising AI chatbots in WordPress — with no user accounts

Product Development Monetising AI chatbots in WordPress — with no user accounts

Five AI personas, a freemium paywall and Nordic Swish payments — built as a custom WordPress plugin that charges users without ever asking them to register.

industry

Travel & hospitality

tech stack

Laravel, AWS (EC2, S3, CloudWatch), Docker, Nginx

service

Maintenance & Support

system risk check

Want results like these for your application?

Start with a System Risk Check — a fixed-price technical audit of your application with a written, prioritised report. The report is yours, whatever you decide next.