Secure Shell (SSH) is a popular protocol used for securely connecting to a server over an encrypted channel. Unlike older protocols like Telnet, which transmit data such as usernames and passwords in cleartext, SSH uses asymmetric encryption to protect your information.


Learning Objectives

By the end of this exercise, you will be able to:

  • Establish a remote connection using standard SSH.
  • Generate and deploy SSH key pairs for passwordless authentication.
  • Securely transfer files between a local machine and a remote server.
  • Understand basic SSH tunneling concepts.

Prerequisites

  • A terminal emulator (e.g., Terminal on macOS/Linux, PowerShell or Command Prompt on Windows).
  • Access to a remote Linux server (e.g., Ubuntu or Kali Linux).
  • The remote server’s IP address and your login credentials.

Exercise 0: Find Out the IP Address

First, identify the IP address of the destination machine:

ip addr show
# or
hostname -I
# or
ip route get 1.1.1.1 | awk '{print $7; exit}'

# Environment variable (recommended for reuse in commands)
export SERVER_IP=$(ip route get 1.1.1.1 | awk '{print $7; exit}')
echo $SERVER_IP
## 192.168.1.166 (as an example)

Exercise 1: Basic Connection

The most basic way to connect to a server is using a username and an IP address:

# Connect to the server
ssh server-user@$SERVER_IP
## If this is your first time connecting, you will be asked to verify the host authenticity. Type yes.
## Enter your password when prompted.

Exercise 2: Secure File Transfer

Transferring files between local and remote machines is a common task. You can use scp (Secure Copy Protocol) or rsync for this purpose:

# Copy a single file to remote server
## Replace /path/ to your actual path within the server
scp file.txt server-user@$SERVER_IP:/path/

# Copy an entire directory recursively
scp -r folder/ server-user@$SERVER_IP:/path/

For large transfers or ongoing synchronization, rsync is a powerful alternative that only transfers modified files and supports resuming interrupted transfers.


Exercise 3: Key-Based Authentication

Using SSH keys is more secure and convenient than passwords. SSH uses a public and private key pair for authentication.

# Generate key (press Enter for defaults)
ssh-keygen -t ed25519 -C "client-user@mylaptop"
## -t specifies the "type" of algorithm to generate the SSH key.
## -C adds a human-readable "comment" to the end of your public key (stored in ~/.ssh/id_ed25519.pub)
## Note: ed25519 is preferred over rsa because it is faster, more secure, and produces smaller keys.

# (optional) Check the private key (do not share with anyone)
cat /home/client-user/.ssh/id_ed25519

# Copy public key to the server
ssh-copy-id server-user@$SERVER_IP
# Enter password one last time

# Should now connect without password
ssh server-user@$SERVER_IP
exit

# Create SSH config on client machine for shortcuts
cat << 'EOF' >> ~/.ssh/config

Host serverABC
    HostName <SERVER_IP_ADDRESS>
    User userABC
    Port 22
    IdentityFile ~/.ssh/id_ed25519
EOF

# Now connect with just the alias:
ssh serverABC

Troubleshooting Connection Issues:

  • Connection timed out: Check firewall status (sudo ufw status on both client and host).
  • Permission denied: Verify ~/.ssh directory permissions (700) and key file permissions (600 for private, 644 for public).
  • Connection refused: Verify the SSH daemon is running using sudo systemctl status ssh.

SSH Architecture & Connection Workflow


Exercise 4: Tailscale Connection

Tailscale simplifies SSH connections by creating a private network (tailnet) between your devices, allowing you to connect securely from anywhere without needing to be on the same local network:

# Install Tailscale on both your local machine and remote server
curl -fsSL https://tailscale.com/install.sh | sh

# Start Tailscale and authenticate
sudo tailscale up
## Follow the authentication URL printed in your terminal output to join the device to your tailnet.
## Enable Tailscale SSH in your Tailscale admin console to permit secure SSH access across devices.

# Check status of connected devices
tailscale status

# Retrieve the IPv4 address of the device
tailscale ip -4
TAILNET_SERVER_IP=$(tailscale ip -4)

# Connect to the remote server via tailnet
ssh server-user@$TAILNET_SERVER_IP

