Halloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix NowHalloween DealsAmazon USOctober picks are moving - compare before checkoutAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk10 min

How to Create and Run Your First Ansible Playbook (Step-by-Step)

A practical first-playbook tutorial: build an inventory, write a minimal YAML playbook, validate it, preview changes, run ansible-playbook, interpret the recap, and fix common failures.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The shortest working path is: install Ansible on a control node, create an inventory that names an authenticated managed host, write a YAML playbook, validate it, preview it, and run it with ansible-playbook -i inventory.ini playbook.yaml. This guide explains every file, command, output status, and common failure so you can make a safe first run rather than simply copy a YAML snippet.

What an Ansible playbook does

Ansible runs from a control node and connects to one or more managed nodes. The control node is the machine where Ansible is installed and where you run commands such as ansible and ansible-playbook. The managed nodes are the systems Ansible controls. An inventory tells Ansible which hosts exist and how to connect to them.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Ansible’s documentation defines playbooks as “automation blueprints, in YAML format, that Ansible uses to deploy and configure managed nodes.” A playbook is a list of plays. Each play maps a set of hosts to an ordered list of tasks. Each task references a module, which is code or a binary Ansible runs on a managed node. Plays and tasks execute from top to bottom.

Your first playbook can deliberately be small. The built-in ansible.builtin.ping module checks that Ansible can communicate with a host, while ansible.builtin.debug prints a message. Together they prove that your inventory, authentication, YAML syntax, module selection, and execution path are working.

Prerequisites and a clean working directory

  • A control node with Ansible installed. Check it with ansible --version.
  • At least one managed node that the control node can reach over the connection method configured in your environment.
  • Credentials and permissions that allow Ansible to authenticate to that node. The exact SSH keys, passwords, privilege escalation, firewall rules, and cloud networking depend on your environment.
  • A text editor and a shell on the control node.

Create a dedicated directory so the inventory and playbook paths are unambiguous:

mkdir ansible_quickstart
cd ansible_quickstart

You will create two files in this directory:

File Purpose
inventory.ini Lists managed hosts, groups them, and can hold connection variables.
playbook.yaml Describes the plays and ordered tasks Ansible should execute.

Using real DNS names or IP addresses in the inventory is essential. A placeholder host name that does not resolve or accept connections will produce an unreachable result even when the YAML is perfect.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Create the inventory

An inventory may be static INI or YAML, or it may come from a dynamic inventory source. For a first run, a static INI file is easiest to inspect. The host group in the example below is named myhosts, matching the playbook that follows.

[myhosts]
server1 ansible_host=203.0.113.10 ansible_user=automation

Replace server1, the address, and the user with values from your environment. The alias server1 is the name Ansible displays; ansible_host is the address it contacts. You can put several hosts under the same group:

[myhosts]
web01 ansible_host=203.0.113.10 ansible_user=automation
web02 ansible_host=203.0.113.11 ansible_user=automation

Inventory groups can carry connection information. For network automation, for example, a group can define the network operating system and the SSH user. Keep secrets out of a plain inventory when possible; use the credential and variable mechanisms appropriate to your deployment rather than committing passwords to source control.

Before running a playbook, make sure the control node can resolve or reach every address and that the selected user is authorized. An inventory only describes a connection; it does not create an account, open a firewall, install a key, or grant permissions.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Write the minimal first playbook

Create playbook.yaml with this content:

- name: My first play
  hosts: myhosts
  tasks:
    - name: Ping my hosts
      ansible.builtin.ping:

    - name: Print message
      ansible.builtin.debug:
        msg: Hello world

The top-level value is a YAML list, so the first character is a hyphen. This file contains one play. Its name labels the play, hosts selects the inventory group, and tasks contains two tasks in order.

How each line maps to Ansible’s model

  • - name: My first play gives the play a readable label that appears in command output.
  • hosts: myhosts selects every host in the inventory group named myhosts.
  • tasks: starts the ordered task list.
  • ansible.builtin.ping: calls the built-in ping module. It is an Ansible connectivity test, not an ICMP ping utility.
  • ansible.builtin.debug: calls the built-in debug module.
  • msg: Hello world supplies the text that debug prints.

Use descriptive names. The play and task names are shown as Ansible progresses, so they make it much easier to identify the step that failed.

Why fully qualified collection names matter

