Skip to content

Log in with SSH keys

In this tutorial, we will set up key-based SSH logins on a Debian 13 server. You'll create a second account called alice, make a key pair for yourself, install the public key for alice, and use it to log in as alice, first by typing the key's passphrase and then with ssh-agent remembering it for you. By the end, you will have logged in with a key, seen how the server and the client recognise each other, and know where each piece is stored.

Everything happens on one server: you'll connect from the server to itself (localhost). That keeps the lesson self-contained, and it works exactly the same way when the client and the server are different machines.

Before you begin

  • A Debian 13 server with the OpenSSH server installed, as it is when you select "SSH server" during installation, and in Debian's cloud images.
  • You're logged in to it as an ordinary user who can use sudo. In this tutorial that user is called labuser; wherever you see labuser in the output, you'll see your own user name.
  • You have never created an SSH key pair for this user on this server. (If ~/.ssh/id_ed25519 already exists, use a fresh Debian 13 machine instead, so you don't overwrite a key you need.)

Step 1: Check that the SSH server is running

The SSH server program is sshd, and on Debian its service is called ssh. Check that it's running:

$ systemctl is-active ssh
active

The server is listening for connections, normally on TCP port 22.

Step 2: Create a second account

Create the account alice, with a home directory and Bash as her shell, and then look at the state of her password:

$ sudo useradd --create-home --shell /bin/bash alice
$ sudo passwd --status alice
alice L 2026-11-07 0 99999 7 -1

The L means the password is locked: alice has no password at all, so nobody can log in as her with one. That's a common situation for accounts that should only ever be used with keys. It also means that the usual shortcut for installing a key, ssh-copy-id, won't work here, because ssh-copy-id itself logs in to the account with a password to copy the key. In Step 4 you'll install the key yourself instead.

Step 3: Create your key pair

As yourself (not with sudo), create an Ed25519 key pair. When ssh-keygen asks where to save the key, press Enter to accept the default. Then type a passphrase twice; nothing is shown while you type. Choose one you'll remember: you'll need it in Step 5.

$ ssh-keygen -t ed25519
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/labuser/.ssh/id_ed25519):
Enter passphrase for "/home/labuser/.ssh/id_ed25519" (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/labuser/.ssh/id_ed25519
Your public key has been saved in /home/labuser/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:q3Vb7m0cXo2T1kFh6Yw9pLzR4sNjE8aUdGiK5HtC1xQ labuser@debian
The key's randomart image is:
+--[ED25519 256]--+
|           .XoBBo|
|         o *.*o+X|
|        = o...+++|
|       E o +.+ +.|
|      o S + + .. |
|       o = o  .  |
|          =    . |
|           o  . .|
|            .o.o=|
+----[SHA256]-----+

ssh-keygen created two files. List them:

$ ls -l ~/.ssh
total 12
-rw------- 1 labuser labuser 411 Nov  7 10:12 id_ed25519
-rw-r--r-- 1 labuser labuser  94 Nov  7 10:12 id_ed25519.pub

Notice the difference in permissions:

  • id_ed25519 is the private key. Only you can read it (-rw-------), and it's encrypted with your passphrase. It never leaves this account.
  • id_ed25519.pub is the public key. Anyone may read it; it's the part you give to servers you want to log in to.

(If your ~/.ssh directory already contained an authorized_keys file, you'll see that too. That's fine.)

Look at the public key:

$ cat ~/.ssh/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK7f3Qm9sW2xVb1nR8cT4yHjL6pZ0eUoDgA5kXwM3iNq labuser@debian

It's one line: the key type, the key itself, and a comment saying who created it. A long key is hard to compare by eye, so SSH tools usually show a short fingerprint of it instead:

$ ssh-keygen -l -f ~/.ssh/id_ed25519.pub
256 SHA256:q3Vb7m0cXo2T1kFh6Yw9pLzR4sNjE8aUdGiK5HtC1xQ labuser@debian (ED25519)

This is the same fingerprint ssh-keygen printed when it created the key. Remember the first few characters; you'll see them again in Step 6.

Step 4: Install the public key for alice

The SSH server lets someone log in as alice with a key if that key's public half is listed in alice's ~/.ssh/authorized_keys file. You'll create that file with sudo, because it belongs in alice's home directory, which you can't write to.

Create the directory and copy your public key into it:

$ sudo mkdir ~alice/.ssh
$ sudo cp ~/.ssh/id_ed25519.pub ~alice/.ssh/authorized_keys
$ sudo ls -la ~alice/.ssh
total 12
drwxr-xr-x 2 root  root  4096 Nov  7 10:14 .
drwx------ 3 alice alice 4096 Nov  7 10:13 ..
-rw-r--r-- 1 root  root    94 Nov  7 10:14 authorized_keys

~alice is a shortcut for alice's home directory, /home/alice.

Because you used sudo, the new directory and file are owned by root, and every user on the server can read them. That would work for logging in, but it isn't how the file should be: alice should own her keys, so that she can add and remove them herself, and nobody else needs to see which keys can log in as her. (The SSH server only insists that nobody other than alice or root can change these files; otherwise another user could add their own key and log in as her.) Give them to alice, make them private, and check the result:

$ sudo chown -R alice:alice ~alice/.ssh
$ sudo chmod 700 ~alice/.ssh
$ sudo chmod 600 ~alice/.ssh/authorized_keys
$ sudo ls -la ~alice/.ssh
total 12
drwx------ 2 alice alice 4096 Nov  7 10:14 .
drwx------ 3 alice alice 4096 Nov  7 10:13 ..
-rw------- 1 alice alice   94 Nov  7 10:14 authorized_keys

Notice that everything belongs to alice, and that only she can read or change it.

Step 5: Log in as alice with your key

Before you connect, look at the server's own key, its host key, so that you can recognise it in a moment:

$ ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key.pub
256 SHA256:Wm4tZ8yQe1Lp0vB3nX7cRk2HdJs9FgU6aYoTi5EwN0M root@debian (ED25519)

The first time you connect to any server, ssh doesn't know its host key yet. Normally it stops and asks you to confirm it:

The authenticity of host 'localhost (::1)' can't be established.
ED25519 key fingerprint is SHA256:Wm4tZ8yQe1Lp0vB3nX7cRk2HdJs9FgU6aYoTi5EwN0M.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

That question is how you make sure you're talking to the right server: you compare the fingerprint with one you got another way, as you just did with ssh-keygen -l. Here you already know the fingerprint, so tell ssh to accept a new host key without asking, with the option StrictHostKeyChecking=accept-new. It still refuses to connect if a server's key ever changes.

Log in as alice. ssh asks for the passphrase of your private key (not a password for alice, who has none):

$ ssh -o StrictHostKeyChecking=accept-new alice@localhost
Warning: Permanently added 'localhost' (ED25519) to the list of known hosts.
Enter passphrase for key '/home/labuser/.ssh/id_ed25519':
Linux debian 6.12.0-1-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.0-1 x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
alice@debian:~$ whoami
alice
alice@debian:~$ exit
logout
Connection to localhost closed.

You logged in as alice without her having a password. The server checked that you hold the private key matching the public key in her authorized_keys, and your private key never left your account.

Step 6: See what each side remembered

Your SSH client saved the server's host key in ~/.ssh/known_hosts. List the fingerprints of the keys in that file:

$ ssh-keygen -l -f ~/.ssh/known_hosts
256 SHA256:Wm4tZ8yQe1Lp0vB3nX7cRk2HdJs9FgU6aYoTi5EwN0M |1|Xq3m9dPZ0rT4aKcVb2nLwE8sHjY=|f7RkN1uQ5oZgW3eCtBmA9yDiP0s= (ED25519)

It's the ED25519 fingerprint you checked in Step 5.

On Debian, host names in this file are scrambled (hashed), which is why you see |1|… instead of localhost; ssh hashes the name you type and compares. From now on, ssh checks the server against this key silently every time you connect, and warns you loudly if it ever doesn't match.

The server, for its part, logged which key was used. Look at its log:

$ sudo journalctl -u ssh --grep alice
Nov 07 10:15:02 debian sshd-session[1342]: Accepted publickey for alice from ::1 port 38654 ssh2: ED25519 SHA256:q3Vb7m0cXo2T1kFh6Yw9pLzR4sNjE8aUdGiK5HtC1xQ
Nov 07 10:15:02 debian sshd-session[1342]: pam_unix(sshd:session): session opened for user alice(uid=1001) by alice(uid=0)
Nov 07 10:15:09 debian sshd-session[1342]: pam_unix(sshd:session): session closed for user alice

Notice the fingerprint at the end of the first line. It's the fingerprint of your key from Step 3. This is how an administrator can tell which key someone logged in with.

Step 7: Let ssh-agent remember your passphrase

Typing the passphrase for every connection quickly gets tiresome. ssh-agent is a small program that keeps your unlocked key in memory and does the key work for ssh, so you type the passphrase once per session.

Start an agent, give it your key, list the keys it holds, and connect:

$ eval "$(ssh-agent -s)"
Agent pid 2051
$ ssh-add
Enter passphrase for /home/labuser/.ssh/id_ed25519:
Identity added: /home/labuser/.ssh/id_ed25519 (labuser@debian)
$ ssh-add -l
256 SHA256:q3Vb7m0cXo2T1kFh6Yw9pLzR4sNjE8aUdGiK5HtC1xQ labuser@debian (ED25519)
$ ssh alice@localhost
Linux debian 6.12.0-1-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.0-1 x86_64
…
alice@debian:~$ exit
logout
Connection to localhost closed.

A few things happened here:

  • ssh-agent -s started the agent and printed two shell variables that tell other programs where to find it. eval set them in your current shell.
  • ssh-add asked for your passphrase once and handed the unlocked key to the agent. ssh-add -l shows the same fingerprint as before.
  • This time ssh didn't ask for anything. It asked the agent to prove that you hold the key, and the agent did so without ever giving the key itself to ssh.
  • ssh didn't ask about the host key either: it's in known_hosts now.

The agent keeps running until you stop it. When you've finished, stop it:

$ eval "$(ssh-agent -k)"
Agent pid 2051 killed
$ ssh-add -l
Could not open a connection to your authentication agent.

The key is gone from memory. The next ssh connection asks for the passphrase again.

What you have learned

  • An SSH key pair has a private key, which stays in your ~/.ssh and is protected by a passphrase, and a public key, which you give to servers.
  • A server lets you log in as a user when your public key is in that user's ~/.ssh/authorized_keys, and that file should belong to the user and be private to them.
  • Accounts can be used with keys only, with no password at all, and you can install a key for such an account with sudo when ssh-copy-id can't help.
  • Fingerprints identify keys: you compared the server's host key fingerprint before trusting it, and found your own key's fingerprint in the server's log.
  • Your client remembers server host keys in ~/.ssh/known_hosts.
  • ssh-agent and ssh-add hold your unlocked key so that you type the passphrase once.

Next steps