# Just like before, you may configure a shortcut in ~/.ssh/config
nano ~/.ssh/config

## Other commands worth mentioning
tailscale ping <device-name>
tailscale logout
tailscale down
tailscale update
  • Power State: If the host machine goes to sleep, the Tailscale service will pause because the operating system is not running. It automatically resumes when the machine wakes up.
  • Key Expiry: If your Tailscale account is configured with key expiry, the node key might expire, requiring re-authentication (common for ephemeral nodes or if configured in the admin console).

Exercise 5: Server Hardening

Securing the SSH daemon on the server is critical. Edit /etc/ssh/sshd_config on your remote server to restrict access:

# Edit sshd_config to harden remote server access
sudo nano /etc/ssh/sshd_config

# Disable root login for better security
PermitRootLogin no

# Disable password authentication once keys are set up
PasswordAuthentication no

# Change default port (e.g., 2222) to reduce brute-force noise
Port 2222

After modifying the configuration, test and restart the SSH daemon:

sudo sshd -t
sudo systemctl restart ssh

Exercise 6: Managing Multiple Identities

If you use passphrases on keys, or manage multiple Git/SSH accounts, use these tools to streamline workflows:

# Start ssh-agent to cache your passphrase in memory
eval "$(ssh-agent -s)"

# Add your key to the agent
ssh-add ~/.ssh/id_ed25519

# For multiple accounts, define host aliases in ~/.ssh/config
cat << 'EOF' >> ~/.ssh/config

Host work-git
    HostName github.com
    IdentityFile ~/.ssh/id_work

Host personal-git
    HostName github.com
    IdentityFile ~/.ssh/id_personal
EOF

# Instead of cloning with the standard URL
git clone [email protected]:company/repo.git

# You replace github.com with your alias
## Uses ~/.ssh/id_work
git clone git@work-git:company/repo.git

## Uses ~/.ssh/id_personal
git clone git@personal-git:username/repo.git

Exercise 7: Advanced Connectivity (Bastions & Port Forwarding)

When a server is only accessible through an intermediary (a bastion host), use ProxyJump. ProxyJump is generally preferred over older -W or -L methods because it is simpler to configure and more secure, ensuring the jump host cannot decrypt end-to-end traffic:

# Connect through a jump host (-J)
ssh -J jump-user@jump-host user@target-server

Local Port Forwarding

Sometimes you need to access a web service running on the remote server (e.g., a database GUI or monitoring tool) that is not exposed to the public internet. You can tunnel this traffic through your SSH connection via Port Forwarding:

ssh -L 8080:localhost:3000 serverABC

This command connects to serverABC and forwards any traffic sent to localhost:8080 on your local machine to localhost:3000 on the remote server.


Exercise 8: Auditing and Compliance

Regularly audit your SSH configuration for cryptographic and configuration weaknesses using tools like ssh-audit:

# Install and run ssh-audit
pip install ssh-audit
ssh-audit <target-IP>

Summary of SSH Tools

ToolPurposeKey Usage / Examples
sshRemote login-p (port), -J (jump), -L (tunnel), -v (debug)
ssh-keygenKey generation-t ed25519, -C (label)
ssh-copy-idDeploy public keysssh-copy-id user@host
ssh-agentPassphrase managereval "$(ssh-agent -s)", ssh-add
scpFile transfer-r (recursive), -P (custom port)
rsyncEfficient file syncrsync -avz (archive/compress/verbose)
ssh-auditSecurity scanningssh-audit <target-IP>
TailscaleMesh networkingup (start), status (nodes), ip -4 (get IP)
SSH ConfigShortcutsHost, HostName, User, IdentityFile

Security Best Practices

  • Use Key Passphrases: Always protect your private keys with a passphrase.
  • Audit Access: Use tools like Teleport for auditing and controlling infrastructure access.
  • Avoid Cleartext: Never use Telnet for remote administration, as it lacks encryption.

Conclusion

Mastering SSH is an essential skill for system administrators and developers alike. By moving beyond basic password authentication to public-key authentication, configuring connection shortcuts, and adopting best practices, you establish a secure, reliable foundation for managing remote infrastructure safely and efficiently.