How to Install Ansible on RHEL 7

Ansible is an agentless automation platform that lets you manage servers, deploy applications, and orchestrate complex workflows using simple YAML-based playbooks. Unlike other configuration management tools, Ansible requires no daemon or database on managed nodes — it connects over SSH and executes tasks on demand. On Red Hat Enterprise Linux 7, Ansible is distributed through the EPEL (Extra Packages for Enterprise Linux) repository, making installation straightforward. This guide walks you through installing Ansible on a RHEL 7 control node, configuring an inventory, setting up SSH key authentication, and running your first ad-hoc commands.

Prerequisites

  • A RHEL 7 system registered with Red Hat Subscription Manager or with access to a local mirror
  • Root or sudo access on the control node
  • At least one managed node reachable over SSH (can be another RHEL 7 system or a VM)
  • Python 2.7 or Python 3.x installed (RHEL 7 ships Python 2.7 by default)
  • Internet access or a configured local EPEL mirror

Step 1: Enable the EPEL Repository

Ansible is not available in the default RHEL 7 repositories. You must enable the EPEL repository first. EPEL is maintained by the Fedora project and provides high-quality additional packages for RHEL.

# Install the EPEL release package directly from Fedora
sudo yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

# Verify EPEL is enabled
yum repolist | grep epel

If your system is registered with Red Hat Subscription Manager, you can alternatively enable the optional repos that sometimes include Ansible builds:

sudo subscription-manager repos --enable rhel-7-server-optional-rpms
sudo subscription-manager repos --enable rhel-7-server-extras-rpms

For most environments, installing EPEL is the simplest path and provides the most up-to-date Ansible release available for RHEL 7.

Step 2: Install Ansible

With EPEL enabled, install Ansible using yum:

sudo yum install -y ansible

This will pull in Ansible along with its Python dependencies including python-paramiko, python-jinja2, python-yaml, and sshpass. After installation, verify the version:

ansible --version

You should see output similar to:

ansible 2.9.27
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Jun 20 2023, 11:36:40) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]

Step 3: Configure the Inventory File

Ansible uses an inventory file to know which hosts to manage. The default inventory is located at /etc/ansible/hosts. Open it in a text editor and define your managed nodes:

sudo vi /etc/ansible/hosts

Add your servers using a simple INI-style format:

# /etc/ansible/hosts

[webservers]
web01.example.com
web02.example.com
192.168.1.50

[dbservers]
db01.example.com ansible_user=dbadmin

[all:vars]
ansible_user=ansible
ansible_python_interpreter=/usr/bin/python

You can also use YAML format for the inventory, or keep per-project inventory files in your playbook directories instead of modifying the global file. Groups help you target specific subsets of hosts with your commands and playbooks.

Step 4: Set Up SSH Key Authentication

Ansible connects to managed nodes over SSH. Password-based authentication works but is not recommended for automation. Generate an SSH key pair on the control node and distribute the public key to each managed node:

# Generate an SSH key pair (accept the defaults or specify a path)
ssh-keygen -t rsa -b 4096 -C "ansible-control" -f ~/.ssh/ansible_rsa

# Copy the public key to each managed node
ssh-copy-id -i ~/.ssh/ansible_rsa.pub [email protected]
ssh-copy-id -i ~/.ssh/ansible_rsa.pub [email protected]
ssh-copy-id -i ~/.ssh/ansible_rsa.pub [email protected]

If ssh-copy-id is not available or the remote user doesn’t exist yet, manually append the public key:

# On each managed node, as root:
useradd ansible
mkdir -p /home/ansible/.ssh
echo "ssh-rsa AAAA...your-public-key..." >> /home/ansible/.ssh/authorized_keys
chmod 700 /home/ansible/.ssh
chmod 600 /home/ansible/.ssh/authorized_keys
chown -R ansible:ansible /home/ansible/.ssh

# Allow ansible user to use sudo without a password
echo "ansible ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/ansible

Step 5: Configure ansible.cfg

The main Ansible configuration file is /etc/ansible/ansible.cfg. You can also place a project-local ansible.cfg in your playbook directory, which takes precedence. Key settings to configure:

sudo vi /etc/ansible/ansible.cfg
[defaults]
inventory          = /etc/ansible/hosts
remote_user        = ansible
private_key_file   = ~/.ssh/ansible_rsa
host_key_checking  = False
log_path           = /var/log/ansible.log
forks              = 10
retry_files_enabled = False

[privilege_escalation]
become             = True
become_method      = sudo
become_user        = root
become_ask_pass    = False

Setting host_key_checking = False is convenient in dynamic environments where host keys change frequently, but in production you should manage known hosts properly. The forks setting controls how many hosts Ansible talks to in parallel.

Step 6: Test Connectivity with the Ping Module

The ping module is Ansible’s built-in connectivity test. It does not use ICMP ping — it connects to the host over SSH and verifies that Python is available:

# Ping all hosts in the inventory
ansible all -m ping

# Ping only the webservers group
ansible webservers -m ping

# Ping a single host
ansible web01.example.com -m ping

A successful response looks like:

web01.example.com | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}

If you see UNREACHABLE errors, check your SSH configuration, firewall rules, and that the ansible user exists on the remote node.

Step 7: Running Ad-Hoc Commands

Ad-hoc commands let you run one-off tasks without writing a playbook. They are useful for quick checks, gathering facts, or performing simple operations across many hosts:

# Check disk usage on all webservers
ansible webservers -m shell -a "df -h"

# Install a package on dbservers
ansible dbservers -m yum -a "name=vim state=present" --become

# Restart a service
ansible webservers -m service -a "name=httpd state=restarted" --become

# Copy a file to all hosts
ansible all -m copy -a "src=/tmp/motd.txt dest=/etc/motd owner=root mode=0644" --become

# Gather all facts about a host
ansible web01.example.com -m setup

# Check uptime
ansible all -m command -a "uptime"

The -m flag specifies the module and -a provides the module arguments. The --become flag enables privilege escalation to root. Ad-hoc commands are great for exploring Ansible’s modules and verifying your inventory before committing logic to playbooks.

Step 8: Ad-Hoc vs Playbooks

Ad-hoc commands are ideal for quick, one-time tasks. When you need repeatability, idempotency, and complex logic, use playbooks. A minimal playbook to install and start Apache looks like:

# install_apache.yml
---
- name: Install and start Apache
  hosts: webservers
  become: true

  tasks:
    - name: Install httpd
      yum:
        name: httpd
        state: present

    - name: Start and enable httpd
      service:
        name: httpd
        state: started
        enabled: true
# Run the playbook
ansible-playbook install_apache.yml

# Dry run (check mode)
ansible-playbook install_apache.yml --check

# Verbose output
ansible-playbook install_apache.yml -v

Ansible is now installed and operational on your RHEL 7 control node. You have configured the inventory, established SSH key-based authentication, tuned ansible.cfg, tested connectivity, and run both ad-hoc commands and a basic playbook. The foundation is in place to build sophisticated automation workflows. The next logical step is learning to write full playbooks with variables, handlers, and roles — which allows you to encapsulate and reuse your automation logic across projects and teams.