ssh — Encrypted Remote Access and Tunneling from the Command Line

Practical guide to SSH — connecting to remote hosts, managing keys, setting up port forwarding and transferring files securely.

SSH (Secure Shell) is the standard tool for logging into remote systems securely, running commands on distant machines, and transferring files – all over a single cryptographically protected connection. Whether you're reaching a lone server or navigating a complex infrastructure with jump hosts and SOCKS proxies, SSH handles it. This guide covers the key commands and options, from your first connection through key management to port forwarding and multiplexing.

Connecting

ssh <user>@<host> — Connect to a remote host as a specific user.

ssh deploy@server.example.com

ssh <host> — Connect using the current local username.

ssh server.example.com

ssh -p <port> <user>@<host> — Connect on a non-standard SSH port.

ssh -p 2222 deploy@server.example.com

ssh -i <keyfile> <user>@<host> — Connect using a specific private key file.

ssh -i ~/.ssh/deploy_key deploy@server.example.com

ssh -v <user>@<host> — Verbose mode. Show debug information during connection for troubleshooting.

ssh -v deploy@server.example.com

ssh -vvv <user>@<host> — Maximum verbosity. Show all debug levels for deep troubleshooting.

ssh -vvv deploy@server.example.com

ssh -o StrictHostKeyChecking=no <user>@<host> — Skip host key verification (insecure, useful for scripts and ephemeral hosts).

ssh -o StrictHostKeyChecking=no deploy@staging.example.com

ssh -o ConnectTimeout=<seconds> <user>@<host> — Set a connection timeout in seconds.

ssh -o ConnectTimeout=5 deploy@server.example.com

Remote Commands

ssh <user>@<host> <command> — Execute a single command on the remote host and return.

ssh deploy@server.example.com uptime

ssh <user>@<host> '<command1> && <command2>' — Execute multiple chained commands remotely.

ssh deploy@server.example.com 'cd /var/www && git pull'

ssh <user>@<host> 'bash -s' < <script> — Execute a local script on the remote host via stdin.

ssh deploy@server.example.com 'bash -s' < deploy.sh

ssh -t <user>@<host> <command> — Force pseudo-terminal allocation. Required for interactive commands like sudo or top.

ssh -t deploy@server.example.com sudo apt update

ssh <user>@<host> 'cat > <remote_file>' < <local_file> — Transfer a file to a remote host using stdin redirection.

ssh deploy@server.example.com 'cat > /tmp/config.json' < config.json

Key Management

ssh-keygen -t ed25519 -C "<comment>" — Generate a new Ed25519 key pair (recommended, most secure and fastest).

ssh-keygen -t ed25519 -C "deploy@server.example.com"

ssh-keygen -t rsa -b 4096 -C "<comment>" — Generate a new RSA key pair with 4096 bits.

ssh-keygen -t rsa -b 4096 -C "user@example.com"

ssh-keygen -t ed25519 -f <path> — Generate a key pair and save to a specific file path.

ssh-keygen -t ed25519 -f ~/.ssh/deploy_key

ssh-keygen -p -f <keyfile> — Change the passphrase of an existing private key.

ssh-keygen -p -f ~/.ssh/id_ed25519

ssh-keygen -l -f <keyfile> — Show the fingerprint of a key file.

ssh-keygen -l -f ~/.ssh/id_ed25519.pub

ssh-keygen -R <host> — Remove a host entry from known_hosts (fixes host key changed warnings).

ssh-keygen -R server.example.com

ssh-keygen -y -f <private_key> — Extract the public key from a private key file.

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

Key Distribution

ssh-copy-id <user>@<host> — Copy your public key to a remote host's authorized_keys file.

ssh-copy-id deploy@server.example.com

ssh-copy-id -i <keyfile> <user>@<host> — Copy a specific public key to the remote host.

ssh-copy-id -i ~/.ssh/deploy_key.pub deploy@server.example.com

ssh-copy-id -p <port> <user>@<host> — Copy public key to a remote host on a non-standard port.

ssh-copy-id -p 2222 deploy@server.example.com

cat <keyfile> | ssh <user>@<host> 'mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys' — Manual alternative to ssh-copy-id when it is not available.

cat ~/.ssh/id_ed25519.pub | ssh deploy@server.example.com 'mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys'

