Provision & Configure Web Server on AWS EC2 Instance using Ansible

How much time does it take for you to provision & configure instances as per a sudden requirement? 1 set of deployment of your Production Environment where the companies main website is loaded is corrupted. What do you do? How much time does it take for you to bring it up again?

Image for post
Image for post
Application Deployment + Configuration Management + Continuous Delivery

Here comes handy, the fastest and simplest way to automate apps and IT infrastructure: ANSIBLE.

I have created a setup on AWS Cloud using 1 single Ansible Playbook. The steps followed are:

First Play

Second Play

Note: Here I will be focusing only on “httpd software” because I am using “ami-0ebc1ac48dfd14136” which is Amazon Linux 2 AMI based on RedHat OS family. For any other OS Family like Debian, you can use software “apache2” and configure accordingly.

Let’s start by building the code:

Step 1 —Ansible config file

Image for post
Image for post

Step 2— Create an Ansible Vault

ansible-vault create mycred.yml
Image for post
Image for post
Image for post
Image for post
Ansible Vault
Image for post
Image for post
Encrypted file
ansible-vault view mycred.yml

Step 3 — Main Playbook

Play 1 — Configure Localhost for Provisioning AWS Instance

Variables -

- hosts: localhost
gather_facts: no
vars_files:
- mycred.yml
vars:
myport: 81
region: ap-south-1
subnet: subnet-c48ee588
sg: websg
type: t2.micro
number: 1

Installations -

tasks:
- name: installing python
package:
name: python36
state: present
- name: installing boto3
pip:
name: boto3
state: present

Security Group for EC2 Instance -

          - name: create security group
ec2_group:
name: "{{ sg }}"
description: The webservers security group
region: "{{ region }}"
aws_access_key: "{{ access_key }}"
aws_secret_key: "{{ secret_key }}"
rules:
- proto: tcp
from_port: 22
to_port: 22
cidr_ip: 0.0.0.0/0
- proto: tcp
from_port: "{{ myport }}"
to_port: "{{ myport }}"
cidr_ip: 0.0.0.0/0
rules_egress:
- proto: all
cidr_ip: 0.0.0.0/0

Provision EC2 Instance -

          - name: launching ec2 instance
ec2:
key_name: key1
instance_type: "{{ type }}"
image: ami-0ebc1ac48dfd14136
wait: true
group: "{{ sg }}"
count: "{{ number }}"
vpc_subnet_id: "{{ subnet }}"
assign_public_ip: yes
region: "{{ region }}"
state: present
aws_access_key: "{{ access_key }}"
aws_secret_key: "{{ secret_key }}"
instance_tags:
Name: webserver
register: ec2

Add to Inventory dynamically -

          - name: Add new instance to host group
add_host:
hostname: "{{ item.public_ip }}"
groupname: webserver
loop: "{{ ec2.instances }}"
- name: Wait for SSH to come up
wait_for:
host: "{{ item.public_dns_name }}"
port: 22
state: started
loop: "{{ ec2.instances }}"

Play 2 — Configure the EC2 Instances to work as Web Servers

- hosts: webserver
gather_facts: no
tasks:
- command: curl
http://ipv4.icanhazip.com
register: x
- debug:
var: x.stdout
- name: Pass variables to role
include_role:
name: httpdserver
vars:
my_ip: x.stdout

Role -

ansible-galaxy list
Image for post
Image for post
cd /etc/ansible/
mkdir roles
cd roles
ansible-galaxy init httpdserver
Image for post
Image for post

vars -

# vars file for httpdserver
my_port: 81
my_path: /var/www/html/

tasks -

- name: install httpd
package:
name: httpd
state: present
register: status
- name: install php
package:
name: php
state: present
- name: configure httpd
template:
src: my.conf
dest: /etc/httpd/conf.d/my.conf
when: status.rc == 0
notify: restart httpd
- name: copy code
get_url:
url:
https://raw.githubusercontent.com/Dakshjain1/php-cloud/master/index.php
dest: "{{ my_path }}index.html"
- name: start httpd
service:
name: httpd
state: started
when: status.rc == 0

template -

Listen {{ my_port }}<Virtualhost {{ my_ip }}:{{ my_port }}>
DocumentRoot {{ my_path }}
</Virtualhost>

Now, what if something is updated in the config file, service was already started so it won’t happen again. For this, I have used the concept of handlers.

handler -

# handlers file for httpdserver
- name: restart httpd
service:
name: httpd
state: restarted

You can find these code files on my GitHub profile.

Now I will run the playbook -

NOTE: subnet is a required variable and it is mandatory to pass

ansible-playbook ec2_v2.yml                                                       -e sebnet=<your subnet id>                                                 -e number=<number of instances to launch>                                      --ask-vault-pass
Image for post
Image for post
3 subnets provisioned and configured using 1 single click ansible-playbook
Image for post
Image for post
All 3 Instances are running on port 81

Stay tuned!! In the next article, I will show you how to balance the load and only 1 URL will run all instances as backend servers.

For any doubt, suggestions, or feedback connect to me on LinkedIn.

Written by

Automation Tech Enthusiast || Terraform Researcher || DevOps || MLOps ||

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store