Skip to content

NetworkManager and netplan

The previous three articles — IP and Routing Tools, DHCP Basics, and DNS Tools — repeated the same warning several times: a change made with the ip command is temporary and disappears on reboot. This article fills exactly that gap — it shows how to write IP, route, and DNS settings to a file, in a way that's persistent and reproducible. Modern Ubuntu/Debian systems offer two main paths for this: netplan, more commonly used on servers, and NetworkManager, used on workstations and some server installs.

netplan: One YAML File, Two Backends

netplan doesn't manage networking itself; it only reads a YAML configuration and generates a matching configuration for one of two backends that do the actual work — systemd-networkd or NetworkManager. Ubuntu Server typically uses systemd-networkd as the backend; Ubuntu Desktop typically uses NetworkManager.

Configuration files live in /etc/netplan/, with a .yaml extension:

ls /etc/netplan/
50-cloud-init.yaml

Warning

The 50-cloud-init.yaml name is itself a warning: on a cloud image this file is regenerated by cloud-init on every boot, so a manual edit to it can silently disappear after the next reboot even though netplan apply worked at the time. To make a change stick on a cloud VM, either put it in a separate higher-numbered file (e.g. /etc/netplan/99-custom.yaml, which overrides by lexical order) or disable cloud-init's network handling:

echo 'network: {config: disabled}' | sudo tee /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg

Separately, netplan YAML can hold secrets (such as WiFi keys), so recent versions warn when these files are world-readable — keep them at chmod 600.

Static IP Configuration

network:
  version: 2
  renderer: networkd
  ethernets:
    enp0s3:
      addresses:
        - 192.168.1.122/24
      routes:
        - to: default
          via: 192.168.1.1
      nameservers:
        addresses: [192.168.1.1, 1.1.1.1]
        search: [internal.local]

The parts:

  • renderer — explicitly specifies which backend this file uses (networkd or NetworkManager);
  • addresses — the IP(s) assigned to the interface, in CIDR notation;
  • routes — additional routes; to: default is how the default gateway is specified;
  • nameservers — DNS servers and the domain search list (search), which are passed to systemd-resolved.

DHCP Configuration

network:
  version: 2
  renderer: networkd
  ethernets:
    enp0s3:
      dhcp4: true
      dhcp6: false

dhcp4: true triggers the process covered in DHCP Basics — the interface automatically obtains its IP, gateway, and DNS servers.

Applying Configuration Safely: try and apply

sudo netplan generate
sudo netplan try

netplan try applies the change immediately, but if the user doesn't press Enter to confirm within a set window (120 seconds by default), it automatically reverts to the previous configuration. This matters most when changing routes or IPs over a remote SSH session: if the new configuration cuts off connectivity, the server reverts itself and recovers without needing console access.

sudo netplan apply

netplan apply, in contrast, applies the change immediately and permanently — there's no confirmation window.

Danger

When changing network configuration on a remote server, always run netplan try first — never start directly with netplan apply. If there's no independent way in through console or a hypervisor console, a bad configuration can cut the server off the network entirely.

Checking syntax before applying:

sudo netplan generate
echo $?

generate only converts the file into the backend's configuration format — it applies nothing. It's a convenient first step for catching a YAML syntax error without touching the live network.

Viewing the current state:

sudo netplan status

systemd-networkd: The Engine Behind netplan

When netplan is set to use the networkd backend, it generates .network and .link files inside /run/systemd/network/ — these are what systemd-networkd actually reads:

sudo cat /run/systemd/network/10-netplan-enp0s3.network

Do not edit these files by hand — they're rewritten by netplan on every apply. They're useful to read for diagnostics only, to confirm the generated value matches what was expected.

NetworkManager: nmcli and nmtui

On some installs — Ubuntu Desktop especially, some cloud images, or servers where renderer: NetworkManager was chosen — networking is managed directly through NetworkManager.

Viewing State

nmcli device status
DEVICE   TYPE      STATE      CONNECTION
enp0s3   ethernet  connected  Wired connection 1
lo       loopback  unmanaged  --

An unmanaged state means NetworkManager isn't managing this interface at all — lo, or an interface explicitly excluded in configuration, for example.

Static Configuration with nmcli

sudo nmcli connection modify "Wired connection 1" \
    ipv4.method manual \
    ipv4.addresses 192.168.1.122/24 \
    ipv4.gateway 192.168.1.1 \
    ipv4.dns "192.168.1.1,1.1.1.1"

sudo nmcli connection up "Wired connection 1"

connection modify changes the configuration but doesn't apply it immediately; connection up reactivates that profile and brings the new settings into effect. This two-step approach gives a brief window to review a change before it takes effect, but it lacks netplan's automatic rollback mechanism like try.

Reverting to DHCP:

sudo nmcli connection modify "Wired connection 1" ipv4.method auto
sudo nmcli connection up "Wired connection 1"

nmtui: A Text-Based Menu Interface

sudo nmtui

nmtui is a keyboard-driven menu that runs in the console; it exposes the same capabilities as nmcli without requiring the exact command syntax to be memorized — convenient for a quick, one-off change or when the exact flags aren't top of mind.

Warning

If a system's netplan configuration has renderer: NetworkManager selected, a change made through nmcli/nmtui will not show up in the netplan YAML file. The next netplan apply can overwrite the NetworkManager profile and silently discard the manual change. Always keep exactly one location — either the netplan YAML or the NetworkManager profile — as the single source of truth, and don't mix the two.