Modern playbooks should use fully qualified collection names (FQCNs), such as ansible.builtin.ping and ansible.builtin.debug. Ansible 2.10 and later recommend this form because different collections can contain modules with the same short name. The FQCN identifies the intended collection and reduces ambiguity. Older examples may show ping: or debug:; those short forms can work, but FQCNs are the clearer default for new files.

Validate before contacting a managed node

Validation catches different classes of mistakes at different stages. Run these commands from the directory containing both files.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Check YAML and playbook structure:
    ansible-playbook --syntax-check -i inventory.ini playbook.yaml
  2. Confirm the selected hosts:
    ansible-playbook --list-hosts -i inventory.ini playbook.yaml
  3. Confirm the selected tasks:
    ansible-playbook --list-tasks -i inventory.ini playbook.yaml

A syntax check verifies that Ansible can parse the playbook; it does not prove that a host is reachable or that a task has permission to perform its operation. Host and task listings show what Ansible intends to target before a connection is attempted.

Preview changes with check mode

For playbooks that alter systems, use check mode before an applying run:

ansible-playbook --check --diff -i inventory.ini playbook.yaml

--check executes the playbook without applying alterations and reports changes Ansible would make. --diff asks modules that support it to show before-and-after differences. Check mode is a preview, not a guarantee: modules vary in their check-mode support, and a real run can still be affected by permissions, connectivity, variables, services, files, or external systems. The ping and debug example normally has no persistent configuration change to preview, but practicing the command establishes a safe habit for later playbooks.

Run the playbook

When the inventory, authentication, and validation checks are ready, run:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
ansible-playbook -i inventory.ini playbook.yaml

The -i option points to the inventory. The final argument is the playbook file. If your files have different names or live elsewhere, substitute their paths. Ansible runs the play from top to bottom and runs tasks within that play from top to bottom. The command ends with a PLAY RECAP for every targeted host.

Understand the output

Typical output identifies the play, then each task. Ansible also performs an implicit Gathering Facts task by default for ordinary managed-node plays. You may see a sequence resembling:

PLAY [My first play] **************************************************************

TASK [Gathering Facts] ***********************************************************
...

TASK [Ping my hosts] *************************************************************
ok: [server1]

TASK [Print message] *************************************************************
ok: [server1] => {
    "msg": "Hello world"
}

PLAY RECAP ***********************************************************************
server1 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

The exact formatting and additional fact details vary by Ansible version and environment, but the status vocabulary is consistent enough to guide troubleshooting.

Status Meaning What to inspect
ok The task completed and did not report a change. For debug, this means the message was printed successfully.
changed The task reports that it altered the managed node. Read the task result and decide whether the change was intended.
unreachable Ansible could not communicate with the host. Address, routing, port access, SSH settings, credentials, and host availability.
failed The connection reached the host, but task execution failed. The error text immediately above the recap, module arguments, permissions, and target state.
skipped A task was intentionally not run, usually because of a condition or selection. Conditions, tags, and host targeting.
rescued A recovery block handled a failure. The original failure and the rescue tasks.
ignored A failure was explicitly allowed to continue. Whether ignoring it leaves the system in an unsafe or incomplete state.

Do not treat an unreachable result as a bad YAML problem: it is normally a communication or authentication issue. A failed result generally means Ansible connected but a task could not complete. Always read the preceding error text before editing the playbook.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use the recap to decide what happened

The recap is per host, not one global score. With multiple hosts, one can be successful while another is unreachable. For the minimal example, a healthy host commonly reports the ping and debug tasks as ok, with no changes. A nonzero changed count is not automatically an error; it indicates that a task says it modified the target. Conversely, an all-green recap does not prove that your intended business outcome is correct, so review the task results and test the managed node.

Idempotency and safe repeat runs

Many Ansible modules check whether the desired final state has already been reached. If it has, they avoid making another change; this behavior is called idempotency. It lets a playbook converge toward a declared state instead of performing the same alteration every time.

Idempotency is not universal. Some modules and task designs can cause a change on every run, and some external operations cannot be safely repeated. Test unfamiliar behavior in a sandbox, inspect the first run’s changed results, and use check mode where the modules support it. Do not infer safety merely because a second invocation completes without an error.

The ping and debug tasks are useful for connectivity and visibility, not for enforcing a lasting configuration state. As you add configuration tasks, prefer modules that describe the desired end state and verify their repeat behavior in a non-production environment.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Network-device playbooks are a separate variation

