jasmine
+
bash
+
+
mvn
+
+
+
bbedit
+
tf
+
+
grafana
+
+
+
strapi
preact
+
+
groovy
tcl
supabase
+
+
tf
+
gin
+
http
+
+
+
+
+
+
qwik
~
+
grafana
jasmine
solid
+
rb
+
wsl
ada
eclipse
+
+
ubuntu
?
+
+
junit
rs
+
gcp
go
+
+
+
+
+
+
λ
+
#
k8s
ios
+
+
pytest
pinecone
tcl
haiku
+
+
+
echo
+
protobuf
eslint
s3
elm
Back to Blog
🤖 Mastering Ansible Automation on AlmaLinux: Automate Everything Like a DevOps Wizard
AlmaLinux Ansible Automation

🤖 Mastering Ansible Automation on AlmaLinux: Automate Everything Like a DevOps Wizard

Published Aug 29, 2025

Learn to install and configure Ansible on AlmaLinux for powerful automation. Master playbooks, inventory management, roles, and real-world automation scenarios to manage your infrastructure effortlessly!

5 min read
0 views
Table of Contents

🤖 Mastering Ansible Automation on AlmaLinux: Automate Everything Like a DevOps Wizard

Hey there, automation enthusiast! 🚀 Are you tired of logging into servers one by one to make the same changes? Ever wished you could manage hundreds of servers as easily as one? Well, let me introduce you to your new superpower - Ansible!

I still remember my life before Ansible… spending entire weekends updating servers manually, copying the same configurations everywhere. 😫 Then I discovered Ansible, and suddenly I could manage my entire infrastructure with simple YAML files! By the end of this guide, you’ll be automating tasks like a pro, and honestly, you’ll wonder how you ever survived without it!

🤔 Why is Ansible Important?

Ansible is like having an army of robot assistants! 🤖 Let me show you why it’s revolutionary:

The Magic of Ansible:

  • 🚀 Agentless Architecture - No software to install on managed nodes
  • 📝 Human-Readable YAML - Configuration as simple text files
  • 🔄 Idempotent Operations - Run multiple times safely
  • 🌍 Massive Scale - Manage thousands of servers simultaneously
  • 🔐 Secure by Default - Uses SSH, no extra ports needed
  • 📚 Huge Module Library - Thousands of pre-built automation tasks
  • 🎯 Perfect State Management - Define desired state, Ansible makes it happen
  • 💰 Free and Open Source - Enterprise features without the cost

🎯 What You Need

Before we start automating everything, let’s check our toolkit! 🛠️ Here’s what you’ll need:

Prerequisites:

  • ✅ AlmaLinux 8 or 9 installed (control node)
  • ✅ At least one target server to manage
  • ✅ SSH access between servers configured
  • ✅ Root or sudo access on all systems
  • ✅ Python installed (usually pre-installed)
  • ✅ Basic YAML understanding (I’ll teach you!)
  • ✅ About 60 minutes of your time
  • ✅ Excitement to automate everything! 🎉

📝 Step 1: Installing Ansible

Let’s get Ansible installed and ready to automate! 🎯 This is where your automation journey begins.

Install Ansible on Control Node:

# Update your system first - always start fresh!
sudo dnf update -y

# Install EPEL repository for extra packages
sudo dnf install epel-release -y

# Install Ansible and dependencies
sudo dnf install ansible ansible-core -y

# Install additional helpful tools
sudo dnf install python3-pip sshpass -y

# Verify Ansible installation
ansible --version
# Output: ansible [core 2.x.x] - Excellent! ✅

# Install ansible-lint for playbook validation
pip3 install ansible-lint --user

# Check Python version (Ansible requirement)
python3 --version
# Should be Python 3.6 or higher

Configure Ansible Settings:

# Create Ansible configuration directory
mkdir -p ~/ansible
cd ~/ansible

# Create ansible.cfg for project settings
cat > ansible.cfg << 'EOF'
[defaults]
# Inventory file location
inventory = ./inventory
# Disable host key checking (for labs only!)
host_key_checking = False
# Set default remote user
remote_user = ansible
# Increase connection timeout
timeout = 30
# Enable command warnings
command_warnings = True
# Pretty output
stdout_callback = yaml
# Speed up gathering facts
gathering = smart
# Parallel execution
forks = 10

