---
title: "SSH"
description: "Comprehensive SSH cheatsheet covering OpenSSH client usage, authentication methods, port forwarding, key management, X11 forwarding, and configuration options. Includes real-world examples and security best practices."
author: "Mohammad Abu Mattar"
canonical: https://mkabumattar.com/cheatsheets/ssh
---

# SSH

h1: 'h1',
  h2: 'h2',
  h3: 'h3',
  h4: 'h4',
  h5: 'h5',
  h6: 'h6',
  p: 'p',
  a: 'a',
  ul: 'ul',
  ol: 'ol',
  li: 'li',
  code: 'code',
  pre: 'pre',
  strong: 'strong',
  em: 'em',
  blockquote: 'blockquote',
  table: 'table',
  th: 'th',
  tr: 'tr',
  td: 'td',
};

## Getting Started

### Basic SSH Connection

Establishing remote connections to servers

**Keywords:** connection, remote, login, host, basic

#### Connect to Remote Host with Default Settings

```bash
ssh hostname
```

_exec_
```bash
The authenticity of host 'hostname (192.168.1.100)' can't be established.
ECDSA key fingerprint is SHA256:abc123xyz...
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'hostname' (ECDSA) to the list of known hosts.
Last login: Wed Feb 28 10:30:42 2026 from 192.168.1.50
user@hostname:~$
```

Connects to a remote host using SSH, with interactive password authentication. The host key is verified and stored in ~/.ssh/known_hosts

- First connection will prompt for host key verification
- Uses default SSH port 22
- Requires password authentication if no keys configured

#### Connect with Specific Username

```bash
ssh user@hostname
```

_exec_
```bash
user@hostname's password:
Last login: Wed Feb 28 10:35:15 2026 from 192.168.1.50
user@hostname:~$
```

Connect using a specific username different from local user. Format is [user@]hostname

- If username not specified, uses current local username
- Can also specify as user@domain.com or user@ip.address

#### Connect to Non-Standard Port

```bash
ssh -p 2222 user@hostname
```

_exec_
```bash
user@hostname's password:
Last login: Wed Feb 28 09:15:22 2026 from 192.168.1.50
user@hostname:~$
```

SSH server might run on ports other than 22. Use -p flag to specify alternative port

- Port must be specified before hostname
- Common alternative port is 2222
- Can also configure in ~/.ssh/config

**Best practices:**

- Always verify host key fingerprint on first connection
- Use non-standard ports to reduce exposure to automated attacks
- Set up public key authentication rather than password

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

## Authentication Methods

### Public Key Authentication

Using SSH keys for passwordless authentication

**Keywords:** keys, public, private, ed25519, rsa, authentication

#### Generate ED25519 SSH Key Pair

```bash
ssh-keygen -t ed25519 -C "user@example.com"
```

_exec_
```bash
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/user/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/user/.ssh/id_ed25519
Your public key has been saved in /home/user/.ssh/id_ed25519.pub
The key fingerprint is: SHA256:xyz123abc... user@example.com
```

Create a new ED25519 key pair. This modern algorithm is preferred over RSA for better security

- Ed25519 is the recommended key type (fast, secure, compact)
- Use -C to add a comment identifying the key
- Protect private key with strong passphrase

#### Add Public Key to Remote Host

```bash
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@hostname
```

_exec_
```bash
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/user/.ssh/id_ed25519.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s)...
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed - if you want to re-run this setup...
Number of key(s) added: 1
```

Copy public key to remote host's authorized_keys. Enables passwordless login

- Requires initial password authentication
- Appends to ~/.ssh/authorized_keys on remote

#### Connect Using Specific Key

```bash
ssh -i ~/.ssh/id_ed25519 user@hostname
```

_exec_
```bash
Last login: Wed Feb 28 11:45:30 2026 from 192.168.1.50
user@hostname:~$
```

Explicitly specify private key for authentication. Useful when multiple keys exist

- SSH tries default keys if -i not specified
- Default keys: ~/.ssh/id_rsa, ~/.ssh/id_ecdsa, ~/.ssh/id_ed25519

**Best practices:**

- Use ED25519 keys instead of RSA for better security and smaller size
- Always protect private keys with passphrase
- Regularly rotate keys (annually recommended)
- Disable password authentication on servers once keys configured

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### Password Authentication

Interactive password-based login

