You run your playbook and watch it fail immediately with "unreachable" or "connection refused" errors. Ansible relies on SSH to communicate with remote hosts, and when that connection breaks, nothing else matters.

The Error

bash
fatal: [webserver]: UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: ssh: connect to host 192.168.1.50 port 22: Connection refused",
    "unreachable": true
}

Or you might see:

bash
fatal: [webserver]: UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: Permission denied (publickey,password).",
    "unreachable": true
}

Quick Diagnosis

First, verify basic connectivity:

```bash # Test raw SSH connection ssh user@192.168.1.50

# Test with verbose output ssh -vvv user@192.168.1.50

# Check if the host is reachable at all ping -c 3 192.168.1.50 ```

If SSH works manually but Ansible fails, the issue is in your Ansible configuration.

Check Ansible Inventory

Verify your inventory has the correct connection parameters:

```bash # List hosts and their variables ansible-inventory --list -y

# Show host-specific connection details ansible-inventory --host webserver ```

Your inventory should specify the correct SSH user and port:

ini
[webservers]
webserver ansible_host=192.168.1.50 ansible_user=deploy ansible_port=2222

Or in YAML format:

yaml
webservers:
  hosts:
    webserver:
      ansible_host: 192.168.1.50
      ansible_user: deploy
      ansible_port: 2222

Common Causes and Fixes

Wrong SSH User

Ansible defaults to connecting as the current user. If your remote user differs:

```bash # Specify user on command line ansible-playbook site.yml -u deploy

# Or in inventory webserver ansible_user=deploy ```

SSH Key Not Loaded

Your SSH key might not be in the agent or accessible:

```bash # List loaded keys ssh-add -l

# Add your key ssh-add ~/.ssh/id_rsa

# Test connection again ansible webserver -m ping ```

Custom SSH Key Path

If you use a non-default key:

ini
[webservers]
webserver ansible_ssh_private_key_file=/home/user/.ssh/deploy_key

Or pass it directly:

bash
ansible-playbook site.yml --private-key=~/.ssh/deploy_key

SSH Host Key Verification

First connection to a new host fails with:

bash
Host key verification failed.

Either accept the key manually:

bash
ssh user@webserver
# Type 'yes' to accept

Or disable checking in ansible.cfg (not recommended for production):

ini
[defaults]
host_key_checking = False

Firewall Blocking SSH

Check if SSH port is accessible:

```bash # Test port connectivity nc -zv 192.168.1.50 22

# Or use telnet telnet 192.168.1.50 22 ```

If blocked, you need firewall access on the target host.

SSH Service Not Running

On the target host:

```bash # Check SSH service status systemctl status sshd # or systemctl status ssh

# Start if not running sudo systemctl start sshd

# Enable on boot sudo systemctl enable sshd ```

Password Authentication Required

If key auth fails and password is required:

```bash # Use password authentication ansible-playbook site.yml --ask-pass

# Or store password (not recommended for security) ansible-playbook site.yml -e "ansible_password=yourpassword" ```

For better security, use SSH keys or Ansible Vault for passwords.

Ansible-Specific SSH Configuration

Create ansible.cfg in your project:

```ini [defaults] inventory = ./inventory remote_user = deploy private_key_file = ~/.ssh/id_rsa host_key_checking = accept_new

[ssh_connection] ssh_args = -o ControlMaster=auto -o ControlPersist=60s pipelining = True ```

The pipelining option significantly speeds up SSH operations by reducing connection overhead.

Verification

Run the simplest possible test:

bash
ansible webserver -m ping -u deploy

Expected output:

bash
webserver | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}

Then verify with a command:

bash
ansible webserver -a "uptime"

Debug Mode

For persistent issues, enable maximum verbosity:

bash
ansible-playbook site.yml -vvvv

Four v's shows the full SSH command being executed, including all arguments. This reveals exactly what Ansible is trying to do.

Quick Checklist

  1. 1.Can you SSH manually? ssh user@host
  2. 2.Is the inventory correct? ansible-inventory --list
  3. 3.Is your SSH key loaded? ssh-add -l
  4. 4.Is SSH running on target? systemctl status sshd
  5. 5.Is the firewall open? nc -zv host 22