SSH Keys Explained: How Public-Key Login Actually Works

Passwords get guessed; keys don't — not practically. This guide shows how SSH public-key login actually works: generating an Ed25519 key pair, installing the public key on a server, what happens during the login handshake, ssh-agent, and fixing the usual Permission denied (publickey) failures.

Written by Projectech8 min readPublished
For B.E./B.Tech Computer Science / IT students who SSH into a VPS, Raspberry Pi or lab server and want to understand what the key commands actually do Topics: SSH, Linux, Git & DevOps
Blueprint-style illustration of a laptop and a server exchanging key and lock symbols for public-key authentication.
Illustration generated for this guide.
In this guide

Every student server story starts the same way: a password typed over SSH, a brute-force botnet trying thousands of logins an hour, and eventually someone's project demo going down because a weak password wasn't the fortress they thought. SSH keys replace the password with something that can't be guessed: a private key your laptop holds and never sends, and a public key the server checks against.

This guide explains how public-key login actually works — not just the commands — so you can set it up on your VPS or Raspberry Pi and fix it when it breaks.

Why keys beat passwords

A password is a shared secret you must type and the server must verify — phishable, re-usable, guessable. An SSH key pair is asymmetric:

  • The private key stays on your machine. It never crosses the network — not even encrypted.
  • The public key sits on every server you want to log into, inside ~/.ssh/authorized_keys.

Knowing the public key gives an attacker nothing useful: it can't be reversed into the private key, and the server never asks you to reveal the private key. Authentication is a challenge-response: the server issues a challenge tied to your public key, and only the holder of the private key can answer it. Stealing the public key is like stealing a padlock — you still can't open it.

Note: Commands below are for the standard OpenSSH client on Linux, macOS and WSL. Windows users: the same commands work in PowerShell's built-in OpenSSH or in WSL.

Step 1: generate a key pair

On your own machine:

ssh-keygen -t ed25519 -C "my-laptop"

Accept the default location (~/.ssh/id_ed25519) and — this matters — set a passphrase when asked. The passphrase encrypts the private key file, so a stolen laptop doesn't automatically mean stolen server access.

What you get:

  • ~/.ssh/id_ed25519 — the private key. Guard it like a password.
  • ~/.ssh/id_ed25519.pub — the public key. A single line starting with ssh-ed25519, followed by a long encoded string and your comment. This is the only file that ever leaves your machine.

Why Ed25519? It's the modern default: short keys, fast, and strong at 256-bit-equivalent security — better than RSA-2048 in a fraction of the size. (-t rsa -b 4096 still works if some old device demands RSA.)

Step 2: install the public key on the server

The easy way:

ssh-copy-id user@server-ip

This appends your .pub contents to the server's ~/.ssh/authorized_keys and fixes permissions for you. The manual equivalent — appending the public-key line to ~/.ssh/authorized_keys on the server — works identically; ssh-copy-id just removes the fiddly bits.

Permissions are the number-one silent failure (sshd refuses to trust sloppy files):

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

If ~/.ssh or authorized_keys is group/world-writable, the server ignores the key and falls back to password — with no helpful error by default.

Step 3: log in and watch it work

ssh user@server-ip

The handshake, simplified:

  1. Your client offers to authenticate with a key; the server looks for the matching public key in authorized_keys.
  2. The server sends a challenge that only the private key can answer (a signature over a session-specific value).
  3. Your client signs it — prompting for the key's passphrase if you set one — and the server verifies the signature against the public key.
  4. The session opens. The private key never left your machine.

The first connection also asks you to verify the host key fingerprint — that's the server proving its identity to you, the mirror image of what you just did. Verify it against your provider's console before typing yes.

ssh-agent: type the passphrase once

A passphrase on every login gets old. ssh-agent holds your decrypted key in memory for the session:

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

Enter the passphrase once; later logins use the agent-held key. On logout or reboot the agent forgets it — the private key file itself stays passphrase-encrypted on disk. (Most desktop Linux and macOS start an agent automatically; check with ssh-add -l.)

Using keys with Git and GitHub

Same mechanism, new authorized_keys list: paste your public key (the .pub file contents) into GitHub → Settings → SSH keys. Then clone with the SSH URL:

git clone git@github.com:username/repo.git

Push and pull then authenticate with your key instead of a password or token prompt. GitHub never sees your private key.

Troubleshooting: "Permission denied (publickey)"

Run the client verbosely and read the output — the answer is almost always in the last 20 lines:

ssh -v user@server-ip