**Keywords:** password, authentication, interactive, prompt

#### Force Password Authentication

```bash
ssh -o PubkeyAuthentication=no user@hostname
```

_exec_
```bash
user@hostname's password:
Last login: Wed Feb 28 10:20:15 2026
user@hostname:~$
```

Disable public key auth and force password authentication. Useful for testing or shared accounts

- Password transmitted securely through SSH tunnel
- Server must have PasswordAuthentication enabled

#### Non-Interactive Password (Using sshpass)

```bash
sshpass -p 'password' ssh user@hostname
```

_exec_
```bash
Last login: Wed Feb 28 11:25:10 2026
user@hostname:~$
```

Pass password non-interactively using sshpass utility. Not recommended for security

- sshpass must be installed separately
- Security risk: password visible in process list and history
- Use SSH keys instead for automation

**Best practices:**

- Use SSH keys for all automation and scripts
- Disable password authentication on production servers
- If password needed, use key-based auth with ssh-agent

**Common errors:**

- **undefined**: undefined

### SSH Agent & Key Forwarding

Use ssh-agent to manage keys across multiple hops

**Keywords:** agent, forwarding, ssh-agent, identity, keys

#### Start SSH Agent in Current Shell

```bash
eval "$(ssh-agent -s)"
```

_exec_
```bash
Agent pid 12345
```

Initialize SSH agent in current shell session. Required before adding keys

- Agent runs as background process
- PID stored in SSH_AUTH_SOCK environment variable

#### Add Private Key to Agent

```bash
ssh-add ~/.ssh/id_ed25519
```

_exec_
```bash
Enter passphrase for /home/user/.ssh/id_ed25519:
Identity added: /home/user/.ssh/id_ed25519 (user@example.com)
```

Add private key to SSH agent. Benefits: Enter passphrase once, agent handles auth on multiple connections

- Prompted for passphrase only once
- Key unlocked in agent memory until timeout or logout

#### Enable Agent Forwarding to Remote Host

```bash
ssh -A user@hostname
```

_exec_
```bash
Last login: Wed Feb 28 12:00:00 2026
user@hostname:~$ ssh-add -l
256 SHA256:xyz... user@example.com (ED25519)
```

Forward SSH agent connection to remote host. Allows using local keys from remote for further hops (jump hosts)

- Requires ForwardAgent yes in ssh_config (or use -A flag)
- Security: Only enable for trusted hosts
- Useful for jump host scenarios

**Best practices:**

- Start ssh-agent once per session
- Use agent forwarding only with fully trusted hosts
- Set SSH_ASKPASS for secure passphrase prompts in X11
- Use AddKeysToAgent in ssh_config for automatic key management

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

## Port Forwarding & Tunneling

### Local Port Forwarding

Forward local port to remote service

**Keywords:** forwarding, local, -L, tunnel, port

#### Forward Local Port to Remote Service

```bash
ssh -L 3306:localhost:3306 user@database-host
```

_exec_
```bash
Last login: Wed Feb 28 08:30:00 2026
user@database-host:~$
```

Forward localhost:3306 through SSH tunnel to remote database server. Local connections to 3306 proxy through SSH

- Format: -L [bind_address:]local_port:remote_host:remote_port
- Connection stays open for tunnel to function
- Useful for accessing internal services through SSH

#### Forward with Non-Standard Local Port

```bash
ssh -L 13306:db.internal:3306 user@bastion-host
```

_exec_
```bash
user@bastion-host:~$
```

Forward local port 13306 to remote database server db.internal:3306. Avoids port conflicts with local services

- Connect to localhost:13306 to access remote database
- Allows multiple forwards on different local ports

#### Forward Multiple Ports

```bash
ssh -L 3306:db:3306 -L 5432:db:5432 user@bastion-host
```

_exec_
```bash
user@bastion-host:~$
```

Forward multiple local ports to different remote services through single SSH connection

- Use multiple -L flags for each port forward
- Efficient: only one SSH tunnel to bastion

**Best practices:**

- Use with privileged ports: sudo ssh -L 80:localhost:8080 ...
- Keep SSH connection alive in separate terminal
- Use -N flag to not execute remote command when only forwarding

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### Remote Port Forwarding

Forward remote port to local service

**Keywords:** forwarding, remote, -R, reverse, tunnel

#### Expose Local Service to Remote Network

