

Last updated: April 2026
Manual server configuration is reproducible in theory and chaotic in practice. Every engineer has a slightly different mental model of what is installed, what version, and what is configured. Ansible fixes this: describe the desired state once in a YAML file and Ansible applies it to every machine in your inventory over SSH.
This is the hands-on beginner guide to Ansible: what it is, how to install it, how to write and run your first playbook, and how to scale from one server to hundreds. Follow along and you will have Ansible installed and your first playbook running in under 20 minutes. If you already know Ansible basics and want the technical reference, the Ansible playbook guide covers YAML syntax, handlers, variables, and tags in depth.
At a glance
Ansible is an agentless automation platform that connects to managed nodes over SSH. Current stable release: ansible-core 2.20.5 (April 2025). Playbooks are YAML files that describe the desired state of your infrastructure: no agent software required on managed nodes. env zero wraps Ansible playbooks with team workflows, role-based access control (RBAC), and audit logs without modifying your YAML.
In this tutorial:
- What is Ansible
- Why use Ansible
- Ansible fundamentals
- Working with Ansible roles
- How to install Ansible
- Ansible tutorial demo: Jenkins on EC2
- Understanding the playbook output
- Integrating Ansible with env zero
- Try it with env zero
- Frequently asked questions
What is Ansible
Ansible is an open-source automation platform built for configuration management, application deployment, and orchestration. Its agentless architecture, YAML-based playbooks, and ability to manage thousands of nodes over SSH have made it the default choice for DevOps teams that need repeatable, auditable infrastructure automation.
The tutorial runs from installation through a real Jenkins CI/CD deployment: Terraform provisions the EC2 instance, Ansible configures it, and you walk away with a working Jenkins environment and a clear mental model of how Ansible fits into a production stack.
Video guide
TLDR: You can find the main repo here.
Why use Ansible
Ansible's appeal starts with its architecture. It connects to managed nodes over SSH and pushes small programs called modules to perform specific tasks. Nothing is installed on those nodes: no agent, no daemon, no persistent process. That means you can apply Ansible to existing infrastructure immediately, without a migration project first.
Playbooks are written in YAML, the same format used by Docker Compose, Kubernetes manifests, and GitHub Actions. Teams already familiar with any of those formats can read and review Ansible playbooks without learning new syntax. That legibility matters during security audits and code reviews, when someone who did not write the automation needs to verify what it actually does.
Idempotency is the feature that makes Ansible safe to run repeatedly. When a task already finds the system in its desired state, subsequent runs make no changes; they confirm the state is correct. Run the same playbook in a CI/CD pipeline on every deployment and it verifies correctness without triggering unnecessary service restarts.
Related reading: 14 Best IaC Tools for Cloud Automation in 2026. Compares Ansible, Terraform, Pulumi, and 11 other IaC tools with guidance on when to use each. Most mature teams use both.
Ansible fundamentals
Five concepts drive everything in Ansible. Understand these before you write a single line of YAML and the rest of the tool clicks into place.
Architecture

