The Nautilus DevOps team wants to install and set up a simple httpd web server on all app servers in Stratos DC. Additionally, they want to deploy a sample web page for now using Ansible only. Therefore, write the required playbook to complete this task. Find more details about the task below.
We already have an inventory file under /home/thor/ansible directory on jump host. Create a playbook.yml under /home/thor/ansible directory on jump host itself.
Using the playbook, install
httpdweb server on all app servers. Additionally, make sure its service should up and running.Using
blockinfileAnsible module add some content in/var/www/html/index.htmlfile. Below is the content:
Welcome to XfusionCorp!
This is Nautilus sample file, created using Ansible!
Please do not modify this file manually!The
/var/www/html/index.htmlfile's user and groupownershould beapacheon all app servers.The
/var/www/html/index.htmlfile's permissions should be0644on all app servers.
Note:
i. Validation will try to run the playbook using command ansible-playbook -i inventory playbook.yml so please make sure the playbook works this way without passing any extra arguments.
ii. Do not use any custom or empty marker for blockinfile module.
📋 Introduction
In the world of DevOps, automation is the cornerstone of efficiency and consistency. The Nautilus DevOps team recently needed to deploy a simple HTTPD web server across all application servers in the Stratos DC with a sample web page. Instead of manually configuring each server, we leveraged Ansible's powerful automation capabilities—specifically the blockinfile module—to complete this task seamlessly.
This blog post documents the complete process, from understanding the requirements to successful deployment and verification.
🎯 The Challenge
The team had specific requirements for all application servers:
| Component | Requirement |
|---|---|
| Web Server | HTTPD (Apache) installed |
| Service Status | Running and enabled on boot |
| Web Page Location | /var/www/html/index.html |
| Content | Specific welcome message |
| File Owner | apache:apache |
| File Permissions | 0644 (rw-r--r--) |
| Content Module | blockinfile with default markers |
Content to Deploy
Welcome to XfusionCorp!
This is Nautilus sample file, created using Ansible!
Please do not modify this file manually!
🛠️ The Solution: Ansible Playbook
Complete Playbook
---
- name: Deploy HTTPD web server with sample page
hosts: all
gather_facts: yes
tasks:
# Task 1: Install httpd web server
- name: Install httpd web server
package:
name: httpd
state: present
become: yes
# Task 2: Start and enable httpd service
- name: Start and enable httpd service
service:
name: httpd
state: started
enabled: yes
become: yes
# Task 3: Create web root directory
- name: Create web root directory
file:
path: /var/www/html
state: directory
mode: '0755'
owner: apache
group: apache
become: yes
# Task 4: Add content using blockinfile module
- name: Add content to index.html using blockinfile
blockinfile:
path: /var/www/html/index.html
block: |
Welcome to XfusionCorp!
This is Nautilus sample file, created using Ansible!
Please do not modify this file manually!
create: yes
owner: apache
group: apache
mode: '0644'
state: present
become: yes
Playbook Breakdown
1. Package Installation
- name: Install httpd web server
package:
name: httpd
state: present
become: yes
Uses the package module to install HTTPD. The package module intelligently chooses the appropriate package manager (yum, apt, etc.) based on the target system.
2. Service Management
- name: Start and enable httpd service
service:
name: httpd
state: started
enabled: yes
become: yes
Ensures the HTTPD service is both running (state: started) and configured to start automatically on boot (enabled: yes).
3. Web Root Directory Setup
- name: Create web root directory
file:
path: /var/www/html
state: directory
mode: '0755'
owner: apache
group: apache
become: yes
Creates the web root directory with proper permissions and ownership.
4. Content Management with Blockinfile
- name: Add content to index.html using blockinfile
blockinfile:
path: /var/www/html/index.html
block: |
Welcome to XfusionCorp!
This is Nautilus sample file, created using Ansible!
Please do not modify this file manually!
create: yes
owner: apache
group: apache
mode: '0644'
state: present
become: yes
The blockinfile module:
- Inserts a block of text into a file
- Uses default markers (
# BEGIN ANSIBLE MANAGED BLOCKand# END ANSIBLE MANAGED BLOCK) - Creates the file if it doesn't exist (
create: yes) - Sets ownership and permissions in one task
- Is idempotent—won't duplicate content if re-run
🚀 Execution and Results
Running the Playbook
cd /home/thor/ansible
ansible-playbook -i inventory playbook.yml
Successful Output
PLAY [Deploy HTTPD web server with sample page] *********************************
TASK [Gathering Facts] **********************************************************
ok: [stapp01]
ok: [stapp02]
ok: [stapp03]
TASK [Install httpd web server] *************************************************
changed: [stapp01]
changed: [stapp02]
changed: [stapp03]
TASK [Start and enable httpd service] *******************************************
changed: [stapp01]
changed: [stapp02]
changed: [stapp03]
TASK [Create web root directory] ************************************************
changed: [stapp01]
changed: [stapp02]
changed: [stapp03]
TASK [Add content to index.html using blockinfile] *****************************
changed: [stapp01]
changed: [stapp02]
changed: [stapp03]
PLAY RECAP *********************************************************************
stapp01 : ok=5 changed=4 unreachable=0 failed=0 skipped=0
stapp02 : ok=5 changed=4 unreachable=0 failed=0 skipped=0
stapp03 : ok=5 changed=4 unreachable=0 failed=0 skipped=0
🔍 Verification
File Existence and Permissions
$ ansible -i inventory all -m shell -a "ls -la /var/www/html/index.html" --become
stapp01 | CHANGED | rc=0 >>
-rw-r--r-- 1 apache apache 179 Aug 30 13:55 /var/www/html/index.html
stapp02 | CHANGED | rc=0 >>
-rw-r--r-- 1 apache apache 179 Aug 30 13:55 /var/www/html/index.html
stapp03 | CHANGED | rc=0 >>
-rw-r--r-- 1 apache apache 179 Aug 30 13:55 /var/www/html/index.html
✅ Permissions: 0644 (rw-r--r--)
✅ Owner: apache:apache
File Content with Markers
$ ansible -i inventory all -m shell -a "cat /var/www/html/index.html" --become
stapp01 | CHANGED | rc=0 >>
# BEGIN ANSIBLE MANAGED BLOCK
Welcome to XfusionCorp!
This is Nautilus sample file, created using Ansible!
Please do not modify this file manually!
# END ANSIBLE MANAGED BLOCK
✅ Content: Matches requirements exactly
✅ Markers: Default markers added automatically by blockinfile
Service Status
$ ansible -i inventory all -m shell -a "systemctl status httpd" --become
stapp01 | CHANGED | rc=0 >>
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled)
Active: active (running) since Sun 2026-08-30 13:55:49 UTC
✅ Service: Active (running)
✅ Enabled: Boot startup configured
📊 Comparison: Before vs After
| Aspect | Before | After |
|---|---|---|
| HTTPD Installed | ❌ Not installed | ✅ Installed on all servers |
| Service Running | ❌ Not running | ✅ Active and running |
| Web Root Directory | ❌ Not present | ✅ Created with correct permissions |
| index.html | ❌ Missing | ✅ Created with correct content |
| File Owner | N/A | ✅ apache:apache |
| File Permissions | N/A | ✅ 0644 |
| Content Markers | N/A | ✅ Default markers present |
💡 Key Learnings
1. The Power of Blockinfile
The blockinfile module is perfect for managing configuration files or content blocks. Key benefits:
- Idempotent: Safe to run multiple times
- Default Markers: Provides clear boundaries for managed content
- Single Task: Handles creation, content insertion, and permissions in one go
2. Idempotency in Action
Running the playbook multiple times won't cause issues:
- First Run: Creates everything (changed=4)
- Second Run: Verifies everything (ok=5, changed=0)
3. Host Pattern Flexibility
Using hosts: all ensures the playbook works regardless of inventory group structure.
4. Service State Management
Combining state: started and enabled: yes ensures both immediate availability and persistence across reboots.
📋 Complete Verification Commands
# Check file exists and permissions
ansible -i inventory all -m shell -a "ls -la /var/www/html/index.html" --become
# Check content with markers
ansible -i inventory all -m shell -a "cat /var/www/html/index.html" --become
# Check ownership
ansible -i inventory all -m shell -a "stat -c '%U:%G' /var/www/html/index.html" --become
# Check permissions
ansible -i inventory all -m shell -a "stat -c '%a' /var/www/html/index.html" --become
# Check service status
ansible -i inventory all -m shell -a "systemctl status httpd" --become
# Test web server response
ansible -i inventory all -m shell -a "curl -s http://localhost/ | head -3" --become
🎉 Conclusion
The Ansible playbook successfully automated the HTTPD web server deployment across all application servers with:
✅ Simple Setup: Just one playbook file
✅ Consistent Results: Same configuration on all servers
✅ Proper Permissions: apache:apache ownership with 0644 permissions
✅ Correct Content: The exact message with default markers
✅ Service Management: Running and enabled on boot
✅ Idempotency: Safe to run multiple times
Business Benefits
- Time Savings: Automated what would be a 15-minute manual task per server
- Consistency: No configuration drift between servers
- Reliability: Idempotent execution ensures predictable results
- Maintainability: Easy to update content or configuration
- Documentation: Playbook serves as living documentation
Next Steps
- Add SSL/TLS Configuration for secure connections
- Implement Virtual Hosts for multiple websites
- Add Health Checks for monitoring
- Integrate with CI/CD for automated deployments
- Add Content Security Policies
📚 Resources
- Ansible Blockinfile Module: Documentation
- Ansible Service Module: Documentation
- Ansible File Module: Documentation
- HTTPD/Apache Documentation: Apache HTTP Server
"Automation is not about eliminating human effort, but about maximizing human potential." 🚀
Top comments (0)