sshd: no hostkeys available -- exiting. is printed when the OpenSSH server starts and cannot load a single host key from /etc/ssh. The fix is one command, sudo ssh-keygen -A, which creates every missing host key type. This guide shows the exact output before and after, why WSL and container images ship without keys, the other two causes that print the same line (bad permissions and a wrong HostKey path), and what clients see after the keys change.

The error

On WSL without systemd, starting the server with the SysV init script looks like this:

text
$ sudo service ssh start
 * Starting OpenBSD Secure Shell server sshd
 sshd: no hostkeys available -- exiting. [fail]

With systemd (a normal Ubuntu server, or WSL with systemd enabled) the unit fails instead, because ssh.service runs sshd -t as ExecStartPre:

text
$ sudo systemctl restart ssh
Job for ssh.service failed because the control process exited with error code.
$ sudo journalctl -u ssh -n 5 --no-pager
... sshd[812]: sshd: no hostkeys available -- exiting.
... systemd[1]: ssh.service: Control process exited, code=exited, status=1/FAILURE

You can reproduce the check yourself at any time, without starting anything:

bash
sudo /usr/sbin/sshd -t

sshd -t validates the configuration and the host keys, then exits. No output and exit code 0 means sshd will start.

Fix: generate the missing host keys

bash
sudo ssh-keygen -A

Expected output when keys were missing:

text
ssh-keygen: generating new host keys: RSA ECDSA ED25519

-A creates every default host key type that does not exist yet, with the default paths and an empty passphrase. It never overwrites a key that is already there, so it is safe to run again: on a host that already has all three keys it prints nothing.

Confirm the files exist and sshd accepts them, then start the server:

bash
ls -l /etc/ssh/ssh_host_*
sudo /usr/sbin/sshd -t && echo "config OK"
sudo service ssh start          # WSL without systemd
sudo systemctl restart ssh      # systemd hosts, including WSL with systemd=true

You should see six files: ssh_host_rsa_key, ssh_host_ecdsa_key, ssh_host_ed25519_key and their .pub files. The private keys must be mode 600 and owned by root.

On Debian and Ubuntu there is a package-level alternative that does the same thing through the openssh-server maintainer script:

bash
sudo dpkg-reconfigure openssh-server

It prints Creating SSH2 ED25519 key; this may take some time ... for each missing type and then tries to restart the service.

Why sshd has no host keys

Host keys identify the server, so they must be unique per machine. Anything that is built once and copied many times deliberately ships without them, and something at first boot is supposed to create them. When that first-boot step never runs, sshd has nothing to load.

  • WSL distributions. The distro is unpacked from a root filesystem image, and openssh-server is often installed later or was installed in the image with its keys removed. Without systemd and cloud-init, nothing generates keys on first start.
  • Docker and other container images. Base images remove /etc/ssh/ssh_host_* so two containers never share a key. Installing openssh-server in a Dockerfile and then deleting or not copying the keys gives the same error at CMD ["/usr/sbin/sshd", "-D"].
  • Golden images and clones. VM templates are commonly “sealed” by deleting host keys; cloud-init or a first-boot script normally recreates them. Clones made without that step fail.
  • Someone deleted or rotated the keys and did not regenerate them, or restored /etc/ssh from a backup without the private keys.

Same error, different cause: permissions or HostKey path

If ls /etc/ssh/ssh_host_* shows the keys but sshd still exits, run sshd -t and read the lines above the error.

Private keys readable by others. sshd refuses any private host key that group or other can read:

text
$ sudo /usr/sbin/sshd -t
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/etc/ssh/ssh_host_ed25519_key' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
sshd: no hostkeys available -- exiting.

Fix the mode and owner:

bash
sudo chown root:root /etc/ssh/ssh_host_*
sudo chmod 600 /etc/ssh/ssh_host_*_key
sudo chmod 644 /etc/ssh/ssh_host_*_key.pub

This happens most often after copying keys from a Windows path (/mnt/c/...) in WSL, because DrvFs files appear with permissive modes unless the mount uses the metadata option.

HostKey points at files that do not exist. If sshd_config or a drop-in under /etc/ssh/sshd_config.d/ sets HostKey, sshd loads only those paths. Print what sshd will actually use:

bash
sudo /usr/sbin/sshd -T | grep -i '^hostkey '
text
hostkey /etc/ssh/ssh_host_rsa_key
hostkey /etc/ssh/ssh_host_ecdsa_key
hostkey /etc/ssh/ssh_host_ed25519_key

Every path listed must exist. Either generate a key at that custom path (sudo ssh-keygen -t ed25519 -f /path/to/key -N '') or remove the custom HostKey line.