Control node: A system on which Ansible is installed. You run Ansible commands such as [.code]ansible-inventory[.code] on a control node.
Inventory: The inventory is created on the control node to define the hosts for Ansible to manage and deploy.
Managed node: A remote system, or host, that Ansible controls.
The Ansible Inventory File
- An inventory is a list of hosts/nodes with IP addresses or hostnames.
- The default location for inventory is /etc/ansible/hosts, but you can define a custom one in any directory.
- You can configure inventory parameters per host, such as host, user, and SSH connection parameters.
Modules
Modules are the units of work in Ansible. Each one does exactly one thing: ansible.builtin.apt installs packages on Debian systems, ansible.builtin.user manages user accounts, ansible.builtin.copy transfers files to remote hosts. There are thousands of built-in modules covering nearly every system administration task. They are grouped into collections, and you can add third-party collections with ansible-galaxy collection install <namespace>.<collection>.
Plugins
Plugins extend Ansible's core behavior. Connection plugins control how Ansible reaches hosts: SSH is the default, but WinRM handles Windows targets and local runs tasks directly on the control node. Callback plugins format and route task output. Filter plugins transform data inside Jinja2 templates. Most users never write a custom plugin, but understanding they exist explains why Ansible handles scenarios no built-in module covers directly. See the Ansible plugins reference for the full list.
Playbooks
Playbooks are the primary unit of automation in Ansible. Each one is a YAML file containing one or more plays. Each play targets a set of hosts and runs a list of tasks in order. When you run ansible-playbook site.yml, Ansible reads the file top to bottom, connects to each targeted host over SSH, and applies every task in sequence. If a task fails, execution stops for that host unless you configure error handling with ignore_errors or a block/rescue block.
Here is a minimal working playbook using fully qualified collection names (FQCN), the recommended best practice since Ansible 2.10:
---
- name: Ensure nginx is installed and running
hosts: webservers
become: true
tasks:
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: true
- name: Start nginx
ansible.builtin.service:
name: nginx
state: started
enabled: trueThe ansible.builtin.apt prefix is the FQCN. It removes ambiguity when multiple collections define modules with the same short name. The become: true directive runs tasks with elevated privileges, the equivalent of sudo.
Related reading: Ansible Playbook Guide: Syntax, Examples & Best Practices. Covers handlers, variables, roles, and tags in depth: the natural next step after this tutorial.
Plays
A play binds a set of hosts to a set of tasks. One playbook can contain multiple plays, each targeting different host groups and defining its own variables and roles. That's how you'd write a single playbook that first configures database servers, then web servers, with distinct task sets for each.
Roles
Roles bundle reusable content like tasks, handlers, and variables for use within a Play.
Tasks
Tasks specify actions to execute on managed hosts. They can be run individually using ad hoc commands.
Handlers
Handlers are special tasks triggered only when notified by a previous task that has made a change.
Vault
Ansible Vault encrypts sensitive values, such as passwords, API keys, and certificates, so they can be committed to version control without exposing secrets. Encrypt a variable file with ansible-vault encrypt vars/secrets.yml and Ansible decrypts it at runtime when you pass --ask-vault-pass or point to a vault password file. Most teams use Vault for local development and move to a secrets manager such as AWS Secrets Manager or HashiCorp Vault for CI/CD pipelines. Any production playbook that touches credentials should use Vault or an equivalent. The Ansible Vault guide covers setup, encrypted variable files, and CI/CD pipeline integration in detail. For variable types, scoping, and precedence, see Mastering Ansible Variables.
Working with Ansible roles
Without roles, playbooks grow into monoliths: hundreds of tasks in a single file, logic duplicated across projects, nothing anyone wants to modify. Roles fix this by organizing automation into a standard directory layout, with separate folders for tasks, handlers, templates, and variable defaults. Each role is self-contained and portable across environments.
Create a new role skeleton with ansible-galaxy init my_role, then reference it from your playbook under a roles: key. This is how production Ansible environments are structured: one role per service, one playbook that composes them.
Related reading: Ansible Playbook Guide: Syntax, Variables, Roles, and Tags. A full deep-dive on roles, handlers, and variables with working examples.
Common pitfalls and how to avoid them
Most Ansible problems fall into a small set of repeating patterns. Knowing them before you hit them saves hours of debugging.
SSH key permissions
Run chmod 600 ~/.ssh/your_key.pem before your first playbook run. Ansible refuses connections if the private key file has permissions broader than 600. This is the most common first-run failure by a wide margin.
Missing become: true
If a task that installs packages or writes to system directories fails with a permission error, check become: true before looking anywhere else. It's almost always that.
Non-idempotent shell tasks
The ansible.builtin.command and ansible.builtin.shell modules run unconditionally, every time, regardless of whether anything has changed. That's fine for one-off operations, but it breaks the "run it a hundred times, get the same result" property that makes Ansible safe in pipelines. Use a purpose-built module when one exists. When you have to use shell, add creates (skip if this file already exists) or changed_when: false to make behavior predictable.
Stale inventory
Verify connectivity before running a full playbook against new infrastructure: ansible all -i inventory.ini -m ansible.builtin.ping. A hostname that changed since the inventory was written produces failures that look like network problems.
Fact caching is a subtler trap. Ansible gathers host facts at playbook start: IP addresses, OS version, disk layout. In pipelines where infrastructure changes mid-run, those facts go stale and produce bugs that are genuinely hard to trace. Disable fact caching or force a refresh with ansible.builtin.setup when current state matters.
These are also the operational questions that get hard fast when a team grows: what playbook ran, against which hosts, triggered by whom. env zero logs every run with the exact playbook version, inventory state, and triggering user. The audit trail exists before anyone thinks to ask for it.
Related reading: Top IaC Security Tools in 2026. Covers Checkov, tfsec, KICS, and other scanners that catch Ansible playbook misconfigurations before they reach production.
What you need before you start
You need two machines: a control node (your laptop, a bastion host, or a CI runner) where you run Ansible commands and at least one managed node (a Linux server Ansible will configure over SSH). Ansible is agentless: nothing is installed permanently on managed nodes.
The control node needs Python 3.10 or later. On Windows, run Ansible inside WSL2 since the control node does not run natively on Windows. Managed nodes need Python 3.8 or later. Most modern Linux distributions ship this by default. Verify with python3 --version on the target before you start.
The step most beginners skip: SSH trust. Ansible uses the same SSH authentication your terminal does. Before running any playbook, confirm you can SSH in manually (ssh user@yourserver) without being prompted for a password. If you get a prompt, copy your public key over first: ssh-copy-id user@yourserver. Getting this wrong is the root cause of nearly every UNREACHABLE error on a first playbook run.
Not sure which IaC tool fits your stack? Top DevOps Tools for Infrastructure Automation in 2026 compares Ansible with Puppet, Chef, and SaltStack.
How to install Ansible
Install ansible-core on any Linux or macOS machine using pip:
pip install ansible-coreVerify with ansible --version. The output shows the ansible-core version, the Python path, and the config file location. On Windows, install via WSL2 since the Ansible control node does not run natively on Windows.
If you're following along with the Jenkins demo below, start a GitHub Codespace from the repo. ansible-core is pre-installed and you can skip local setup entirely.
Commands in this tutorial were tested on Ubuntu 24.04 LTS and macOS Sonoma. Installation is identical on Debian 12 and most RHEL-based distributions.
Ansible tutorial demo
No cloud account? All concepts in this tutorial (installing Ansible, writing an inventory file, and running your first playbook) apply to any SSH-accessible Linux host. The Jenkins-on-EC2 demo below requires AWS. To follow along without a cloud account, open the demo repo in a GitHub Codespace: ansible-core is pre-installed and ready to use.
This demo automates the setup of a Jenkins CI/CD environment on an EC2 instance: Terraform provisions the infrastructure, Ansible handles configuration, and Docker runs Jenkins as a container for a portable, isolated deployment.
Below is a diagram of what you will build:

