Containerizing a Legacy Application Without a Full Rewrite

A retail client came to us with a PHP application originally built in 2013, deployed by SSHing into an EC2 instance and running a shell script that had accumulated undocumented tweaks for over a decade — specific PHP extension versions, a locally patched ImageMagick, and a cron job nobody remembered the purpose of. A full rewrite wasn't on the table; the app worked and the business needed deploys to stop being a manual, risky process.
We started by reproducing the existing server exactly inside a Docker container, not improving anything yet — same PHP 7.4 version, same extensions, same file paths. This felt unsatisfying but was the right call: the goal was to eliminate 'it works on the production server for reasons nobody understands' before changing anything else. Getting an identical environment running in a container took about a week, mostly spent finding config files that lived outside version control.
Session state turned out to be the biggest blocker to actually scaling this. The app stored PHP sessions on local disk, which is invisible when you have one server and breaks immediately once you run multiple container instances behind a load balancer — users got logged out randomly as requests hit different containers. We moved sessions to Redis, which was a small code change but required understanding session handling logic that hadn't been touched in years.
The undocumented cron job turned out to matter: it was regenerating a sitemap file and clearing a local file cache every fifteen minutes. In a containerized, multi-instance setup, local file caches per container are actively wrong — the cache buster running on one instance doesn't help the other three. We replaced the local cache with a shared Redis cache and moved the sitemap generation to a proper scheduled job outside the app containers entirely.
Six weeks in, the app runs on ECS with three container instances behind an ALB, deploys are a `git push` triggering a pipeline instead of an SSH session, and nothing about the application's actual business logic changed. Containerizing legacy apps is mostly archaeology — finding the state that was quietly relying on a single server — more than it is writing new code.


