Posted on
Artificial Intelligence

Artificial Intelligence SSH Troubleshooting

Author
  • User
    linuxbash
    Posts by this author
    Posts by this author

AI-Assisted SSH Troubleshooting: Turn Noisy Logs Into Clear Fixes

Ever stared at 500 lines of ssh -vvv output at 2 a.m. and thought, “There must be a faster way”? Good news: artificial intelligence can help you make sense of SSH logs, pinpoint likely causes, and suggest concrete fixes—if you feed it the right evidence.

In this guide, you’ll learn a practical, reproducible workflow to:

  • Capture the right data from both client and server

  • Sanitize it safely

  • Ask an AI the right questions

  • Validate and implement fixes quickly

We’ll also cover real-world SSH failures and their reliable command-line remedies.


Why use AI for SSH troubleshooting?

  • SSH errors are terse and context-sensitive. The fix often depends on a small detail buried in verbose logs.

  • AI excels at pattern-matching across long logs, comparing error patterns against known failure modes.

  • The bottleneck isn’t “answers,” it’s input quality. Structured, sanitized evidence gets you useful responses.

Security note: Never paste secrets or private keys into any AI tool. Sanitize thoroughly and keep sensitive data local whenever possible.


Prerequisites: Install the core tools

You likely have some of these already. Install what’s missing using your package manager.

  • OpenSSH client and server

    • apt:
    sudo apt update
    sudo apt install -y openssh-client openssh-server
    
    • dnf:
    sudo dnf install -y openssh-clients openssh-server
    
    • zypper:
    sudo zypper install -y openssh
    
    • Start/enable server (if needed):
    # Debian/Ubuntu
    sudo systemctl enable --now ssh
    # RHEL/Fedora/SUSE
    sudo systemctl enable --now sshd
    
  • Network reachability tools (netcat + nmap)

    • apt:
    sudo apt install -y netcat-openbsd nmap
    
    • dnf:
    sudo dnf install -y nmap-ncat nmap
    
    • zypper:
    sudo zypper install -y netcat-openbsd nmap
    
  • Packet capture (optional but useful)

    • apt:
    sudo apt install -y tcpdump
    
    • dnf:
    sudo dnf install -y tcpdump
    
    • zypper:
    sudo zypper install -y tcpdump
    
  • SELinux tools (for SELinux-enabled servers)

    • apt:
    sudo apt install -y policycoreutils selinux-utils
    
    • dnf:
    sudo dnf install -y policycoreutils policycoreutils-python-utils
    
    • zypper:
    sudo zypper install -y policycoreutils
    
  • Firewall frontends (server-side; install what matches your distro)

    • apt (UFW):
    sudo apt install -y ufw
    
    • dnf (Firewalld):
    sudo dnf install -y firewalld
    sudo systemctl enable --now firewalld
    
    • zypper (Firewalld):
    sudo zypper install -y firewalld
    sudo systemctl enable --now firewalld
    

The AI-friendly troubleshooting workflow

1) Capture a clean, reproducible SSH attempt

From the client:

ssh -vvv -o ConnectTimeout=10 -o StrictHostKeyChecking=yes -o BatchMode=yes user@example.com -p 22 2>&1 | tee ssh_client_vvv.log

If you can access the server (console, IPMI, or alternative account), collect server-side logs:

Systemd-based:

# Debian/Ubuntu typically uses 'ssh', RHEL/Fedora 'sshd' (try both)
sudo journalctl -u ssh -n 300 --no-pager > sshd_journal.log || true
sudo journalctl -u sshd -n 300 --no-pager >> sshd_journal.log || true

Non-systemd or extra context:

# Debian/Ubuntu auth log
sudo tail -n 300 /var/log/auth.log > sshd_authlog.log 2>/dev/null || true

# RHEL/Fedora/CentOS auth log
sudo tail -n 300 /var/log/secure > sshd_secure.log 2>/dev/null || true

Network reachability checks (client-side):

nc -vz example.com 22
nmap -Pn -p 22 example.com

Service/listening socket (server-side):

sudo ss -tlnp | grep -E ':(22|2222)\s'
sudo grep -nE '^(Port|ListenAddress|PermitRootLogin|PasswordAuthentication|PubkeyAuthentication|KexAlgorithms|HostKeyAlgorithms|PubkeyAcceptedKeyTypes|Match)\b' /etc/ssh/sshd_config

2) Sanitize before sharing with any AI

Remove secrets, private keys, tokens, and internal-only details. Examples:

# Strip likely base64-like blobs (public keys, tokens)
sed -i -E 's/[A-Za-z0-9+\/=]{24,}/[REDACTED]/g' ssh_client_vvv.log

# Mask IPs/hostnames (customize your patterns)
sed -i -E 's/([0-9]{1,3}\.){3}[0-9]{1,3}/[IP]/g' ssh_client_vvv.log
sed -i -E 's/\b([a-zA-Z0-9._-]+\.)+[a-zA-Z]{2,}\b/[HOST]/g' ssh_client_vvv.log

# Mask usernames
sed -i -E 's/\buser@example.com\b/user@[HOST]/g' ssh_client_vvv.log
sed -i -E 's/\buser\b/[USER]/g' ssh_client_vvv.log

Do not ever paste from ~/.ssh/id_* private keys. Public keys are usually fine but still consider redaction.

3) Ask the AI precise, testable questions

Give it structure:

Context:

- Client OS/SSH: Ubuntu 22.04, OpenSSH_8.9p1

- Server OS/SSH: RHEL 9, OpenSSH_8.7p1

- Network: Port 22, public IP, corporate firewall present

- What changed: Upgraded client yesterday, same server

Goal:

- Explain why auth fails and list the top 3 likely causes with commands to confirm/refute each.

Artifacts:

- Key client log lines:
  <paste a few lines around the actual error from ssh_client_vvv.log>

- Key server log lines (if any):
  <paste from sshd_journal.log or /var/log/auth.log>

- Reachability:
  nc/nmap results summarized

This structure nudges the AI to give you hypotheses plus concrete commands to validate them.

4) Validate AI suggestions deterministically

Whatever the AI proposes, run the simplest commands to confirm or deny. Examples:

# Check file permissions (client and server user)
ls -ld ~/.ssh && ls -l ~/.ssh
# Should be:
# ~/.ssh -> 700
# private keys -> 600
# authorized_keys -> 600
# *.pub -> 644

# Server is listening on expected port(s)
sudo ss -tlnp | grep sshd

# Firewall status
sudo ufw status verbose 2>/dev/null || true
sudo firewall-cmd --state 2>/dev/null || true

# Algorithm availability
ssh -Q key | head
ssh -Q kex | head

5) Automate your triage (script you can paste into a ticket)

Save this as ssh-triage.sh on the client:

#!/usr/bin/env bash
set -euo pipefail

HOST="${1:-}"
PORT="${2:-22}"
USER="${3:-$USER}"

if [[ -z "$HOST" ]]; then
  echo "Usage: $0 <host> [port] [user]" >&2
  exit 1
fi

STAMP="$(date +%Y%m%d_%H%M%S)"
OUTDIR="ssh_triage_${HOST}_${STAMP}"
mkdir -p "$OUTDIR"

# Client-side attempt
ssh -vvv -o ConnectTimeout=10 -o BatchMode=yes -p "$PORT" "${USER}@${HOST}" 2>&1 | tee "$OUTDIR/client_ssh_vvv.log" || true

# Reachability
{
  echo "=== nc -vz ${HOST} ${PORT} ==="
  nc -vz "$HOST" "$PORT" 2>&1 || true
  echo
  echo "=== nmap -Pn -p ${PORT} ${HOST} ==="
  nmap -Pn -p "$PORT" "$HOST" 2>&1 || true
} | tee "$OUTDIR/reachability.log"

# Basic env
{
  echo "=== ssh -V ==="
  ssh -V 2>&1
  echo
  echo "=== uname -a ==="
  uname -a
} | tee "$OUTDIR/client_env.log"

