Getting Started
Install Ansible, write an inventory, and run your first ad-hoc command and playbook
Getting Started
This page takes you from zero to "I ran a playbook against a real host." Assume you can SSH into a Linux box somewhere — that's all Ansible needs.
Installation
Install Ansible on your control node (your laptop, a bastion, or a CI runner). Managed hosts need only SSH and Python — no agent.
# macOS
brew install ansible
# Linux (Debian/Ubuntu)
sudo apt update
sudo apt install ansible
# pip (any platform; useful in CI containers)
python3 -m pip install --user ansible
# Verify
ansible --versionFor projects that need a specific version, use a virtualenv or pipx so each project pins its own Ansible release.
Your First Inventory
An inventory lists the hosts Ansible can talk to. Start with a single YAML file:
# inventory/hosts.yml
all:
children:
webservers:
hosts:
web-01:
ansible_host: 203.0.113.10
web-02:
ansible_host: 203.0.113.11
vars:
ansible_user: deploy
ansible_ssh_private_key_file: ~/.ssh/deploy_keyNow sanity-check connectivity:
ansible all -i inventory/hosts.yml -m pingA passing run looks like:
web-01 | SUCCESS => { "changed": false, "ping": "pong" }
web-02 | SUCCESS => { "changed": false, "ping": "pong" }If you get "Permission denied" or "Host key verification failed", fix SSH first — Ansible is just SSHing.
Ad-hoc Commands
Before writing playbooks, get a feel for modules using ad-hoc commands:
# Run any command across the fleet
ansible webservers -i inventory/hosts.yml -m shell -a "uptime"
# Install a package (idempotent — won't reinstall if already there)
ansible webservers -i inventory/hosts.yml -m apt -a "name=htop state=present" --become
# Copy a file
ansible webservers -i inventory/hosts.yml -m copy -a "src=./motd dest=/etc/motd" --become
# Gather facts (every variable Ansible knows about the host)
ansible web-01 -i inventory/hosts.yml -m setup--become is "run this with sudo." Most config tasks need it.
Your First Playbook
A playbook is a YAML file that runs multiple tasks across hosts. Make this:
# site.yml
---
- name: Configure web servers
hosts: webservers
become: true
tasks:
- name: Install base packages
apt:
name:
- curl
- htop
- jq
state: present
update_cache: true
- name: Ensure deploy user exists
user:
name: deploy
groups: sudo
shell: /bin/bash
- name: Copy MOTD
copy:
src: ./files/motd
dest: /etc/motd
owner: root
mode: '0644'Run it:
# Dry run first — show what would change
ansible-playbook -i inventory/hosts.yml site.yml --check --diff
# Apply it
ansible-playbook -i inventory/hosts.yml site.ymlOutput ends with a per-host summary:
PLAY RECAP **********************************************************
web-01 : ok=4 changed=2 unreachable=0 failed=0
web-02 : ok=4 changed=2 unreachable=0 failed=0Read it as: ok = task ran successfully, changed = task actually modified the host, failed = real problems. A second ansible-playbook run should report 0 changed — that's idempotency in action.
The Workflow
# Reach out and check connectivity
ansible all -i inventory/hosts.yml -m ping
# Dry run with diff
ansible-playbook -i inventory/hosts.yml site.yml --check --diff
# Apply
ansible-playbook -i inventory/hosts.yml site.yml
# Apply to a subset
ansible-playbook -i inventory/hosts.yml site.yml --limit web-01
# Apply just tagged tasks
ansible-playbook -i inventory/hosts.yml site.yml --tags deployWhat's Next
You can configure a host with a playbook. Next, learn how Ansible's vocabulary really fits together — inventory groups, plays, tasks, modules, variables, facts → Core Concepts.