Ansible is an open-source IT automation tool developed by Red Hat that allows managing server configuration, application deployment, and task automation using human-readable YAML playbooks. Unlike Chef or Puppet (which require agents installed on managed nodes), Ansible is agentless — it connects to managed servers via SSH and executes tasks using Python, with no permanent agent process running. This makes Ansible particularly suited to RHEL environments where minimising installed software and attack surface is important. Ansible on RHEL 9 is available directly from Red Hat’s repositories and is the recommended automation tool in Red Hat’s ecosystem. This guide covers installing Ansible on RHEL 9, configuring an inventory, running ad-hoc commands, and writing basic playbooks.

Prerequisites

  • RHEL 9 control node (where Ansible runs)
  • SSH access to managed nodes (target servers)
  • Python 3.9+ on managed nodes (RHEL 9 default)

Step 1 — Install Ansible

# Enable the EPEL and Ansible AppStream
dnf install -y epel-release
dnf install -y ansible-core

# Or install the full Ansible package (more modules)
dnf install -y ansible

ansible --version

Step 2 — Configure Inventory

# /etc/ansible/hosts (or create a project-specific inventory)
# /srv/ansible/inventory.ini
[webservers]
web1.example.com ansible_user=admin
web2.example.com ansible_user=admin

[databases]
db1.example.com ansible_user=admin ansible_port=2222

[production:children]
webservers
databases

[all:vars]
ansible_python_interpreter=/usr/bin/python3

Step 3 — Run Ad-Hoc Commands

# Test connectivity to all hosts
ansible all -i inventory.ini -m ping

# Run a command on all web servers
ansible webservers -i inventory.ini -m command -a "uptime"

# Install a package on all hosts (requires sudo)
ansible all -i inventory.ini -m dnf -a "name=nginx state=present" -b

# Gather facts about a host
ansible web1.example.com -i inventory.ini -m setup | grep ansible_os

Step 4 — Write a Basic Playbook

# /srv/ansible/webserver.yml
---
- name: Configure web servers
  hosts: webservers
  become: true  # Use sudo

  vars:
    http_port: 80
    server_name: "{{ inventory_hostname }}"

  tasks:
    - name: Install Nginx
      dnf:
        name: nginx
        state: present

    - name: Ensure Nginx is running and enabled
      systemd:
        name: nginx
        state: started
        enabled: true

    - name: Open HTTP port in firewall
      firewalld:
        service: http
        permanent: true
        state: enabled
        immediate: true

    - name: Deploy index.html from template
      template:
        src: templates/index.html.j2
        dest: /var/www/html/index.html
        owner: nginx
        group: nginx
        mode: '0644'
ansible-playbook -i inventory.ini webserver.yml

Conclusion

Ansible on RHEL 9 provides idempotent server configuration management that can be run repeatedly without changing a correctly-configured system. The most critical Ansible concept is idempotency: each task should check the current state and only make changes when necessary — the dnf module only installs a package if it is not already present, and the systemd module only starts a service if it is not already running. This makes Ansible playbooks safe to re-run at any time as a configuration convergence check, not just as a one-time setup script.

Next steps: How to Write Ansible Playbooks for Server Automation on RHEL 9, How to Install Terraform on RHEL 9, and How to Install Jenkins on RHEL 9.