Network devices use different connection plugins and module families from the generic managed-node example. The official network workflow still requires a playbook and an inventory, but a network play commonly includes connection: ansible.netcommon.network_cli and gather_facts: false. A minimal shape is:

- name: Inspect network devices
  hosts: switches
  connection: ansible.netcommon.network_cli
  gather_facts: false
  tasks:
    - name: Gather network facts
      <network-facts-module>:

    - name: Show collected facts
      ansible.builtin.debug:
        var: ansible_facts

The placeholder above is intentional: the correct network facts module depends on the network operating system and collection in use, so do not copy an arbitrary module name. In the inventory, groups can hold values such as ansible_network_os and the SSH user. Network modules and connection plugins differ from the generic managed-node workflow; configure the device-specific collection and variables before running against production equipment.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot a failed first run

The playbook fails the syntax check

  • Check indentation. YAML uses spaces, and a task must be nested under tasks.
  • Check colons, hyphens, and quoting around values that contain special YAML characters.
  • Confirm the module key includes its trailing colon, as in ansible.builtin.ping:.
  • Run ansible-playbook --syntax-check -i inventory.ini playbook.yaml again after each correction so the reported line remains relevant.

The play runs zero hosts

Run the --list-hosts command and compare the play’s hosts: value with the inventory group spelling. Group names are not automatically inferred. If the play says myhosts but the inventory defines servers, no intended host is selected.

A host is unreachable

  • Verify the address in ansible_host and that DNS or routing from the control node works.
  • Confirm the managed node is powered on and accepting the connection type your inventory selects.
  • Check the user name and authentication method. Ansible cannot repair an invalid key, password, or account from inside a play that never connects.
  • Review firewall, security-group, jump-host, and port requirements in your environment.
  • Use the complete error message to distinguish a timeout, refused connection, host-key issue, or authentication failure; each requires a different fix.

The host is reachable but a task fails

Read the module error immediately above the recap. Check the task’s arguments, the remote user’s permissions, the target operating system, and any missing collection. A successful ping proves communication, not that every module can run with the current privileges or that the requested resource exists.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Facts gathering causes a problem

Ordinary plays gather facts by default, so a failure there can occur before your first named task. Inspect the fact-gathering error and target compatibility. Network-device plays commonly set gather_facts: false and invoke a device-appropriate facts module explicitly, as shown in the network variation.

Version and compatibility considerations

For Ansible 2.10 and later, prefer FQCN module names. Also check the documentation for the exact installed release: ansible-core 2.19 introduced significant templating changes that may require playbook updates. A playbook copied from an older tutorial can therefore need adjustment even when its YAML parses. Record the output of ansible --version with your project notes and test changes against the version that will run them.

Version differences can affect module arguments, collection availability, templating behavior, connection plugins, and check-mode support. Treat a successful syntax check as only one compatibility signal; run the playbook in a sandbox and inspect the actual task results before production use.

A repeatable first-playbook workflow

  1. Create a project directory and keep the inventory and playbook paths explicit.
  2. Define a real host group in inventory.ini, including the address and connection user required by your environment.
  3. Write one clearly named play targeting that group.
  4. Add small, named tasks using FQCNs, beginning with ansible.builtin.ping and ansible.builtin.debug.
  5. Run --syntax-check before attempting a connection.
  6. Run --list-hosts and --list-tasks to verify scope.
  7. Use --check --diff for configuration changes when the modules support meaningful previews.
  8. Apply the playbook with ansible-playbook -i inventory.ini playbook.yaml.
  9. Read each task result and the per-host recap, rather than relying only on the process exit message.
  10. Repeat in a sandbox, confirm idempotent behavior where expected, and only then target production.

What to learn after the connectivity test

Once this playbook works, expand one behavior at a time. Add a task that expresses a specific desired state, run the syntax and scope checks again, preview it where supported, and inspect whether the second run reports no unnecessary change. Then separate hosts into meaningful inventory groups and move connection variables into the appropriate inventory, group, or host variable structure for your environment.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For larger projects, dynamic inventory can replace a hand-maintained static file, but the playbook still needs a predictable host pattern and a tested authentication path. Keep task names specific, use FQCNs consistently, and preserve the command output from test runs so a later failure can be compared with a known-good recap.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.