The RHEL Family: nmcli and Legacy ifcfg-* Files

On the RHEL/CentOS/Fedora family, the primary tool is also NetworkManager, managed with the same nmcli/nmtui. Historically, configuration was stored in /etc/sysconfig/network-scripts/ifcfg-<interface> files:

TYPE=Ethernet
BOOTPROTO=static
NAME=enp0s3
DEVICE=enp0s3
IPADDR=192.168.1.122
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
DNS1=192.168.1.1
ONBOOT=yes

Modern RHEL versions can read these files, but NetworkManager may also store configuration in its own keyfile format (/etc/NetworkManager/system-connections/) — the exact format depends on version and configuration. On Debian/Ubuntu, the equivalent but differently-formatted legacy path — /etc/network/interfaces — still works on systems with the ifupdown package installed, but is not the default on modern Ubuntu Server installs.

Note

Configuration file location and format vary across distributions: Ubuntu Server uses netplan YAML, the RHEL family uses NetworkManager keyfiles or ifcfg-*, and some minimal systems use /etc/network/interfaces. Don't mix a general rule with distribution-specific detail — always check which tool is actually in use first (networkctl, nmcli, or cat /etc/os-release).

Practical Scenario: A netplan Change That Could Cut the Server Off the Network

Task: an internal server needs an additional static IP, but a configuration mistake could sever the existing SSH connection.

Safety note: this operation changes network configuration. If possible, practice it on an isolated test VM first; on a production server, only proceed once independent access is ready through console or a hypervisor console.

Step 1 — save the current state:

sudo cp /etc/netplan/50-cloud-init.yaml ~/50-cloud-init.yaml.bak
ip -brief address show > ~/network-before.txt
ip route show >> ~/network-before.txt

Step 2 — edit the YAML file: add the new address to the addresses list:

network:
  version: 2
  renderer: networkd
  ethernets:
    enp0s3:
      addresses:
        - 192.168.1.122/24
        - 192.168.1.150/24
      dhcp4: false
      routes:
        - to: default
          via: 192.168.1.1
      nameservers:
        addresses: [192.168.1.1, 1.1.1.1]

Step 3 — check syntax (without applying yet):

sudo netplan generate
echo $?

Step 4 — apply safely:

sudo netplan try

Open a new SSH session in another terminal (without closing the existing one) and confirm the connection still works, then press Enter in the first session to confirm the change.

Step 5 — verify:

ip -brief address show
ping -c 3 192.168.1.1

Step 6 — rollback on failure: if netplan try didn't revert automatically, or a manual rollback is needed:

sudo cp ~/50-cloud-init.yaml.bak /etc/netplan/50-cloud-init.yaml
sudo netplan apply

Common Mistakes

Testing Directly with netplan apply

A bad configuration is applied immediately and permanently. netplan try exists specifically to avoid this risk — don't skip it.

Mixing Manual NetworkManager Changes with netplan

Making a manual change with nmcli on an interface managed under renderer: NetworkManager, then losing it on the next netplan apply, is the direct result of never deciding which system is the source of truth.

Missing a YAML Indentation Error

Whitespace is meaningful in netplan's YAML format; a misplaced key can silently move an entire block under the wrong field. Always run netplan generate right after an edit, before apply.

Editing a File Generated by systemd-networkd by Hand

Files inside /run/systemd/network/ are rewritten on the next netplan apply; a manual edit there is lost. Changes always belong in /etc/netplan/*.yaml.

Interview angle

A useful interview question to be ready for: "why does netplan need a renderer field at all if there's only one backend on most Ubuntu Server installs?" The honest answer is that the renderer determines not just what gets configured but which daemon enforces it at runtime — systemd-networkd and NetworkManager have different reload semantics, different ways of reporting state (networkctl versus nmcli), and mixing tools that assume the wrong backend is a common source of "my change didn't take effect" confusion. Explicitly declaring the renderer avoids ambiguity about which daemon actually owns the interface.

Exercises

  1. Compare the output of netplan status and ip -brief address show to determine which renderer (networkd or NetworkManager) the current configuration uses.
  2. On a test VM, back up the existing netplan file, change a DHCP interface to a static IP, and apply the change safely with netplan try.
  3. Read the output of nmcli device status and nmcli connection show, and explain the difference between the unmanaged and connected states.
  4. Repeat the practical scenario above: deliberately write YAML with incorrect indentation, find the error with netplan generate, fix it, and only then apply it with netplan try.

Verification criterion: for exercise 4, netplan generate must report the syntax error and exit with a nonzero status before any change reaches the live network — if netplan try runs before the error is caught, back up further and check the indentation again.

References

  • Netplan — official documentation: https://netplan.readthedocs.io/en/stable/
  • Netplan — netplan-try(8): https://netplan.readthedocs.io/en/stable/netplan-try/
  • Ubuntu Server — Netplan networking configuration: https://ubuntu.com/server/docs/netplan-introduction
  • freedesktop.org: systemd.network(5): https://www.freedesktop.org/software/systemd/man/latest/systemd.network.html
  • GNOME/NetworkManager — nmcli(1): https://networkmanager.dev/docs/api/latest/nmcli.html
  • Red Hat Enterprise Linux 9 — Configuring and managing networking: https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/configuring_and_managing_networking/