Tools Overview
The demo uses three tools:
- Terraform: You'll use Terraform to automate the creation of your EC2 instance and related networking resources. We won't spend too much time explaining Terraform since our focus is on Ansible.
- Ansible: Ansible will install Docker, configure the Jenkins environment, and run Jenkins inside a Docker container on the EC2 instance.
- Docker: You will use Docker to run Jenkins as a container on your EC2 instance.
Step 1: Provision Infrastructure with Terraform
The first step is to create the infrastructure needed for our Jenkins environment using Terraform.
Navigate to the Terraform directory: Start by navigating to the directory where your Terraform configuration files are located.
Initialize Terraform: Initialize your Terraform environment to download the necessary provider plugins and prepare your working directory.
Apply the Terraform configuration: Apply the Terraform configuration to create your AWS infrastructure. The [.code]-auto-approve[.code] flag will bypass manual approval for the changes. Be careful using this flag in production environments.
Terraform will create the following resources:
- A VPC (Virtual Private Cloud) with subnets
- Security groups to control access to your EC2 instance
- An EC2 instance where Jenkins will be installed
- An Elastic IP for public access to the instance
After the process is completed, Terraform will output critical information, such as the public IP address of the EC2 instance and a private SSH key for secure access.
Step 2: Prepare Ansible Inventory and SSH Key
With the EC2 instance created, we need to prepare the Ansible inventory file, which Ansible uses to know which hosts to manage.
Additionally, we’ll prepare the SSH key that Ansible will use to authenticate with the EC2 instance.
Update the Ansible Inventory file: Replace the placeholder in the Ansible inventory file with the actual public IP address of your EC2 instance. This can be done using a simple [.code]sed[.code] command.
After updating, verify the inventory file to confirm the IP address was inserted correctly.
Extract and prepare the SSH key: Extract the private key generated by Terraform and save it to a file that Ansible can use to connect to the EC2 instance.
Set the correct permissions on the private key file to secure it.
Step 3: Configure the EC2 instance with Ansible
Now that the infrastructure is in place and the inventory and SSH key are prepared, you can move on to configuring the EC2 instance using Ansible.
Navigate to the Ansible directory: Change your directory to where the Ansible playbook is located.
Run the Ansible playbook: Execute the playbook to configure the EC2 instance. It installs Docker, sets up the Jenkins container, and verifies the service is running.
The playbook playbook.yaml file consists of several tasks that automate the following steps, more details will be provided in a later section:
- Install pip3 and unzip: These are required for installing Python packages and handling compressed files.
- Add Docker GPG apt Key: Adds the GPG key for the official Docker repository.
- Add Docker Repository: Configures the Docker repository in your package manager.
- Install Docker: Installs the latest version of Docker CE (Community Edition).
- Install Docker Module for Python: Installs the Docker module for Python, enabling Ansible to manage Docker containers.
- Pull Jenkins Docker Image: Pulls
jenkins/jenkins:lts(the stable long-term support image) from Docker Hub. - Set Permissions: Sets the correct ownership and permissions for Jenkins data directories.
- Create and Start Jenkins Container: Creates and starts the Jenkins container, mapping necessary ports and volumes.
Step 4: Verify Jenkins Setup
Once the Ansible playbook has completed its execution, Jenkins should be up and running on your EC2 instance. Let’s verify that everything is set up correctly.
Access Jenkins: Open a web browser and navigate to the public IP address of your EC2 instance using port 8080.
This will bring up the Jenkins login page:

