Toolmingo
Guides7 min read

How to Use SSH: Keys, Config, Tunnels, and SCP

A complete SSH guide covering key generation, ssh-agent, ~/.ssh/config shortcuts, port forwarding (local/remote/dynamic), SCP/rsync file transfer, and common troubleshooting steps.

SSH (Secure Shell) is how you connect to remote servers, transfer files, and create encrypted tunnels. This guide covers everything from your first connection to advanced port forwarding — with copy-ready commands for each step.

Quick reference

Task Command
Connect to server ssh user@host
Connect on custom port ssh -p 2222 user@host
Generate ED25519 key ssh-keygen -t ed25519 -C "email@example.com"
Copy public key to server ssh-copy-id user@host
Copy file to server scp file.txt user@host:/remote/path/
Copy file from server scp user@host:/remote/file.txt ./local/
Copy directory recursively scp -r dir/ user@host:/remote/
Local port forward ssh -L 8080:localhost:3000 user@host
Remote port forward ssh -R 9090:localhost:8080 user@host
SOCKS proxy (dynamic) ssh -D 1080 user@host
Keep connection alive ssh -o ServerAliveInterval=60 user@host
Run command remotely ssh user@host "ls -la /var/log"
Verbose connection debug ssh -vvv user@host

Generating SSH keys

ED25519 is the recommended algorithm — smaller, faster, and more secure than RSA 2048.

# Generate an ED25519 key (preferred)
ssh-keygen -t ed25519 -C "your_email@example.com"

# Generate an RSA 4096 key (if the server requires RSA)
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

# Files created:
# ~/.ssh/id_ed25519      — private key (never share this)
# ~/.ssh/id_ed25519.pub  — public key (safe to share)

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

Passphrase: Add one. It encrypts the private key on disk so a stolen file isn't immediately usable.


Copying your public key to a server

# Easiest method — copies key and sets correct permissions
ssh-copy-id user@host

# Custom key or port
ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 2222 user@host

# Manual method (when ssh-copy-id is unavailable)
cat ~/.ssh/id_ed25519.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

The server will now accept your key without a password prompt.


SSH config file

~/.ssh/config lets you create shortcuts and set per-host options. No more remembering long hostnames, ports, or usernames.

# ~/.ssh/config

# A named shortcut
Host myserver
    HostName 203.0.113.10
    User ubuntu
    Port 2222
    IdentityFile ~/.ssh/id_ed25519

# Another server with a jump host
Host prod
    HostName 10.0.0.50
    User deploy
    ProxyJump bastion

Host bastion
    HostName bastion.example.com
    User ec2-user

# Apply to all hosts
Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3
    AddKeysToAgent yes
    IdentityFile ~/.ssh/id_ed25519

With this config:

ssh myserver       # connects to ubuntu@203.0.113.10 -p 2222
ssh prod           # connects via bastion jump host automatically

SSH agent

ssh-agent holds your decrypted keys in memory so you only enter the passphrase once per session.

# Start the agent (usually auto-started by your OS)
eval "$(ssh-agent -s)"

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

# List loaded keys
ssh-add -l

# Remove all keys
ssh-add -D

# macOS: store passphrase in Keychain (add to ~/.ssh/config)
Host *
    AddKeysToAgent yes
    UseKeychain yes

Port forwarding

Port forwarding tunnels traffic through an SSH connection. Useful for accessing databases, internal dashboards, and bypassing firewalls.

Local port forwarding

Makes a remote service available on your local machine.

# Access a remote database (port 5432) as if it were local (port 5433)
ssh -L 5433:localhost:5432 user@host

# Now connect locally:
psql -h localhost -p 5433 -U myuser mydb

# Access an internal server via a jump host
# Forwards local 8080 → internal-server:80 (through host)
ssh -L 8080:internal-server.local:80 user@host

Pattern: -L local_port:target_host:target_port

  • local_port — port on your machine
  • target_host — host as seen from the SSH server
  • target_port — port on the target

Remote port forwarding

Exposes your local machine to the remote server. Useful for sharing a local dev server.

# Makes your local port 3000 available as port 9090 on the remote server
ssh -R 9090:localhost:3000 user@host

# Anyone on the remote server can now reach your local app:
# curl http://localhost:9090

Pattern: -R remote_port:target_host:target_port

For remote forwarding to be accessible outside the server, set GatewayPorts yes in /etc/ssh/sshd_config.

Dynamic port forwarding (SOCKS proxy)

Routes all traffic through the SSH server — effectively a VPN.

ssh -D 1080 -N user@host
# -N: don't open a shell, just forward
# -f: run in background

# Configure your browser or system to use SOCKS5 proxy:
# Host: 127.0.0.1  Port: 1080

Running commands remotely

# Run a single command
ssh user@host "df -h"

# Run multiple commands
ssh user@host "cd /var/log && tail -n 50 syslog"

# Pipe local data to remote command
cat local.sql | ssh user@host "psql -U postgres mydb"

# Run a local script on the remote server
ssh user@host bash < local_script.sh

