Deploying a WebServer on AWS using Ansible

Image credit: https://miro.medium.com/max/375/1*PzXLK0lbmPb6FdUasHC1EQ.png

Welcome, this article shows a simple yet powerful way to deploy Web Server on the AWS using Ansible.

Ansible is an open-source software provisioning, configuration management, and application-deployment tool enabling infrastructure as code.

Prerequisites for this project:
1. AWS account should be created and, AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are required.
2. Ansible version 2.9 should be installed. Refer to this for the Ansible installation.

Steps:
In this project, I’m following three main steps for the deployment of the webserver on the AWS using Ansible.
1. Launching instance in the AWS cloud
2. Updating inventory dynamically
3. Configuring web server using the ROLE in Ansible.

Ansible provides us a module named ec2 for provisioning EC2 instance on the AWS. But for login to the AWS, we required AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. So, we will create one file and inside this file, we will declare these secrets. To make this file secure, let's store these credentials in the ansible vault.

Create the Ansible-Vault using the command

$ ansible-vault create secret.yml

Inside this secret.yml file declare two variables. One is for AWS_ACCESS_KEY_ID and another is for AWS_SECRET_ACCESS_KEY.

This file is password protected and encrypted. Even if anyone comes to this file, he can’t able to see the data inside vault unless the data is decrypted.

Now, create a playbook that will launch EC2 instance using this secret credentials inside launchAWSInstance/secret.yml file.

launchAWSInstance/launch.yml

When this playbook runs it will launch the EC2 instance with the tag “AutoWebConfig”.

Now, we will create a dynamic inventory that will update dynamically according to the instances present in the AWS.

For this purpose, Ansible provides us pre-created files for EC2. Just download the ec2.py and ec2.ini files form the Ansible on the GitHub branch stable-2.9 and place these files in the folder that has all of the inventory files.

Link for ec2.py and ec2.ini files:

As we are working in the Mumbai region on AWS, let's update the ec2.ini file for the Mumbai(ap-south-1) region.

If we run the script as it is, it will update the inventory for all of the instances running on the AWS. But, I only want to configure the instances that I had launched for the purpose of launching webserver. So, what I can do, I will tag these instances with the Name and named them as “AutoWebConfig”. This will enable us to apply the filter to pick the specific instances for the inventory.

So, we will apply a filter and say that pick all the instances whose tag Name starts with “Auto” and add them to the inventory. For this we have to update the ec2.ini file as follow:

The final step we have to do is that we have to export the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY and AWS_REGION as environmental variables.

$ export AWS_REGION = ap-south-1$ export AWS_ACCESS_KEY_ID = YOUR_AWS_ACCESS_KEY_ID$ export AWS_SECRET_ACCESS_KEY = YOUR_AWS_SECRET_ACCESS_KEY

Finally, we had successfully done the setup for updating inventory dynamically and according to our requirements.

We can test this by running the file.

As the IP of the target host is updated to the inventory even though lots of other instances are running on the cloud at the same time. I can conclude that my setup is working perfectly.

ROLE is a powerful concept for managing playbook. Roles provide a framework for fully independent, or interdependent collections of variables, tasks, files, templates, and modules.

In the final phase of our project, we will create a ROLE to configure the webserver in the instance running on AWS.

Let’s start by creating the ROLE named webserver.

$ ansible-galaxy init webserver

We can see that there are separate folders for managing the ansible-playbook. We can store all of the variable files in the vars folder, all of the task files in the tasks folder, and so on.

In the tasks/main.yml file, we can write all the tasks for configuring the webserver.

What this code does, it will install the httpd package only if the AMI we are using is the Amazon distribution.
After that, it will create a directory for storing the website code files.
Here, we are configuring the web server and setting up the document root directory as /var/www/ankush/ and the port as 8123.

The configuration file(files/localconf.conf) will look like this:

We had used Jinja templating in this file. The variables port and documentRoot are declared inside the vars/main.yml file.

As the httpd configuration files are located at /etc/httpd/conf.d/ we will copy this file at /etc/httpd/conf.d location in the server.

As we had set the document root at /var/www/ankush/, we will copy the website code at /var/www/ankush/ location.

And finally, we will start the httpd service.

But, it may possible that we will change the web server configuration in the future and that time we want that the change will automatically be updated by restarting the httpd service. For this, we have to write on handler in the handlers/main.yml file.

Whenever the webserver configuration file is changed, it will restart the httpd service.

handlers/main.yml file:

vars/main.yml file:

After running this configuration, our website will be available at the port 8123.

We had created the role. But how the Ansible come to know that this is the role?
For this, we have to update the configuration file of the ansible and tell that all of the roles are present at /etc/myroles/ directory.

$ vim /etc/ansible/ansible.cfg# Inside ansible.cfg file update following line with the path your roles are inroles_path = /etc/myroles/

Save the file and exit.

Now, check if the roles are globally available in your system or not.

$ ansible-galaxy role list

As we can see, the webserver role is available for the entire system.

Finally, we will write the code in the launchAWSInstance/launch.yml playbook to run the webserver role against the dynamic inventory.

The final code for our playbook to launch and configure the EC2 instance will look like the following:

/launchAWSInstance/launch.yml

Running the whole setup:

$ ansible-playbook --ask-vault-pass launch.yml

This will fail with the following error:

There are two reasons for this failure.
1. The default user is set as ankush in ansible.cfg file. But the Amazon Linux has the user name as ec2-user.
2. For ssh into the instance, ansible required the private key file(.pem file). But it unable to find this file.

For fixing these errors, we have to go to the ansible configuration file.

$ vim /etc/ansible/ansible.cfg

Change the remote user to the ec2-user.

Update the location of the private key file:

Now, we are all set to deploy the WebServer on the AWS.

$ ansible-playbook --ask-vault-pass launch.yml

It will ask for a vault password. Enter that password and press enter.

As we are seeing in the above picture the EC2 instance is created, inventory is updated dynamically and webserver is configured on the EC2 instance.

Open the web browser and go to the Public IP of the instance. As the port on which webserver listening is 8123, go to that port. The name of the page is home.html.

Our final URL will be https://13.126.216.128:8123/home.html

Finally, we had successfully launched the website.

This setup is so much robust that we can provision and configure as many instances as we want.

Thanks for reading!

If you liked this article, please applaud it.
You can also follow me on Twitter at @cankush625 or find me on LinkedIn.

Tech blogger, researcher and integrator