What is Ansible? 8 Powerful Concepts Beginners Must Know
You have 50 Linux servers. All of them need Nginx installed, configured the same way, with the same SSL certificates, the same security settings, and the same application deployed. You could SSH into each one manually — but that takes hours and one mistake affects one server differently from the rest.
Or you could write a single Ansible playbook and run it across all 50 servers simultaneously. Done in minutes. Identical configuration on every server. Repeatable forever.
Ansible makes infrastructure management this simple.
So, what is Ansible exactly? It is the world’s most popular IT automation and configuration management tool — used by Red Hat, NASA, the US Department of Defense, Twitter, and hundreds of thousands of organizations to manage infrastructure at any scale. In 2026, Ansible is one of the most essential skills in DevOps and system administration.
In this beginner-friendly guide, we break down what is Ansible across 8 powerful concepts — with real YAML playbook examples, practical patterns, and clear guidance for getting started.
Let’s go. 🚀
What is Ansible? (Simple Definition)
What is Ansible? Ansible is a free, open-source IT automation platform that automates configuration management, application deployment, task execution, and IT orchestration. It uses simple, human-readable YAML files called playbooks to describe automation tasks, and connects to managed servers over SSH — requiring no software installed on the target servers.
What is Ansible’s “agentless” advantage?
Most configuration management tools (Chef, Puppet, SaltStack) require an agent — software that must be installed and running on every managed server before you can manage it.
Chef/Puppet approach:
Control Machine → Agent (installed on Server 1) → Configuration applied
→ Agent (installed on Server 2) → Configuration applied
→ Agent (installed on Server 3) → Configuration applied
Problems:
❌ Agent must be installed first (chicken-and-egg)
❌ Agent consumes resources on every server
❌ Agent must be kept updated and maintained
❌ If agent crashes, server becomes unmanageable
Ansible agentless approach:
Control Machine → SSH → Server 1 → Configuration applied
→ SSH → Server 2 → Configuration applied
→ SSH → Server 3 → Configuration applied
Benefits:
✅ No software needed on managed servers
✅ Works on any server that has SSH and Python
✅ Zero overhead on managed servers
✅ Dead simple to start — just need SSH access
What is Ansible used for?
- ⚙️ Configuration management — Install and configure software on servers consistently
- 🚀 Application deployment — Deploy applications to hundreds of servers simultaneously
- 🔄 Continuous delivery — Automate release pipelines and environment setup
- 📦 Provisioning — Set up new servers from scratch automatically
- 🔐 Security compliance — Enforce security policies across all servers
- 🔧 Orchestration — Coordinate complex multi-step, multi-server workflows
Ansible in 2026:
- Owned by Red Hat (acquired in 2015, now part of IBM)
- Over 60,000 GitHub stars
- Ansible Galaxy has 12,000+ roles and collections
- Used in 75%+ of enterprise DevOps deployments
💡 Simple Analogy: What is Ansible like in everyday terms? Think of Ansible like a detailed recipe book combined with a kitchen robot. The recipe (playbook) describes exactly how to prepare a dish — what ingredients (packages) to get, in what order to add them (tasks), and how to present the final result (configuration). The robot (Ansible) follows the recipe precisely for every dinner guest (server) — whether you are cooking for 1 or 1,000, every plate comes out identical.
A Brief History of Ansible
Understanding what is Ansible includes knowing its origin:
- 2012 — Michael DeHaan created Ansible while at Red Hat. Goal: make automation simple enough that anyone could use it, not just experienced sysadmins.
- 2013 — Ansible Inc. founded to support commercial adoption
- 2015 — Red Hat acquired Ansible Inc. for $150 million. Open-source development continued.
- 2016 — Ansible Tower (commercial UI) launched — providing a GUI, RBAC, and API for enterprise use
- 2017 — Ansible became the most popular IT automation tool, overtaking Puppet and Chef in new deployments
- 2019 — Ansible Collections introduced — better module packaging and distribution
- 2020 — AWX (open-source Ansible Tower) became the upstream project
- 2022 — Ansible 6.0 with full Collections support and improved performance
- 2023 — Red Hat Ansible Automation Platform 2.4 with Event-Driven Ansible
- 2026 — Ansible 10.x is the current version. The most widely used configuration management tool globally.
8 Powerful Concepts of Ansible
Concept 1: Ansible Architecture — How It Works 🏗️
What is Ansible’s architecture? Simple and flat — a control node runs Ansible and connects to managed nodes via SSH.
Control Node (your laptop or CI/CD server)
├── Ansible installed here
├── Playbooks stored here
├── Inventory file here
└── Connects via SSH →
Managed Nodes (your servers)
├── Server 1: web-01.example.com
├── Server 2: web-02.example.com
├── Server 3: db-01.example.com
└── No Ansible software required — just SSH + Python
What Ansible does when you run a playbook:
1. Read inventory — which servers to connect to
2. Read playbook — what tasks to run
3. SSH into each server
4. Upload small Python modules temporarily
5. Execute the tasks (install packages, copy files, etc.)
6. Return results
7. Remove temporary files
8. Report success/failure for each task on each server
Installation:
bash
# Ubuntu/Debian
sudo apt update
sudo apt install ansible
# macOS
brew install ansible
# Python pip (any OS)
pip install ansible
# Verify
ansible --version
# ansible [core 2.17.x]
Test connection to managed nodes:
bash
# Ping all hosts in inventory
ansible all -m ping -i inventory.yml
# Run a command on all servers
ansible all -m command -a "uptime" -i inventory.yml
# Run as root user
ansible all -m command -a "whoami" -i inventory.yml --become
Concept 2: Inventory — Defining Your Servers 📋
What is Ansible inventory? A file that tells Ansible which servers to manage and how to connect to them. Servers can be organized into groups for targeted automation.
Static inventory (INI format):
ini
# inventory.ini
# Individual servers
web-01.example.com
web-02.example.com
# Group: web servers
[webservers]
web-01.example.com
web-02.example.com
web-03.example.com ansible_port=2222 # Custom SSH port
# Group: database servers
[databases]
db-01.example.com
db-02.example.com
# Group of groups
[production:children]
webservers
databases
# Variables for a group
[webservers:vars]
ansible_user=ubuntu
nginx_port=80
# Variables for all servers
[all:vars]
ansible_python_interpreter=/usr/bin/python3
ansible_ssh_private_key_file=~/.ssh/id_rsa
Static inventory (YAML format — recommended):
yaml
# inventory.yml
all:
vars:
ansible_user: ubuntu
ansible_python_interpreter: /usr/bin/python3
children:
webservers:
hosts:
web-01.example.com:
ansible_host: 10.0.1.10
nginx_port: 80
web-02.example.com:
ansible_host: 10.0.1.11
nginx_port: 80
web-03.example.com:
ansible_host: 10.0.1.12
nginx_port: 443
databases:
hosts:
db-01.example.com:
ansible_host: 10.0.2.10
postgresql_version: "16"
db-02.example.com:
ansible_host: 10.0.2.11
postgresql_version: "16"
staging:
hosts:
staging-01.example.com:
ansible_host: 10.0.3.10
Dynamic inventory — generate from AWS, GCP, Azure:
bash
# Install AWS dynamic inventory plugin
pip install boto3
# Use AWS EC2 dynamic inventory
ansible all -i aws_ec2.yaml -m ping
# aws_ec2.yaml
plugin: amazon.aws.aws_ec2
regions:
- ap-south-1
filters:
tag:Environment: production
instance-state-name: running
keyed_groups:
- key: tags.Role
prefix: role
Concept 3: Playbooks — Automation in YAML 📝
What is Ansible playbook? The core of Ansible — a YAML file describing what tasks to run on which servers in what order.
A complete playbook — install and configure Nginx:
yaml
# nginx-setup.yml
---
- name: Install and Configure Nginx Web Server
hosts: webservers # Run on all servers in webservers group
become: true # Run as root (sudo)
vars:
nginx_version: "latest"
server_name: "futuretechzone.in"
app_port: 3000
tasks:
- name: Update apt package cache
apt:
update_cache: yes
cache_valid_time: 3600 # Skip if cache is less than 1 hour old
- name: Install Nginx
apt:
name: "nginx={{ nginx_version }}"
state: present
- name: Create Nginx site configuration
template:
src: templates/nginx-site.conf.j2
dest: /etc/nginx/sites-available/{{ server_name }}
owner: root
group: root
mode: "0644"
notify: Reload Nginx # Trigger handler when this changes
- name: Enable the site
file:
src: /etc/nginx/sites-available/{{ server_name }}
dest: /etc/nginx/sites-enabled/{{ server_name }}
state: link
- name: Remove default Nginx site
file:
path: /etc/nginx/sites-enabled/default
state: absent
- name: Ensure Nginx is started and enabled on boot
service:
name: nginx
state: started
enabled: yes
- name: Open firewall ports
ufw:
rule: allow
port: "{{ item }}"
proto: tcp
loop:
- "80"
- "443"
handlers:
- name: Reload Nginx
service:
name: nginx
state: reloaded
Running the playbook:
bash
# Run the playbook
ansible-playbook nginx-setup.yml -i inventory.yml
# Dry run — see what would change without making changes
ansible-playbook nginx-setup.yml -i inventory.yml --check
# Verbose output — see exactly what Ansible is doing
ansible-playbook nginx-setup.yml -i inventory.yml -v
# Run only on specific hosts
ansible-playbook nginx-setup.yml -i inventory.yml --limit web-01.example.com
# Run only specific tags
ansible-playbook nginx-setup.yml -i inventory.yml --tags "install,configure"
Playbook execution output:
PLAY [Install and Configure Nginx Web Server] *****
TASK [Update apt package cache] ******************
changed: [web-01.example.com]
ok: [web-02.example.com] # Already up to date
TASK [Install Nginx] ****************************
changed: [web-01.example.com]
changed: [web-02.example.com]
TASK [Create Nginx site configuration] **********
changed: [web-01.example.com]
changed: [web-02.example.com]
PLAY RECAP *************************************
web-01.example.com : ok=6 changed=4 unreachable=0 failed=0
web-02.example.com : ok=6 changed=4 unreachable=0 failed=0
Concept 4: Modules — Ansible’s Building Blocks 🔧
What is Ansible module? Pre-built units of functionality that perform specific tasks — installing packages, managing files, controlling services, creating users, and much more. Ansible ships with thousands of modules.
Essential built-in modules:
yaml
# Package management
- name: Install packages (Ubuntu/Debian)
apt:
name:
- nginx
- git
- python3-pip
state: present # present, absent, latest
- name: Install packages (RHEL/CentOS)
yum:
name: httpd
state: latest
- name: Install Python packages
pip:
name:
- requests
- boto3
state: present
# File management
- name: Copy a file
copy:
src: files/app.conf
dest: /etc/app/app.conf
owner: root
group: root
mode: "0644"
- name: Create a directory
file:
path: /var/app/logs
state: directory
owner: www-data
mode: "0755"
- name: Delete a file
file:
path: /tmp/old-config.conf
state: absent
- name: Render a template
template:
src: templates/nginx.conf.j2 # Jinja2 template
dest: /etc/nginx/nginx.conf
# Service management
- name: Start and enable a service
service:
name: nginx
state: started
enabled: yes
# User management
- name: Create a user
user:
name: deploy
shell: /bin/bash
groups: sudo
append: yes
create_home: yes
- name: Add SSH key for user
authorized_key:
user: deploy
state: present
key: "{{ lookup('file', 'files/deploy.pub') }}"
# Command execution
- name: Run a shell command
shell: |
npm install
npm run build
args:
chdir: /var/www/app
- name: Run command (no shell features needed)
command: /usr/bin/python3 manage.py migrate
# Git operations
- name: Clone a repository
git:
repo: https://github.com/myorg/myapp.git
dest: /var/www/myapp
version: main
force: yes
# Docker operations
- name: Pull a Docker image
docker_image:
name: nginx
tag: latest
source: pull
- name: Run a Docker container
docker_container:
name: webapp
image: myapp:latest
state: started
ports:
- "3000:3000"
env:
NODE_ENV: production
DATABASE_URL: "{{ database_url }}"
Custom modules — write your own:
python
# library/check_service.py — custom module
from ansible.module_utils.basic import AnsibleModule
import subprocess
def main():
module = AnsibleModule(argument_spec=dict(
service=dict(type="str", required=True)
))
service = module.params["service"]
result = subprocess.run(["systemctl", "is-active", service], capture_output=True, text=True)
is_active = result.stdout.strip() == "active"
module.exit_json(
changed=False,
service=service,
active=is_active,
status=result.stdout.strip()
)
main()
Concept 5: Variables and Templates — Dynamic Configuration 🎨
What is Ansible variables? Values that make playbooks flexible and reusable across different environments and servers.
Variable sources and precedence (highest to lowest):
Extra vars (--extra-vars on command line)
Task vars
Block vars
Role vars
Inventory host vars
Inventory group vars
Role defaults
Defining variables:
yaml
# playbook-level vars
vars:
app_name: "futuretechzone"
app_port: 3000
db_name: "production_db"
# vars_files — separate variable files
vars_files:
- vars/common.yml
- vars/{{ ansible_os_family }}.yml # Load OS-specific vars
yaml
# group_vars/webservers.yml — applies to all servers in 'webservers' group
nginx_worker_processes: auto
nginx_worker_connections: 1024
app_log_level: info
# group_vars/all.yml — applies to ALL servers
ntp_servers:
- 0.pool.ntp.org
- 1.pool.ntp.org
timezone: Asia/Kolkata
# host_vars/web-01.example.com.yml — host-specific variables
nginx_port: 443
ssl_enabled: true
server_id: 1
Jinja2 templates — dynamic configuration files:
nginx
# templates/nginx-site.conf.j2
server {
listen {{ nginx_port | default(80) }};
server_name {{ server_name }};
{% if ssl_enabled %}
listen 443 ssl;
ssl_certificate /etc/ssl/certs/{{ server_name }}.crt;
ssl_certificate_key /etc/ssl/private/{{ server_name }}.key;
{% endif %}
location / {
proxy_pass http://localhost:{{ app_port }};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
{% if enable_cache | default(false) %}
proxy_cache_valid 200 1m;
{% endif %}
}
location /static/ {
root /var/www/{{ app_name }};
expires 1y;
add_header Cache-Control "public, immutable";
}
access_log /var/log/nginx/{{ app_name }}_access.log;
error_log /var/log/nginx/{{ app_name }}_error.log;
}
Using variables in tasks:
yaml
tasks:
- name: Create app directory
file:
path: /var/www/{{ app_name }}
state: directory
- name: Set config variable
set_fact:
config_file: "/etc/{{ app_name }}/config.yml"
- name: Show all server facts
debug:
msg: |
OS: {{ ansible_distribution }} {{ ansible_distribution_version }}
CPU Cores: {{ ansible_processor_vcpus }}
Memory: {{ ansible_memtotal_mb }}MB
IP: {{ ansible_default_ipv4.address }}
Concept 6: Roles — Reusable Automation Components 📦
What is Ansible role? A structured way to organize related tasks, variables, templates, and handlers into a reusable unit — like a self-contained module for a specific purpose.
Ansible role directory structure:
roles/
└── nginx/
├── tasks/
│ ├── main.yml # Main tasks file
│ ├── install.yml # Installation tasks
│ └── configure.yml # Configuration tasks
├── handlers/
│ └── main.yml # Handlers (notify triggers)
├── templates/
│ └── nginx.conf.j2 # Jinja2 configuration templates
├── files/
│ └── ssl-params.conf # Static files to copy
├── vars/
│ └── main.yml # Role-specific variables
├── defaults/
│ └── main.yml # Default variable values (lowest priority)
├── meta/
│ └── main.yml # Role metadata and dependencies
└── README.md
Creating a reusable nginx role:
yaml
# roles/nginx/defaults/main.yml
nginx_port: 80
nginx_user: www-data
nginx_worker_processes: auto
nginx_worker_connections: 1024
yaml
# roles/nginx/tasks/main.yml
---
- name: Include installation tasks
import_tasks: install.yml
- name: Include configuration tasks
import_tasks: configure.yml
yaml
# roles/nginx/tasks/install.yml
---
- name: Install Nginx
apt:
name: nginx
state: present
update_cache: yes
- name: Ensure Nginx service is enabled
service:
name: nginx
enabled: yes
Using roles in a playbook:
yaml
# site.yml — main playbook using roles
---
- name: Configure Web Servers
hosts: webservers
become: true
roles:
- common # Applied first (security, NTP, etc.)
- nginx # Install and configure Nginx
- nodejs # Install Node.js runtime
- app # Deploy the application
- name: Configure Database Servers
hosts: databases
become: true
roles:
- common
- postgresql
- pgbouncer
Ansible Galaxy — download community roles:
bash
# Install a role from Ansible Galaxy
ansible-galaxy install geerlingguy.nginx
ansible-galaxy install geerlingguy.docker
ansible-galaxy install geerlingguy.postgresql
# Install from requirements file
# requirements.yml
roles:
- name: geerlingguy.nginx
version: "3.2.0"
- name: geerlingguy.docker
version: "6.1.0"
ansible-galaxy install -r requirements.yml
# Use installed role in playbook
- hosts: webservers
roles:
- geerlingguy.nginx
Concept 7: Real-World Playbook — Complete Application Deployment 🚀
What is Ansible doing in a real deployment? Here is a complete playbook deploying a Node.js application to production servers:
yaml
# deploy-app.yml — Deploy Node.js application
---
- name: Deploy FutureTechZone Application
hosts: webservers
become: true
vars:
app_name: futuretechzone
app_dir: /var/www/{{ app_name }}
app_user: deploy
node_version: "20"
git_repo: "https://github.com/myorg/futuretechzone.git"
git_branch: "main"
pm2_app_name: "{{ app_name }}"
pre_tasks:
- name: Ensure deployment user exists
user:
name: "{{ app_user }}"
shell: /bin/bash
create_home: yes
- name: Ensure app directory exists
file:
path: "{{ app_dir }}"
state: directory
owner: "{{ app_user }}"
recurse: yes
tasks:
- name: Clone or update application repository
git:
repo: "{{ git_repo }}"
dest: "{{ app_dir }}"
version: "{{ git_branch }}"
force: yes
become_user: "{{ app_user }}"
notify: Restart Application
- name: Create environment file
template:
src: templates/env.j2
dest: "{{ app_dir }}/.env"
owner: "{{ app_user }}"
mode: "0600"
notify: Restart Application
- name: Install Node.js dependencies
npm:
path: "{{ app_dir }}"
state: present
production: yes
become_user: "{{ app_user }}"
- name: Build application
shell: npm run build
args:
chdir: "{{ app_dir }}"
become_user: "{{ app_user }}"
- name: Run database migrations
shell: npm run migrate
args:
chdir: "{{ app_dir }}"
become_user: "{{ app_user }}"
run_once: true # Only run on first server
- name: Check if PM2 app is running
command: pm2 show {{ pm2_app_name }}
register: pm2_status
ignore_errors: yes
changed_when: false
become_user: "{{ app_user }}"
- name: Start application with PM2 (if not running)
shell: pm2 start ecosystem.config.js --env production
args:
chdir: "{{ app_dir }}"
become_user: "{{ app_user }}"
when: pm2_status.rc != 0
- name: Save PM2 configuration
shell: pm2 save
become_user: "{{ app_user }}"
changed_when: false
handlers:
- name: Restart Application
shell: pm2 reload {{ pm2_app_name }}
become_user: "{{ app_user }}"
post_tasks:
- name: Verify application is responding
uri:
url: "http://localhost:{{ app_port }}/health"
status_code: 200
retries: 5
delay: 10
Running with variables:
bash
# Deploy with custom variables
ansible-playbook deploy-app.yml \
-i inventory.yml \
--extra-vars "git_branch=release/2.0 app_port=3001" \
--limit production-web \
-v
Concept 8: Ansible vs Terraform — Configuration Management vs IaC 🆚
What is the difference between Ansible and Terraform? The most important comparison for anyone learning infrastructure automation.
| Aspect |
Ansible |
Terraform |
| Primary purpose |
Configuration management |
Infrastructure provisioning |
| Approach |
Procedural (how to configure) |
Declarative (what to create) |
| State tracking |
No built-in state |
State file tracks resources |
| Idempotency |
Mostly (modules handle it) |
Fully idempotent |
| Language |
YAML |
HCL |
| Agentless |
✅ SSH |
✅ API-based |
| Cloud resources |
Limited |
Excellent |
| Software config |
Excellent |
Limited |
| Learning curve |
Easier |
Moderate |
| Best for |
Configuring existing servers |
Creating cloud infrastructure |
They complement each other perfectly:
Terraform:
→ Create cloud infrastructure (EC2 instances, RDS, VPC, S3)
→ "Give me 5 Ubuntu servers on AWS"
Ansible:
→ Configure the infrastructure Terraform created
→ "Install Docker, Node.js, and deploy the app on those 5 servers"
Together:
1. Terraform creates the servers
2. Ansible configures them
3. CI/CD pipeline runs both automatically
Ansible vs Chef vs Puppet:
| Feature |
Ansible |
Chef |
Puppet |
| Language |
YAML |
Ruby DSL |
Puppet DSL |
| Agent required |
❌ (SSH) |
✅ |
✅ |
| Learning curve |
Easiest |
Steepest |
Moderate |
| Community |
Largest |
Large |
Large |
| Enterprise features |
AWX/Tower |
Chef Automate |
Puppet Enterprise |
| Best for |
All-purpose |
Complex Ruby shops |
Enterprise Windows |
| Trend 2026 |
Growing |
Declining |
Stable |
Ansible Best Practices
yaml
# Good Ansible practices:
# 1. Use descriptive task names
- name: Install Nginx web server (not just "install nginx")
apt:
name: nginx
state: present
# 2. Always use modules instead of shell when possible
# BAD:
- name: Install nginx
shell: apt-get install -y nginx
# GOOD:
- name: Install nginx
apt:
name: nginx
state: present
# 3. Use become: true at play level, not task level
- hosts: webservers
become: true # All tasks run as root
# 4. Use handlers for service restarts
# BAD — restarts after every change even if not needed:
- name: Copy config
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
- name: Restart Nginx
service:
name: nginx
state: restarted
# GOOD — only restarts if config changed:
- name: Copy config
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
notify: Restart Nginx
handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
# 5. Use vault for secrets
ansible-vault encrypt_string 'mySecretPassword' --name db_password
# Result: db_password: !vault | $ANSIBLE_VAULT;1.1;AES256 ...
Conclusion
Now you have a thorough understanding of what is Ansible — the agentless automation tool that makes managing infrastructure at any scale simple, consistent, and reliable.
Here is a quick recap of the 8 powerful concepts:
- ✅ Architecture — Agentless control node to managed nodes via SSH
- ✅ Inventory — Defining server groups in INI or YAML format
- ✅ Playbooks — YAML automation workflows with tasks, handlers, and variables
- ✅ Modules — Pre-built building blocks for every server operation
- ✅ Variables and Templates — Dynamic, environment-specific configuration
- ✅ Roles — Reusable, shareable automation components
- ✅ Real-World Deployment — Complete Node.js application deployment playbook
- ✅ Ansible vs Terraform — Complementary tools, not competitors
What is Ansible’s lasting importance? Configuration drift — servers slowly diverging from their intended state through manual changes — is one of the most persistent problems in system administration. Ansible eliminates it. Write the desired state once, run it as often as needed, and every server stays exactly where it should be. For any organization managing more than a handful of servers, Ansible is the difference between controlled infrastructure and chaos.
Install Ansible on your machine, point it at a test server, and run your first ping. Then write a simple playbook to install Nginx. The experience of watching one command configure multiple servers simultaneously is immediately compelling.
Related Articles
External Resource
Frequently Asked Questions