The whole idea in one sentence
The client private key and the public key in the remote authorized_keys must match — that is all. Debugging therefore revolves around two things: whether the pair matches, and whether the remote sshd is willing to trust that authorized_keys file (bad permissions make sshd silently refuse to read it).
ssh-keygen -t ed25519 -C "you@laptop" # Generate a key pair (just press Enter all the way)
ssh-copy-id user@server # Write the public key into the remote authorized_keys
ssh user@server # Verify: success when no password is requestedThe standard three steps and how to verify
(1) Generate a key: prefer ed25519 (shorter, faster, secure), defaulting to ~/.ssh/id_ed25519; (2) Distribute: ssh-copy-id is the most reliable (it appends and fixes permissions); on Windows without it, manually append the key to the remote ~/.ssh/authorized_keys; (3) Verify: ssh -o BatchMode=yes user@server echo ok — BatchMode forbids interactive passwords, so a clean ok proves passwordless auth truly works, far more trustworthy than "no password prompt appeared".
type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh user@server "cat >> ~/.ssh/authorized_keys"
# How to distribute the public key manually on WindowsGate 1: file permissions
sshd is extremely picky: if authorized_keys or .ssh is group-writable it silently ignores the whole file (no error, just a fallback to password auth). Correct values: ~/.ssh 700, authorized_keys 600, private key 600. Same on the Windows side — a too-open private key triggers UNPROTECTED PRIVATE KEY FILE and refuses to use it.
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_ed25519Gate 2: the home directory
The sneakier trap: the home directory itself being group/other-writable (common with shared mounts or legacy chmod 777 after manual useradd) — sshd refuses to trust authorized_keys all the same. Check with ls -ld /home/user and tighten to 750 or stricter. The checking order is always home → .ssh → file.
ls -ld /home/user # The home directory must not be group/other writable
chmod 750 /home/user # Tighten it when neededGate 3: SELinux and the server log
On RHEL/CentOS with SELinux enforcing, a wrong security context on authorized_keys also fails silently (especially after manually mv/cp-ing the file). restorecon -rv ~/.ssh restores the standard context. For any stuck scenario there is one ultimate weapon: the server log tail -f /var/log/secure (Debian/Ubuntu: /var/log/auth.log) combined with a client-side -v reconnect — with both sides visible, the problem has nowhere to hide.
restorecon -rv ~/.ssh # Fix the SELinux context
ssh -v user@server # Verbose client handshake
tail -f /var/log/secure # Why the server rejected itLevel up: config aliases and multiple keys
Put frequent connections into ~/.ssh/config: one Host alias replaces a long command line and can bind a different key per server — much cleaner than typing -i every time, and git remotes and deploy scripts benefit equally.
Host prod
HostName 203.0.113.10
User deploy
IdentityFile ~/.ssh/id_ed25519_prod
ServerAliveInterval 60
# After that, just run: ssh prod