```bash
ssh -R 8080:localhost:8080 user@public-server
```

_exec_
```bash
user@public-server:~$
```

Forward remote port 8080 to local service on 8080. Remote server can access local service. Enables public access to private service

- Format: -R [bind_address:]remote_port:local_host:local_port
- Requires GatewayPorts yes on remote server for external access
- Useful for exposing localhost dev server to internet

#### Bind to All Interfaces on Remote

```bash
ssh -R '*':3000:localhost:3000 user@public-server
```

_exec_
```bash
user@public-server:~$
```

Expose local service to all interfaces on remote host (not just localhost). Requires GatewayPorts enabled

- Use '*' or empty bind_address for all interfaces
- Security: Only do for development, not production

**Best practices:**

- Use with caution: exposes local services to remote network
- Pair with -N flag when only tunneling
- Verify GatewayPorts setting on remote server

**Common errors:**

- **undefined**: undefined

### Dynamic Port Forwarding (SOCKS Proxy)

Create SOCKS proxy through SSH tunnel

**Keywords:** forwarding, dynamic, -D, socks, proxy, tunnel

#### Create SOCKS5 Proxy

```bash
ssh -D 1080 user@ssh-server
```

_exec_
```bash
Last login: Wed Feb 28 09:15:00 2026
user@ssh-server:~$
```

Create SOCKS5 proxy on localhost:1080. All traffic through proxy routes through SSH tunnel to remote network

- Format: -D [bind_address:]local_port
- Browser/application must support SOCKS5
- Useful for accessing services on remote private network

#### Configure Browser to Use SOCKS Proxy

```bash
# Firefox: Preferences > General > Network Settings > SOCKS Host
# localhost, port 1080, SOCKS v5

# Or use command-line tool
curl --socks5 localhost:1080 https://internal.company.com
```

_exec_
```bash
<!DOCTYPE html>
<html>
<head><title>Internal Company Site</title></head>
<body>Welcome to internal site</body>
</html>
```

Route traffic through SOCKS proxy to access internal services as if on remote network

- Many tools support SOCKS: curl, youtube-dl, etc.

**Best practices:**

- Keep SSH connection running while using proxy
- Use -N flag to not spawn shell
- Verify proxy is working: 'netstat -tlnp | grep 1080'

**Common errors:**

- **undefined**: undefined

## Key Management

### Creating and Managing Keys

Generate, manage, and secure SSH keys

**Keywords:** keygen, key, generation, ed25519, rsa, passphrase

#### Generate RSA Key for Legacy Systems

```bash
ssh-keygen -t rsa -b 4096 -C "legacy-key"
```

_exec_
```bash
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Your identification has been saved in /home/user/.ssh/id_rsa
Your public key has been saved in /home/user/.ssh/id_rsa.pub
```

Create RSA key for systems that don't support Ed25519. Use 4096-bit for adequate security

- RSA requires larger key size (4096) compared to Ed25519 (256)
- Slower but widely supported

#### List Keys Added to Agent

```bash
ssh-add -l
```

_exec_
```bash
256 SHA256:xyz... user@example.com (ED25519)
4096 SHA256:abc... legacy-key (RSA)
```

Display all keys currently loaded in SSH agent with their fingerprints

- Shows key type, fingerprint, and comment
- Returns exit code 1 if agent not running

#### Export Public Key from Private Key

```bash
ssh-keygen -y -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pub
```

_exec_
```bash
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJxyz... user@example.com
```

Recover/regenerate public key from existing private key

- Useful if public key lost
- Only works if you have the private key

**Best practices:**

- Store keys in ~/.ssh/ directory with 600 permissions
- Use strong passphrase (20+ characters)
- Rotate keys annually or after suspicious activity
- Use separate keys for different purposes/hosts if needed

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### Managing Authorized Keys

Control which keys can access your account

**Keywords:** authorized_keys, permissions, access, control

#### View Authorized Keys

```bash
cat ~/.ssh/authorized_keys
```

_exec_
```bash
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO.../key1 user@host1
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO.../key2 user@host2
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAA... legacy-key
```

Display all public keys that can authenticate as current user. One key per line

- File location: ~/.ssh/authorized_keys
- Permissions must be 600
- Directory ~/.ssh must be 700

#### Remove Specific Key