# Redact likely secrets
for f in "$OUTDIR"/*.log; do
  sed -i -E 's/[A-Za-z0-9+\/=]{24,}/[REDACTED]/g' "$f"
  sed -i -E 's/([0-9]{1,3}\.){3}[0-9]{1,3}/[IP]/g' "$f"
done

echo "Triage bundle ready in: $OUTDIR"
echo "Next: Copy only the relevant error lines into your AI prompt (avoid sensitive data)."

Make it executable:

chmod +x ssh-triage.sh

Real-world examples (and solid fixes)

1) Connection timed out / refused

Symptoms:

  • nc -vz example.com 22 times out or refuses

  • nmap -Pn -p 22 example.com shows filtered/closed

Checks and fixes:

# On the server, ensure sshd is running
sudo systemctl status sshd || sudo systemctl status ssh

# Open the firewall
# UFW (Debian/Ubuntu)
sudo ufw allow 22/tcp
sudo ufw reload

# firewalld (RHEL/Fedora/SUSE)
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload

# Confirm listening
sudo ss -tlnp | grep ':22'

If using a non-standard port (e.g., 2222), update the firewall accordingly and ensure your SSH command uses -p 2222.

2) WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!

Cause: The server’s host key changed (legit reimage) or a possible MITM attack.

Safe resolution steps:

  • Out-of-band verify the server rebuild/change with your team.

  • If verified legit:

    ssh-keygen -R example.com
    ssh-keyscan -H example.com >> ~/.ssh/known_hosts
    
  • If unverified: stop and investigate.

3) Permission denied (publickey)

Likely causes:

  • Wrong key used, ssh-agent offering too many keys, or wrong file permissions

  • Server-side authorized_keys missing/wrong ownership

  • SELinux context on ~/.ssh incorrect (on SELinux systems)

Fix checklist:

# Client: force a specific key and prevent agent spam
ssh -i ~/.ssh/id_ed25519 -o IdentitiesOnly=yes user@example.com

# Client: fix perms
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_* ~/.ssh/authorized_keys 2>/dev/null || true
chmod 644 ~/.ssh/*.pub 2>/dev/null || true

# Server: correct ownership and perms
sudo chown -R user:user ~user/.ssh
sudo chmod 700 ~user/.ssh
sudo chmod 600 ~user/.ssh/authorized_keys

# Server: restore SELinux context (if enabled)
sudo restorecon -Rv ~user/.ssh

Also confirm:

# Server sshd_config critical lines
sudo grep -E '^(PubkeyAuthentication|PasswordAuthentication|AuthorizedKeysFile|Match)\b' /etc/ssh/sshd_config

# Restart sshd after changes
sudo systemctl restart sshd || sudo systemctl restart ssh

4) No matching host key type / No matching key exchange method

Cause: Algorithm mismatch, often after OpenSSH deprecations (e.g., ssh-rsa SHA-1 signatures disabled in newer clients).

Quick workaround for a known legacy target:

# ~/.ssh/config
Host legacy-host
    HostName example.com
    User root
    HostKeyAlgorithms +ssh-rsa
    PubkeyAcceptedKeyTypes +ssh-rsa

Long-term fix: upgrade the legacy server/client to support modern algorithms. At minimum, prefer ed25519 keys:

ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_ed25519

5) Too many authentication failures

Cause: ssh-agent offering many keys; server rejects before trying the right one.

Fix:

ssh-add -l            # See loaded keys
ssh-add -D            # Remove all keys
ssh -i ~/.ssh/id_ed25519 -o IdentitiesOnly=yes user@example.com

Or limit keys per host in ~/.ssh/config:

Host myhost
    HostName example.com
    User user
    IdentitiesOnly yes
    IdentityFile ~/.ssh/id_ed25519

Pro tips for using AI effectively (and safely)

  • Minimize and focus: paste only the error lines around the failure, plus a short environment summary.

  • Keep sensitive data out: redact usernames, IPs, domains, and any token-looking strings.

  • Ask for hypotheses and verification commands; then run them yourself.

  • Convert a validated fix into a script or Ansible task so you never repeat the same manual steps.


Conclusion and next steps

AI won’t replace your Bash skills—but it will save you time by turning messy SSH logs into targeted, testable leads. Adopt the triage workflow above, keep a sanitized evidence bundle ready, and make AI your log-reading assistant while you stay in control of the commands and changes.

Call to action:

  • Drop the ssh-triage.sh script into your toolbox and use it on your next SSH issue.

  • Build a team runbook with the real-world checks above.

  • Iterate: each solved case becomes a faster fix next time.

Got a tricky SSH failure pattern? Feed it through this workflow and watch your mean-time-to-fix shrink.