Usual suspects, in order:

  1. Server-side permissions. ~/.ssh must be 700, authorized_keys 600, owned by the login user. Fix via console or password login.
  2. Wrong public key installed. The .pub on the server must match the private key your client offers. Regenerating keys and forgetting to update the server is the classic.
  3. Wrong username. ssh root@... when the key sits in ubuntu's authorized_keys (or vice versa).
  4. Client offering the wrong key. With several keys, point at the right one: ssh -i ~/.ssh/id_ed25519 user@server-ip.
  5. Passphrase confusion. A wrong passphrase looks like a key failure; run ssh-add and retry to isolate it.
  6. sshd config. Some hardened servers set PasswordAuthentication no and have no key installed — then only console or VNC access recovers the box.

Common mistakes

  1. Sharing the private key — emailing it to a teammate, screenshotting it, committing it to a repo. One key per person per machine; teammates generate their own and you add their public keys.
  2. No passphrase on a laptop key — convenient until the laptop is stolen. Passphrase plus agent is the sane middle ground.
  3. Pasting the private key where the public key goes — key fields on GitHub and VPS panels want the .pub single line, never the private-key file (the one whose first line says BEGIN PRIVATE KEY).
  4. One key everywhere, forever — acceptable for a student setup, but know that revoking means removing one line from every server's authorized_keys.
  5. Ignoring the host-key prompt — the one time "just type yes" is wrong is when the fingerprint changed unexpectedly; that can mean a man-in-the-middle or a rebuilt server. Verify out-of-band.

Quick checklist

  • Key generated with Ed25519 and a passphrase
  • Public key installed via ssh-copy-id (or manual append)
  • Server ~/.ssh is 700, authorized_keys is 600
  • Host key fingerprint verified on first connect
  • ssh-agent set up so the passphrase isn't retyped constantly
  • Private key backed up somewhere safe (encrypted), never in a repo

FAQ

Can someone log in with just my public key? No. The public key only lets the server verify a signature — producing the signature needs the private key. That is the whole point of asymmetric authentication.

I lost my private key. Am I locked out? Of key-based login, yes — but the public key on the server is harmless without it. Log in via password (if enabled) or your provider's console, install a fresh public key, and delete the old line from authorized_keys.

Should I use the same key for GitHub and my VPS? For a student setup it's acceptable, but separate keys per purpose make revocation surgical: if the laptop is lost you remove one public key from each server instead of rotating everything.

Why does SSH still ask for a password after I set up keys? Almost always server-side permissions (700/600), the wrong key installed, or the client offering a different key than the one on the server. ssh -v tells you which.

Is ssh-copy-id safe on a shared machine? It only copies your public key. The real risk is generating keys on a machine you don't trust — generate on your own device and copy the public key over.

Do keys expire? OpenSSH keys don't expire by themselves. Rotation is manual: generate a new pair, deploy the new public key everywhere, remove the old line.

Limitations

  • Keys authenticate who you are, not what you're allowed to do — server-side authorization (sudo rules, file permissions) is a separate layer.
  • This guide doesn't cover certificate-based SSH (SSH CAs), hardware security keys (FIDO2 key types), or agent forwarding — all real, all beyond student-basics scope.
  • If you disable password authentication entirely, keep a tested recovery path (provider console) — a broken key setup with no password fallback means lockout.

Where to go from here

More project guides

More in Computer / IT

JWT Authentication for Students: Tokens, Signatures, Refresh Flows and a Node.js Implementation

How does JWT login actually work? When a user logs in, the server issues a signed token in three parts — header, payload, signature. The client sends it back as an Authorization: Bearer header, and the server verifies the signature instead of looking up a session. This guide decodes a real token by hand, walks through the full login and refresh flow, and builds a working Node.js implementation with bcrypt password hashing, token rotation, and storage rules that survive a viva.

Read guide

SQL vs NoSQL for Final-Year Projects: Which Database Should You Pick?

MySQL or MongoDB for your final-year project? SQL databases store data in related tables with enforced schemas, joins and transactions — the right default when your data is structured and money or records must stay consistent. NoSQL document stores trade the rigid schema for flexible, nested documents that ship faster when your data shape keeps changing. This guide compares them with a worked hospital-appointment example in both, a decision table, and rules matched to common project archetypes.

Read guide

Docker for Student Projects: Images, Containers and Compose from Zero

End ‘it works on my machine’ failures: learn what Docker images and containers actually are, write lean Dockerfiles that exploit layer caching, persist data with volumes, orchestrate app-plus-database with Compose, and package an evaluator-proof submission — with the debugging table for every error you will definitely meet.

Read guide