Skip to main content
Navigation
HomeTechnical ReferenceJournalGitHubGitHub
Sidebar — toggle document categories via the logo
Categories

SSH & Remote Access

Overview​

SSH (Secure Shell) is the standard protocol for securely connecting to and managing remote Linux systems. Beyond interactive shells, SSH provides encrypted file transfer, port forwarding, agent forwarding, and key-based authentication — all essential for daily operations work.

SSH keys​

Key types and generation​

An SSH key pair consists of a private key kept on your machine and a public key installed on servers. ssh-keygen creates and manages both; Ed25519 is the recommended algorithm for new keys.

# Generate an Ed25519 key (modern, recommended)
ssh-keygen -t ed25519 -C "john@example.com"

# Generate an RSA key (4096-bit)
ssh-keygen -t rsa -b 4096 -C "john@example.com"

# Generate with specific filename
ssh-keygen -t ed25519 -f ~/.ssh/prod_key -C "production access"

# Change passphrase on existing key
ssh-keygen -p -f ~/.ssh/id_ed25519

# Inspect a public key
ssh-keygen -l -f ~/.ssh/id_ed25519.pub

Common key types​

TypeAlgorithmRecommendation
ed25519Ed25519Preferred — fast, compact, secure
rsa (3072+)RSAFallback for older servers
ecdsaECDSAP-256 curve; usable but Ed25519 is better
dsaDSADeprecated — avoid

Copying keys to a server​

ssh-copy-id installs your public key into the remote account's authorized_keys, enabling password-less logins.

ssh-copy-id user@remote-host # copy default key
ssh-copy-id -i ~/.ssh/prod_key user@host # copy specific key
ssh-copy-id -p 2222 user@host # non-standard port

Manual method if ssh-copy-id is unavailable:

cat ~/.ssh/id_ed25519.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

Connecting​

Basic connections​

The basic ssh invocation opens an interactive shell on a remote host. Common options select a non-standard port, a specific identity file, and the verbosity level for diagnosing connection problems.

ssh user@host # standard connection
ssh -p 2222 user@host # non-standard port
ssh -i ~/.ssh/prod_key user@host # specific identity file
ssh -v user@host # verbose (debugging connection issues)
ssh -vvv user@host # very verbose

Connection patterns​

Beyond interactive shells, SSH can run a single remote command, pipe a local script to a remote shell, or hop through a jump host to reach hosts in a private network.

# Run a single command
ssh user@host "uptime"
ssh user@host "sudo systemctl restart nginx"

# Run a local script on a remote host
ssh user@host "bash -s" < local_script.sh

# Multi-hop (jump host)
ssh -J jump-user@bastion.internal target-user@10.0.1.50

# Escape sequences (from an active session)
~. # force disconnect
~^Z # background the connection
~? # list escape sequences

SSH client configuration​

The ~/.ssh/config file allows persistent per-host connection settings.

Basic host configuration​

Persistent settings for a host live in a config block: an alias, the real hostname, user, port, and identity file. Wildcard patterns apply shared defaults to groups of hosts.

# ~/.ssh/config

Host prod-web-1
HostName 10.0.1.50
User deploy
Port 22
IdentityFile ~/.ssh/prod_key

Host prod-web-2
HostName 10.0.1.51
User deploy
IdentityFile ~/.ssh/prod_key

# Wildcard patterns
Host staging-*
User ubuntu
IdentityFile ~/.ssh/staging_key
StrictHostKeyChecking no
UserKnownHostsFile /dev/null

Host *.internal
ProxyJump bastion.internal
User admin

Useful SSH config options​

OptionPurposeExample
HostNameTarget hostname or IPHostName 10.0.0.5
UserUsernameUser deploy
PortSSH portPort 2222
IdentityFilePrivate key pathIdentityFile ~/.ssh/prod_key
ProxyJumpJump hostProxyJump bastion
ForwardAgentAgent forwardingForwardAgent yes
ServerAliveIntervalKeep-alive intervalServerAliveInterval 60
ServerAliveCountMaxMax keep-alive countServerAliveCountMax 5
CompressionEnable compressionCompression yes
StrictHostKeyCheckingAccept unknown hostsStrictHostKeyChecking accept-new
UserKnownHostsFileKnown hosts fileUserKnownHostsFile ~/.ssh/known_hosts
LocalForwardLocal port forwardLocalForward 5432 db.internal:5432
RemoteForwardRemote port forwardRemoteForward 8080 localhost:80

Server keep-alive settings​

Keep-alive settings prevent idle connections from being dropped by NATs or firewalls. Configure them per-connection on the client side, or globally for all sessions on the server.

# Client-side keep-alive
ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=5 user@host

# Server-side keep-alive (/etc/ssh/sshd_config)
ClientAliveInterval 60
ClientAliveCountMax 5

Port forwarding (tunneling)​

Local port forwarding​

Access a remote service through an SSH tunnel:

# Forward local port 8080 to remote:80
ssh -L 8080:localhost:80 user@web-server

# Forward local port 5432 to a database via a jump host
ssh -L 5432:db.internal:5432 user@bastion

# Access remote service on localhost:8080
curl http://localhost:8080

Remote port forwarding​