Fix checklist

  1. Run sudo /usr/sbin/sshd -t and read every line it prints.
  2. No keys in /etc/ssh: run sudo ssh-keygen -A.
  3. Keys present but “UNPROTECTED PRIVATE KEY FILE”: chmod 600 the private keys, owner root:root.
  4. Custom HostKey lines: check sshd -T | grep -i '^hostkey ' and make each path exist.
  5. Run sshd -t again until it prints nothing, then start or restart the service.
  6. Connect once from a client and accept the new host key fingerprint (see the FAQ below).

WSL notes

  • With or without systemd. Check whether WSL booted systemd with ps -p 1 -o comm=. If it prints systemd, use systemctl. If not, use sudo service ssh start, which does not survive a wsl --shutdown. To get systemd, add this to /etc/wsl.conf inside the distro and run wsl --shutdown from Windows:

    ini
    [boot]
    systemd=true
  • Privilege separation directory. Running /usr/sbin/sshd directly (not through service or systemd) can fail with Missing privilege separation directory: /run/sshd. Create it with sudo mkdir -p /run/sshd; the init script and the systemd unit normally do this for you.

  • Port 22 already in use. If the Windows OpenSSH Server service is also running, pick a different Port for the WSL sshd or stop the Windows service.

  • Reaching WSL from another machine. In the default NAT networking mode, WSL is only reachable from the Windows host. Either set networkingMode=mirrored under [wsl2] in %UserProfile%\.wslconfig (Windows 11 22H2 and later), or forward a port with netsh interface portproxy and allow it in Windows Firewall.

Ubuntu and distro differences

SystemOpenSSHHow keys are normally createdNotes
Ubuntu 24.04 LTS9.6p1openssh-server postinst at installssh.socket is enabled by default; ssh.service runs sshd -t before starting
Ubuntu 26.04 LTS10.2p1openssh-server postinst at installSame unit layout as 24.04; DSA keys no longer exist in OpenSSH 10
Debian 12 and 139.2p1, 10.0p1postinst, or dpkg-reconfigure openssh-serverSame fix
Fedora, RHEL, Rockyvariessshd-keygen@.service at boot, per key typesudo ssh-keygen -A also works
Alpinevariesnot created by apk add openssh-serverIn containers, run ssh-keygen -A in the entrypoint

On Ubuntu 24.04 and 26.04 socket activation means ssh.socket can be listening while every connection is reset because ssh.service fails its sshd -t check. Look at journalctl -u ssh, not only at systemctl status ssh.socket. If you also change Port in sshd_config, run sudo systemctl daemon-reload and sudo systemctl restart ssh.socket so the socket picks up the new port.

Containers: generate keys at start, not at build

Running ssh-keygen -A in a Dockerfile bakes one set of host keys into the image, so every container started from it has the same identity. Generate them when the container starts instead:

dockerfile
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y --no-install-recommends openssh-server \
 && rm -f /etc/ssh/ssh_host_* && mkdir -p /run/sshd
CMD ["/bin/sh", "-c", "ssh-keygen -A && exec /usr/sbin/sshd -D -e"]

If the container must keep a stable identity across restarts, mount the host keys from a volume or a Kubernetes Secret with mode 0600.

FAQ

Is it safe to run ssh-keygen -A on a server that already works?

Yes. It only creates key types that are missing and leaves existing keys untouched, so clients keep seeing the same fingerprints.

Clients now say “REMOTE HOST IDENTIFICATION HAS CHANGED!” What do I do?

That is expected after new host keys are generated: the client remembers the old key in ~/.ssh/known_hosts. Verify the new fingerprint on the server with ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub, then remove the stale entry on the client with ssh-keygen -R hostname (and ssh-keygen -R '[localhost]:2222' for a non-standard port) and connect again.

Why do my WSL host keys disappear?

They should not. Keys live in the distro’s ext4 virtual disk and survive wsl --shutdown and reboots. If they vanish, the distro was reset, unregistered and reimported, or a script is recreating /etc/ssh. Check ls -l --time-style=full-iso /etc/ssh/ssh_host_* to see when they were written.

Can I copy host keys from my old machine?

You can, when you want the new machine to keep the same identity (for example a rebuilt server with the same name). Copy all six files, then set owner root:root, mode 600 on private keys and 644 on .pub files. Never reuse one set of keys across many different machines.

Do I still need a DSA host key?

No. OpenSSH 9.8 disabled DSA by default and OpenSSH 10.0 removed it, so ssh-keygen -A only creates RSA, ECDSA and Ed25519 keys. If an old client cannot connect after that, see SSH no matching host key type found: their offer ssh-dss.