[ssh_connection]
# Speed up SSH connections
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
pipelining = True
EOF

echo "Ansible configured! 🎯"

🔧 Step 2: Setting Up Inventory and SSH Access

Time to tell Ansible about your servers! 📋 This is your infrastructure map.

Create Inventory File:

# Create inventory file with your servers
cat > inventory << 'EOF'
# Ansible Inventory File
# Groups help organize servers by function

[webservers]
web1 ansible_host=192.168.1.101 ansible_user=ansible
web2 ansible_host=192.168.1.102 ansible_user=ansible

[databases]
db1 ansible_host=192.168.1.110 ansible_user=ansible
db2 ansible_host=192.168.1.111 ansible_user=ansible

[loadbalancers]
lb1 ansible_host=192.168.1.120 ansible_user=ansible

# Group all AlmaLinux servers
[almalinux:children]
webservers
databases
loadbalancers

# Variables for all AlmaLinux servers
[almalinux:vars]
ansible_python_interpreter=/usr/bin/python3
ansible_become=yes
ansible_become_method=sudo
EOF

# Test inventory
ansible-inventory --list -y
# Shows your server hierarchy in YAML format

Set Up SSH Key Authentication:

# Generate SSH key pair (if you don't have one)
ssh-keygen -t rsa -b 4096 -f ~/.ssh/ansible_key -N ""

# Create ansible user on all target servers
# Run this on each target server:
sudo useradd -m -s /bin/bash ansible
echo "ansible ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/ansible

# Copy SSH key to all servers (from control node)
for server in 192.168.1.101 192.168.1.102 192.168.1.110; do
    ssh-copy-id -i ~/.ssh/ansible_key.pub ansible@$server
done

# Test connectivity to all servers
ansible all -m ping

# Should see SUCCESS messages! 🎉
# web1 | SUCCESS => {
#     "changed": false,
#     "ping": "pong"
# }

🌟 Step 3: Creating Your First Playbooks

Let’s write some automation magic! ✨ Playbooks are where Ansible shines.

Basic System Configuration Playbook:

# Create your first playbook
cat > site.yml << 'EOF'
---
# My First Ansible Playbook! 🎯
- name: Configure AlmaLinux Servers
  hosts: almalinux
  become: yes
  
  tasks:
    - name: Update all packages 📦
      dnf:
        name: "*"
        state: latest
      tags: updates
    
    - name: Install essential packages 🛠️
      dnf:
        name:
          - vim
          - wget
          - curl
          - htop
          - git
          - firewalld
        state: present
      tags: packages
    
    - name: Start and enable firewalld 🔥
      systemd:
        name: firewalld
        state: started
        enabled: yes
      tags: firewall
    
    - name: Configure timezone ⏰
      timezone:
        name: America/New_York
      tags: timezone
    
    - name: Create admin user 👤
      user:
        name: sysadmin
        groups: wheel
        shell: /bin/bash
        create_home: yes
        state: present
      tags: users
    
    - name: Set message of the day 📝
      copy:
        content: |
          ************************************************
          *  Welcome to {{ ansible_hostname }}! 🎉
          *  This server is managed by Ansible
          *  Last configured: {{ ansible_date_time.date }}
          ************************************************
        dest: /etc/motd
      tags: motd
EOF

# Run the playbook!
ansible-playbook site.yml

# Run only specific tags
ansible-playbook site.yml --tags packages,firewall

Web Server Setup Playbook:

# Create web server configuration playbook
cat > webserver.yml << 'EOF'
---
- name: Configure Web Servers 🌐
  hosts: webservers
  become: yes
  
  vars:
    doc_root: /var/www/html
    http_port: 80
    domain: example.com
  
  tasks:
    - name: Install Apache web server 🖥️
      dnf:
        name: httpd
        state: present
    
    - name: Create document root 📁
      file:
        path: "{{ doc_root }}"
        state: directory
        owner: apache
        group: apache
        mode: '0755'
    
    - name: Create index.html 📄
      template:
        src: index.html.j2
        dest: "{{ doc_root }}/index.html"
        owner: apache
        group: apache
        mode: '0644'
    
    - name: Configure Apache 🔧
      template:
        src: httpd.conf.j2
        dest: /etc/httpd/conf/httpd.conf
        backup: yes
      notify: restart apache
    
    - name: Open firewall for HTTP 🔓
      firewalld:
        service: http
        permanent: yes
        state: enabled
        immediate: yes
    
    - name: Start Apache service 🚀
      systemd:
        name: httpd
        state: started
        enabled: yes
  
  handlers:
    - name: restart apache
      systemd:
        name: httpd
        state: restarted
EOF

# Create template for index.html
cat > index.html.j2 << 'EOF'
<!DOCTYPE html>
<html>
<head>
    <title>Welcome to {{ ansible_hostname }}! 🎉</title>
</head>
<body>
    <h1>🚀 Server: {{ ansible_hostname }}</h1>
    <p>Managed by Ansible on {{ ansible_date_time.date }}</p>
    <p>IP Address: {{ ansible_default_ipv4.address }}</p>
    <p>OS: {{ ansible_distribution }} {{ ansible_distribution_version }}</p>
</body>
</html>
EOF

# Run the web server playbook
ansible-playbook webserver.yml

✅ Step 4: Advanced Automation with Roles

Let’s organize our automation with roles! 🎭 This is professional-grade stuff.

Create a Database Role:

# Create role structure
mkdir -p roles/mariadb/{tasks,handlers,templates,files,vars,defaults}

# Create main task file
cat > roles/mariadb/tasks/main.yml << 'EOF'
---
# MariaDB Installation and Configuration Tasks
- name: Install MariaDB packages 💾
  dnf:
    name:
      - mariadb-server
      - mariadb
      - python3-PyMySQL
    state: present

- name: Start and enable MariaDB 🚀
  systemd:
    name: mariadb
    state: started
    enabled: yes

- name: Secure MariaDB installation 🔐
  mysql_user:
    name: root
    host: "{{ item }}"
    password: "{{ mysql_root_password }}"
    login_unix_socket: /var/lib/mysql/mysql.sock
  with_items:
    - localhost
    - 127.0.0.1
    - ::1

- name: Remove anonymous users 🚫
  mysql_user:
    name: ''
    host_all: yes
    state: absent
    login_user: root
    login_password: "{{ mysql_root_password }}"

- name: Remove test database 🗑️
  mysql_db:
    name: test
    state: absent
    login_user: root
    login_password: "{{ mysql_root_password }}"

- name: Create application database 📊
  mysql_db:
    name: "{{ app_database }}"
    state: present
    login_user: root
    login_password: "{{ mysql_root_password }}"

- name: Create application user 👤
  mysql_user:
    name: "{{ app_user }}"
    password: "{{ app_password }}"
    priv: "{{ app_database }}.*:ALL"
    state: present
    login_user: root
    login_password: "{{ mysql_root_password }}"
EOF

# Create defaults
cat > roles/mariadb/defaults/main.yml << 'EOF'
---
mysql_root_password: "SecureRootPass123!"
app_database: myapp
app_user: appuser
app_password: "AppPass456!"
EOF

# Create playbook using the role
cat > database.yml << 'EOF'
---
- name: Deploy MariaDB Database Servers
  hosts: databases
  become: yes
  
  roles:
    - mariadb
EOF

# Run the database playbook
ansible-playbook database.yml

🎮 Quick Examples

Let’s see Ansible in action with real-world scenarios! 🚀

Example 1: Security Hardening Playbook

cat > security-hardening.yml << 'EOF'
---
- name: Security Hardening for AlmaLinux 🛡️
  hosts: almalinux
  become: yes
  
  tasks:
    - name: Disable root SSH login 🔒
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^PermitRootLogin'
        line: 'PermitRootLogin no'
      notify: restart sshd
    
    - name: Configure fail2ban 🚫
      block:
        - name: Install fail2ban
          dnf:
            name: fail2ban
            state: present
        
        - name: Configure fail2ban for SSH
          copy:
            content: |
              [sshd]
              enabled = true
              port = ssh
              logpath = %(sshd_log)s
              maxretry = 3
              bantime = 3600
            dest: /etc/fail2ban/jail.local
        
        - name: Start fail2ban
          systemd:
            name: fail2ban
            state: started
            enabled: yes
    
    - name: Set up automatic updates 🔄
      dnf:
        name: dnf-automatic
        state: present
    
    - name: Configure automatic updates
      lineinfile:
        path: /etc/dnf/automatic.conf
        regexp: '^apply_updates'
        line: 'apply_updates = yes'
    
    - name: Enable automatic updates timer
      systemd:
        name: dnf-automatic.timer
        state: started
        enabled: yes
  
  handlers:
    - name: restart sshd
      systemd:
        name: sshd
        state: restarted
