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:

bash
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:

bash
ping -c 3 192.168.1.100

If 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:

bash
ssh ansible_user@192.168.1.100

If you use a specific SSH key:

bash
ssh -i ~/.ssh/ansible_key ansible_user@192.168.1.100

Common 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:

bash
ssh webserver01 'cat ~/.ssh/authorized_keys'

Host key verification failed: Add the host to known_hosts:

bash
ssh-keyscan -H 192.168.1.100 >> ~/.ssh/known_hosts

Step 3: Verify Ansible Inventory Configuration

Check your inventory file for correct connection parameters:

bash
ansible-inventory -i inventory --list | grep -A 10 "webserver01"

Your inventory should specify the correct details:

ini
[webservers]
webserver01 ansible_host=192.168.1.100 ansible_user=deploy ansible_port=22

Common 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:

bash
ansible webserver01 -i inventory -m ping -vvv

The -vvv flag shows you exactly what Ansible is trying to do:

bash
<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:

bash
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:

bash
export ANSIBLE_SSH_ARGS="-F /dev/null"
ansible webserver01 -i inventory -m ping

Step 6: Verify SSH Key Permissions

SSH is picky about key file permissions. Check them:

bash
ls -la ~/.ssh/ansible_key

Correct permissions: - Private key: 600 (read/write for owner only) - Public key: 644 - Directory: 700

Fix with:

bash
chmod 600 ~/.ssh/ansible_key
chmod 644 ~/.ssh/ansible_key.pub
chmod 700 ~/.ssh

Step 7: Check for Python Issues

Even if SSH works, Ansible needs Python on the target. Test this:

bash
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:

ini
webserver01 ansible_host=192.168.1.100 ansible_python_interpreter=/usr/bin/python3

Step 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:

bash
ssh webserver01 'sudo iptables -L -n'

Or for firewalld:

bash
ssh webserver01 'sudo firewall-cmd --list-all'

Quick Verification

After making fixes, verify connectivity:

bash
ansible webserver01 -i inventory -m ping

Expected output:

bash
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.