Keys, Config, and Tunnels#

Concepts#

SSH Key Authentication#

Key-based auth is more secure than passwords: the private key never leaves your machine, and it can be protected with a passphrase.

Generate a Key Pair#

ssh-keygen -t ed25519 -C "your_email@example.com"
# -t ed25519: modern, fast, secure algorithm
# -C: comment (usually your email)

It asks for:

  • File: default ~/.ssh/id_ed25519 (press Enter)
  • Passphrase: encrypts the private key (recommended — adds a second factor)

This creates two files:

  • ~/.ssh/id_ed25519 — your private key (never share this)
  • ~/.ssh/id_ed25519.pub — your public key (put this on servers)

Copy Public Key to a Server#

ssh-copy-id user@hostname
# Prompts for password one last time
# Copies your public key to ~/.ssh/authorized_keys on the server

Now you can log in without a password:

ssh user@hostname
# Logs in using your key — no password prompt!

Manual Key Setup#

If ssh-copy-id is not available:

# On the server:
mkdir -p ~/.ssh
chmod 700 ~/.ssh
# Paste your public key into:
nano ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

SSH File Permissions#

SSH is strict about permissions. Wrong permissions = refused connection:

Path Permission Meaning
~/.ssh/ 700 Owner only
~/.ssh/authorized_keys 600 Owner read/write only
~/.ssh/id_ed25519 600 Private key — owner only
~/.ssh/id_ed25519.pub 644 Public key — anyone can read
~/.ssh/config 600 Config — owner only

All of these codes are explained in File Permissions.

SSH Agent#

If your key has a passphrase, you’d normally type it every time. The SSH agent caches the decrypted key in memory:

# Start the agent (usually auto-started on desktop)
eval "$(ssh-agent -s)"

# Add your key (prompts for passphrase once)
ssh-add ~/.ssh/id_ed25519

# List loaded keys
ssh-add -l

# Now SSH connections use the cached key — no passphrase prompt

SSH Config File#

~/.ssh/config saves connection settings so you don’t have to type them every time:

# ~/.ssh/config

Host myserver
    HostName 192.168.1.100
    User kmiguel
    Port 22
    IdentityFile ~/.ssh/id_ed25519

Host webdev
    HostName dev.example.com
    User deploy
    Port 2222
    ForwardAgent yes

Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3

Now instead of:

ssh -p 2222 deploy@dev.example.com

You just type:

ssh webdev

Common options:

Option Meaning
HostName Real hostname or IP
User Username on the remote
Port SSH port
IdentityFile Which private key to use
ForwardAgent Forward your SSH agent to the remote (use cautiously)
ServerAliveInterval Send keepalive every N seconds (prevents timeout)
ProxyJump Jump through another SSH server (bastion host)

Port Forwarding (Tunnels)#

SSH can forward network ports through the encrypted connection.

Local Port Forwarding#

Access a remote service through a local port:

ssh -L 8080:localhost:80 user@server
# Now http://localhost:8080 on YOUR machine → port 80 on the SERVER

Use case: access a web app on a remote server that only listens on localhost.

Remote Port Forwarding#

Expose a local service through the remote server:

ssh -R 9090:localhost:3000 user@server
# Now port 9090 on the SERVER → port 3000 on YOUR machine

Dynamic Port Forwarding (SOCKS Proxy)#

ssh -D 1080 user@server
# Creates a SOCKS proxy on localhost:1080
# Configure your browser to use it — all traffic goes through the server

SOCKS is similar to an HTTP proxy but there are some very important differences denoted in this article.

Copying Keys Between Machines#

# Copy your public key to clipboard (install xclip first)
cat ~/.ssh/id_ed25519.pub | xclip -selection clipboard

# Or just display it and copy manually
cat ~/.ssh/id_ed25519.pub

Lab#

Exercise 1: Generate an SSH Key#

# Generate a key pair (if you don't have one)
ls ~/.ssh/id_ed25519 2>/dev/null || ssh-keygen -t ed25519 -C "lab@course"

# View your public key
cat ~/.ssh/id_ed25519.pub

# Check permissions
ls -la ~/.ssh/

Exercise 2: Set Up Key Authentication (Localhost)#

# Copy key to localhost
ssh-copy-id $(whoami)@localhost

# Test — should connect without password
ssh $(whoami)@localhost "echo 'Key auth works!'"

Exercise 3: Create an SSH Config#

cat > ~/.ssh/config << 'EOF'
Host local
    HostName localhost
    User $USER

Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3
EOF

# Fix the $USER placeholder
sed -i "s/\$USER/$(whoami)/" ~/.ssh/config
chmod 600 ~/.ssh/config

# Test
ssh local "hostname"

Exercise 4: Local Port Forwarding#

# Start a simple web server on port 8888
python3 -m http.server 8888 &
WEB_PID=$!

# Forward local port 9999 to localhost:8888 through SSH
ssh -f -N -L 9999:localhost:8888 $(whoami)@localhost

# Test — both should show the same content
curl -s http://localhost:8888 | head -5
curl -s http://localhost:9999 | head -5

# Clean up
kill $WEB_PID
pkill -f "ssh.*9999:localhost:8888"

Exercise 5: SSH Agent#

# Check if agent is running
echo $SSH_AUTH_SOCK

# List loaded keys
ssh-add -l

# Add your key
ssh-add ~/.ssh/id_ed25519

# Verify
ssh-add -l

Review#

1. How do you generate an SSH key pair?

ssh-keygen -t ed25519 -C "comment". This creates a private key (~/.ssh/id_ed25519) and a public key (~/.ssh/id_ed25519.pub).

2. How do you install your public key on a server?

ssh-copy-id user@host. This copies your public key to ~/.ssh/authorized_keys on the server. After that, you can log in without a password.

3. What is the SSH agent?

A program that caches your decrypted private keys in memory. You type your passphrase once (ssh-add), and subsequent SSH connections use the cached key without re-prompting.

4. What does the `~/.ssh/config` file do?

It stores connection presets (hostname, user, port, key, options) so you can connect with ssh shortname instead of typing the full command every time.

5. What is local port forwarding?

ssh -L local_port:target:target_port user@server — creates a tunnel so that connecting to localhost:local_port on your machine actually reaches target:target_port through the SSH server.


Previous: SSH Fundamentals | Next: tmux