EOF

# Run security hardening
ansible-playbook security-hardening.yml

echo "Security hardening complete! 🔐"

Example 2: Application Deployment Playbook

cat > deploy-app.yml << 'EOF'
---
- name: Deploy Node.js Application 🚀
  hosts: webservers
  become: yes
  
  vars:
    app_name: myapp
    app_port: 3000
    app_dir: /opt/{{ app_name }}
    github_repo: https://github.com/example/myapp.git
  
  tasks:
    - name: Install Node.js and npm 📦
      dnf:
        name:
          - nodejs
          - npm
          - git
        state: present
    
    - name: Create app directory 📁
      file:
        path: "{{ app_dir }}"
        state: directory
        owner: "{{ ansible_user }}"
        group: "{{ ansible_user }}"
    
    - name: Clone application from Git 🔄
      git:
        repo: "{{ github_repo }}"
        dest: "{{ app_dir }}"
        version: main
      become_user: "{{ ansible_user }}"
    
    - name: Install npm dependencies 📚
      npm:
        path: "{{ app_dir }}"
        state: present
      become_user: "{{ ansible_user }}"
    
    - name: Create systemd service 🎯
      template:
        src: app.service.j2
        dest: /etc/systemd/system/{{ app_name }}.service
    
    - name: Start application service 🚀
      systemd:
        name: "{{ app_name }}"
        state: started
        enabled: yes
        daemon_reload: yes
    
    - name: Configure nginx reverse proxy 🔄
      template:
        src: nginx-app.conf.j2
        dest: /etc/nginx/conf.d/{{ app_name }}.conf
      notify: reload nginx
  
  handlers:
    - name: reload nginx
      systemd:
        name: nginx
        state: reloaded
EOF

echo "Application deployment playbook ready! 🎊"

Example 3: Backup Automation

cat > backup-automation.yml << 'EOF'
---
- name: Automated Backup System 💾
  hosts: all
  become: yes
  
  vars:
    backup_dir: /backup
    retention_days: 7
  
  tasks:
    - name: Create backup directory 📁
      file:
        path: "{{ backup_dir }}"
        state: directory
        mode: '0755'
    
    - name: Create backup script 📝
      copy:
        content: |
          #!/bin/bash
          DATE=$(date +%Y%m%d_%H%M%S)
          
          # Backup important directories
          tar -czf {{ backup_dir }}/etc_${DATE}.tar.gz /etc
          tar -czf {{ backup_dir }}/home_${DATE}.tar.gz /home
          
          # Backup databases if MariaDB exists
          if systemctl is-active mariadb &>/dev/null; then
              mysqldump --all-databases > {{ backup_dir }}/databases_${DATE}.sql
              gzip {{ backup_dir }}/databases_${DATE}.sql
          fi
          
          # Clean old backups
          find {{ backup_dir }} -type f -mtime +{{ retention_days }} -delete
          
          echo "Backup completed at $(date)" >> {{ backup_dir }}/backup.log
        dest: /usr/local/bin/ansible-backup.sh
        mode: '0755'
    
    - name: Schedule backup with cron 📅
      cron:
        name: "Ansible automated backup"
        minute: "0"
        hour: "2"
        job: "/usr/local/bin/ansible-backup.sh"
        user: root
    
    - name: Run initial backup 🚀
      command: /usr/local/bin/ansible-backup.sh
      args:
        creates: "{{ backup_dir }}/backup.log"
EOF

# Run backup automation
ansible-playbook backup-automation.yml

echo "Backup automation configured! 💾"

🚨 Fix Common Problems

Don’t worry if something doesn’t work right away! Here are solutions:

Problem 1: SSH Connection Failed

# Check SSH connectivity
ssh ansible@target-server

# If password prompt appears, SSH key not working
# Re-copy SSH key
ssh-copy-id -i ~/.ssh/ansible_key.pub ansible@target-server

# Check SSH config
ansible -m ping target-server -vvv
# Shows detailed connection debugging

# Fix host key verification issues
export ANSIBLE_HOST_KEY_CHECKING=False
# Or add to ansible.cfg permanently

