DevOpsil
Ansible
86%
Needs Review

Fix Ansible 'Unreachable' Host Errors

Riku TanakaRiku Tanaka4 min read

The Error: Host Unreachable

Your Ansible playbook fails with:

fatal: [web-server-01]: UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh:
    ssh: connect to host 10.0.1.50 port 22: Connection timed out",
    "unreachable": true
}

Or with a different variant:

fatal: [web-server-01]: UNREACHABLE! => {
    "msg": "Failed to connect to the host via ssh:
    Permission denied (publickey,gssapi-keyex,gssapi-with-mic)"
}

Ansible cannot establish an SSH connection to the target host.

Root Cause

The UNREACHABLE error is a transport-layer failure, not an Ansible module failure. It means SSH itself cannot connect. Common causes:

  1. Host is down or unreachable — wrong IP, firewall blocking port 22, or host is offline
  2. SSH key authentication fails — wrong key, key not added to authorized_keys, or agent not running
  3. Wrong username — Ansible is connecting as the wrong user
  4. SSH host key changed — the host was rebuilt and the old key is in known_hosts
  5. Python missing on the target — Ansible needs Python on the remote host to execute modules

Step-by-Step Fix

1. Test raw SSH connectivity

# Test from the Ansible control node
ssh -v -i ~/.ssh/id_rsa [email protected]

# Test with the exact settings Ansible would use
ansible web-server-01 -m ping -vvvv

The -vvvv flag shows the full SSH command Ansible constructs, including which key, user, and port it uses.

2. Verify host is reachable on the network

# Check basic connectivity
ping -c 3 10.0.1.50

# Check if SSH port is open
nc -zv 10.0.1.50 22
# or
nmap -p 22 10.0.1.50

If the port is filtered, check firewall rules on the target:

# On the target (if accessible via console)
sudo iptables -L -n | grep 22
sudo ufw status
sudo firewall-cmd --list-all

3. Fix SSH key authentication

# Verify the key file exists and has correct permissions
ls -la ~/.ssh/id_rsa
# Must be -rw------- (600)

chmod 600 ~/.ssh/id_rsa

# Ensure the public key is on the target
ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]

# Check the SSH agent has the key loaded
ssh-add -l
ssh-add ~/.ssh/id_rsa

4. Check your Ansible inventory and variables

# Show how Ansible resolves connection vars for a host
ansible-inventory --host web-server-01

Verify these variables in your inventory:

[webservers]
web-server-01 ansible_host=10.0.1.50 ansible_user=deploy ansible_ssh_private_key_file=~/.ssh/id_rsa

Or in group_vars/all.yml:

ansible_user: deploy
ansible_ssh_private_key_file: ~/.ssh/id_rsa
ansible_port: 22

5. Fix host key verification failures

If the target was rebuilt and has a new host key:

# Remove the old key
ssh-keygen -R 10.0.1.50

# Or for a hostname
ssh-keygen -R web-server-01

To disable host key checking (only in dev/CI):

# ansible.cfg
[defaults]
host_key_checking = False

6. Fix missing Python on the target

fatal: [web-server-01]: FAILED! => {
    "msg": "/usr/bin/python: No such file or directory"
}

Set the Python interpreter explicitly:

# Inventory
web-server-01 ansible_python_interpreter=/usr/bin/python3

Or use the raw module to install Python first:

- name: Bootstrap Python on fresh hosts
  hosts: new_servers
  gather_facts: false
  tasks:
    - name: Install Python
      raw: apt-get update && apt-get install -y python3
      become: true

7. Increase connection timeout

For slow networks or cloud instances that take time to boot:

# ansible.cfg
[defaults]
timeout = 30

[ssh_connection]
ssh_args = -o ConnectTimeout=30 -o ConnectionAttempts=3

Prevention Tips

  • Use ansible -m ping as a smoke test before running playbooks to catch connectivity issues early.
  • Standardize SSH configuration across all managed hosts — same user, same key, same Python path.
  • Set ansible_python_interpreter = auto in modern Ansible (2.12+) to auto-detect Python.
  • Use SSH multiplexing in ansible.cfg for faster connections:
    [ssh_connection]
    pipelining = True
    ssh_args = -o ControlMaster=auto -o ControlPersist=60s
    
  • Test inventory changes in a dry run (--check) before applying playbooks to production.
Share:

Was this article helpful?

Riku Tanaka
Riku Tanaka

SRE & Observability Engineer

If it's not measured, it doesn't exist. SLO-driven, metrics-obsessed, and the person who gets paged at 3 AM so you don't have to. Observability isn't optional.

Related Articles

More in Ansible

View all →

Discussion