Linux
Intermediate 14 min read Linux

SSH: Secure Remote Access

SSH is how you reach every server, container and cloud VM: one encrypted channel for a shell, file transfer and port forwarding. Learn to connect with ssh user@host, generate and install key pairs with ssh-keygen and ssh-copy-id, understand the permissions that keep authorized_keys safe, use scp and the SSH config file, and harden sshd_config so password logins and root logins are locked down.

sshsecure shellssh-keygenid_ed25519id_rsaauthorized_keysssh-copy-idscpssh configPasswordAuthenticationPermitRootLoginport 22encryptionlinux
Introduction

What is this?

SSH (Secure Shell) is the encrypted protocol you use to get a command line on a remote machine, transfer files and forward ports. Instead of sending your password over the network in plain text like Telnet, SSH encrypts everything between your client and the server, and it can authenticate you with cryptographic keys instead of passwords entirely.

Motivation

Why do you need it?

  • SSH is the universal remote control for servers: clouds, VMs, containers, switches and appliances all expose SSH as the admin interface.
  • Everything is encrypted — the session, the password prompt and file transfers — so credentials are never readable on the wire.
  • Key-based authentication removes passwords from the equation: servers that disable passwords cannot be brute-forced with login guessing.
  • One key pair works across all your machines: add the public key to a new server and you log in instantly, everywhere.
  • Beyond shells, SSH powers git over SSH, Ansible connections, SCP/rsync file transfer and encrypted tunnels to internal services.
Think about it

Mental model

Imagine

A passport-controlled border crossing

Think of

SSH authentication

Your private key is the passport you never show — the border agent only ever sees the ID page (public key). You prove you hold the passport by signing a challenge the agent sends; the agent proves the country is real by showing its own credential (the host key). Your passport never leaves your pocket, and the whole exchange happens in an encrypted tunnel.

Mechanics

How it works

  • The client connects to port 22 and the server sends its host key; the client verifies it against its known_hosts file (first contact is "trust on first use").
  • Both sides agree on a session key using public-key cryptography (key exchange), so all further traffic is encrypted without ever sending secrets over the wire.
  • For password login the password is sent inside the encrypted session. For key login the server sends a challenge the client must sign with your private key.
  • The server checks the matching public key against ~/.ssh/authorized_keys of the user you are logging in as; matching the signature grants access.
  • The server enforces file permissions: ~/.ssh must not be group/world-writable and authorized_keys must be private, or SSH refuses to trust the keys.

How an SSH key-authentication session is established.

Client connects
Host key verification
Key exchange
Sign the challenge
authorized_keys check
Encrypted session
Reference

Key commands

ssh deploy@myserver

Open an encrypted shell session as the deploy user on myserver.

Welcome to Ubuntu 24.04.1 LTS (GNU/Linux 6.8.0-45-generic x86_64)
ssh-keygen -t ed25519 -C "you@example.com"

Generate an Ed25519 key pair — modern, fast and the recommended default.

Generating public/private ed25519 key pair.
Your identification has been saved in /home/you/.ssh/id_ed25519
Your public key has been saved in /home/you/.ssh/id_ed25519.pub
ssh-copy-id deploy@myserver

Install your public key into the server's authorized_keys file.

Number of key(s) added: 1
Now try logging into the machine, with: "ssh deploy@myserver"
ls -la ~/.ssh

List your key pair and the client config file.

drwx------ 2 you you 4096 Aug  8 10:30 .
-rw------- 1 you you  464 Aug  8 10:30 id_ed25519
-rw-r--r-- 1 you you   92 Aug  8 10:30 id_ed25519.pub
scp app.jar deploy@myserver:/opt/app/

Securely copy a file over the SSH connection.

app.jar    100%   12MB   6.0MB/s   00:02
grep -E "^(PasswordAuthentication|PermitRootLogin)" /etc/ssh/sshd_config

Check the two hardening settings that matter most.

PasswordAuthentication no
PermitRootLogin no
Hands-on

Examples

Go from password login to passwordless key login on a server

Go from password login to passwordless key login on a server
# On your laptop: generate a modern key pair (no passphrase)
ssh-keygen -t ed25519 -C "you@example.com" -f ~/.ssh/id_ed25519 -N ""
# Install your public key on the server (asks for the password once)
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@myserver
# Now connect — no password prompt, straight into a shell
ssh deploy@myserver
# Hardening: turn off password auth on the server
sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart ssh

ssh-keygen creates a private key that stays on your laptop and a public key that is safe to share. ssh-copy-id appends that public key to ~/.ssh/authorized_keys on the server. From then on the server can prove you hold the private key by asking you to sign a challenge — no password needed — and disabling PasswordAuthentication removes the login-guessing attack surface entirely.

Real world

In production

  • Server administration: every cloud VM, on-prem box and network appliance is managed through an SSH session.
  • Automation transport: Ansible runs over SSH by default, and CI/CD pipelines push and run code via SSH to deploy targets.
  • Secure file movement: scp and rsync over SSH replace FTP for transfers, and git pushes to GitHub/GitLab use SSH keys.
  • Tunnels to private services: ssh -L 8080:db.internal:3306 server gives you an encrypted path to a database behind a firewall.
  • Secrets at rest and in motion: keys in CI secret stores and agent-based key management keep credentials off disk and out of repositories.
Guidelines

