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.comssh <host> — Connect using the current local username.
ssh server.example.comssh -p <port> <user>@<host> — Connect on a non-standard SSH port.
ssh -p 2222 deploy@server.example.comssh -i <keyfile> <user>@<host> — Connect using a specific private key file.
ssh -i ~/.ssh/deploy_key deploy@server.example.comssh -v <user>@<host> — Verbose mode. Show debug information during connection for troubleshooting.
ssh -v deploy@server.example.comssh -vvv <user>@<host> — Maximum verbosity. Show all debug levels for deep troubleshooting.
ssh -vvv deploy@server.example.comssh -o StrictHostKeyChecking=no <user>@<host> — Skip host key verification (insecure, useful for scripts and ephemeral hosts).
ssh -o StrictHostKeyChecking=no deploy@staging.example.comssh -o ConnectTimeout=<seconds> <user>@<host> — Set a connection timeout in seconds.
ssh -o ConnectTimeout=5 deploy@server.example.comRemote Commands
ssh <user>@<host> <command> — Execute a single command on the remote host and return.
ssh deploy@server.example.com uptimessh <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.shssh -t <user>@<host> <command> — Force pseudo-terminal allocation. Required for interactive commands like sudo or top.
ssh -t deploy@server.example.com sudo apt updatessh <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.jsonKey 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_keyssh-keygen -p -f <keyfile> — Change the passphrase of an existing private key.
ssh-keygen -p -f ~/.ssh/id_ed25519ssh-keygen -l -f <keyfile> — Show the fingerprint of a key file.
ssh-keygen -l -f ~/.ssh/id_ed25519.pubssh-keygen -R <host> — Remove a host entry from known_hosts (fixes host key changed warnings).
ssh-keygen -R server.example.comssh-keygen -y -f <private_key> — Extract the public key from a private key file.
ssh-keygen -y -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pubKey Distribution
ssh-copy-id <user>@<host> — Copy your public key to a remote host's authorized_keys file.
ssh-copy-id deploy@server.example.comssh-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.comssh-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.comcat <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_ed25519ssh-add — Add the default key (~/.ssh/id_rsa, id_ed25519, etc.) to the agent.
ssh-addssh-add -l — List fingerprints of all keys currently loaded in the agent.
ssh-add -lssh-add -L — List full public keys currently loaded in the agent.
ssh-add -Lssh-add -d <keyfile> — Remove a specific key from the agent.
ssh-add -d ~/.ssh/deploy_keyssh-add -D — Remove all keys from the agent.
ssh-add -Dssh -A <user>@<host> — Enable agent forwarding. Allows the remote host to use your local SSH keys.
ssh -A deploy@bastion.example.comPort 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.comssh -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.comssh -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.comssh -D <port> <user>@<host> — Dynamic port forwarding. Create a SOCKS5 proxy on the local port.
ssh -D 1080 deploy@server.example.comssh -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.comssh -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.comJump 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-serverssh -J <user1>@<jump1>,<user2>@<jump2> <user>@<target> — Chain multiple jump hosts to reach the target.
ssh -J admin@bastion1,admin@bastion2 deploy@internal-serverssh -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-serverssh -o ProxyJump=<jump_host> <user>@<target_host> — Alternative syntax using the ProxyJump option.
ssh -o ProxyJump=bastion.example.com deploy@internal-serverSCP (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.comsftp -P <port> <user>@<host> — Connect via SFTP on a non-standard SSH port.
sftp -P 2222 deploy@server.example.comsftp> 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 -lasftp> lcd <path> — Change the local working directory.
sftp> lcd ~/DownloadsConfig 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 deployHost <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_keyHost <alias> with HostName, ProxyJump — Define a host that connects through a jump host (bastion).
Host internal-db
HostName db.internal
ProxyJump bastion.example.comHost * with ServerAliveInterval, ServerAliveCountMax — Global settings for all hosts. Keep connections alive with periodic pings.
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
AddKeysToAgent yesHost <pattern>* with User, IdentityFile — Use wildcards to apply settings to multiple hosts.
Host aws-*
User ec2-user
IdentityFile ~/.ssh/aws_keyMultiplexing & 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.comssh -O check <user>@<host> — Check if a multiplexed master connection is running.
ssh -O check deploy@server.example.comssh -O exit <user>@<host> — Terminate a multiplexed master connection.
ssh -O exit deploy@server.example.comssh -o ServerAliveInterval=<seconds> <user>@<host> — Send keep-alive packets to prevent connection timeout.
ssh -o ServerAliveInterval=60 deploy@server.example.comEscape 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:3306Security & Troubleshooting
ssh-keyscan <host> — Fetch the public host keys from a remote server.
ssh-keyscan server.example.com >> ~/.ssh/known_hostsssh-keyscan -t ed25519 <host> — Fetch only a specific key type from the remote server.
ssh-keyscan -t ed25519 server.example.comssh -Q key — List all supported key types by the local SSH client.
ssh -Q keyssh -Q cipher — List all supported ciphers by the local SSH client.
ssh -Q cipherssh -Q mac — List all supported MAC algorithms.
ssh -Q macchmod 700 ~/.ssh — Set correct permissions on the .ssh directory (required for SSH to work).
chmod 700 ~/.sshchmod 600 ~/.ssh/id_ed25519 — Set correct permissions on a private key file (must not be accessible by others).
chmod 600 ~/.ssh/id_ed25519chmod 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
- OpenSSH – official website – documentation and changelog
- ssh(1) – manual page – every option at a glance
- Secure Shell – Wikipedia – background and history
Related Commands
- 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