Most developers discover Ansible with a simple localhost example. It works, it’s clean, and everything feels predictable. Then comes the real task: running playbooks against remote hosts. That’s where things can either feel magical… or frustrating.
Let’s walk through how Ansible actually interacts with remote machines, how to set it up correctly, and what tends to break in real environments.
What “Remote Hosts” Really Means in Ansible
Ansible doesn’t require agents on remote machines. Instead, it connects over SSH (or WinRM for Windows). When you run a playbook, Ansible:
- Reads your inventory
- Connects to each host via SSH
- Executes tasks using temporary modules
- Returns results
This agentless model is simple, but it also means your SSH setup must be correct.
A Minimal Working Example
Let’s start with a basic inventory and playbook.
Inventory file (hosts.ini)
1[web]
2192.168.1.10
3192.168.1.11
4
5[db]
6192.168.1.20
7Playbook (setup.yml)
1- name: Configure web servers
2 hosts: web
3 become: true
4
5 tasks:
6 - name: Install nginx
7 apt:
8 name: nginx
9 state: present
10 update_cache: yes
11Run it with:
1ansible-playbook -i hosts.ini setup.ymlIf SSH access works, Ansible handles the rest.
SSH Configuration: Where Most Issues Start
A common mistake developers make is assuming Ansible manages authentication. It doesn’t. It relies entirely on your SSH setup.
You should aim for passwordless SSH:
1ssh-copy-id user@192.168.1.10Then test manually:
1ssh user@192.168.1.10If this fails, Ansible will fail too.
Defining SSH details in inventory
You can specify connection details per host:
1192.168.1.10 ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/id_rsaOr group-wide:
1[web:vars]
2ansible_user=ubuntu
3ansible_ssh_private_key_file=~/.ssh/id_rsaPrivilege Escalation (become)
Most remote tasks require elevated privileges. That’s where become comes in.
Instead of logging in as root, you typically:
- Connect as a normal user
- Escalate privileges using sudo
1- hosts: web
2 become: true
3If sudo requires a password, you can pass it with:
1ansible-playbook setup.yml --ask-become-passInventory Isn’t Just a List of IPs
Inventory becomes powerful when you structure it logically.
Example:
1[web]
2web1.example.com
3web2.example.com
4
5[db]
6db1.example.com
7
8[production:children]
9web
10db
11This allows you to:
- Target specific groups
- Apply different configurations
- Reuse playbooks across environments
You can then run:
1ansible-playbook -i hosts.ini setup.yml --limit webAd-hoc Commands Before Full Playbooks
Before running a full playbook, it’s smart to test connectivity.
1ansible all -i hosts.ini -m pingIf this fails, don’t bother debugging your playbook yet. Fix connectivity first.
Handling Different Environments
In real setups, you’ll have dev, staging, and production environments. Instead of duplicating playbooks, use separate inventory files:
1inventory/
2 dev.ini
3 staging.ini
4 prod.ini
5Run against a specific environment:
1ansible-playbook -i inventory/prod.ini setup.ymlThis keeps your automation consistent while adapting to different infrastructures.
Common Pitfalls (and How to Avoid Them)
1. SSH Works Manually but Not in Ansible
This often happens due to missing key configuration or incorrect user settings. Always define ansible_user explicitly if unsure.
2. Python Not Installed on Remote Hosts
Ansible requires Python on the target machine. Minimal OS images sometimes don’t include it.
Fix:
1ansible all -i hosts.ini -m raw -a "apt-get update && apt-get install -y python3"3. Permission Denied Errors
This is usually a sudo issue. Either:
- Enable passwordless sudo
- Use
--ask-become-pass
4. Host Key Checking Problems
For automation environments, you may want to disable strict host checking:
1export ANSIBLE_HOST_KEY_CHECKING=FalseUse this carefully in production.
A Slightly More Realistic Example
Let’s configure both web and database servers in one playbook:
1- name: Setup web servers
2 hosts: web
3 become: true
4
5 tasks:
6 - name: Install nginx
7 apt:
8 name: nginx
9 state: present
10
11- name: Setup database servers
12 hosts: db
13 become: true
14
15 tasks:
16 - name: Install PostgreSQL
17 apt:
18 name: postgresql
19 state: present
20Here’s where Ansible shines: one command, multiple systems, consistent results.
Performance Considerations
By default, Ansible runs tasks in parallel across hosts. You can control this using the forks setting:
1ansible-playbook setup.yml -f 10Higher values speed up execution but can overload your control machine or network.
Why This Approach Works Well in DevOps
Running Ansible playbooks against remote hosts gives you:
- Centralized control
- No agent maintenance
- Easy scaling across environments
- Repeatable infrastructure changes
It’s especially effective for provisioning servers, patching systems, and enforcing configuration consistency.
Closing Thought
Once your SSH and inventory are solid, Ansible becomes predictable. Most “Ansible problems” aren’t really Ansible problems—they’re environment or access issues.
Get connectivity right first, keep your inventory clean, and your playbooks will behave exactly the way you expect.