SSH
What Is SSH?
- SSH (Secure Shell) is a protocol for logging into remote machines and running commands on them
- Runs over TCP port 22 by default
- Replaced older tools like
telnetandrshthat sent everything as plain text - Uses TLS-style encryption: all traffic between client and server is encrypted
- See the Certificates chapter for background on public-key cryptography
Connecting with a Password
- Simplest way to connect:
$ ssh tut@remote.example.com
tut@remote.example.com's password:
Last login: Mon Mar 3 09:14:22 2026
tut@remote:~$
- The shell prompt changes to show we are now on the remote machine
- Type
exitor press Ctrl-D to close the connection - Password authentication is convenient but has risks:
- Weak passwords can be guessed by automated scanners
- Passwords can be captured if the user is tricked into connecting to the wrong host
- Most administrators disable it in favor of key-pair authentication
Key-Pair Authentication
- More secure alternative: generate a key pair
- A private key that stays on your machine and is never shared
- A public key that you copy to remote machines
- When connecting, the server issues a challenge that only the holder of the private key can answer
- The private key never travels over the network
Generating a Key Pair
$ ssh-keygen -t ed25519 -C "tut@example.com"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/Users/tut/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/tut/.ssh/id_ed25519
Your public key has been saved in /Users/tut/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:abc123xyz456... tut@example.com
ed25519is a modern elliptic-curve algorithm; use it instead of the olderrsa-Cadds a comment to identify the key (conventionally your email address)- The passphrase encrypts the private key on disk
- If someone steals the file, they still cannot use the key without the passphrase
- An empty passphrase is convenient but less secure
Copying the Public Key to a Server
$ ssh-copy-id tut@remote.example.com
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
tut@remote.example.com's password:
Number of key(s) added: 1
ssh-copy-idappends the public key to~/.ssh/authorized_keyson the remote machine- After this,
ssh tut@remote.example.comno longer asks for a password
Host Key Verification
- The first time you connect to a new server, SSH shows its host key fingerprint:
$ ssh tut@remote.example.com
The authenticity of host 'remote.example.com (203.0.113.5)' can't be established.
ED25519 key fingerprint is SHA256:abc123xyz456...
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'remote.example.com' to the list of known hosts.
- SSH stores the fingerprint in
~/.ssh/known_hosts - If the fingerprint changes on a later connection, SSH refuses to connect
- This protects against man-in-the-middle attacks
- Could also mean the server was reinstalled — verify with the administrator before overriding
ssh-agent
- Typing the private key passphrase every time is tedious
ssh-agentholds decrypted keys in memory for the duration of a session
$ eval "$(ssh-agent -s)"
Agent pid 12345
$ ssh-add ~/.ssh/id_ed25519
Enter passphrase for /Users/tut/.ssh/id_ed25519:
Identity added: /Users/tut/.ssh/id_ed25519 (tut@example.com)
ssh-addwithout arguments adds the default key (~/.ssh/id_ed25519)- On macOS, keys are stored in the system Keychain automatically
The SSH Config File
~/.ssh/configlets you define shortcuts for frequently used hosts:
Host myserver
HostName remote.example.com
User tut
IdentityFile ~/.ssh/id_ed25519
ForwardAgent yes
ssh myservernow expands tossh -i ~/.ssh/id_ed25519 tut@remote.example.comForwardAgent yespasses your localssh-agentthrough to the remote machine- Useful when the remote machine itself needs to connect to a third machine using your keys
Copying Files
scpcopies files over an SSH connection — same syntax ascpbut with a host prefix:
$ scp local_data.csv tut@remote.example.com:~/data/
$ scp tut@remote.example.com:~/results/output.csv .
rsyncis more efficient for large or frequently updated files:- Only transfers the parts that changed
- Can resume interrupted transfers
$ rsync -avz data/ tut@remote.example.com:~/data/
SSH Tunnels
- Sometimes a service is running on a remote machine but is not directly reachable
- E.g., a database that accepts connections only from
localhost
- E.g., a database that accepts connections only from
- Use local port forwarding to create a tunnel:
$ ssh -L 5432:localhost:5432 tut@remote.example.com
- This binds port 5432 on your local machine to port 5432 on the remote machine
- Connections to
localhost:5432on your laptop go through the SSH connection to the remote machine - Useful for database administration, Jupyter notebooks running on a cluster, etc.
Programmatic SSH with paramiko
paramikois a Python library for SSH connections:
import paramiko
client = paramiko.SSHClient()
client.load_system_host_keys()
client.connect("remote.example.com", username="tut")
stdin, stdout, stderr = client.exec_command("ls ~/data")
for line in stdout:
print(line.strip())
client.close()
load_system_host_keys()reads~/.ssh/known_hoststo verify the server- Use
paramiko.AutoAddPolicy()only in trusted environments where you control the server
Exercise: Keys and Config
-
Generate an
ed25519key pair. What are the permissions on~/.ssh/id_ed25519? Why are those permissions necessary? -
Add an entry to
~/.ssh/configfor a machine you have access to and verify thatssh <alias>connects without specifying a username or hostname. -
Use
scpto copy a small file to a remote machine and back. Then do the same withrsync. What differences do you notice?