I was recently asked to change the tenancy of several EC2 instances from ‘dedicated’ to ‘default’, which basically means that these instances will not use dedicated hardware to run, instead, they will run on hardware shared with other tenants (it is less expensive).
AWS won’t let you change the tenancy of an instance once it has been started. So, what you have to do is to create an AMI (Amazon Machine Image), recreate the instance using that AMI as a template, and copy the instance details by hand (such as IP address, tags, UserData, etc.), which makes this process prone to human error.
Also many EBS volumes of these instances were encrypted using a wrong Key, so I had to re-encrypt them using the right one.
In order to avoid errors and lots of work, I created the next script, which hopefully, might help you too!
-You have to install AWS PowerShell Tools first. -Then you have to configure AWS CLI Credentials. -Make sure the script migrates all of the attributes your instances use, we migrated most of them, but not all. -Once the process is finished, make sure the instances were migrated correctly, then you will have to manually delete the created AMIs and its snapshots from the AWS EC2 console. -You can always go to the log file to get the instance information in order to rebuild it manually from the AMI, if the creation of the new instance fails after the original instance is terminated.
In this guide, I want to show you the steps that I’ve taken to deploy this blog completely from scratch; this is the first time I use all these different technologies and it has been very fun to set up, so I wanted to share with you how easy it was ;).
Download and extract the WordPress files into your computer. In this case, I saved the zip file into E:\wordpress-5.2.2.zip.
=> Expand the file using the Expand-Archive .\wordpress-5.2.2.zip -DestinationPath . command, or your favorite unzipping tool.
=> Create a new GitHub Repo. In this case the name of the repo will be ‘wordpressdemo’ and it will be private.
=> After you hit the “Create repository” button and the repo is succesfully created, you have to upload the WordPress files into it using the following commands.
cd E:\wordpress (you have to run these commands from your WordPress folder) echo "wordpressdemo" >> README.md (it creates a dummy readme file, optional) git init (it initializes an empty local Git repository) git add . (it adds all the files into the commit) git commit -m "first commit" (it creates the first commit) git remote add origin https://github.com/santiagovarela86/wordpressdemo.git (it configures the local Git repo to upload files to your Github repo) git push -u origin master (it uploads the files)
=> Ok, so you now have the first commit in your Github repo with all of the WordPress files in it.
Create an AWS RDS Instance using the AWS RDS Console, once you’re in there, click on “Databases”, then click “Create Database”. In this case, I clicked on “Easy create” and selected the MySQL engine type.
=> Then for the DB instance size, you have to choose the Free tier option, pick a name for the DB instance identifier (I used the ‘wordpressdemo’ instance name), pick a username (I left the default username ‘admin’) and select the option to automatically generate a password, then click on “Create Database”, and that’s about it.
=> While the DB is being created, you will have to take note of the generated password in order to connect to the DB later.
=> Click on “View credential details” to get the password.
=> Once the DB is created, you have to get the DB endpoint to configure the WordPress site. To get it, go to the AWS RDS Console > Databases, click on the DB you created and you will see something like this. Take note of the endpoint URL.
=> Using MySQL Workbench you have to connect to your DB instance to create a new schema named “wordpressdemo”, just like the DB instance name.
=> Hit apply, commit the changes and the database is ready.
Create an Elastic Beanstalk App, using the AWS Beanstalk Console. Select the option “Create New Application” at the top right corner of the screen, then fill in the details and hit on “Create”.
=> After clicking on “Create” you wil get this message stating that you do not have any environment configured for this app. So you have to click on “Create one now”.
=> Then proceed to create a new Web Server environment.
=> Configure it this way; it is not necessary for the environment name to match the domain name; the platform needed for a WordPress site is PHP.
=> Then hit on “Create environment” and that’s it. The creation of the environment will take a few minutes.
=> Once the environment is ready, you have to set up the environment variables to generalize the DB parameters in the code. To do this, go to the Configuration section of the environment at the AWS Elastic Beanstalk Console.
=> Then on the Software category, click on “Modify”.
=> Then at the bottom of the screen you will see the Environment Properties section.
=> You have to create the following environment variables, used by the application (wp-config.php file) to get the DB connection parameters.
The parameters are:
RDS_HOSTNAME: it is the RDS endpoint URL RDS_DB_NAME: it is the DB instance name RDS_PASSWORD: it is the DB auto generated password RDS_USERNAME: it is the DB username RDS_CHARSET: utf8
=> Once you do this, the Beanstalk environment is almost ready. You still need to grant permissions for the the environment to access the DB. To do so, you have to take note of the Security Group Name the Beanstalk environment.
=> Then go to the AWS RDS Console, and get into the WordPressdemo Database configuration. Click on the default VPC security group.
=> Once inside the security group click the “Inbound” tab, and then click “Edit”.
=> Then click on “Add Rule”, a new line will appear, then in Type choose “All traffic”, in Source choose “Custom” and start writing the Beanstalk Security Group Name; a dropdown list will appear, then you have choose the matching Group ID (which AWS automatically translates from the Security Group Name).
=> Hit save and that’s it. You could optionally create a new Security Group for the DB, and only allow Inbound traffic coming from the Elastic Beanstalk for a more granular or increased security, I just left the DB in the default SG in this case.
Create an AWS CodePipeline to deploy the PHP app to the Beanstalk environment. To do this you will have to go to the AWS CodePipeline console. From this console, click on “Create pipeline”.
=> Then choose a Pipeline name, and leave the rest of the parameters with its default values. Then click “Next”.
=> For the Source Stage you have to choose the GitHub provider. Then click on “Connect to Github”. You will be prompted with a Github login interface.
=> Once you successfully authenticate with Github, you will have to select the Origin Repo and Branch. In this case the Repo is ‘wordpressdemo’ and the branch is ‘master’. Then click on “Next”.
=> You have to skip the Build Stage configuration. Click on “Skip build stage”. You will be prompted with a message warning you about not having a build stage, dismiss it and click on “Skip build stage”.
=> Then for the Deploy Stage you have to choose the previously created Elastic Beanstalk Application and environment, then click “Next”.
=> After reviewing the configuration and checking that everything is OK, click on “Create Pipeline”.
=> After a few moments, the pipeline is created and the App is correctly deployed to the Beanstalk environment.
=> Then, if you go to the AWS Elastic Beanstalk Console, and then you get into the environment created for this guide, you can click the environment’s URL to check that the APP was successfully deployed.
=> But wait, you are not done yet. You have to upload the wp-config.php file with the correct Database parameters. To do so, copy the wp-config-sample.php file to a new wp-config.php file, and overwrite the MySQL configuration section of it.
=> After saving the file, you will have to commit and push the changes to the repo to get the Blog published, using these commands:
cd E:\wordpress git status (always a good idea before committing) git add . (to add the new file(s) to the commit) git commit -m "Setting DB parameters" (to create the commit) git push (to upload the commit to Github)
=> The commit and push to the Github repo triggered an automatic CodePipeline deployment to the Elastic Beanstalk environment.
=> Now the Blog is up and running with the proper DB configuration.
=> Initial setup screen. Since we provided the wp-config.php file with the DB parameters, the DB configuration screen will not appear in the wizard.
=> After the initial setup you can login and manage the site. But be careful… the communication to the blog is not encrypted. So the passwords are sent over the network using plain text. Not good. That’s why you have to setup an SSL certificate.
Now you must do 2 things, first configure the AWS nameserver delegation in your DNS registrar in order to manage the zone from our AWS Console.
=> Configure Nameserver Delegation: After you create the hosted zone from the AWS Console, you have to take note of the values of the NS record in order to configure them into the nameservers configuration inside your DNS registrar’s management homepage; that step will vary depend to whom did you buy your domain name, so I won’t be covering this step in this guide, but it is a fairly simple task.
=> Create these public DNS records in your AWS Route 53 Hosted Zone.
Name: empty, Type: A, Alias: Yes, Value: Load Balancer Public URL, you can get this from your LB configuration page. (this is for santiagovarela.com)
Name: www, Type: CNAME, Alias: No, TTL: 300, Value: Load Balancer Public URL, you can get this from your LB configuration page. (this one is for www.santiagovarela.com)
Name: randomId (provided by the SSL vendor), Type: CNAME, Alias: No, TTL: 60, Value: FQDN provided by your SSL vendor to validate your domain.
In order to create an Elastic Load Balancer and configure an SSL certificate, you have to go to the AWS EC2 Console > Load Balancers > Create new Load Balancer > Application Load Balancer.
=> Click on Next to configure the SSL Certificate, here you will have to enter the private and public key as well as the certificate chain, all of this have to be provided by the entity you purchased the SSL certificate from.
In my case I bought the cheapest of the SSL certificates, it only validates that I own the santiagovarela.com domain. It doesn’t validate my identity, but it is enough for this blog and to keep the traffic encrypted, most importantly.
=> Then you will have to create a new Security Group for the Load Balancer, to allow public internet traffic to reach it.
=> After that, you have to create a new target group to tell the Load Balancer what to load balance and also to configure the Health indicator (a URL in your site that would return an HTTP 200 OK Response).
=> Click on Next to configure the actual targets inside the target group. Select the WordPressdemo-env instance, then click “Add to registered” on port 80. Then click Next.
=> Then click on Review, and Review again, and that’s it. Your Load Balancer will be listening to both HTTP and HTTPS traffic, using the SSL certificate for HTTPS, and redirecting all traffic to your Elastic Beanstalk environment to the port HTTP 80.
=> Now, let’s limit the access to the PHP Beanstalk Environment by means of granting access to it, only to the Load Balancer Security Group.
From the EC2 Console, go to Security Groups, find the one related to the PHP Beanstalk environment, edit the Inbound Rules, then select the Load Balancer Security Group ID pointing to port 80.
=> So ideally at this point, your Database, Beanstalk environment, Elastic Balancer, all of them are assigned to a different security group. Security Group for the DB only allows traffic coming from the Beanstalk environment, then the Beanstalk Security Group only allows traffic from the Load Balancer, and then the Load Balancer Security Group allows all traffic coming from the Internet.
=> At this point all what’s left is to configure SSL inside WordPress, for that I just used and activated the Really Simple SSL plugin. Which automatically configures the site and validates the certificate installation.
We have seen how straight forward is to create a multi tier application leveraging Amazon Web Services.
It is pretty simple to create multiple environments, for instance a development, testing, QA or a production environment for the same Application, link all of them to a different branch of the same repo, and configure them to get automatically updated as soon as the code changes.
By having the DB parameterized at the environment level, we can have the same configuration files for all the different environments, greatly improving our productivity and reducing the posibility of bugs and divergent code.
If you have any doubts, suggestions or corrections, please leave a comment ;).
Note: WordPress stores some of its information in the files located on the Beanstalk EC2 instance. So, if you delete the App environment or try to recreate it, you will lose information (images, for instance). Also, If you redeploy the code using CodePipeline, it will break the blog.
This is a simple, single instance, not highly available, nor fault tolerant nor continuosly integrated example.