```bash
grep -v "key1" ~/.ssh/authorized_keys > /tmp/authorized_keys.tmp
mv /tmp/authorized_keys.tmp ~/.ssh/authorized_keys
```

_exec_
```bash
(file updated)
```

Remove specific key by filtering it out. Revokes access for that key

- Use tools like ssh-keyscan for managing multiple hosts

#### Set Command Restrictions on Key

```bash
echo 'command="/usr/local/bin/backup.sh" ssh-ed25519 AAAAC3...' >> ~/.ssh/authorized_keys
```

_exec_
```bash
(user logging in with this key will only run backup.sh)
```

Restrict key to only execute specific command. Useful for automation/backups with limited permissions

- Key can only run the specified command
- Useful for automated backups, deployments

**Best practices:**

- Regularly audit authorized_keys for unused keys
- Use command restrictions for service accounts
- Keep permissions: ~/.ssh/ (700) and authorized_keys (600)
- Include descriptive comments in pub keys

**Common errors:**

- **undefined**: undefined

## Configuration & Advanced Setup

### SSH Config File

Configure hosts, defaults, and connection settings in ~/.ssh/config

**Keywords:** config, configuration, host, options, aliases

#### Basic Host Configuration

```bash
cat ~/.ssh/config
```

_exec_
```bash
Host myserver
  HostName server.example.com
  User admin
  Port 2222
  IdentityFile ~/.ssh/id_ed25519

Host *.internal
  User intern_user
  ProxyJump bastion
```

Define host aliases and connection parameters in ~/.ssh/config. Simplifies repeated connections

- Format: Host pattern followed by configuration options
- * and ? wildcards supported in Host patterns
- Configuration applied in order, first match wins

#### Connect Using Host Alias

```bash
ssh myserver
```

_exec_
```bash
Last login: Wed Feb 28 14:30:00 2026
admin@myserver:~$
```

Use hostname alias instead of full connection details. All config parameters applied automatically

- Reads from ~/.ssh/config automatically
- Command line options override config file

#### Jump Host / Bastion Configuration

```bash
Host bastion
  HostName bastion.company.com
  User bastionuser

Host internal-*.company.com
  ProxyJump bastion
  User internaluser

ssh internal-db.company.com
```

_exec_
```bash
(SSH connects through bastion automatically)
Last login: Wed Feb 28 15:00:00 2026
internaluser@internal-db:~$
```

Use ProxyJump to tunnel through bastion host to reach internal servers. Cleaner than -J flag

- ProxyJump added in OpenSSH 7.3
- Can chain multiple jumps: ProxyJump host1,host2

**Best practices:**

- Use descriptive Host names
- Set IdentityFile explicitly to avoid trying all keys
- Use StrictHostKeyChecking accept-new for automation
- Set AddKeysToAgent yes for automatic key management

**Common errors:**

- **undefined**: undefined

### Connection Multiplexing

Reuse SSH connections for faster subsequent logins

**Keywords:** multiplexing, master, control, connection, sharing

#### Enable Connection Multiplexing

```bash
# Add to ~/.ssh/config
Host *
  ControlMaster auto
  ControlPath ~/.ssh/control-%h-%r-%p
  ControlPersist 3600
```

_exec_
```bash
(settings saved)
```

Enable multiplexing globally. Auto reuses master connections for 1 hour

- ControlMaster auto: automatically create master on first connection
- ControlPath: location of control socket
- ControlPersist 3600: keep master alive for 1 hour after last client

#### Multiple Connections Using Master

```bash
# First connection (creates master)
ssh user@host

# In another terminal: reuses existing connection
ssh user@host
```

_exec_
```bash
(second connection opens instantly)
```

Second and subsequent connections reuse the master SSH tunnel, bypassing authentication

- Dramatically faster since TCP/auth already done
- Check control sockets: ls -la ~/.ssh/control-*

#### Explicitly Check Master Connection

```bash
ssh -O check user@host
```

_exec_
```bash
Master running (pid=12345)
```

Check if multiplexed connection is active to a host

- exit code 0 if master running
- Useful for scripts

**Best practices:**

- Enable for frequently accessed hosts
- Set appropriate ControlPersist timeout
- Use %h (host), %r (user), %p (port) in ControlPath

**Common errors:**

- **undefined**: undefined

## Security Best Practices

### Protecting Your Keys

Keep SSH keys secure from unauthorized access