SSH Agent

eval "$(ssh-agent -s)" — Start the SSH agent and set environment variables in the current shell.

eval "$(ssh-agent -s)"

ssh-add <keyfile> — Add a private key to the SSH agent.

ssh-add ~/.ssh/id_ed25519

ssh-add — Add the default key (~/.ssh/id_rsa, id_ed25519, etc.) to the agent.

ssh-add

ssh-add -l — List fingerprints of all keys currently loaded in the agent.

ssh-add -l

ssh-add -L — List full public keys currently loaded in the agent.

ssh-add -L

ssh-add -d <keyfile> — Remove a specific key from the agent.

ssh-add -d ~/.ssh/deploy_key

ssh-add -D — Remove all keys from the agent.

ssh-add -D

ssh -A <user>@<host> — Enable agent forwarding. Allows the remote host to use your local SSH keys.

ssh -A deploy@bastion.example.com

Port Forwarding (Tunneling)

ssh -L <local_port>:<target_host>:<target_port> <user>@<host> — Local port forwarding. Access a remote service through a local port.

ssh -L 3306:localhost:3306 deploy@server.example.com

ssh -L <local_port>:<remote_host>:<remote_port> <user>@<host> — Forward to a host accessible from the SSH server (not just localhost).

ssh -L 5432:db.internal:5432 deploy@bastion.example.com

ssh -R <remote_port>:<local_host>:<local_port> <user>@<host> — Remote (reverse) port forwarding. Expose a local service on the remote host.

ssh -R 8080:localhost:3000 deploy@server.example.com

ssh -D <port> <user>@<host> — Dynamic port forwarding. Create a SOCKS5 proxy on the local port.

ssh -D 1080 deploy@server.example.com

ssh -L <local_port>:<target>:<target_port> -N <user>@<host> — Forward a port without opening a remote shell (-N = no command).

ssh -L 3306:localhost:3306 -N deploy@server.example.com

ssh -L <local_port>:<target>:<target_port> -N -f <user>@<host> — Forward a port in the background (-f = fork to background).

ssh -L 3306:localhost:3306 -N -f deploy@server.example.com

Jump Hosts (Bastion/ProxyJump)

ssh -J <jump_host> <user>@<target_host> — Connect to a target host through a jump host (bastion).

ssh -J bastion.example.com deploy@internal-server

ssh -J <user1>@<jump1>,<user2>@<jump2> <user>@<target> — Chain multiple jump hosts to reach the target.

ssh -J admin@bastion1,admin@bastion2 deploy@internal-server

ssh -J <jump_host>:<port> <user>@<target_host> — Use a jump host running SSH on a non-standard port.

ssh -J bastion.example.com:2222 deploy@internal-server

ssh -o ProxyJump=<jump_host> <user>@<target_host> — Alternative syntax using the ProxyJump option.

ssh -o ProxyJump=bastion.example.com deploy@internal-server

SCP (Secure Copy)

scp <local_file> <user>@<host>:<remote_path> — Copy a local file to a remote host.

scp ./config.json deploy@server.example.com:/etc/app/

scp <user>@<host>:<remote_file> <local_path> — Copy a file from a remote host to the local machine.

scp deploy@server.example.com:/var/log/app.log ./logs/

scp -r <local_dir> <user>@<host>:<remote_path> — Copy a directory recursively to a remote host.

scp -r ./dist/ deploy@server.example.com:/var/www/html/

scp -P <port> <local_file> <user>@<host>:<remote_path> — Copy using a non-standard SSH port (note: uppercase -P for scp).

scp -P 2222 ./config.json deploy@server.example.com:/etc/app/

scp -i <keyfile> <local_file> <user>@<host>:<remote_path> — Copy using a specific private key file.

scp -i ~/.ssh/deploy_key ./app.tar.gz deploy@server.example.com:/tmp/

scp <user>@<host1>:<file> <user>@<host2>:<path> — Copy a file between two remote hosts (data flows through local machine).

scp deploy@server1.example.com:/backup.sql deploy@server2.example.com:/import/

SFTP (Secure File Transfer)

sftp <user>@<host> — Start an interactive SFTP session with a remote host.

sftp deploy@server.example.com

