You're running your playbook and suddenly hit that dreaded red error message: FAILED! => {"unreachable": true}. The playbook grinds to a halt, and you're left wondering whether it's a network issue, SSH configuration problem, or something else entirely.
Let's walk through diagnosing and fixing this step by step.
Understanding the Error
When Ansible reports a host as unreachable, it means the control node cannot establish a connection to the target host. The error typically looks like this:
TASK [Gather Facts] ***********************************************************
fatal: [webserver01]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: connect to host 192.168.1.100 port 22: Connection refused", "unreachable": true}The key information is buried in that error message. In this case, Connection refused tells us SSH isn't running or the port is wrong. Other common messages include Connection timed out, No route to host, or Host key verification failed.
Step 1: Verify Basic Network Connectivity
Before diving into Ansible specifics, confirm the host is reachable:
ping -c 3 192.168.1.100If ping fails with Destination Host Unreachable or times out, you have a network-level issue. Check your routing, firewall rules, or VPN connection.
If ping works but Ansible fails, the issue is likely SSH-specific.
Step 2: Test SSH Manually
Try connecting with SSH directly using the same credentials Ansible would use:
ssh ansible_user@192.168.1.100If you use a specific SSH key:
ssh -i ~/.ssh/ansible_key ansible_user@192.168.1.100Common issues you'll encounter:
Connection refused:
``bash
# Check if SSH service is running on the target
ssh webserver01 'systemctl status sshd'
# Or if you can access the host directly
systemctl status sshd
sudo systemctl start sshd
Permission denied: The user doesn't have SSH access or the key is wrong. Verify the key is in the authorized_keys file:
ssh webserver01 'cat ~/.ssh/authorized_keys'Host key verification failed: Add the host to known_hosts:
ssh-keyscan -H 192.168.1.100 >> ~/.ssh/known_hostsStep 3: Verify Ansible Inventory Configuration
Check your inventory file for correct connection parameters:
ansible-inventory -i inventory --list | grep -A 10 "webserver01"Your inventory should specify the correct details:
[webservers]
webserver01 ansible_host=192.168.1.100 ansible_user=deploy ansible_port=22Common inventory mistakes:
- Wrong IP address or hostname
- Incorrect SSH port (some servers use 2222 or other non-standard ports)
- Missing or wrong username
Step 4: Use Ansible's Verbose Mode for Details
Run your playbook with increased verbosity to see the full SSH command and error:
ansible webserver01 -i inventory -m ping -vvvThe -vvv flag shows you exactly what Ansible is trying to do:
<192.168.1.100> ESTABLISH SSH CONNECTION FOR USER: deploy
<192.168.1.100> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/user/.ansible/cp/ansible-ssh-%h-%p-%r -o StrictHostKeyChecking=no 192.168.1.100 '/bin/sh -c '"'"'echo ~deploy && sleep 0'"'"''This reveals exactly what options Ansible is passing to SSH. Look for issues like wrong user, timeout values, or authentication methods.
Step 5: Check SSH Config Conflicts
Your local ~/.ssh/config file might interfere with Ansible's settings. Check for entries matching your target hosts:
cat ~/.ssh/config | grep -A 5 "webserver01"If you have conflicting settings, either fix the config file or tell Ansible to use a different SSH config:
export ANSIBLE_SSH_ARGS="-F /dev/null"
ansible webserver01 -i inventory -m pingStep 6: Verify SSH Key Permissions
SSH is picky about key file permissions. Check them:
ls -la ~/.ssh/ansible_keyCorrect permissions:
- Private key: 600 (read/write for owner only)
- Public key: 644
- Directory: 700
Fix with:
chmod 600 ~/.ssh/ansible_key
chmod 644 ~/.ssh/ansible_key.pub
chmod 700 ~/.sshStep 7: Check for Python Issues
Even if SSH works, Ansible needs Python on the target. Test this:
ansible webserver01 -i inventory -m raw -a "python3 --version"If Python isn't installed or not in the expected path, specify it in your inventory:
webserver01 ansible_host=192.168.1.100 ansible_python_interpreter=/usr/bin/python3Step 8: Handle Firewall Issues
If SSH works but Ansible can't execute commands, a firewall might be blocking outbound traffic from the target. Check firewall rules on the target:
ssh webserver01 'sudo iptables -L -n'Or for firewalld:
ssh webserver01 'sudo firewall-cmd --list-all'Quick Verification
After making fixes, verify connectivity:
ansible webserver01 -i inventory -m pingExpected output:
webserver01 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}Prevention Tips
Add these to your ansible.cfg to prevent common issues:
```ini [defaults] host_key_checking = False timeout = 30 retry_files_enabled = False
[ssh_connection] ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o ConnectTimeout=30 pipelining = True ```
The unreachable host error is frustrating but methodical troubleshooting almost always reveals the root cause. Start with network connectivity, verify SSH manually, then check Ansible-specific configuration. The verbose output is your best friend for spotting the actual issue.