**Keywords:** security, permissions, passphrase, protection, best-practices

#### Fix SSH Directory Permissions

```bash
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_*
chmod 600 ~/.ssh/authorized_keys
chmod 644 ~/.ssh/*.pub
```

_exec_
```bash
(permissions updated)
```

SSH requires specific permissions for security. SSH will refuse keys with wrong permissions

- ~/.ssh directory: 700 (rwx------)
- Private key files: 600 (rw-------)
- Public key files: 644 (rw-r--r--)
- authorized_keys: 600 (rw-------)

#### Test Key Permissions

```bash
ls -la ~/.ssh/
```

_exec_
```bash
total 32
drwx------ 2 user user 4096 Feb 28 10:30 .
-rw------- 1 user user  464 Feb 28 10:30 id_ed25519
-rw-r--r-- 1 user user   89 Feb 28 10:30 id_ed25519.pub
-rw------- 1 user user 1679 Feb 28 10:30 authorized_keys
```

Verify all permissions are correct. Private keys only readable by owner

- First column shows permissions
- Directory should start with 'd'
- Private keys should be 'rw-------'

#### Rotate Compromised Key

```bash
# Step 1: Remove old key from authorized_keys on all servers
grep -l "old_key_fingerprint" ~/.ssh/authorized_keys | while read f; do
  sed -i '/old_key_fingerprint/d' "$f"
done

# Step 2: Delete local private key
rm ~/.ssh/id_rsa

# Step 3: Generate new key
ssh-keygen -t ed25519 -C "new-key"
```

_exec_
```bash
(key rotated)
```

After compromise, remove old key from all authorized_keys and generate new one

- Must rotate across all servers
- May need temporary password access to add new key

**Best practices:**

- Never share private keys
- Always use passphrase to protect keys
- Set strict file permissions (700/600)
- Rotate keys annually or after suspected compromise
- Use separate keys for different purposes

**Common errors:**

- **undefined**: undefined

### Host Key Verification

Verify remote host authenticity to prevent MITM attacks

**Keywords:** host-key, fingerprint, verification, known_hosts, mitm

#### First Connection Host Key Verification

```bash
ssh user@newhost
```

_exec_
```bash
The authenticity of host 'newhost (192.168.1.100)' can't be established.
ED25519 key fingerprint is SHA256:abcxy123...
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])?
```

On first connection, SSH shows host key fingerprint for verification. Accept only if verified from trusted source

- Fingerprint should match official host key
- Answer 'yes' to add to ~/.ssh/known_hosts
- Subsequent connections won't show this prompt

#### Verify Host Key Fingerprint Manually

```bash
# On the remote host
ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key.pub
```

_exec_
```bash
256 SHA256:abcxy123... root@newhost (ED25519)
```

Verify fingerprint matches what SSH showed during connection attempt

- Run on remote server admin console
- Compare with fingerprint displayed during SSH connection

#### Check Existing Host Key

```bash
ssh-keygen -l -f ~/.ssh/known_hosts
```

_exec_
```bash
256 SHA256:old_key... hostname1 (ED25519)
256 SHA256:new_key... hostname2 (ED25519)
```

Display all known host keys and their fingerprints from ~/.ssh/known_hosts

- Helps identify if host key has changed
- Unexpected changes may indicate compromise or reconfiguration

**Best practices:**

- Always verify host key on first connection
- Update ~/.ssh/known_hosts when host keys change
- Use DNSSEC SSHFP records for DNS-based verification
- Monitor for unexpected host key changes

**Common errors:**

- **undefined**: undefined

## Advanced Usage

### Jump Hosts & Bastion Patterns

Connect through intermediate hosts to reach internal servers

**Keywords:** jump, bastion, intermediate, multi-hop, proxy

#### Single Hop Through Jump Host

```bash
ssh -J user@bastion:2222 user@internal-server
```

_exec_
```bash
Last login: Wed Feb 28 16:30:00 2026
user@internal-server:~$
```

Use jump host to reach internal server. SSH tunnels through bastion automatically

- Format: -J [user@]host[:port]
- Can specify non-standard port on jump host
- Automatically applies ProxyCommand

#### Multiple Hops Through Jump Hosts

```bash
ssh -J user@bastion1,user@bastion2 user@final-host
```

_exec_
```bash
(connected through chain of hosts)
user@final-host:~$
```

