No network after reboot: Ubuntu 24.04 and AlmaLinux 9
A server that answered pings before the reboot and is silent after it is rarely a mystery. It is almost always one of five things, and checking them in the right order tells you which one inside a minute. This guide covers the two stacks on a current machine: Ubuntu 24.04 LTS, where netplan generates config for systemd-networkd, and AlmaLinux 9, where NetworkManager owns every interface. AlmaLinux 9 has no network.service and no network-scripts package, so much of the older advice you will find cannot work there at all.
Get a console before you need one
All of this assumes you can type on the machine while the network is down. If SSH is the broken part, you need out of band access: the VNC or serial console in the panel of your VPS, or IPMI and a serial port on a dedicated server. Test it once while everything still works; three in the morning is a bad time to learn the console password was never set.
A login prompt on the serial line is one command on both distributions:
systemctl enable --now serial-getty@ttyS0.service
Putting the bootloader and kernel there too differs. On Ubuntu 24.04 add console=tty1 console=ttyS0,115200 to GRUB_CMDLINE_LINUX_DEFAULT in /etc/default/grub and run update-grub. On AlmaLinux 9 use grubby, which rewrites every installed kernel entry. RHEL 9 moved the UEFI grub config back under /boot/grub2/, so the /boot/efi/EFI/ path from version 7 and 8 is no longer where you regenerate it.
grubby --update-kernel=ALL --args="console=ttyS0,115200"
No console, and you must edit network config over SSH anyway? Arm a restore first. A bare reboot timer only helps if your change was runtime only, so include the copy back:
cp /etc/netplan/60-static.yaml /root/60-static.yaml.good
systemd-run --on-active=5m /bin/sh -c "cp /root/60-static.yaml.good /etc/netplan/60-static.yaml; systemctl reboot"
It prints a transient unit name; stop that timer with systemctl stop once you are safely back in. On AlmaLinux arm the same thing around the profile keyfile in /etc/NetworkManager/system-connections/, copying it back with cp -p so it keeps mode 600, because nmcli writes your change to disk and a wrong address survives the reboot on its own.
Four questions, in this order
ip -br link
ip -br addr
ip route
cat /etc/resolv.conf
Link, address, route, name resolution. Each depends on the one before it, which is why guessing costs time. The -br flag prints one line per interface. On the DNS line the two distributions part ways: Ubuntu 24.04 resolves through systemd-resolved and resolvectl status tells you everything, while on AlmaLinux 9 systemd-resolved is an opt-in extra that is off out of the box, NetworkManager writes /etc/resolv.conf itself and the equivalent command there is nmcli -f IP4.DNS,IP6.DNS device show enp1s0.
| What you see | Where the fault is |
|---|---|
| Interface not listed at all | Name changed, or the driver did not load |
| State DOWN or NO-CARRIER | Layer 1: cable, switch port, virtual NIC not attached |
| Link UP, no address | Config not applied, or DHCP got no answer |
| Address present, no default route | Gateway missing from the config |
| 1.1.1.1 pings, names do not | DNS |
| Ping works, SSH refused | Not the network |
Then confirm with traffic, near to far:
ping -c3 192.0.2.1
ping -c3 1.1.1.1
getent hosts cloudhosting.lv
Gateway reachable but nothing beyond it points upstream, not at your config.
Ubuntu 24.04: netplan and systemd-networkd
Config lives in /etc/netplan/*.yaml, read in filename order, so a later file overrides an earlier one for the same keys, while every key you do not repeat keeps the value it had in the earlier file. Netplan 1.0 in 24.04 complains if a file is readable by anyone but root, so chmod 600 them. YAML wants spaces: a single tab is a parse error, usually reported at a line number that is not the tab.
netplan get
netplan generate
netplan status --all
netplan generate validates and writes the networkd units without touching the running network. A minimal static config:
network:
version: 2
renderer: networkd
ethernets:
enp1s0:
match:
macaddress: "52:54:00:11:22:33"
set-name: enp1s0
dhcp4: false
dhcp6: false
addresses:
- 192.0.2.10/24
routes:
- to: default
via: 192.0.2.1
nameservers:
addresses: [192.0.2.1, 9.9.9.9]
Note routes: and not gateway4:. The old key is deprecated and netplan warns about it every time it runs.
Now the command that saves careers. netplan try applies the new config, waits 120 seconds for Enter, and rolls back if you do not press it. Break your own SSH session and you cannot press Enter, so it reverts and hands the machine back. Two limits: it needs an interactive terminal, and it only undoes what netplan changed, not an address you added by hand with ip. Use netplan apply when you are already on the console.
netplan try
networkctl status enp1s0
networkctl reconfigure enp1s0
journalctl -b -u systemd-networkd
A boot that stalls two minutes on systemd-networkd-wait-online is a configured interface that never comes up, usually a second NIC nothing is plugged into. Mark it optional: true in netplan.
AlmaLinux 9: NetworkManager and nmcli
No ifup, no /etc/init.d/network, and network-scripts was removed in RHEL 9. NetworkManager still reads legacy ifcfg- files, but that format is deprecated and anything nmcli creates is a keyfile in /etc/NetworkManager/system-connections/ ending in .nmconnection, mode 0600. Start here:
nmcli device status
nmcli -f NAME,DEVICE,AUTOCONNECT,ACTIVE connection show
journalctl -b -u NetworkManager
The usual culprit is in that third column: a profile with autoconnect set to no. It works perfectly when you bring it up by hand and is never applied at boot. Installers, cloning and nmcli connection add without the flag all produce it.
nmcli connection modify "enp1s0" connection.autoconnect yes
nmcli connection modify "enp1s0" ipv4.method manual ipv4.addresses 192.0.2.10/24 ipv4.gateway 192.0.2.1 ipv4.dns "192.0.2.1 9.9.9.9"
nmcli connection up "enp1s0"
modify writes the file, it does not touch the live connection. Follow it with connection up or nmcli device reapply enp1s0, or you will test a change that is not in effect. Edited a keyfile in an editor? Run nmcli connection reload first so NetworkManager picks it up.
The second classic is two profiles for one device, typically a leftover "Wired connection 1" beside your static profile. Both autoconnect, one wins, and you do not want that decided by luck. Delete the stray one with nmcli connection delete uuid ... or set connection.autoconnect-priority. On the console, nmtui does the same in a text UI and is harder to typo.
DNS here does not go through systemd-resolved. On AlmaLinux 9 that service is off unless you switched it on yourself, and NetworkManager writes /etc/resolv.conf as an ordinary file whose first line reads # Generated by NetworkManager. That is the healthy state, so do not go turning it into a symlink. resolvectl ships in a separate package, so it can be missing, and even when it is present it reports an empty DNS state on a stock machine while names resolve perfectly well through glibc. Check what actually serves the machine:
cat /etc/resolv.conf
nmcli -f IP4.DNS,IP6.DNS device show enp1s0
getent hosts cloudhosting.lv
An empty file, or one still full of a previous provider's resolvers, means the servers on the profile are wrong: set them with nmcli connection modify "enp1s0" ipv4.dns "192.0.2.1 9.9.9.9" and bring the connection up again. If a DHCP answer keeps overwriting them, add ipv4.ignore-auto-dns yes. That is where the familiar "IP works, names do not" symptom comes from.
cloud-init keeps putting the old config back
Signature: your change works, you reboot, the old config is back and your file has been rewritten. On cloud images of both distributions cloud-init regenerates network config on boot, on Ubuntu into /etc/netplan/50-cloud-init.yaml, on AlmaLinux into NetworkManager profiles.
cloud-init status --long
head -5 /etc/netplan/50-cloud-init.yaml
Turn network handling off by creating /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg containing one line:
network: {config: disabled}
Then put your config in its own file that sorts after the cloud-init one, for example /etc/netplan/60-static.yaml, again mode 600. Leave the cloud-init file alone; if the image is re-provisioned, yours should be the one that survives. One trap here: netplan merges the two files key by key for the same interface, it does not replace one with the other. Matching is by interface id, so read the cloud-init file first and reuse the exact id it declares, eth0 or enp1s0 or whatever it happens to be. A different id for the same card leaves you with two definitions instead of one override, and the cloud-init dhcp4: true keeps running. Anything you do not repeat stays in force, and the key that hurts is dhcp4: true from the cloud image. Leave it standing and the machine runs your static address and a DHCP client on the same NIC: two default routes with unpredictable metrics, DHCP nameservers competing with the ones you configured, and behaviour that changes from boot to boot. That is why the example above spells out dhcp4: false and dhcp6: false. Check the merged result with netplan get, which prints the combined tree rather than any single file.
The interface has a different name than yesterday
Predictable names come from firmware and PCI topology, so enp1s0 becomes ens18 after a NIC is added, a virtual NIC model changes, or a disk moves into different hardware. The config now names an interface that does not exist, nothing gets configured, and ip -br link shows a stranger.
ip -br link
udevadm info -q property /sys/class/net/ens18 | grep ID_NET_NAME
Query the name ip -br link actually prints, not the one in your config: the old interface is gone from sysfs, so asking about it returns nothing but an unknown device error. The ID_NET_NAME_* values that come back are the candidates udev chose between, which tells you whether the name follows the slot, the PCI path or the MAC address.
Fix the config rather than renaming the world back: on Ubuntu match on macaddress with set-name as above, on AlmaLinux set connection.interface-name to the new name, or bind the profile to the card with 802-3-ethernet.mac-address. One caveat bites people who template VMs: cloning changes the MAC, so a MAC match then matches nothing. Templates should match a name pattern or use DHCP.
When ping works and SSH does not
Then the network is fine and you are debugging the wrong layer.
ss -tlnp | grep :22
systemctl status ssh.service ssh.socket
systemctl status sshd
Ubuntu 24.04 moved OpenSSH to socket activation, so use the second command there and the third on AlmaLinux. The consequence catches people out: the Port directive in sshd_config is ignored on 24.04, because the socket unit is what listens. Run systemctl edit ssh.socket, set an empty ListenStream= to clear the default, then ListenStream=2222. On AlmaLinux 9 a non standard port also needs SELinux to agree: semanage port -a -t ssh_port_t -p tcp 2222, from policycoreutils-python-utils.
Firewall rules are the other half. On AlmaLinux anything added with firewall-cmd without --permanent disappears on reboot; firewall-cmd --runtime-to-permanent keeps what is live.
Prove the fix survives
A network repaired with ip addr add is not repaired, it is borrowed until the next boot. Once the config is right, reboot deliberately, console open, at a time you chose. Then confirm the services that bring it up are enabled at all, first line on Ubuntu, second on AlmaLinux, where systemd-resolved is deliberately not part of the check because a healthy machine reports it as disabled:
systemctl is-enabled systemd-networkd systemd-resolved
systemctl is-enabled NetworkManager
ip -br addr; ip route
Keep a copy of the working config off the machine, with the address, gateway and interface name written down. It turns a bad night into five minutes of typing. If a server in our Riga data centre stays dark after all this, our engineers are reachable around the clock and IT support can go in over the console with you.