Lab 12 (B): Multi-OS Apache Installation + Bootstrap Web Page Deployment via Ansible¶
🎯 Objectives¶
- Install Apache automatically across Ubuntu, RedHat, and Amazon Linux systems.
- Detect OS family dynamically.
- Deploy a custom Bootstrap “Welcome” web page that confirms Ansible deployment.
Pre-Reqs¶
1. Deploy Nodes¶
- Deploy either Ubuntu/AMI node in Public Subnet give it a name
control-node. - Deploy 1 Ubunut Node again in Public Subnet
- Deploy 1 Amazon Linux node again in Public Subnet
2. Install Ansible¶
# Update your system
sudo apt update -y
# Install dependencies
sudo apt install -y software-properties-common
# Add the official Ansible PPA
sudo add-apt-repository --yes --update ppa:ansible/ansible
# Install Ansible
sudo apt install -y ansible
# Verify installation
ansible --version
Expected output example:
ansible [core 2.16.5]
python version = 3.10.12
jinja version = 3.1.2
# Update system
sudo yum update -y
# Install Python and pip if not already installed
sudo yum install -y python3 python3-pip
# Install Ansible via pip (recommended for latest version)
sudo pip3 install ansible
# Verify installation
ansible --version
3. Copy your keys¶
Your .pem file (e.g., aws_key.pem) is required by Ansible to connect securely to AWS EC2 instances.
Here’s how to safely transfer it to your Ansible control node (Ubuntu or Amazon Linux) from Windows or macOS.
-
Open PowerShell in the folder where your
.pemfile is located, for example:cd "C:\Users\<YourUsername>\Downloads" -
Use
scp(Secure Copy) to copy your key to the control node:scp -i C:\Users\<YourUsername>\.ssh\lab-key.pem aws_key.pem ubuntu@<CONTROL_NODE_IP>:/home/ubuntu/.ssh/Replace:
<CONTROL_NODE_IP>→ public or private IP of your Ansible control node.lab-key.pem→ the key used to access the control node itself.aws_key.pem→ the key file you want to copy.
-
Set proper permissions once inside the control node:
chmod 600 ~/.ssh/aws_key.pem
⚠️ If PowerShell says "
scpnot recognized", install it by:
- Installing Git for Windows and using its Git Bash terminal, or
- Installing OpenSSH Client via:
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
-
Navigate to where your
.pemfile is located:cd ~/Downloads -
Copy the file to your control node using
scp:-
In the below command
lab-key.pemis the key which you will use to connect to your control node andaws_key.pemis the key for the new nodes that you deployed. You can use the same keys if you prefer but in enterprise all nodes will have different keys. -
I have deployed ansible on my ubuntu VM, if you have deployed on AMI Node then use
ec2-user@<Control-Node-IP>
scp -i ~/.ssh/lab-key.pem aws_key.pem ubuntu@<CONTROL_NODE_IP>:/home/ubuntu/.ssh/ -
-
SSH into the control node and adjust permissions:
ssh -i ~/.ssh/lab-key.pem ubuntu@<CONTROL_NODE_IP> chmod 600 ~/.ssh/aws_key.pem
Your Directory Structure on Control Node¶
ansible-lab-apache/
├── ansible.cfg
├── inventory.ini
├── site.yml
└── templates/
└── index.html.j2
0. Create ansible-lab-apache directory¶
sudo mkdir ansible-lab-apache
# Move into the directory
cd ansible-lab-apache
1. Create inventory.ini¶
[webservers]
ubuntu-web ansible_host=10.0.1.10 ansible_user=ubuntu
rhel-web ansible_host=10.0.1.11 ansible_user=ec2-user
amazon-web ansible_host=3.12.45.67 ansible_user=ec2-user ansible_ssh_private_key_file=~/.ssh/aws_key.pem
2. Create ansible.cfg¶
[defaults]
inventory = ./inventory.ini
host_key_checking = False
retry_files_enabled = False
timeout = 30
forks = 10
3. Create site.yml — Main Playbook¶
---
- name: Deploy Apache with custom Bootstrap index page
hosts: webservers
become: true
gather_facts: true
vars:
apache_map:
Debian:
pkg: apache2
service: apache2
webroot: /var/www/html
RedHat:
pkg: httpd
service: httpd
webroot: /var/www/html
Amazon:
pkg: httpd
service: httpd
webroot: /var/www/html
tasks:
- name: Fail if OS not supported
fail:
msg: "Unsupported OS family: {{ ansible_os_family }}"
when: ansible_os_family not in apache_map.keys()
- name: Display detected OS family
debug:
msg: "Installing Apache on {{ ansible_distribution }} ({{ ansible_os_family }})"
- name: Update package cache (Debian)
apt:
update_cache: yes
when: ansible_os_family == 'Debian'
- name: Install Apache package
package:
name: "{{ apache_map[ansible_os_family].pkg }}"
state: present
- name: Ensure Apache is enabled and started
service:
name: "{{ apache_map[ansible_os_family].service }}"
state: started
enabled: yes
- name: Deploy Bootstrap-based index.html
template:
src: templates/index.html.j2
dest: "{{ apache_map[ansible_os_family].webroot }}/index.html"
mode: '0644'
- name: Verify Apache webroot ownership
file:
path: "{{ apache_map[ansible_os_family].webroot }}"
owner: root
group: root
state: directory
- name: Restart Apache after deployment
service:
name: "{{ apache_map[ansible_os_family].service }}"
state: restarted
- name: Test page availability
uri:
url: "http://127.0.0.1"
return_content: yes
register: webpage
- name: Display page title from Apache
debug:
msg: "{{ webpage.content | regex_search('<title>(.*?)</title>', '\\1') }}"
4. Create templates/index.html.j2 template file¶
This Jinja2 template creates a clean Bootstrap 5 landing page with a message that it was deployed via Ansible.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Welcome to Ansible Deployed Web Server</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
background: linear-gradient(135deg, #007BFF, #6610f2);
color: #fff;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
font-family: 'Segoe UI', sans-serif;
}
.card {
background: rgba(255,255,255,0.1);
border: none;
border-radius: 1rem;
padding: 2rem;
box-shadow: 0 8px 16px rgba(0,0,0,0.2);
}
</style>
</head>
<body>
<div class="container">
<div class="card">
<h1 class="display-4 mb-3">🚀 Welcome to {{ ansible_distribution }} Web Server!</h1>
<p class="lead">This page was <strong>automatically deployed by Ansible</strong> from control host <em>{{ ansible_hostname }}</em>.</p>
<hr class="my-4">
<p>Managed Node: <strong>{{ inventory_hostname }}</strong><br>
OS Family: <strong>{{ ansible_os_family }}</strong><br>
Deployment Time: <strong>{{ ansible_date_time.date }} {{ ansible_date_time.time }}</strong></p>
<a href="https://www.ansible.com/" class="btn btn-light mt-3">Learn More about Ansible</a>
</div>
</div>
</body>
</html>
5. Run the playbook¶
ansible-playbook -i inventory.ini site.yml
Sample output:
TASK [Display detected OS family] *****************************************
ok: [ubuntu-web] => {
"msg": "Installing Apache on Ubuntu (Debian)"
}
ok: [amazon-web] => {
"msg": "Installing Apache on Amazon Linux (Amazon)"
}
6. Verify¶
From your control node or browser:
curl http://<webserver-ip>
Or open in browser:
http://10.0.1.10
http://3.12.45.67
Expected: A Bootstrap “Welcome” page showing OS name, hostname, and “Deployed by Ansible Host”.
Learning Outcomes¶
✅ Configure multi-OS automation logic using ansible_os_family
✅ Deploy dynamic templates using template module
✅ Understand inventory grouping and privilege escalation
✅ Automate service installation and configuration idempotently