☜

Making SSH wait for an online interface

While configuring SSH on a personal media server, I ran into some issues after configuring it to only listen for connections on the LAN interface with ListenAddress 192.168.0.107. Inspecting the service logs show that SSH fails to bind to this address, this is because of the startup order, the SSH service is trying to bind to the address before this network interface has become routable.

Sep 02 13:34:53 utility-server systemd[1]: Starting OpenBSD Secure Shell server...
Sep 02 13:34:54 utility-server sshd[692]: error: Bind to port 22 on 192.168.0.107 failed: Cannot assign requested address.
Sep 02 13:34:54 utility-server sshd[692]: fatal: Cannot bind any address.
Sep 02 13:34:54 utility-server systemd[1]: ssh.service: Main process exited, code=exited, status=255/EXCEPTION
Sep 02 13:34:54 utility-server systemd[1]: ssh.service: Failed with result 'exit-code'.
Sep 02 13:34:54 utility-server systemd[1]: Failed to start OpenBSD Secure Shell server.

So the problem at hand is entirely about timing, which means it's time for SystemD to shine. These are the steps I took.

Configure network

The first step was to replace existing network management with systemd-networkd, and configure the network with a .network file. This is what my configuration looks like.

# /etc/systemd/network/10-DHCP.network
[Match]
Name = enp2s0f0

[Network]
DHCP = yes

# This makes the network-online.target only fire if this interface is routable, and has
# an IPv4 address. Without this, SSH would still start too early, perhaps because IPv6
# was coming online before IPv4?
[Link]
RequiredForOnline=routable
RequiredFamilyForOnline=ipv4

Override SSH service definition

In the first step I configured the network, and set requirements for it to be deemed online. I then altered the SSH service configuration to only make it try to start when the newly defined requirements are met, e.g. the enp2s0f0 interface is routable and has an IPv4 address.

# /etc/systemd/system/sshd.service.d/sshd.override.conf
# Make the ssh service start after the network is deemed online.
[Unit]
After=network-online.target
Requires=network-online.target

Reloading and enabling the new configuration.

$ systemctl daemon-reload
$ systemctl enable systemd-networkd-wait-online
$ systemctl start systemd-networkd-wait-online
$ systemctl restart ssh

Now SSH starts up without crashing after a reboot.