Expose a local service to a remote host:

# Expose local port 3000 to remote:8080
ssh -R 8080:localhost:3000 user@public-server

# Now others on public-server can access your local service via port 8080

Dynamic (SOCKS) forwarding​

Create a SOCKS proxy through the SSH connection:

ssh -D 1080 user@bastion
# Configure browser to use SOCKS5 proxy at localhost:1080

Background tunnels​

Adding -fN sends the connection to the background after authentication and suppresses the remote shell — useful for keeping a tunnel open without occupying a terminal.

ssh -fN -L 5432:db.internal:5432 user@bastion
# -f: background, -N: no remote command

SSH agent​

The ssh-agent holds decrypted private keys in memory, so you only type your passphrase once per session.

Starting the agent​

The agent keeps decrypted keys in memory so you only enter your passphrase once per session. Start it, add your keys, then list what is loaded to confirm.

eval "$(ssh-agent)" # start a new agent
ssh-add # add default key (~/.ssh/id_rsa, etc.)
ssh-add ~/.ssh/prod_key # add a specific key
ssh-add -l # list loaded keys
ssh-add -L # list public keys
ssh-add -d ~/.ssh/prod_key # remove a key
ssh-add -D # remove all keys
ssh-add -t 3600 ~/.ssh/prod_key # add key with 1-hour lifetime

Agent forwarding​

Agent forwarding lets you use your local keys on a remote host without copying them:

ssh -A user@bastion # forward agent
ssh -A -J user@bastion 10.0.1.50 # jump host with agent forwarding

Security note: Agent forwarding exposes your agent socket to the remote host. Use with caution on untrusted servers, or prefer ProxyJump (which doesn't expose the agent).

Server configuration​

Key server settings (/etc/ssh/sshd_config)​

These hardened sshd_config settings enforce key-only authentication: disable root login and password auth, restrict which users may log in, and set timeouts to kill idle sessions.

Port 22
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
AllowUsers deploy admin
MaxAuthTries 3
ClientAliveInterval 60
ClientAliveCountMax 5
X11Forwarding no

After editing:

sshd -t # test configuration syntax
systemctl reload sshd # apply changes without dropping connections
systemctl restart sshd # restart sshd (may drop existing sessions)

Managing authorized keys​

The authorized_keys file grants login access to the matching private key. Each line holds one public key, and options at the start of a line can restrict what that key may do.

# ~/.ssh/authorized_keys (one key per line)
ssh-ed25519 AAAAC3... deploy@host

# Restrict a key to a single command
command="/opt/backup/run.sh" ssh-ed25519 AAAAC3... backup-bot

# Restrict a key by source IP
from="10.0.0.0/8" ssh-ed25519 AAAAC3... internal-user

File transfer​

scp​

scp copies files securely over SSH — to and from remote hosts, recursively for directories, and with attribute preservation.

# Copy to remote
scp file.txt user@host:/path/to/destination/
scp -P 2222 file.txt user@host:~/app/

# Copy from remote
scp user@host:/var/log/syslog ./logs/

# Recursive copy
scp -r configs/ user@host:/etc/myapp/

# Preserve attributes
scp -p file.txt user@host:/tmp/

rsync​

rsync efficiently synchronizes files between local and remote systems with delta transfers.

# Basic sync to remote
rsync -avz ./www/ user@host:/var/www/

# Sync from remote
rsync -avz user@host:/var/log/ ./logs/

# Dry-run (preview without transferring)
rsync -avzn ./www/ user@host:/var/www/

# Delete files on destination that don't exist on source
rsync -avz --delete ./www/ user@host:/var/www/

# Common flags
rsync -avP ./dir/ user@host:/dir/ # archive mode, verbose, show progress
FlagEffect
-aArchive mode: recursive, preserve permissions, timestamps, symlinks
-vVerbose
-zCompress during transfer
-PShow progress and keep partial files
-nDry-run
--deleteRemove files on dest not present on source
--excludeExclude patterns (e.g., --exclude='*.log')
-e "ssh -p 2222"Use specific SSH port

sftp​

sftp provides an interactive, FTP-style session over SSH for browsing, uploading, and downloading files.

sftp user@host # interactive FTP-like session
sftp -P 2222 user@host # non-standard port

Interactive commands: ls, cd, get, put, mget, mput, rm, mkdir, bye.

Troubleshooting connectivity​

Work through connection failures systematically: increase verbosity, check DNS and port reachability, verify known_hosts and key permissions, and inspect the server's authentication logs.

# Verbose connection attempts
ssh -vvv user@host

# Check DNS
dig +short host.example.com

# Check port reachability
nc -zv host.example.com 22
telnet host.example.com 22

# Check known_hosts issues
ssh-keygen -R host.example.com # remove host from known_hosts
ssh -o StrictHostKeyChecking=no user@host # skip host key check (insecure)

# Check key permissions
ls -la ~/.ssh/
# Should be: dir=700, private keys=600, public keys=644
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_*
chmod 644 ~/.ssh/id_*.pub

# Check server logs
ssh user@host "sudo tail -50 /var/log/auth.log" # Debian
ssh user@host "sudo tail -50 /var/log/secure" # RHEL

See also​