# Test with explicit SSH key
ansible all -m ping --private-key ~/.ssh/ansible_key

Problem 2: Privilege Escalation Failed

# Check sudo configuration on target
ssh ansible@target-server
sudo -l  # Should show NOPASSWD

# Fix sudoers file
echo "ansible ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/ansible

# Test privilege escalation
ansible target-server -m command -a "whoami" --become
# Should return: root

# Use different escalation method
ansible-playbook site.yml --become-method=su --ask-become-pass

Problem 3: Module Not Found

# List available modules
ansible-doc -l | grep module_name

# Install missing Python dependencies
pip3 install pymysql  # For MySQL modules
pip3 install psycopg2  # For PostgreSQL

# Check module documentation
ansible-doc dnf  # Shows module usage

# Update Ansible to get latest modules
sudo dnf update ansible-core

# Install ansible collections
ansible-galaxy collection install community.general

📋 Simple Commands Summary

Your Ansible command cheat sheet! 📚 Keep this handy:

TaskCommandWhat It Does
Test Connectionansible all -m pingPing all servers 🏓
Run Playbookansible-playbook site.ymlExecute playbook 🚀
Check Syntaxansible-playbook site.yml --syntax-checkValidate YAML ✅
Dry Runansible-playbook site.yml --checkPreview changes 👀
List Hostsansible all --list-hostsShow inventory 📋
Gather Factsansible hostname -m setupGet system info 📊
Run Commandansible all -a "uptime"Execute command 💻
Install Roleansible-galaxy install role_nameGet role 📦
Limit Hostsansible-playbook site.yml --limit webserversTarget specific 🎯
Use Tagsansible-playbook site.yml --tags packagesRun tagged tasks 🏷️
Verbose Modeansible-playbook site.yml -vvvDebug output 🔍
Check Variablesansible hostname -m debug -a "var=ansible_os_family"Show vars 📝

💡 Tips for Success

Here are my pro tips for Ansible mastery! 🎯

Best Practices:

  • 📝 Use version control - Keep playbooks in Git
  • 🏷️ Tag everything - Makes selective runs easy
  • 🔐 Encrypt secrets - Use ansible-vault for passwords
  • 📚 Create reusable roles - Don’t repeat yourself
  • 🧪 Test in staging first - Never test in production
  • 📖 Document variables - Future you will thank you
  • 🎯 Keep it simple - Start small, grow gradually
  • 🔄 Make idempotent - Safe to run multiple times

Performance Tips:

  • Use pipelining - Reduces SSH overhead
  • 🚀 Increase forks - Parallel execution
  • 📊 Cache facts - Don’t gather repeatedly
  • 🎯 Limit scope - Target specific hosts
  • 💾 Use local actions - When possible
  • 🔧 Optimize loops - Use batch operations

🏆 What You Learned

Amazing work! Look at what you’ve mastered! 🎊

Your Achievements:

  • ✅ Installed and configured Ansible
  • ✅ Set up inventory management
  • ✅ Created powerful playbooks
  • ✅ Organized code with roles
  • ✅ Automated system configuration
  • ✅ Deployed applications automatically
  • ✅ Implemented security hardening
  • ✅ Set up backup automation
  • ✅ Learned troubleshooting techniques
  • ✅ Became an automation expert!

🎯 Why This Matters

Your Ansible skills are transforming how you manage infrastructure! 🌟

With Ansible mastery, you can now:

  • 🚀 Manage thousands of servers - As easily as one
  • Save countless hours - Automate repetitive tasks
  • 🔒 Ensure consistency - Same config everywhere
  • 📝 Document infrastructure - Code is documentation
  • 🎯 Deploy faster - From hours to minutes
  • 🛡️ Improve security - Apply patches instantly
  • 💰 Reduce costs - Less manual work needed
  • 🌟 Scale effortlessly - Growth is just more YAML

Remember when you had to SSH into each server manually? Now you’re orchestrating entire data centers with simple playbooks! You’ve evolved from a server administrator to an infrastructure conductor. That’s absolutely incredible! 🌟

Keep automating, keep learning, and most importantly, enjoy your newfound automation superpowers! 🦸‍♂️

Happy automating, and welcome to the world of infrastructure as code! 🙌


P.S. - Don’t forget to share your coolest playbooks with the community. We all learn from each other! ⭐