Chain multiple jump hosts. Connection routes through bastion1 -> bastion2 -> final-host

- Separate hosts with commas
- Each hop authenticates independently

#### Persistent Jump Host Configuration

```bash
# ~/.ssh/config
Host bastion
  HostName bastion.company.com
  User admin

Host internal-*
  ProxyJump bastion
  User devuser

# Usage: ssh internal-server1
```

_exec_
```bash
(automatic jump through bastion)
```

Configure jump host in ~/.ssh/config for permanent setup. All internal-* hosts use bastion

- ProxyJump simpler than older ProxyCommand
- Inherits authentication from config

**Best practices:**

- Keep bastion host security hardened
- Monitor bastion access logs
- Use MFA on bastion if possible
- Implement host key verification

**Common errors:**

- **undefined**: undefined

### X11 Forwarding

Run graphical applications on remote servers and display locally

**Keywords:** x11, graphical, display, gui, forwarding

#### Enable X11 Forwarding

```bash
ssh -X user@remote-host
```

_exec_
```bash
user@remote-host:~$ gedit &
(gedit window opens on local display)
```

Forward X11 display from remote to local machine. Start GUI apps on remote, see them locally

- Requires X11 server on local machine (native on Linux/macOS)
- -X: standard X11 forwarding
- -Y: trusted X11 forwarding (skips security checks)

#### Trusted X11 Forwarding

```bash
ssh -Y user@remote-host
```

_exec_
```bash
user@remote-host:~$ firefox &
(firefox window opens on local display)
```

Trusted X11 forwarding allows apps to access X11 security extensions. Faster but less secure

- Use for trusted hosts only
- -Y skips X11 SECURITY extension
- Performance improvement over standard -X

#### Test X11 Forwarding

```bash
ssh -X user@remote-host
echo $DISPLAY
```

_exec_
```bash
localhost:10.0
```

DISPLAY variable set by SSH indicates X11 tunnel is active

- DISPLAY set to localhost:N where N > 0
- Value 0 would indicate no X11 forwarding

**Best practices:**

- Use only on trusted connections
- Disable remote X11 forwarding if not needed (in sshd_config)
- Verify ForwardX11 disabled for untrusted hosts

**Common errors:**

- **undefined**: undefined

## Practical Real-World Examples

### Common Use Cases

Real-world examples and practical patterns

**Keywords:** examples, practical, real-world, scenarios, use-cases

#### Copy Files Using SCP

```bash
# Copy file from local to remote
scp /local/path/file user@host:/remote/path/

# Copy file from remote to local
scp user@host:/remote/path/file /local/path/

# Copy directory recursively
scp -r user@host:/remote/path/ /local/path/
```

_exec_
```bash
file                      100%   1234KB    5.2MB/s   00:00
```

SCP (secure copy) transfers files through SSH tunnel. Secure alternative to FTP

- Uses SSH for encryption
- -r flag for recursive directory copy
- -P for non-standard port (uppercase!)

#### Sync Directory with rsync Over SSH

```bash
# Sync local to remote
rsync -avz -e ssh /local/path/ user@host:/remote/path/

# Sync remote to local
rsync -avz -e ssh user@host:/remote/path/ /local/path/

# With non-standard SSH port
rsync -avz -e 'ssh -p 2222' /local/path/ user@host:/remote/path/
```

_exec_
```bash
sending incremental file list
file1
file2
sent 1234 bytes  received 567 bytes
total size is 5678  speedup is 3.21
```

rsync over SSH for efficient file synchronization. Only transfers changed files

- Much faster than scp for large directories
- -a: archive mode (preserves permissions)
- -v: verbose, -z: compress
- Better for backups and deployments

#### Run Remote Command and Get Output

```bash
# Execute single command
ssh user@host "ps aux | grep nodejs"

# Execute multiple commands
ssh user@host "cd /app && npm start"

# Run command and capture output
result=$(ssh user@host "docker ps -a")
echo "$result"
```

_exec_
```bash
user        12345  0.5 15.3 234567 89012 ?  Sl  14:30   0:05 node /app/server.js
```

Execute remote commands and get output without interactive shell. Useful for scripts

- Command in quotes runs on remote, output sent to stdout
- Exit code preserved: useful in bash conditionals
- Great for cronjobs and automation

#### Automated Backup to Remote Host

