What's Actually Happening
SSH connection to Azure Virtual Machine fails. Cannot access VM remotely, connection times out or is refused.
The Error You'll See
```bash $ ssh azureuser@vm-ip
ssh: connect to host vm-ip port 22: Connection refused ```
Connection timeout:
```bash $ ssh azureuser@vm-ip
ssh: connect to host vm-ip port 22: Connection timed out ```
Authentication failed:
```bash $ ssh azureuser@vm-ip
Permission denied (publickey) ```
VM unreachable:
```bash $ ping vm-ip
Destination unreachable ```
Why This Happens
- 1.VM not running - VM is stopped or deallocated
- 2.NSG blocking SSH - Network Security Group doesn't allow port 22
- 3.SSH not installed - SSH service not running on VM
- 4.Wrong credentials - Incorrect username or SSH key
- 5.Public IP missing - VM doesn't have public IP assigned
- 6.Firewall blocking - Azure or VM firewall blocking SSH
Step 1: Check VM Status
```bash # Check VM status with Azure CLI: az vm show --name myVM --resource-group myRG --query powerState -o tsv
# Should show: VM running # Other states: VM deallocated/stopped, VM stopped
# Check VM details: az vm show --name myVM --resource-group myRG
# List all VMs: az vm list --output table
# Check VM instance view: az vm get-instance-view --name myVM --resource-group myRG
# Start VM if stopped: az vm start --name myVM --resource-group myRG
# Or via Azure Portal: # Virtual Machines -> myVM -> Start
# Check VM availability: az vm list --query "[?name=='myVM'].{Name:name, PowerState:powerState}" -o table ```
Step 2: Check Public IP Address
```bash # Get VM public IP: az vm list-ip-addresses --name myVM --resource-group myRG -o table
# Or: az vm show --name myVM --resource-group myRG --query "publicIps" -o tsv
# Check IP configuration: az network public-ip show --name myPublicIP --resource-group myRG
# Check if IP is static or dynamic: az network public-ip show --name myPublicIP --resource-group myRG --query publicIpAllocationMethod -o tsv
# Verify IP is assigned: az network public-ip show --name myPublicIP --resource-group myRG --query ipAddress -o tsv
# Create public IP if missing: az network public-ip create --name myPublicIP --resource-group myRG
# Attach to VM: az network nic update --name myNic --resource-group myRG --public-ip-address myPublicIP ```
Step 3: Check Network Security Group
```bash # Check NSG associated with VM: az vm show --name myVM --resource-group myRG --query "networkProfile.networkInterfaces[0].networkSecurityGroup.id" -o tsv
# List NSG rules: az network nsg rule list --nsg-name myNSG --resource-group myRG -o table
# Check SSH rule (port 22): az network nsg rule show --nsg-name myNSG --resource-group myRG --name AllowSSH
# Create SSH rule if missing: az network nsg rule create \ --nsg-name myNSG \ --resource-group myRG \ --name AllowSSH \ --protocol Tcp \ --direction Inbound \ --priority 100 \ --source-address-prefix '*' \ --source-port-range '*' \ --destination-address-prefix '*' \ --destination-port-range 22 \ --access Allow
# Or in Azure Portal: # Networking -> Add inbound port rule -> SSH (22)
# Check effective security rules: az vm list-effective-nsg-rules --name myVM --resource-group myRG -o table ```
Step 4: Check SSH Service on VM
```bash # If VM accessible via serial console: # Azure Portal -> Support + Troubleshooting -> Serial console
# In serial console: # Check SSH service: sudo systemctl status sshd sudo systemctl status ssh
# If not running: sudo systemctl start sshd
# Check SSH config: sudo cat /etc/ssh/sshd_config
# Check SSH port: sudo grep Port /etc/ssh/sshd_config
# If port changed, update NSG rule
# Check SSH is installed: dpkg -l | grep openssh-server # Ubuntu/Debian rpm -qa | grep openssh-server # RHEL/CentOS
# Install SSH if missing: sudo apt install openssh-server # Ubuntu sudo yum install openssh-server # RHEL/CentOS
# Enable SSH: sudo systemctl enable sshd sudo systemctl start sshd ```
Step 5: Check SSH Key Authentication
```bash # Check authorized keys on VM: # Via serial console: sudo cat /home/azureuser/.ssh/authorized_keys
# Check SSH key exists locally: ls ~/.ssh/id_rsa.pub ls ~/.ssh/id_rsa
# Generate SSH key if missing: ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa
# Add key to VM: # Via Azure CLI: az vm user update --name myVM --resource-group myRG --username azureuser --ssh-key-value ~/.ssh/id_rsa.pub
# Or reset SSH key: az vm user reset-ssh --name myVM --resource-group myRG --username azureuser --ssh-key-value ~/.ssh/id_rsa.pub
# Or via Portal: # Reset Password -> Reset SSH public key
# Test connection: ssh -i ~/.ssh/id_rsa azureuser@vm-ip
# Use verbose mode: ssh -vvv azureuser@vm-ip ```
Step 6: Check Network Connectivity
```bash # Test ping: ping vm-ip
# Test port 22: nc -zv vm-ip 22 telnet vm-ip 22
# Check from different location: # Use Azure Network Watcher: az network watcher connectivity-check \ --source-resource vm-source \ --dest-resource vm-dest \ --dest-port 22
# Check IP flow: az network watcher run-configuration-diagnostic \ --resource myVM \ --resource-group myRG \ --direction Inbound \ --protocol TCP \ --source-ip 10.0.0.1 \ --destination-ip vm-ip \ --destination-port 22
# Use Azure Network Watcher IP flow verify: # Azure Portal -> Network Watcher -> IP flow verify
# Check routing: az network watcher show-next-hop \ --resource-group myRG \ --source-ip 10.0.0.1 \ --destination-ip vm-ip \ --vm-name myVM
# Traceroute: traceroute vm-ip ```
Step 7: Reset SSH Configuration
```bash # Reset SSH via Azure CLI: az vm reset-ssh --name myVM --resource-group myRG
# Or via Portal: # Support + Troubleshooting -> Reset password -> Reset configuration only
# Reset SSH extension: az vm extension set \ --name VMAccessForLinux \ --publisher Microsoft.OSTCExtensions \ --vm-name myVM \ --resource-group myRG \ --settings '{"reset_ssh": true}'
# Reset specific user: az vm user reset-ssh \ --name myVM \ --resource-group myRG \ --username azureuser
# After reset, wait 2-3 minutes # Then try SSH again ```
Step 8: Check VM Firewall
```bash # Check iptables on VM: # Via serial console: sudo iptables -L -n
# Check if SSH blocked: sudo iptables -L -n | grep 22
# Allow SSH through iptables: sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# Or flush rules (careful!): sudo iptables -F
# Check firewalld (RHEL/CentOS): sudo firewall-cmd --list-all
# Allow SSH: sudo firewall-cmd --add-service=ssh --permanent sudo firewall-cmd --reload
# Check UFW (Ubuntu): sudo ufw status
# Allow SSH: sudo ufw allow ssh sudo ufw allow 22/tcp
# Disable UFW temporarily: sudo ufw disable ```
Step 9: Use Serial Console Access
```bash # Azure Serial Console provides direct access: # Azure Portal -> VM -> Support + troubleshooting -> Serial console
# Wait for login prompt: # Login with: # Username: azureuser # Password: (if password auth enabled)
# Or use root if configured
# In serial console:
# Check network: sudo ip addr show
# Check SSH: sudo systemctl status sshd
# Check logs: sudo journalctl -u sshd -f sudo tail -f /var/log/auth.log
# Fix SSH config: sudo nano /etc/ssh/sshd_config
# Restart SSH: sudo systemctl restart sshd
# Check authorized_keys: sudo cat /home/azureuser/.ssh/authorized_keys ```
Step 10: Azure SSH Verification Script
```bash # Create verification script: cat << 'EOF' > /usr/local/bin/check-azure-ssh.sh #!/bin/bash
VM_NAME=$1 RG_NAME=$2
if [ -z "$VM_NAME" ] || [ -z "$RG_NAME" ]; then echo "Usage: $0 vm-name resource-group" exit 1 fi
echo "=== VM Status ===" az vm show --name $VM_NAME --resource-group $RG_NAME --query powerState -o tsv
echo "" echo "=== VM Public IP ===" az vm list-ip-addresses --name $VM_NAME --resource-group $RG_NAME --query "[0].virtualMachine.network.publicIpAddresses[0].ipAddress" -o tsv
echo "" echo "=== Network Security Group Rules ===" NSG=$(az vm show --name $VM_NAME --resource-group $RG_NAME --query "networkProfile.networkInterfaces[0].networkSecurityGroup.id" -o tsv | cut -d'/' -f9) if [ -n "$NSG" ]; then az network nsg rule list --nsg-name $NSG --resource-group $RG_NAME --query "[?destinationPortRange=='22']" -o table else echo "No NSG attached" fi
echo "" echo "=== SSH Key for User ===" az vm show --name $VM_NAME --resource-group $RG_NAME --query "osProfile.adminUsername" -o tsv echo "Key configured via VM access extension"
echo "" echo "=== Connectivity Test ===" IP=$(az vm list-ip-addresses --name $VM_NAME --resource-group $RG_NAME --query "[0].virtualMachine.network.publicIpAddresses[0].ipAddress" -o tsv) if [ -n "$IP" ]; then echo "Testing SSH port 22 on $IP..." timeout 5 nc -zv $IP 22 2>&1 || echo "Connection failed" else echo "No public IP found" fi
echo "" echo "=== Recommendations ===" echo "1. Ensure VM is running" echo "2. Check NSG allows port 22" echo "3. Verify SSH key is correct" echo "4. Use serial console for internal checks" echo "5. Reset SSH if configuration corrupted" EOF
chmod +x /usr/local/bin/check-azure-ssh.sh
# Usage: /usr/local/bin/check-azure-ssh.sh myVM myRG
# Quick test: alias azure-vm-ssh='ssh -vvv azureuser@' ```
Azure SSH Checklist
| Check | Command | Expected |
|---|---|---|
| VM running | az vm show powerState | VM running |
| Public IP | az vm list-ip-addresses | IP assigned |
| NSG SSH rule | az network nsg rule list | Allow port 22 |
| SSH key | az vm user update | Key added |
| SSH service | systemctl status sshd | Running |
| Network connectivity | nc -zv vm-ip 22 | Connected |
Verify the Fix
```bash # After fixing SSH issue
# 1. Check VM running az vm show --name myVM --resource-group myRG --query powerState -o tsv // VM running
# 2. Get public IP az vm list-ip-addresses --name myVM --resource-group myRG // IP returned
# 3. Test port 22 nc -zv vm-ip 22 // Connected
# 4. SSH connect ssh -i ~/.ssh/id_rsa azureuser@vm-ip // Connected successfully
# 5. Verify in VM sudo systemctl status sshd // Active running
# 6. Check authorized_keys cat ~/.ssh/authorized_keys // Contains your key ```
Related Issues
- [Fix Azure VM Cannot Connect](/articles/fix-azure-vm-cannot-connect)
- [Fix SSH Connection Refused](/articles/fix-ssh-connection-refused)
- [Fix SSH Key Permission Denied](/articles/fix-ssh-key-permission-denied)