Retrieve Jenkins Admin password: The initial Jenkins admin password is stored on the EC2 instance. SSH into the instance to retrieve it as shown below, replacing ‘public_ip’ with your public IP.
Get the password:
Copy this password and use it to log into Jenkins.
Complete Jenkins setup: After logging in, follow the Jenkins setup wizard to install recommended plugins or skip the plugin installation to expedite the process. Once completed, your Jenkins instance will be ready to use.

Understanding the playbook output
After a successful run, Ansible prints a recap at the bottom of the terminal:
PLAY RECAP *******************************
ec2_instance : ok=12 changed=8 unreachable=0 failed=0 skipped=0| Counter | What it means | If nonzero, do this |
|---|---|---|
ok | Task confirmed state or applied a change | Normal |
changed | Task modified something on the host | Normal on first run; should drop to 0 on repeat |
unreachable | SSH connection failed before any task ran | Check SSH key path and inventory IP address |
failed | Task ran but returned an error; execution stopped | Re-run with ansible-playbook -v for detail |
skipped | Task had a when: condition that evaluated false | Normal |
A clean first run shows unreachable=0 failed=0. Run the exact same playbook a second time and changed drops to zero. Nothing was modified because the system is already in the desired state. That is idempotency in action: the property that makes Ansible safe to include in CI/CD pipelines without triggering unnecessary restarts or configuration changes.
Integrating Ansible with env0
env zero connects directly to your Git repository, version-controls your Ansible runs, and gives your team a shared control plane without modifying a single YAML file.
Every run is now in the system. In the env zero UI, create a project and define an environment using an Ansible template. Set the Ansible version, paste in the SSH key Terraform generated, and point the environment at your GitHub repository.
The SSH key used here corresponds to the private key generated earlier with Terraform, giving Ansible authenticated access to your EC2 instance.

