In today’s rapidly evolving software development landscape, maintaining secure, consistent, and easily manageable infrastructure environments is crucial. In our recent initiative, we took over a client’s project previously developed and managed by another vendor. Our initial audit revealed several legacy infrastructure and architectural shortcomings. This turned out to be an excellent opportunity to showcase how containerisation, combined with Infrastructure as Code (IaC) approach, can significantly enhance stability, consistency, and security.
Modernising Legacy Infrastructure: Key Issues and DevOps Approach
Initially, the project’s infrastructure featured services installed directly on the host servers, including Nginx, PHP-FPM, Redis, and MySQL. QA and staging environments, though hosted on a single physical server, lacked clear separation, making them prone to cross-environment interference and resource contention. Each environment shared critical configuration files, which increased complexity and heightened risks during deployments, upgrades, and routine maintenance tasks.

Recognising these challenges, our DevOps team put together a comprehensive improvement plan. Their primary objective was to implement environment isolation, ensure consistent configuration management, reduce infrastructure complexity, and strengthen security controls.
Containerisation and Infrastructure as Code in Action
Containerisation of legacy services was at the heart of our infrastructure migration approach. Using Docker and Docker Compose, we encapsulated all key services—frontend applications (React with Nginx), backend applications (Laravel and PHP-FPM), Redis, and MySQL—into clearly defined, independent containers. This logical separation was further strengthened by enforcing resource limits for containers running QA and staging environments. This change minimised resource interference and greatly improved reliability.
Crucially, we standardised critical configuration files across environments, including:Â
php-fpm.confÂ
Supervisord.conf
Php.ini
as well as configuration files for Nginx and MySQL.Â
We also standardised the .env files for both frontend and backend applications, supporting consistent infrastructure as code practices. SSL certificate generation was also containerised using automated scripts.
Enhancing Observability, Security, and Deployment Stability
For enhanced infrastructure observability, we deployed a dedicated monitoring server built upon Prometheus and Grafana. This server collects metrics from all environments via agents such as Node Exporter, cAdvisor, and Promtail, significantly improving monitoring capabilities and issue diagnostics.
Security improvements were integral. We transitioned from using standard AWS IAM users to AWS IAM EC2 instance profiles for backend applications, tightened AWS security groups, and introduced resource limits for QA and staging containers. This minimised cross-environment interference, improved resource provisioning, and reduced costs by removing unused resources.
We built the new infrastructure entirely through Terraform, adopting an IaC approach. This enabled repeatable and consistent infrastructure provisioning, making environments easier to manage and reducing human errors.
Conclusion
The results were compelling:
Performance increased by approximately 3% just due to optimised software configurations, the infrastructure became simpler to maintain, and deployment stability improved dramatically.
Containerisation allowed us to deploy the same thoroughly tested images from QA and staging directly into production, considerably reducing deployment risks.
Additionally, the new Prometheus and Grafana-based monitoring system provided enhanced visibility into infrastructure performance across all environments.
Overall, adopting containerisation and infrastructure as code (IaC) at earlier stages of a project leads to a more secure, scalable, and maintainable infrastructure, supporting higher software quality.