SSH connections are notoriously brittle, and trying to automate them with Bash scripts often feels like wrestling an octopus.

Here’s how to make SSH play nice with your automation goals.

First, you need to get past the password prompt. The standard, and most secure, way to do this is with SSH keys.

ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

This command generates a public and private key pair. The public key (~/.ssh/id_rsa.pub by default) is what you’ll copy to the remote server. The private key (~/.ssh/id_rsa) stays on your local machine and should be kept secret.

To copy the public key to the remote server, use ssh-copy-id:

ssh-copy-id user@remote_host

This command appends your public key to the ~/.ssh/authorized_keys file on the remote_host for the specified user. If it prompts for a password, you’re still in a manual step. The goal is passwordless login. Once this is done, you should be able to ssh user@remote_host without a password.

Now, you can execute commands remotely:

ssh user@remote_host 'ls -l /var/log'

This will log into remote_host as user, run ls -l /var/log, print the output to your local terminal, and then disconnect.

For more complex tasks, you’ll want to script these remote commands. Let’s say you want to check disk usage on multiple servers.

#!/bin/bash

SERVERS=("server1.example.com" "server2.example.com" "server3.example.com")
USER="admin"

for server in "${SERVERS[@]}"; do
  echo "--- Disk usage on $server ---"
  ssh "$USER@$server" 'df -h /'
  echo ""
done

This script iterates through a list of servers, and for each one, it SSHes in and runs df -h / to check the root filesystem usage. The "${SERVERS[@]}" syntax ensures that if any server names had spaces (which they shouldn’t, but as an example), they’d be handled correctly.

A common pitfall is dealing with interactive prompts on the remote server. If a command you’re running remotely expects user input, ssh will hang, or the script will fail.

Consider a scenario where you need to restart a service that prompts for confirmation:

# This will likely hang!
# ssh user@remote_host 'sudo systemctl restart apache2'

To avoid this, many commands have non-interactive options. For systemctl, you often don’t need a confirmation. If you did, you might need to pipe yes to it, though this is generally discouraged for security reasons. A better approach is to use commands that inherently support non-interactive execution.

For example, if you were using apt-get, you might use:

ssh user@remote_host 'DEBIAN_FRONTEND=noninteractive apt-get update -y'

The DEBIAN_FRONTEND=noninteractive environment variable tells apt-get to avoid any prompts and use default answers. The -y flag also confirms any questions.

Another useful tool for more advanced automation is sshpass. While less secure than SSH keys, it can be a quick way to handle password-based authentication in scripts if keys are not an option (though this should be a last resort).

# NOT RECOMMENDED FOR PRODUCTION USE
# sshpass -p 'your_password' ssh user@remote_host 'ls -l'

If you must use sshpass, it’s better to store the password in a secure file and use sshpass -f:

# In a file named ~/.ssh/mypassword (permissions 600)
# your_password

# Then in your script:
# sshpass -f ~/.ssh/mypassword ssh user@remote_host 'ls -l'

However, the primary recommendation remains SSH keys.

When automating tasks, especially those involving sudo, you might encounter sudo password prompts. To bypass this, you can configure sudo on the remote server to allow specific users to run specific commands without a password.

Edit the sudoers file using visudo on the remote server:

# On the remote server:
sudo visudo

Add a line like this:

your_user ALL=(ALL) NOPASSWD: /usr/sbin/systemctl restart apache2

This allows your_user to run sudo systemctl restart apache2 without a password. Be very judicious with NOPASSWD entries.

For more robust scripting, consider using tools like Ansible, Chef, or Puppet, which are designed for infrastructure automation and handle many of these complexities more gracefully. However, for simple, ad-hoc tasks, Bash with SSH keys is a powerful combination.

The next hurdle you’ll likely face is dealing with network interruptions or slow connections that cause SSH sessions to hang or drop mid-command.

Want structured learning?

Take the full Bash course →