avatarNicholas Martin

Summary

The author describes the process of migrating PHP websites from an outdated cPanel EC2 instance to AWS Elastic Beanstalk, resulting in cost savings, improved scalability, reliability, resiliency, and performance.

Abstract

The author, who has been managing PHP websites on a cPanel LAMP stack since 2005, details the journey of transitioning these sites from a costly and outdated AWS EC2 instance to a more modern and efficient AWS Elastic Beanstalk environment. This migration was driven by the need to upgrade from CentOS 6, which was no longer supported as of November 2020, and the desire to leverage AWS's scalability and performance benefits. The author successfully migrated the websites, including updating hardcoded paths, configuring PHP settings for larger file uploads, and implementing SSL certificates and HTTP to HTTPS redirection. The move also involved addressing compatibility issues with PHP 7 by using an older PHP version (5.6) and changing the storage of uploaded images from the server to an S3 bucket with CloudFront distribution. The author used Docker to facilitate local testing and deployment, utilizing a custom Dockerfile to set up the necessary PHP/Apache environment with additional extensions for image manipulation and MySQL support.

Opinions

  • The author views the migration as an opportunity for cost savings and modernization, particularly appreciating the scalability, reliability, resiliency, and performance improvements offered by AWS Elastic Beanstalk.
  • There is a clear preference for modern technologies and practices, as the author considered rewriting the websites in React/Node.js but ultimately decided against it due to client budget constraints.
  • The author expresses satisfaction with the ease of use and flexibility provided by the Elastic Beanstalk CLI and the ability to deploy code directly from Visual Studio Code.
  • The author values the seamless integration of AWS services, such as Elastic Beanstalk, Amazon RDS, Amazon S3, Amazon Cloudfront, and Amazon Route 53, in the migration process.
  • There is an acknowledgment of the learning curve involved in adopting new technologies like Docker, but also an appreciation for the existing resources, such as pre-configured Docker images, that facilitate the transition.
  • The author emphasizes the importance of maintaining backward compatibility by using an older version of PHP (5.6) to support legacy code, showcasing a pragmatic approach to problem-solving.
  • The author recognizes the benefits of using AWS services for improved website performance and user experience, particularly noting the quicker load times after migration.

Migrating PHP websites from an old LAMP stack to AWS Elastic Beanstalk

How adopting Docker and Elastic Beanstalk have enabled me to migrate old PHP websites from a very outdated cPanel EC2 instance.

Photo by Kendall Henderson on Unsplash

In one of my previous posts, I mentioned that I’ve been running a cPanel based LAMP stack since 2005, which I use to host all my PHP websites. As technology progressed (and the dedicated hardware kept having issues), I eventually migrated from a dedicated rack to an on-demand AWS EC2 instance as a way of saving costs. This happened way back in 2014, and back then I was very happy with the cost savings I was making for a self-managed cPanel server!

Bear in mind, this was initially costing me around $190 per month for the instance and $45 a month for the cPanel license. It was a c3.large instance with a 200gb magnetic storage attached to it and a number of Elastic IPs. It also had a load balancer in front of it (yep, no idea why…).

Fast forward to the last year or so, and I’ve put a lot of effort into learning about scalability, reliability, resiliency, and performance — all of which AWS provides (check the post above).

However, there are still a few websites that I look after which are still running on my old cPanel EC2 instance, so I’ve kept it running alongside all my other projects. Because the LAMP stack doesn’t have as much on it anymore, I took the opportunity to downgrade it to an m3.medium instance in early 2018. This was the best option at the time that didn’t require me to configure a completely new instance.

Last year, cPanel’s WHM started warning me that CentOS 6 would no longer be supported as of November 2020. Naturally, I saw this as an opportunity to potentially migrate away from PHP and use the React/Node.js combo I’ve come to love over the years. However, my clients simply don’t have the budget to support it until nearer the time. I certainly played with the idea of doing the work anyway, but I had to admit defeat as it would be too much work considering I have plenty of other projects that need to take priority.

Last week, I was investigating whether Elastic Beanstalk supported .NET core (for work), and discovered that PHP was also supported… after a quick experiment, I had finally found what I was looking for!

As of right now, my AWS bill is around $220 per month, with the old server contributing around $80. It’s a substantial chunk which I can replace with t2.nano instances for about $15 per website (there are 4 in total). While that doesn’t seem like much of a cost saving, it means that I no longer need to pay $45 for the cPanel license as well. Furthermore, each website now benefits from scalability, reliability, resiliency, and performance.

I’ve got one more site to migrate before the end of the month, and then I can celebrate! So I figured I would share my process with you…

Photo by Caleb Woods on Unsplash

Migrating PHP websites from an EC2 instance to Elastic Beanstalk

It’s worth mentioning at this point that my PHP websites didn’t make use of Composer or any PHP frameworks, so in a way, it’s fairly vanilla PHP.

It’s also worth mentioning that I had already migrated the databases to Amazon RDS.

I wasn’t sure whether it was even possible, so I decided to do a proof of concept. For this, I focused on migrating the most recent PHP website I developed. I wasn’t quite sure how easy it was, but it seemed like it was as easy as zipping up the public_html folder and uploading the zip to Elastic Beanstalk. So I did just that and it almost worked!

There were a few hardcoded /home/user/public_html/... paths which I needed to update, but now that the instance was up and running, I made use of the Elastic Beanstalk CLI, which meant I could push up the code within Visual Studio Code using eb deploy.

In a matter of minutes, I could navigate my way around the website using the elastic beanstalk domain:

(not actually the URL, but I’m surprised that one is available!)

I double checked all the functionality and discovered that images over 2MB couldn’t be uploaded, so I needed to change the default PHP configuration to something much higher to support high-resolution images. Worth noting that the images are only temporarily stored on the server, as they are uploaded to S3 after being resized.

To increase the default, create a .ebextensions/change_upload_size.config file with the following configuration:

files:
    "/etc/php.d/99uploadsize.ini":
        mode: "000644"
        owner: root
        group: root
        content: |
            upload_max_filesize = 100M
            post_max_size = 100M
commands:
    remove_old_ini:
        command: "rm -f /etc/php.d/99uploadsize.ini.bak"

That now resolves the issue with uploading photos, so everything now worked perfectly. I was extremely confident at this point that it was now ready for production, so I just needed to configure the SSL certificate on the load balancer, and finally jump into Route 53 to point the domain to the new environment. Worth noting that you will need to configure an SSL certificate within the same region for it to be available to Elastic Beanstalk

Within a few moments, it had switched over… and you could really tell the difference because it loaded so much quicker than before.

I had forgotten one thing though, which was to automatically redirect users to HTTPS. Worth noting that .htaccess files work as expected, but I wanted to make sure I wasn’t going to get caught out by anything and found this can be achieved by creating another config file .ebextensions/https-redirect-php.config with the following:

files:
   /etc/httpd/conf.d/http-redirect.conf:
     mode: "000644"
     owner: root
     group: root
     content: |
       RewriteEngine On
       RewriteCond %{HTTP:X-Forwarded-Proto} !https
       RewriteCond %{HTTP_USER_AGENT} !ELB-HealthChecker
       RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

I’m honestly not sure if the naming is config filename is important, but I have a feeling you could roll up all configuration into one file if you wanted.

That’s it up and running, completely seamless without any downtime either!

Onto the next websites…

The next website, although a little older was a breeze using what I had already learned. Within about 30 minutes it was successfully up and running.

The one I’ve been working on tonight is definitely a little more challenging as it was a website I inherited back in 2008, so the source code was overly complicated and very much outdated. This became more apparent when I was met with quite a few errors, as most of the methods used were removed in PHP 7.

I decided it would be too much work to support 7.2, and found that you could configure the Elastic Beanstalk environment to use PHP 5.6. This was all that was needed to get it up and running!

There’s just one more thing…

I completely forgot that all of the websites stored any uploaded images directly onto the server. This is a problem for elastic beanstalk as the images would be lost if the instance gets destroyed or not be copied across to the replicas.

So I basically had one option, which was to modify the websites to upload the images to an S3 bucket instead of storing them locally and deliver the images via CloudFront instead. This, in turn, helps reduce the load on the servers and increases scalability and load times.

Now that I had already made the websites live, I wanted to test my changes locally as I had no doubt it would be a trial and error. The problem was, my machine isn’t actually configured to run PHP websites locally.

Enter Docker

Having played with Docker over the last few weeks, I decided to investigate this as an option. It didn’t take long to discover that there is a Docker image already configured for PHP/Apache, but doesn’t quite have what I need (mysql/mysqli), so I created a Dockerfile with the following configuration:

FROM php:5.6-apache
RUN apt-get update
RUN apt-get upgrade -y
# enable mod_rewrite
RUN a2enmod rewrite
# install gd library and extensions for image manipulation
RUN apt-get install -y build-essential libssl-dev zlib1g-dev libpng-dev libjpeg-dev libfreetype6-dev
RUN docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
&& docker-php-ext-install gd
# install mysql libraries
RUN docker-php-ext-install mysql mysqli pdo pdo_mysql

Then you just need to build it with docker build -t websiteimage . and run it with:

docker run -d -p 8080:80 --name website websiteimage

Head to http://localhost:8080/ and it should be up and running!

If you want to deploy changes to the running container (instead of having to rebuild every time) just run the following in the command line:

docker cp . website:/var/www/html/

That’s all folks…

Photo by Kats Weil on Unsplash

I hope you’ve enjoyed this little insight into what I’ve been working on this weekend. If you appreciate it, please do give a couple of claps and perhaps follow me for even more stories and guides!

AWS
PHP
Elastic Beanstalk
Migration
Infrastructure
Recommended from ReadMedium