03. Persistent Network Configuration
Supported Versions: Ubuntu Server 24.04 LTS (primary), Rocky Linux 9 (alternative) Last Updated: September 15, 2026
An address added with ip address add changes the running kernel configuration. It is not an instruction for the next boot. In this chapter you give the network's configuration owner a durable instruction, then compare the saved configuration with what the VM actually uses.
Prerequisites and outcomes
Complete addressing and interfaces and prepare the course lab. Use two disposable VMs and their hypervisor consoles. Both VMs may run Ubuntu; learning Rocky at the same time is optional.
| Item | Required state |
|---|---|
| Client lab NIC | 192.0.2.10/24 after this lesson |
| Server lab NIC | 192.0.2.20/24 after this lesson |
| Lab network | Same internal virtual network, no DHCP server, router or uplink |
| Management NIC | Separate existing NAT/DHCP connection; preserve its address, routes and DNS configuration |
| Identity | Record each NIC's MAC in the hypervisor and match it inside the guest |
| Access and tools | Guest console, sudo access, an editor, ip, and the installed network manager's tools |
Run the commands inside the named VM, never on the workstation hosting the VMs. Do not install or enable a second network manager to follow an alternative branch. If a required tool is absent, return to lab preparation.
You will be able to identify configuration ownership, persist a static address, explain when DHCP/gateway/DNS settings are appropriate, verify after reboot, and undo only your lab changes. First take a VM snapshot and keep the console open. Perform each step separately; an error means inspect it before proceeding.
1. Identify the NIC and the owner
On each VM, read the inventory without changing anything:
cat /etc/os-release
ip -br link
ip -br address
ip -4 route show
ip -6 route show default
systemctl is-active systemd-networkd NetworkManagerip -br link pairs interface names with MAC addresses. Match the hypervisor's lab MAC, not the first interface in the list. The NAT/DHCP NIC normally carries the management default route. Record its identity and current route/DNS settings before continuing. systemctl is-active may return a nonzero status because one of the two services is absent or inactive; that alone is not a fault.
Throughout this chapter, replace REPLACE_WITH_LAB_NIC with the name you just verified. Variables belong to the current shell; independent blocks repeat them. Never assign a lab value to shell variables such as HOME or PATH.
LAB_IF='REPLACE_WITH_LAB_NIC'
ip link show dev "$LAB_IF"
ip -4 address show dev "$LAB_IF"
ip -4 route show dev "$LAB_IF"The second command shows the kernel's current addresses; it does not identify who will recreate them. Finish chapter 02's targeted cleanup of its temporary address before starting here. A newly added lab NIC should have no remaining temporary IPv4 address. Do not remove an address owned by an existing profile just because you did not expect it.
Choose the owner from evidence:
| Evidence | Configuration owner and action |
|---|---|
Ubuntu Netplan YAML selects networkd; networkctl status identifies the corresponding network file | Follow branch A |
| Rocky NetworkManager reports a managed device and its profiles | Follow branch B |
Netplan selects NetworkManager | Netplan is an upstream source of configuration too; inspect the YAML and generated profile before editing |
cloud-init, a provisioning tool, direct .network files, wildcard matches, or multiple definitions own the same NIC | Resolve ownership before adding another definition; use a clean course VM if the source is unclear |
Netplan translates YAML into backend configuration. systemd-networkd and NetworkManager apply configuration to devices; nmcli and nmtui both talk to NetworkManager. A running service does not prove it owns every NIC. The Ubuntu Server path used here is not a claim about every Ubuntu image, Ubuntu Desktop, or Debian installation.
Branch A ownership checks: Ubuntu Netplan/networkd
LAB_IF='REPLACE_WITH_LAB_NIC'
sudo netplan get
sudo ls -l /etc/netplan
networkctl status "$LAB_IF"
sudo ls -l /etc/systemd/network /run/systemd/network
resolvectl statusnetplan get displays the merged configuration; inspect the actual YAML files with sudo less /etc/netplan/ACTUAL_FILE.yaml, using a filename from the listing. Also inspect any existing /lib/netplan and /run/netplan directories. networkctl status shows the matching network file, if any. resolvectl status records the existing DNS servers and links.
Netplan combines differently named YAML files in lexical order: later scalar values replace earlier ones, but lists can be concatenated. Adding a later file with an empty address/DNS list is not a general way to erase an earlier list. A differently named definition can also match the same NIC. See Netplan file merging.
The procedure below requires a lab NIC with no existing persistent definition, including wildcard matches in direct networkd files. If an installer already defined it, inspect that file's owner and take a backup before deliberately editing its exact lab stanza instead; do not paste this file over the installer file or keep two definitions. A cloud-init comment is a reason to inspect the provisioning source, not to disable cloud-init globally. For a first lab, adding the internal NIC after the OS's initial setup avoids many such conflicts.
Branch B ownership checks: Rocky NetworkManager
LAB_IF='REPLACE_WITH_LAB_NIC'
nmcli --version
nmcli device status
nmcli -f GENERAL,IP4,IP6,CONNECTIONS device show "$LAB_IF"
nmcli -f NAME,UUID,TYPE,DEVICE,AUTOCONNECT connection showdevice describes the NIC; connection describes a saved profile. Their names need not match. GENERAL.CON-UUID identifies the currently active profile, if one exists. CONNECTIONS helps identify compatible profiles, including inactive ones. Record the previous lab profile's UUID and whether it was active; preserve the management profile.
Inspect each compatible profile with nmcli connection show uuid ACTUAL_UUID. Record its connection.interface-name, 802-3-ethernet.mac-address, connection.autoconnect, and connection.autoconnect-priority. Empty device/MAC bindings can allow an Ethernet profile to match multiple NICs. Do not change such a shared profile merely to simplify the lab.
Rocky 9 supports NetworkManager's keyfile configuration and may also have older ifcfg profiles. Do not infer the storage format solely from an interface name. The versioned Rocky 9 guide covers that release; the unversioned guide now discusses Rocky 10.
2A. Persist the address with Netplan/networkd
Use this branch only after branch A's ownership checks. Repeat it on the client and server with their own MAC and address.
Back up and create one owned file
On each Ubuntu VM, create a new recovery directory. If it already exists, stop and inspect that earlier attempt; do not replace its backup.
sudo mkdir -m 700 /root/network-beginner-03
sudo cp -a /etc/netplan /root/network-beginner-03/netplan-before
sudo sh -c 'umask 077; set -C; : > /etc/netplan/90-beginner-lab.yaml'
sudoedit /etc/netplan/90-beginner-lab.yamlcp -a preserves the original files and permissions. The small sh command creates a root-only empty file; set -C refuses to overwrite an existing file. sudoedit opens an editable copy using your configured editor.
Paste this complete YAML document, using spaces rather than tabs. Replace the example MAC with the client's actual lab MAC. On the server, replace the MAC with the server's lab MAC and change the address to 192.0.2.20/24.
network:
version: 2
ethernets:
beginner-lab:
renderer: networkd
match:
macaddress: "02:00:00:00:00:10"
dhcp4: false
dhcp6: false
accept-ra: false
link-local: []
addresses:
- 192.0.2.10/24
optional: true| Setting | Meaning in this lab |
|---|---|
version: 2 | Netplan's configuration schema version |
beginner-lab | A definition ID; MAC matching selects the NIC without renaming it |
Device-level renderer | Select networkd for this definition without changing the global renderer |
dhcp4: false | No DHCP request on a network that has no DHCP server |
| IPv6 and link-local settings | Keep this isolated exercise IPv4-only on this NIC; this is not a host-wide IPv6 recommendation |
addresses | One address with a /24 prefix; the connected subnet needs no gateway |
optional: true | networkd does not hold up boot waiting for this lab NIC; it still configures it |
There is deliberately no routes or nameservers block. Neither VM is a router or DNS server. Guessing 192.0.2.1 as a gateway would not create one. The management NIC retains its original configuration.
Validate, try, and observe
sudo chmod 600 /etc/netplan/90-beginner-lab.yaml
sudo netplan generate
sudo netplan getchmod 600 allows only root to read/write the file. generate checks and generates backend configuration without applying it in this normal, already booted session. Success is usually silent. Check the merged output: exactly the intended lab address/MAC, no added lab gateway/DNS, and the original management definition. A valid YAML document can still contain the wrong MAC or address.
From the VM console, start the trial:
sudo netplan try --timeout 120While the confirmation prompt waits, use a second console/login to inspect:
LAB_IF='REPLACE_WITH_LAB_NIC'
ip -4 address show dev "$LAB_IF"
ip -4 route show dev "$LAB_IF"
ip -4 route show default
ip -6 route show default
networkctl status "$LAB_IF"
resolvectl statusExpect the local 192.0.2.0/24 route, the correct .10 or .20 address, no default route/DNS introduced by the lab NIC, and the original management path still available. Confirm the trial only after those checks. Configure both VMs before requiring a successful peer ping.
try and apply operate on the merged configuration, not only the new file, and can reapply networking across devices. Console access remains necessary even when the management definition was not edited. try intends to revert an unconfirmed trial, but Netplan documents rollback bugs. Timeout or Ctrl+C is not proof of recovery; inspect runtime state and the files on disk.
Netplan recovery and rollback
Keep the working lab configuration for later lessons. To abandon this change, recover from the console:
- Inspect
/etc/netplan/90-beginner-lab.yamland confirm it is the file created here. - Move only that file outside Netplan's input directories.
- Generate and apply the remaining, previously working configuration.
sudo mv -i /etc/netplan/90-beginner-lab.yaml /root/network-beginner-03/90-beginner-lab.failed.yaml
sudo netplan generate
sudo netplan applymv -i asks before replacing a previous failure copy. If generate fails, stop before apply. If you chose to edit an existing owner file instead of using the fresh-NIC path, compare it with its corresponding file in netplan-before and restore that exact edited file, then generate/apply; do not replace the entire directory.
Recheck addresses, routes and management access. A now-unmanaged lab NIC can retain runtime state. Only if this lesson's exact address is still present, remove that address:
LAB_IF='REPLACE_WITH_LAB_NIC'
LAB_CIDR='192.0.2.10/24'
sudo ip address del "$LAB_CIDR" dev "$LAB_IF"On the server set LAB_CIDR='192.0.2.20/24'. If the initial inventory recorded the lab NIC administratively down, restore that state with sudo ip link set dev "$LAB_IF" down in the same shell. Do not delete management routes or flush interfaces. Before rebooting as a final recovery step, verify that the disk configuration is the restored one. If ownership or recovery is unclear, restore the pre-lesson VM snapshot.
2B. Persist the address with NetworkManager
On each Rocky VM, use branch B's inventory. This path creates beginner-lab-static on each guest. It must be a new name; if that name already exists, inspect the previous attempt instead of adding a duplicate.
Keep compatible older profiles as recovery options. For predictable reboot selection, disable autoconnect only for profiles exclusively bound to the lab NIC, recording each original value first:
OLD_LAB_UUID='REPLACE_WITH_CONFIRMED_LAB_PROFILE_UUID'
nmcli -f connection connection show uuid "$OLD_LAB_UUID"
sudo nmcli connection modify uuid "$OLD_LAB_UUID" connection.autoconnect noSkip this block if there is no old lab profile. Repeat for any other lab-only candidates; leave the current activation alone for now. If a candidate is unbound/shared or its ownership is uncertain, resolve that ambiguity before proceeding. DEVICE=-- only means inactive, not harmless.
Create the new profile; this block first saves it without autoactivation:
LAB_IF='REPLACE_WITH_LAB_NIC'
LAB_MAC='REPLACE_WITH_LAB_MAC'
LAB_CIDR='192.0.2.10/24'
sudo nmcli connection add type ethernet con-name beginner-lab-static \
ifname "$LAB_IF" 802-3-ethernet.mac-address "$LAB_MAC" \
connection.autoconnect no \
ipv4.method manual ipv4.addresses "$LAB_CIDR" \
ipv4.gateway "" ipv4.dns "" ipv4.never-default yes \
ipv6.method disabled
nmcli -f connection,802-3-ethernet,ipv4,ipv6 connection show id beginner-lab-staticUse .20/24 on the server. manual requires an address/prefix. The interface and MAC bindings restrict which device can use this profile; mac-address matches the permanent MAC rather than changing it. Empty gateway/DNS and never-default yes keep it local. IPv6 is disabled only in this lab profile. connection add saves persistently by default; saved does not yet mean active.
Record the new UUID from the output. Activate this exact profile, then inspect runtime state:
LAB_IF='REPLACE_WITH_LAB_NIC'
LAB_UUID='REPLACE_WITH_NEW_LAB_PROFILE_UUID'
sudo nmcli --wait 30 connection up uuid "$LAB_UUID" ifname "$LAB_IF"
nmcli -f GENERAL,IP4,IP6 device show "$LAB_IF"
ip -4 route showActivation can replace the previous active profile on this NIC. Expect the intended address, connected subnet route and no lab gateway/DNS. Compare the management route with the initial inventory. Inspect journalctl -u NetworkManager -b -n 50 --no-pager if activation fails. A timeout does not prove the saved profile disappeared.
After successful observations, enable activation on subsequent boots:
LAB_UUID='REPLACE_WITH_NEW_LAB_PROFILE_UUID'
sudo nmcli connection modify uuid "$LAB_UUID" connection.autoconnect yes
nmcli -f connection.id,connection.uuid,connection.autoconnect connection show uuid "$LAB_UUID"The same profile in nmtui
If nmtui is already available, open the existing dedicated profile:
sudo nmtui edit beginner-lab-staticUse Tab to move, arrow keys to choose, Space to toggle and Enter to accept. Check profile name/device, set IPv4 to Manual, expand it, and verify the single .10/24 or .20/24 address. Keep Gateway, DNS servers and search domains empty; select Never use this network for default route in Routes where offered. Keep IPv6 Disabled and automatic connection enabled after validation.
Choose Cancel for inspection only or OK to save intended edits. Saving changes the same NetworkManager profile as nmcli; it is not a separate configuration layer. After saving, inspect with nmcli connection show, then activate the recorded UUID using the previous block. Menus vary by package version; if a property is absent, set it with nmcli and verify. Do not use a general deactivate/reactivate action on the management connection.
NetworkManager recovery and rollback
From the console, inspect the recorded new UUID, then remove only your profile. If creation never succeeded, skip this new-profile block and still restore any previous autoconnect values you changed:
LAB_UUID='REPLACE_WITH_NEW_LAB_PROFILE_UUID'
nmcli -f connection,ipv4 connection show uuid "$LAB_UUID"
sudo nmcli connection modify uuid "$LAB_UUID" connection.autoconnect no
sudo nmcli connection down uuid "$LAB_UUID"
sudo nmcli connection delete uuid "$LAB_UUID"An “already inactive” result from down is acceptable after you have verified the UUID; an unrelated error requires investigation. Other compatible profiles may autoactivate when a connection goes down, so inspect the device again.
If an older lab profile existed, restore every autoconnect value you recorded. Reactivate it only if it was active before the lesson:
LAB_IF='REPLACE_WITH_LAB_NIC'
OLD_LAB_UUID='REPLACE_WITH_PREVIOUS_LAB_PROFILE_UUID'
OLD_AUTOCONNECT='yes'
sudo nmcli connection modify uuid "$OLD_LAB_UUID" connection.autoconnect "$OLD_AUTOCONNECT"
sudo nmcli --wait 30 connection up uuid "$OLD_LAB_UUID" ifname "$LAB_IF"Use the recorded yes or no, not a guessed value. If the previous profile was inactive, omit the up line. If no previous profile existed, no old profile needs restoring: verify that the lesson address is gone. Return the lab link's original up/down state if necessary, and compare management addressing/routes/DNS with the initial record. Do not delete all Ethernet profiles or restart networking globally.
3. DHCP, gateways and DNS: when the settings belong
Static addressing assigns the administrator's chosen address. DHCP requests a lease from an actual DHCP server, which may also supply routes and DNS. Enabling DHCP on the internal course network will not produce a lease. A DNS server answers name questions; a gateway forwards packets beyond an on-link network. One device may provide both services, but neither role follows just from its IP ending in .1.
The following are optional adaptation examples, not changes to the two-VM course lab. Use a separate disposable practice VM/interface identified by its hypervisor MAC, with console access, no conflicting owner, and an existing DHCP-enabled virtual network or an administrator-specified routed network. Never substitute either course VM's management NIC.
DHCP on a network that actually provides it
For a spare networkd-owned NIC on a DHCP-enabled practice network, a complete Netplan definition is:
network:
version: 2
ethernets:
practice-dhcp:
renderer: networkd
match:
macaddress: "02:00:00:00:00:30"
dhcp4: true
dhcp4-overrides:
use-routes: false
use-dns: false
use-domains: false
dhcp6: false
accept-ra: false
link-local: []
optional: trueReplace the example MAC with the spare NIC's MAC. These overrides request an address while declining DHCP routes, DNS and search domains, preserving the practice VM's existing management path. It still gets the connected subnet route. On an intentionally selected primary uplink, an administrator may instead accept DHCP routes and DNS; this course does not change an existing uplink.
Use the same new-file/backup procedure with a distinct file such as 90-beginner-dhcp.yaml, mode 600, generate, merged-output inspection and try. Check networkctl status and ip address for a lease. If none arrives, inspect carrier, the virtual-network selection and DHCP service/scope availability. Remove only this new file and apply the restored configuration to undo it; check for residual lab addresses as in branch A.
For an otherwise unconfigured NetworkManager-owned spare NIC, the equivalent saved profile is:
PRACTICE_IF='REPLACE_WITH_SPARE_NIC'
PRACTICE_MAC='REPLACE_WITH_SPARE_MAC'
sudo nmcli connection add type ethernet con-name beginner-practice-dhcp \
ifname "$PRACTICE_IF" 802-3-ethernet.mac-address "$PRACTICE_MAC" \
connection.autoconnect no ipv4.method auto \
ipv4.never-default yes ipv4.ignore-auto-routes yes ipv4.ignore-auto-dns yes \
ipv6.method disabled
sudo nmcli --wait 60 connection up id beginner-practice-dhcp ifname "$PRACTICE_IF"
nmcli -f GENERAL,IP4,DHCP4 device show "$PRACTICE_IF"The name must be unused. Record its UUID and use branch B's UUID-based rollback to delete only this new profile. Because this example is autoconnect no, the settings are saved but activation is manual after a reboot. If adapting an existing dedicated practice profile from static to DHCP, set ipv4.method auto and clear ipv4.addresses, ipv4.gateway, ipv4.routes, ipv4.dns and ipv4.dns-search in the same connection modify operation; otherwise old static values can coexist with DHCP. Record the old values first and restore them to undo that adaptation.
Durable gateway and DNS settings on a routed practice network
Suppose a separate practice VM, not either course VM, has an administrator-assigned 10.77.0.10/24, a real on-link router 10.77.0.1, and a reachable resolver 10.77.0.53 serving training.example. Its exercise NIC must be the explicitly chosen default uplink, with no competing management default route; use the hypervisor console. The administrator must ensure these sample values describe that practice network before you use them.
For Netplan/networkd, the complete definition would be:
network:
version: 2
ethernets:
practice-uplink:
renderer: networkd
match:
macaddress: "02:00:00:00:00:40"
dhcp4: false
dhcp6: false
accept-ra: false
link-local: []
addresses:
- 10.77.0.10/24
routes:
- to: default
via: 10.77.0.1
nameservers:
addresses:
- 10.77.0.53
search:
- training.exampleto: default supplies a route for destinations without a more specific match. via is the router's on-link address. nameservers.addresses selects the resolver; search can expand a short name such as web to web.training.example. It does not create DNS records. Use a separately backed-up, owned file, replace the MAC, and repeat branch A's permission/validation/trial/recovery process.
With NetworkManager, on the equivalent fresh, owned practice NIC:
PRACTICE_IF='REPLACE_WITH_PRACTICE_UPLINK'
PRACTICE_MAC='REPLACE_WITH_PRACTICE_MAC'
sudo nmcli connection add type ethernet con-name beginner-practice-routed \
ifname "$PRACTICE_IF" 802-3-ethernet.mac-address "$PRACTICE_MAC" \
connection.autoconnect no \
ipv4.method manual ipv4.addresses 10.77.0.10/24 \
ipv4.gateway 10.77.0.1 ipv4.never-default no \
ipv4.dns 10.77.0.53 ipv4.dns-search training.example \
ipv6.method disabled
sudo nmcli --wait 30 connection up id beginner-practice-routed ifname "$PRACTICE_IF"
nmcli -f GENERAL,IP4 device show "$PRACTICE_IF"Inspect the new profile before activation, record its UUID, and enable autoconnect only after successful checks if boot activation is wanted. Remove it by UUID to roll back as in branch B. For either backend, verify ip route get 10.77.0.53, the default route, and an administrator-provided DNS record. Inspect resolvectl status where resolved is active, or NetworkManager's active DNS and /etc/resolv.conf otherwise. Do not hand-edit a generated resolv.conf or treat a temporary resolvectl dns command as a durable profile change.
4. Verify the course lab after a reboot
Return to the two course VMs' static configuration. Save your work, then reboot each disposable guest from its console with sudo reboot. After login, rematch the NIC MACs; shell variables do not survive reboot.
On the client:
LAB_IF='REPLACE_WITH_CLIENT_LAB_NIC'
ip -4 address show dev "$LAB_IF"
ip -4 route get 192.0.2.20
ip -4 route show default
ping -n -c 3 -W 2 192.0.2.20On the server, inspect .20/24 and run ip -4 route get 192.0.2.10 plus ping -n -c 3 -W 2 192.0.2.10. Route lookup should select the lab NIC and local lab source address, without via. The management default route can still exist and should match the original configuration. DHCP lease details can legitimately renew.
| Observation | First investigation |
|---|---|
| Address absent after reboot | Wrong MAC, unsaved file/profile, disabled autoconnect, or competing owner |
| Extra lab address/DNS/default route | Merged YAML lists, another matching definition/profile, or leftover temporary state |
NO-CARRIER | Hypervisor cable/adapter state and internal-network attachment |
| Correct route, no ping reply | Peer address, same internal network, neighbor discovery and ICMP policy; continue to chapter 04 |
| Management access changed | Use the console and the relevant rollback; do not flush routes |
Completion check
- Identify the lab and management NICs from MAC evidence on both VMs.
- Explain which file/profile owns the lab NIC and distinguish saved from active state.
- Verify
.10/24and.20/24survive reboot with an on-link peer route. - Show that the lab NIC added no gateway/DNS and management configuration is preserved.
- Record peer-ping results and investigate failures rather than inventing a gateway.
- Identify the exact new file/profile to undo and the previous state to restore.
- Explain why the optional DHCP/routed examples require a different prepared network.
Leave the working static lab addresses in place for the next lesson. Keep backup notes until the course is complete.
Primary sources and further reading
- Ubuntu Server: configuring networks
- Netplan examples, YAML reference, file permissions
- Netplan generate and merging, Netplan try and recovery caveats
- NetworkManager nmcli examples, nmcli manual, profile properties, nmtui
- Rocky Linux 9 network configuration
Previous: addressing and interfaces · Quiz · Next: DNS and connectivity