Specify the folder containing the playbook, then set ANSIBLE_CLI_inventory as an environment variable. That's the only configuration change needed beyond what Terraform already produced.

Trigger a run. env zero clones the repo, loads variables, and executes the playbook.
After approval, every task from the CLI demo above runs inside the platform. The deployment that lived in your terminal is now tracked, auditable, and repeatable by anyone on the team with the right access.

The result: every Ansible run is tracked with full audit logs, role-based access control (RBAC) governs who can trigger deployments, and drift detection runs continuously against live infrastructure. env zero works with every IaC framework, including Terraform, OpenTofu, Pulumi, and CloudFormation, so teams that mix tools across projects don't need separate control planes for each one.
The Four Stages of Infrastructure as Code Automation covers how governance fits into the full IaC lifecycle, from the first playbook to enterprise-scale policy enforcement.
Related reading: Drift Detection in IaC: Prevent Your Infrastructure from Breaking. How env zero detects and remediates drift between your Ansible-managed infrastructure and the desired state in version control.
Try it with env zero
Running Ansible locally works for a single engineer. The moment a second person runs a playbook against shared infrastructure, the questions start: who approved this run, did it use the right playbook version, why did it touch three extra hosts on Thursday?
| Without env zero | With env zero |
|---|---|
| Playbooks run from engineers' laptops | All runs triggered through a governed UI or API |
| No record of who ran what or when | Full audit log: user, playbook version, changed hosts |
| SSH keys managed per-engineer | Centralized credentials, no keys on developer machines |
| Drift goes undetected until something breaks | Continuous drift detection with automatic alerting |
Teams running Ansible at scale see this pattern quickly. Automation Anywhere went from full-day rollouts to minutes for multi-region deployments. Drift that had been invisible became instantly detectable. The YAML did not change. The operating model around it did.
Start a free trial or book a demo.
Ready to write your first Ansible playbook? Our Ansible Playbook Guide covers YAML syntax, handlers, variables, and a full step-by-step deployment example.
Frequently asked questions
Q: What is the difference between Ansible and Jenkins?
Ansible is an automation tool primarily for configuration management, whereas Jenkins is a CI/CD tool focused on automating software builds, tests, and deployments. They serve different purposes but can complement each other. Here’s a quick comparison:
| Ansible | Jenkins | |
|---|---|---|
| Use Case | Infrastructure setup, app deployment | Building, testing, deploying software |
| Setup | Agentless | Requires agents on nodes |
| Language | YAML | Groovy, Shell Scripts |
Q: How do I create a directory in Ansible?
To create a directory in Ansible, use the ‘file’ module with [.code]state: directory[.code]. Example:
Q: Can Ansible be used with Windows?
Yes. Ansible can manage Windows servers using WinRM instead of SSH. Use Windows-specific modules from the ansible.windows collection, such as ansible.windows.win_shell and ansible.windows.win_package. Configure WinRM on the target machines first. See the official docs: Using Ansible and Windows
Q: How does Ansible compare to Terraform?
Ansible and Terraform are better together. Terraform is ideal for provisioning infrastructure, while Ansible excels at configuring that infrastructure once it's up. Both tools allow you to automate your entire environment from start to finish. You can learn more here: 14 Best IaC Tools for Cloud Automation in 2026
Q: How do I start learning Ansible?
Start with YAML syntax basics, then install ansible-core on a control node and write a simple playbook that installs a package on a test server. The official Getting Started guide walks through the initial setup. Once you can run a playbook end-to-end, explore variables, inventory groups, and roles as your automation grows.
Q: Is Ansible easy to learn?
Yes. Ansible has a shallower learning curve than most automation tools. If you know basic Linux administration and have written any YAML (Docker Compose, GitHub Actions, Kubernetes manifests), you can write a working playbook in an hour. The error messages are readable, the official documentation covers most common tasks with examples, and there's no custom DSL to learn.
Q: How long does it take to learn Ansible?
You can learn the basics in a few hours: install ansible-core, write a playbook that installs a package on a test server, and you have covered the core workflow. Writing production-quality playbooks with roles, variables, vault-encrypted secrets, and CI/CD integration typically takes a few weeks of hands-on practice. Mastering dynamic inventory, custom modules, and performance tuning takes longer.
Q: Should I learn Python or Ansible?
Depends on the goal. For automating infrastructure configuration and application deployment, start with Ansible. It's purpose-built for that work and doesn't require Python knowledge to use effectively. If you want to write custom modules or plugins, Python becomes valuable since Ansible is built on it. The two complement each other: Ansible for the infrastructure workflow, Python for the edge cases Ansible can't handle cleanly on its own.
Q: What is the difference between ansible-core and ansible?
ansible-core is the minimal base package containing the Ansible engine, built-in modules, and plugins maintained directly by the project. The ansible package bundles ansible-core with a curated set of community collections. For production environments, most teams install ansible-core directly and add only the specific collections they need via ansible-galaxy collection install. This keeps the automation environment lean and auditable. Current stable release: ansible-core 2.20.5.
Q: How do I run Ansible without writing a playbook?
Use ad hoc commands. The syntax is: ansible <pattern> -i inventory.ini -m <module> -a "<args>". For example, to ping all hosts: ansible all -i inventory.ini -m ansible.builtin.ping. Ad hoc commands are useful for quick checks and one-off operations. For anything you will run more than once, write a playbook: it is reusable, version-controlled, and reviewable.
Q: Do I need to install anything on the servers Ansible manages?
No. Ansible is agentless by design. The control node connects over SSH and pushes temporary modules at runtime. Nothing is installed permanently on managed nodes. The only requirement is Python 3.8 or later on each managed node. Most modern Linux distributions include this by default. Verify with python3 --version on the target host before running your first playbook.
Q: How do I test an Ansible playbook without running it?
Use the --check flag: ansible-playbook site.yml -i inventory.ini --check. This performs a dry run: Ansible reports what changes would be made without applying them. Combine with -v for verbose output to see detailed reasoning. Not all modules support check mode; those that do not will be skipped and flagged in the output.
Q: What does idempotent mean in Ansible?
Idempotent means running the same playbook multiple times produces the same result as running it once. If a task finds the system already in the desired state, it makes no changes and reports ok rather than changed. Run the same playbook twice and the second run shows changed=0. This property makes Ansible safe to include in CI/CD pipelines. You can run it on every deployment without triggering unnecessary service restarts.
Q: What is the difference between Ansible and Puppet?
Both tools automate configuration management, but they differ in architecture and approach. Puppet uses an agent-based model: a Puppet agent runs on each managed node, polls a central Puppet server, and applies configuration on a schedule. Ansible is agentless: it connects over SSH and runs tasks on demand. Puppet uses its own DSL; Ansible uses YAML. For most teams starting from scratch, Ansible has a shallower learning curve and no agent deployment overhead.
Q: Is Ansible free to use?
Yes. ansible-core is open source under the GPL license and free to use. Red Hat also offers Ansible Automation Platform, a commercial product that adds a web UI, certified content collections, and enterprise support. For most teams starting with Ansible automation, ansible-core is sufficient. The pip install ansible-core install covered in this tutorial gives you the full automation engine at no cost.
Q: What Python version do managed nodes require?
Ansible requires Python 3.8 or later on managed nodes, with 3.10 or later recommended. Most modern Linux distributions include a compatible version by default: Ubuntu 22.04 ships Python 3.10, RHEL 9 ships Python 3.9, Debian 12 ships Python 3.11. If you manage older systems, install Python 3 separately before running Ansible against them. Check with python3 --version on the target host.
Once you're comfortable with Ansible fundamentals, the next question is usually where Ansible fits alongside Terraform. Ansible vs Terraform: When to Choose One, Use Both, or Consider OpenTofu maps the boundary between the two tools, covers how to orchestrate them together in production, and explains what's changed in 2026 with the IBM acquisition and OpenTofu's ephemeral outputs.

.webp)

![Using Open Policy Agent (OPA) with Terraform: Tutorial and Examples [2026]](https://cdn.prod.website-files.com/63eb9bf7fa9e2724829607c1/69d6a3bde2ffe415812d9782_post_th.png)