```bash
#!/bin/bash
# backup.sh - automated backup script

LOCAL_PATH="/home/user/important-data"
BACKUP_HOST="backup.example.com"
BACKUP_USER="backup"
BACKUP_PATH="/backups/$(hostname)"

# Create backup
tar czf - "$LOCAL_PATH" | ssh $BACKUP_USER@$BACKUP_HOST \
  "cat > $BACKUP_PATH/backup-$(date +%Y%m%d).tar.gz"

echo "Backup completed"
```

_exec_
```bash
Backup completed
```

Stream compressed backup to remote server. Efficient and no local temporary files

- tar pipes directly through SSH
- No local disk space needed for backup
- Useful for cron jobs with SSH key auth

#### Port Forward for Database Connection

```bash
# Terminal 1: Create tunnel
ssh -L 3306:internal-db:3306 -N user@bastion

# Terminal 2: Connect to local port
mysql -h localhost -u dbuser -p
```

_exec_
```bash
Enter password:
Welcome to MariaDB Monitor. Commands...
```

Access private database server through SSH tunnel. Database thinks it's local

- -N: don't execute remote command
- Keep tunnel running in separate terminal
- Connection is end-to-end encrypted

#### SSH Agent for Automated Deployments

```bash
#!/bin/bash
# deploy.sh - automated deployment

# Start SSH agent for this script
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/deploy-key

# Deploy to multiple servers
for server in web1 web2 web3; do
  ssh -o StrictHostKeyChecking=accept-new deploy@$server \
    "cd /app && git pull && npm start"
done

# Kill agent when done
ssh-agent -k
```

_exec_
```bash
deployment to web1... done
deployment to web2... done
deployment to web3... done
```

Use SSH agent in scripts for passwordless authentication. Clean up after

- ssh-agent managed within script
- StrictHostKeyChecking=accept-new for new hosts
- Always kill agent to avoid leaked credentials

**Best practices:**

- Use SSH keys for all automation
- Validate output and errors in scripts
- Use -o BatchMode=yes in scripts to fail fast
- Log all remote operations for audit trail

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

## Troubleshooting

### Debugging SSH Connection Issues

Diagnose and fix common SSH problems

**Keywords:** troubleshooting, debug, verbose, error, fix

#### Enable Verbose Output for Debugging

```bash
# Single verbose (-v): shows authentication method
ssh -v user@host

# Double verbose (-vv): shows handshake details
ssh -vv user@host

# Triple verbose (-vvv): shows all details including crypto
ssh -vvv user@host
```

_exec_
```bash
OpenSSH_8.0p1 Ubuntu 1:8.0p1-6ubuntu1, OpenSSL 1.1.1
debug1: Reading configuration data /home/user/.ssh/config
debug1: No more authentication methods to try.
Permission denied (publickey,password).
```

Verbose flags show detailed connection process. Level indicates where connection fails

- -v: high-level flow
- -vv: detailed authentication
- -vvv: packet-level (very verbose)

#### Check SSH Key Permissions

```bash
# Check directory permissions
ls -ld ~/.ssh

# Check key file permissions
ls -l ~/.ssh/id_*
```

_exec_
```bash
drwx------ 2 user user 4096 Feb 28 10:00 /home/user/.ssh
-rw------- 1 user user  1234 Feb 28 10:00 /home/user/.ssh/id_ed25519
-rw-r--r-- 1 user user   456 Feb 28 10:00 /home/user/.ssh/id_ed25519.pub
```

SSH refuses to use keys with improper permissions. Directory 700, private keys 600

- Private keys must be readable only by owner
- Use 'chmod 700 ~/.ssh' and 'chmod 600 ~/.ssh/id_*'

#### Test Remote SSH Server Configuration

```bash
# List available authentication methods
ssh -o PreferredAuthentications=none user@host

# Test specific auth method
ssh -o PreferredAuthentications=publickey user@host
ssh -o PreferredAuthentications=password user@host
```

_exec_
```bash
Permission denied (publickey).
debug1: Authentications that can continue: publickey,password
```

Test which authentication methods server allows. Helpful for debugging auth failures

- Shows which methods server supports
- Can isolate auth method issues

**Best practices:**

- Always start with -v flag when debugging
- Check permissions first: 90% of issues are permission problems
- Test with alternate auth methods (e.g., password) to isolate key issues

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined
- **undefined**: undefined
