Skip to content
AgileLogics
6 min read

Remote Automation with SSH

Prerequisites: Security for shell scripts, Error handling in scripts

SSH runs commands on remote machines securely. Combined with Bash, it automates work across many servers.

Keys instead of passwords

# illustrative
ssh-keygen -t ed25519 -C "ada@laptop"      # create a key pair (once)
ssh-copy-id deploy@web1.example.com       # install the public key on the server
ssh deploy@web1.example.com               # log in without a password

The private key (~/.ssh/id_ed25519) never leaves your machine — protect it with a passphrase and chmod 600. Only the public key goes on servers.

Save connection settings in ~/.ssh/config:

Host web1
  HostName web1.example.com
  User deploy
  IdentityFile ~/.ssh/id_ed25519

Now ssh web1 is enough.

Running remote commands

# illustrative
ssh web1 'df -h / && uptime'

for host in web1 web2 web3; do
  echo "== $host"
  ssh -o ConnectTimeout=5 "$host" 'systemctl is-active nginx' || echo "problem on $host"
done
  • Single quotes send the command to the remote shell unexpanded.
  • To send a local value safely, quote it with printf %q: ssh web1 "ls -- $(printf '%q' "$dir")".
  • Longer remote scripts can be piped in: ssh web1 'bash -s' < script.sh.

Copying files

# illustrative
scp report.pdf web1:/tmp/
rsync -avz --delete ./site/ web1:/var/www/site/

rsync only transfers what changed, which makes repeated deployments fast. --delete removes files on the server that no longer exist locally — test with --dry-run first.

A simple deploy

# illustrative
set -euo pipefail
release=$(date +%Y%m%d%H%M%S)
rsync -az ./build/ "web1:/srv/app/releases/$release/"
ssh web1 "ln -sfn /srv/app/releases/$release /srv/app/current && sudo systemctl reload app"

Switching a current symlink makes the release change instant, and rolling back is just pointing the link at the previous release.

Beyond scripts

For managing many servers, configuration tools such as Ansible (which runs over SSH) describe the desired state declaratively and are safer to rerun than hand-written loops.