Ansible Automation for Beginners: Your First Playbook to Production

July 31, 2026 · 8 min read

You have 15 servers. They all need the same Nginx config, the same firewall rules, the same monitoring agent. You could SSH into each one and run commands manually — or you could write one YAML file and let Ansible handle it in under a minute. That's the promise of Ansible: describe what you want, not how to do it.

Ansible is a configuration management and automation tool that uses SSH to connect to remote machines. No agents to install, no daemons to manage, no complex architecture. You write a playbook, point it at your servers, and it executes tasks in order. If something fails, it tells you exactly what went wrong.

1. Installation

Ansible runs on your control node (your laptop, a CI runner, a bastion host). It connects to managed nodes over SSH — those nodes need nothing installed.

# macOS
pip3 install ansible

# Ubuntu/Debian
sudo apt update && sudo apt install -y ansible

# Verify
ansible --version

Ansible requires Python 3 on the control node. Managed nodes also need Python (2.7+ or 3.5+), which is pre-installed on virtually every Linux distribution. For nodes without Python, you can use raw module tasks that execute shell commands directly.

2. Inventory: Telling Ansible Where to Connect

The inventory file lists your hosts. The simplest format is INI:

# inventory.ini
[webservers]
web1 ansible_host=192.168.1.10
web2 ansible_host=192.168.1.11

[dbservers]
db1 ansible_host=192.168.1.20

[all:vars]
ansible_user=deploy
ansible_ssh_private_key_file=~/.ssh/id_ed25519

You can also use YAML format or dynamic inventory scripts that pull hosts from AWS, GCP, or any cloud provider's API. Dynamic inventory is essential when you auto-scale — static files don't work when instances come and go.

Test connectivity with:

ansible all -i inventory.ini -m ping

This isn't an ICMP ping — it's Ansible connecting over SSH, transferring a small Python script, and running it. If it returns "pong", you're good.

3. Your First Playbook

A playbook is a YAML file that defines a set of tasks to run on specific hosts:

# site.yml
---
- name: Configure web servers
  hosts: webservers
  become: yes
  tasks:
    - name: Install Nginx
      apt:
        name: nginx
        state: present
        update_cache: yes

    - name: Copy Nginx config
      copy:
        src: files/nginx.conf
        dest: /etc/nginx/nginx.conf
        owner: root
        group: root
        mode: '0644'
      notify: Restart Nginx

    - name: Ensure Nginx is running
      service:
        name: nginx
        state: started
        enabled: yes

  handlers:
    - name: Restart Nginx
      service:
        name: nginx
        state: restarted

Run it:

ansible-playbook -i inventory.ini site.yml

Key things happening here:

4. Variables and Templates

Hardcoding values in playbooks gets messy fast. Ansible lets you define variables at multiple levels:

# group_vars/webservers.yml
---
nginx_worker_processes: 4
nginx_worker_connections: 1024
server_name: example.com

Use Jinja2 templates to generate config files dynamically:

# templates/nginx.conf.j2
worker_processes {{ nginx_worker_connections }};
events {
    worker_connections {{ nginx_worker_connections }};
}
http {
    server {
        listen 80;
        server_name {{ server_name }};
        root /var/www/html;
    }
}

Reference the template in your playbook with the template module:

- name: Deploy Nginx config from template
  template:
    src: templates/nginx.conf.j2
    dest: /etc/nginx/nginx.conf
  notify: Restart Nginx

Variable precedence matters. Ansible has 22 levels of precedence — from role defaults (lowest) to extra vars passed with -e (highest). In practice, keep it simple: define defaults in group_vars/, override with -e for one-off runs.

5. Roles: Organizing Complexity

When your playbook grows past 50 lines, split it into roles. A role is a directory structure that encapsulates tasks, templates, variables, and handlers:

roles/
└── nginx/
    ├── tasks/main.yml
    ├── templates/nginx.conf.j2
    ├── handlers/main.yml
    ├── defaults/main.yml
    └── files/static-site.conf

Use the role in your playbook:

- name: Configure web servers
  hosts: webservers
  become: yes
  roles:
    - nginx
    - monitoring
    - firewall

Roles are reusable. The same nginx role can be used across dev, staging, and production. Share roles across projects via Ansible Galaxy — think of it as npm or pip for Ansible.

6. Real-World Patterns

Conditional execution

Run tasks only when a condition is met:

- name: Install security updates (Debian/Ubuntu only)
  apt:
    upgrade: safe
    update_cache: yes
  when: ansible_os_family == "Debian"

- name: Install security updates (RHEL/CentOS only)
  yum:
    name: "*"
    state: latest
    security: yes
  when: ansible_os_family == "RedHat"

Loops

Iterate over lists to create multiple resources:

- name: Create app users
  user:
    name: "{{ item.name }}"
    groups: "{{ item.groups }}"
    shell: /bin/bash
  loop:
    - { name: "deploy", groups: "sudo" }
    - { name: "monitoring", groups: "adm" }
    - { name: "backup", groups: "disk" }

Vault for secrets

Never store passwords in plain text. Ansible Vault encrypts sensitive data:

# Encrypt a file
ansible-vault encrypt group_vars/webservers/vault.yml

# Run playbook with vault password
ansible-playbook site.yml --ask-vault-pass

# Or use a password file (CI-friendly)
ansible-playbook site.yml --vault-password-file ~/.vault_pass

7. Ad-Hoc Commands

Not everything needs a playbook. For quick one-off tasks, use ad-hoc commands:

# Check disk space on all web servers
ansible webservers -i inventory.ini -a "df -h"

# Restart a service across all servers
ansible webservers -i inventory.ini -m service -a "name=nginx state=restarted" --become

# Copy a file to all servers
ansible all -i inventory.ini -m copy -a "src=motd.txt dest=/etc/motd" --become

Ad-hoc commands are great for troubleshooting and quick checks. For anything you'll run more than once, write a playbook.

8. Tips for Production Use

Summary

Ansible's power comes from its simplicity: no agents, YAML-based playbooks, SSH transport, and idempotent execution. Start with a single playbook that configures one server. Add inventory for multiple hosts. Extract common logic into roles. Encrypt secrets with Vault. Preview with --check.

The jump from "manually SSH-ing into servers" to "one command configures everything" is the biggest productivity multiplier in infrastructure management. Ansible makes that jump accessible — install it, write your first playbook, and you'll never go back.