sftp -P <port> <user>@<host> — Connect via SFTP on a non-standard SSH port.

sftp -P 2222 deploy@server.example.com

sftp> get <remote_file> <local_path> — Download a file from the remote host (inside SFTP session).

sftp> get /var/log/app.log ./logs/

sftp> put <local_file> <remote_path> — Upload a file to the remote host (inside SFTP session).

sftp> put ./config.json /etc/app/

sftp> ls — List files in the current remote directory.

sftp> ls -la

sftp> lcd <path> — Change the local working directory.

sftp> lcd ~/Downloads

Config File (~/.ssh/config)

Host <alias> with HostName, User — Define a host alias with default user. Connect with: ssh

Host production
  HostName server.example.com
  User deploy

Host <alias> with HostName, Port, IdentityFile — Define a host with custom port and key file.

Host staging
  HostName staging.example.com
  Port 2222
  IdentityFile ~/.ssh/staging_key

Host <alias> with HostName, ProxyJump — Define a host that connects through a jump host (bastion).

Host internal-db
  HostName db.internal
  ProxyJump bastion.example.com

Host * with ServerAliveInterval, ServerAliveCountMax — Global settings for all hosts. Keep connections alive with periodic pings.

Host *
  ServerAliveInterval 60
  ServerAliveCountMax 3
  AddKeysToAgent yes

Host <pattern>* with User, IdentityFile — Use wildcards to apply settings to multiple hosts.

Host aws-*
  User ec2-user
  IdentityFile ~/.ssh/aws_key

Multiplexing & Keep-Alive

ssh -o ControlMaster=auto -o ControlPath=/tmp/ssh-%r@%h:%p -o ControlPersist=10m <user>@<host> — Enable connection multiplexing. Subsequent SSH sessions reuse the connection.

ssh -o ControlMaster=auto -o ControlPath=/tmp/ssh-%r@%h:%p -o ControlPersist=10m deploy@server.example.com

ssh -O check <user>@<host> — Check if a multiplexed master connection is running.

ssh -O check deploy@server.example.com

ssh -O exit <user>@<host> — Terminate a multiplexed master connection.

ssh -O exit deploy@server.example.com

ssh -o ServerAliveInterval=<seconds> <user>@<host> — Send keep-alive packets to prevent connection timeout.

ssh -o ServerAliveInterval=60 deploy@server.example.com

Escape Sequences

~. — Terminate a stuck SSH session. Press Enter first, then type ~. (tilde dot).

~.

~^Z — Suspend the SSH session and return to local shell. Resume with fg.

~^Z

~# — List all forwarded connections in the current session.

~#

~? — Show a list of all available escape sequences.

~?

~C — Open the SSH command line to add port forwards on-the-fly during a session.

~C then: -L 3306:localhost:3306

Security & Troubleshooting

ssh-keyscan <host> — Fetch the public host keys from a remote server.

ssh-keyscan server.example.com >> ~/.ssh/known_hosts

ssh-keyscan -t ed25519 <host> — Fetch only a specific key type from the remote server.

ssh-keyscan -t ed25519 server.example.com

ssh -Q key — List all supported key types by the local SSH client.

ssh -Q key

ssh -Q cipher — List all supported ciphers by the local SSH client.

ssh -Q cipher

ssh -Q mac — List all supported MAC algorithms.

ssh -Q mac

chmod 700 ~/.ssh — Set correct permissions on the .ssh directory (required for SSH to work).

chmod 700 ~/.ssh

chmod 600 ~/.ssh/id_ed25519 — Set correct permissions on a private key file (must not be accessible by others).

chmod 600 ~/.ssh/id_ed25519

chmod 644 ~/.ssh/authorized_keys — Set correct permissions on authorized_keys.

chmod 644 ~/.ssh/authorized_keys

Conclusion

SSH is far more than a terminal replacement: keys instead of passwords, agent forwarding for bastion hosts, port tunnels for locked-down services, and multiplexing for fast reconnections make it the backbone of any infrastructure. Keep your config file tidy and protect your keys with passphrases – you'll work faster and more securely at the same time.

Further Reading

  • scp – securely copy files to and from remote hosts
  • ssh-keygen – generate and manage SSH key pairs
  • mosh – SSH alternative for unreliable or high-latency connections