Best practices

  • Generate Ed25519 keys, never reuse a passphrase-locked key in scripts — use ssh-agent for interactive sessions and dedicated keys per service.
  • Keep your private key private: 600 permissions on id_ed25519, never commit it, never copy it to another machine.
  • Set strict permissions on the server: chmod 700 ~/.ssh and chmod 600 ~/.ssh/authorized_keys.
  • Use one key pair per purpose (personal, deploy, CI) so you can revoke one without touching the others.
  • Harden sshd_config: PasswordAuthentication no, PermitRootLogin no, and prefer key-only access on production.
  • Put per-host options in ~/.ssh/config (user, port, key) instead of long command lines — and test config changes with ssh -G host.
Watch out

Common mistakes

  • Copying the private key (id_ed25519) instead of the public key (id_ed25519.pub) to a server.
  • Leaving ~/.ssh or authorized_keys world-readable, which makes sshd silently ignore the keys.
  • Forgetting the username: ssh server instead of ssh user@server, then being puzzled by a login as the wrong account.
  • Editing sshd_config and not restarting sshd, so the hardening never takes effect.
  • Adding a key without a passphrase to a shared or CI machine, then leaking the private key.
  • Ignoring the host key warning after a server rebuild and blindly accepting a changed key without verifying.
Root cause analysis

Common issues

Error
Permission denied (publickey)
Root cause

The server found no matching public key in authorized_keys, or it rejected the key because of wrong file permissions.

Fix

Re-run ssh-copy-id, confirm the key is in ~/.ssh/authorized_keys on the server, and verify ~/.ssh is 700 and authorized_keys is 600.

Error
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED
Root cause

The server's host key differs from the one stored in ~/.ssh/known_hosts — usually a reinstall or IP reuse, possibly a man-in-the-middle.

Fix

Verify the host is legitimately yours (out-of-band), then remove the stale entry with ssh-keygen -R host and reconnect.

Error
ssh: connect to host port 22: Connection refused
Root cause

sshd is not installed or running, the service failed to start, or a firewall is dropping the port.

Fix

On the server run systemctl status ssh, check sshd -t for config errors, and confirm the port is open with ss -tlnp. Verify firewall rules allow inbound 22.

Error
Bad owner or permissions on ~/.ssh/config
Root cause

The SSH client refuses to use a config file it considers insecure.

Fix

chmod 600 ~/.ssh/config (and ensure ~/.ssh is 700).

When things break

Debugging tips

  • Run ssh -v user@host (or -vvv) to see exactly which key is tried, which auth method fails and where the connection stalls.
  • Check server logs for rejected attempts: journalctl -u ssh or tail -f /var/log/auth.log | grep sshd.
  • Verify permissions with ls -ld ~/.ssh ~/.ssh/authorized_keys and stat -c "%a %n" on the server.
  • Test each hop: ping the host, then nc -vz host 22, then ssh -v — isolate network vs authentication.
  • Dry-run config parsing on the server with sshd -t before restarting sshd after any config edit.
Interviews

Interview checkpoint

Practice

Hands-on lab

Set up passwordless SSH to localhost and harden it
15 min · intermediate
In progress
Objectives
  • Install and start an OpenSSH server in a container
  • Generate an Ed25519 key pair and inspect ~/.ssh
  • Install your public key with ssh-copy-id and log in without a password
  • Copy files with scp and harden sshd_config to key-only access

Set up passwordless SSH to localhost and harden it

15 min · intermediate

0/8 steps
0%
sandbox · Linux sandbox
$
Try these commands
Test yourself

Quick quiz

0/6
1

On the server, where must your public key be placed to allow key-based login?

2

Which permissions should the ~/.ssh directory have on the server?

3

Your private SSH key should never leave your machine.

4

Which command installs your public key on a remote server automatically?

5

Which sshd_config setting disables password-based logins?

6

You set up keys and disabled password auth. A new teammate reports they still get "Permission denied (publickey)". What is the most likely cause?

Quick reference

Cheat sheet

Connect
ssh user@hostConnect to a remote host
ssh -p 2222 user@hostConnect on a non-default port
ssh user@host "cmd"Run one remote command and exit
ssh -i ~/.ssh/mykey user@hostUse a specific private key
exitClose the remote session
Keys
ssh-keygen -t ed25519 -C "you@example.com"Generate a modern key pair
cat ~/.ssh/id_ed25519.pubView your public key
ssh-copy-id user@hostInstall your public key on the server
ssh-add ~/.ssh/id_ed25519Load a key into the agent
File transfer
scp file.txt user@host:/tmp/Copy a file to the server
scp -r logs/ user@host:/var/logs/Copy a directory recursively
scp user@host:/etc/app.conf .Copy a file from the server
scp -P 2222 file user@host:/tmpscp on a non-default port
Server layout & permissions
~/.ssh/authorized_keysPublic keys allowed to log in
chmod 700 ~/.sshDirectory must be private
chmod 600 ~/.ssh/authorized_keysKey file must be private
/etc/ssh/sshd_configServer settings (needs restart)
ssh-keygen -R hostForget a host key after it changed
Hardening (sshd_config)
PasswordAuthentication noDisable password logins
PermitRootLogin noDisable root logins entirely
Port 2222Move SSH off the default port
PermitEmptyPasswords noNever allow empty passwords
service ssh restartApply sshd_config changes
Go deeper

Official documentation