# Preserve environment variables with -t (allocate TTY)
ssh -t user@host "sudo systemctl restart nginx"

File transfer: SCP and rsync

SCP (simple, built-in)

# Upload a file
scp file.txt user@host:/home/user/

# Download a file
scp user@host:/var/log/app.log ./

# Copy a directory recursively
scp -r ./dist/ user@host:/var/www/html/

# With custom port
scp -P 2222 file.txt user@host:/tmp/

# Using a config alias
scp file.txt myserver:/tmp/

rsync (efficient for large transfers)

# Sync a local directory to remote (only changed files)
rsync -avz ./dist/ user@host:/var/www/html/

# Options explained:
# -a  archive (preserves permissions, timestamps, symlinks)
# -v  verbose
# -z  compress during transfer

# Sync with SSH on custom port
rsync -avz -e "ssh -p 2222" ./dist/ user@host:/var/www/

# Dry run (see what would change without changing anything)
rsync -avzn ./dist/ user@host:/var/www/html/

# Delete remote files that no longer exist locally
rsync -avz --delete ./dist/ user@host:/var/www/html/

# Exclude patterns
rsync -avz --exclude 'node_modules/' --exclude '.env' ./ user@host:/app/

rsync is preferred for deployments: it skips unchanged files, compresses data, and handles interruptions gracefully.


Jump hosts (ProxyJump)

When your target server is only reachable through a bastion/jump host:

# One-time: connect to prod through bastion
ssh -J ec2-user@bastion.example.com ubuntu@10.0.0.50

# SCP through a jump host
scp -J bastion.example.com file.txt ubuntu@10.0.0.50:/tmp/

# In ~/.ssh/config (cleaner)
Host prod
    HostName 10.0.0.50
    User ubuntu
    ProxyJump bastion

Host bastion
    HostName bastion.example.com
    User ec2-user

Server-side SSH configuration

Common settings in /etc/ssh/sshd_config (restart with sudo systemctl restart sshd after changes):

# Disable password auth (key-only)
PasswordAuthentication no

# Disable root login
PermitRootLogin no

# Change default port
Port 2222

# Allow specific users only
AllowUsers ubuntu deploy

# Timeout idle sessions after 10 minutes
ClientAliveInterval 300
ClientAliveCountMax 2

# Enable X11 forwarding (GUI apps over SSH)
X11Forwarding yes

Common mistakes

1. Wrong file permissions SSH refuses to use keys if permissions are too open.

chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
chmod 600 ~/.ssh/authorized_keys
chmod 644 ~/.ssh/config

2. Using RSA 2048 instead of ED25519 RSA 2048 is considered borderline for long-term security. Use ED25519 for new keys, or RSA 4096 if ED25519 isn't supported.

3. No passphrase on the private key A key without a passphrase is as dangerous as a plain-text password in a file. Always add a passphrase and use ssh-agent.

4. Forgetting -R needs GatewayPorts yes for external access Remote port forwards bind to 127.0.0.1 by default. Add GatewayPorts yes to sshd_config to allow external access.

5. Using password auth on public-facing servers Bots constantly attempt SSH password logins. Disable password auth (PasswordAuthentication no) once your key works.

6. Killing port forwards accidentally Add -N -f to run the tunnel in the background without opening a shell, and consider autossh to auto-restart dropped tunnels.


FAQ

How do I keep an SSH connection from timing out?

Add to ~/.ssh/config:

Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3

This sends a keepalive packet every 60 seconds. Alternatively, configure TCPKeepAlive yes on the server side.

How do I debug an SSH connection that won't work?

Use verbose mode — it prints every step of the handshake:

ssh -vvv user@host
# Look for lines like "Permission denied" or "No such identity file"

How do I transfer a file without SCP/rsync?

Use cat and pipes through the SSH connection:

# Upload: pipe local file to remote
cat file.tar.gz | ssh user@host "cat > /remote/file.tar.gz"

# Download: pipe remote file to local
ssh user@host "cat /remote/file.tar.gz" > file.tar.gz

What's the difference between ssh-copy-id and manually editing authorized_keys?

Both do the same thing: append your public key to ~/.ssh/authorized_keys on the server. ssh-copy-id also creates the directory and sets the correct permissions automatically. The manual method is useful when ssh-copy-id isn't available (e.g., on Windows).

How do I use SSH with GitHub/GitLab?

# Generate and add your key (already done? skip)
ssh-keygen -t ed25519 -C "your@email.com"

# Copy public key
cat ~/.ssh/id_ed25519.pub

# Add it in GitHub: Settings → SSH keys → New SSH key

# Test connection
ssh -T git@github.com
# "Hi username! You've successfully authenticated..."

# Clone via SSH (not HTTPS)
git clone git@github.com:user/repo.git

How do I forward a GUI application over SSH (X11)?

# Connect with X11 forwarding
ssh -X user@host     # untrusted (safer)
ssh -Y user@host     # trusted (needed for some apps)

# Then run a GUI app
firefox &

Requires an X11 server on your local machine (XQuartz on macOS, built-in on Linux, VcXsrv/WSL on Windows).

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools