Manually Editing netplan to Set IP/Gateway/DNS on a NIC When cloud-init Auto-Generates the Config
How to permanently configure IP, gateway, and DNS on an extra NIC when /etc/netplan/50-cloud-init.yaml is auto-generated by cloud-init on an Ubuntu server, explained step by step.
Environment: Ubuntu (netplan + cloud-init) + a server with multiple NICs
[00] The Problem
In the past you just wrote a yaml file under /etc/netplan/ and ran netplan apply. But at some point the config stops sticking, or disappears after a reboot. Look at the top of the file and you will see this comment:
1
2
3
4
5
# This file is generated from information provided by the datasource. Changes
# to it will not persist across an instance reboot. To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
In other words, this file is regenerated by cloud-init on every boot. Even if you edit it directly, cloud-init can overwrite it on reboot and your changes are gone. This post covers how to turn off cloud-init’s network management and manage netplan yourself.
[01] (Most Important) Confirm the Exact Interface Name First
Before anything else, confirm the actual interface name. If even one character is wrong, netplan apply won’t take effect (e.g. ens801f0np0 vs ens810f0np0 — the digit order is easy to mix up).
1
2
3
4
5
6
7
8
# Interface list and state (simplest)
ip -br link
# Map to hardware
sudo lshw -c network -short
# Check by PCI device
lspci | grep -i ethernet
Example ip -br link output:
1
2
3
4
lo UNKNOWN 00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
ens259f0 UP aa:bb:cc:00:11:01 <BROADCAST,MULTICAST,UP,LOWER_UP>
ens801f0np0 DOWN aa:bb:cc:00:11:0a <BROADCAST,MULTICAST>
ens801f1np1 DOWN aa:bb:cc:00:11:0b <BROADCAST,MULTICAST>
Pin down the interface you want to configure by both name and MAC address. This post assumes you’re configuring ens801f0np0 (an extra NIC currently in the DOWN state).
If an interface like ens259f0 is already UP and your SSH session comes in through it, do not touch that interface’s config. A wrong change there will drop your connection.
[02] Check the Current netplan State
1
2
ls /etc/netplan/
cat /etc/netplan/50-cloud-init.yaml
Example auto-generated 50-cloud-init.yaml (with personal info replaced):
1
2
3
4
5
6
7
8
9
10
11
12
13
network:
ethernets:
ens259f0:
addresses:
- 192.168.0.108/24
nameservers:
addresses:
- 192.168.0.10
search: []
routes:
- to: default
via: 192.168.0.1
version: 2
This file holds the config for your current management interface ens259f0. Keep that in mind — it matters in [05].
[03] Disable cloud-init’s Network Management
Exactly as the comment at the top of the file says, stop cloud-init from touching netplan anymore.
1
2
3
sudo tee /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg <<'EOF'
network: {config: disabled}
EOF
This does not delete a file — it adds one small disable file. Once it’s in place, cloud-init will no longer regenerate or overwrite 50-cloud-init.yaml on reboot.
[04] Write the netplan yaml
Rather than editing the existing file, prefer a separate file. netplan merges every .yaml under /etc/netplan/ in numeric filename order, so you can just write the new interface on its own.
1
sudo vim /etc/netplan/60-custom.yaml
Contents (adjust the values to your environment):
1
2
3
4
5
6
7
8
9
10
11
12
# 60-custom.yaml: static IP for the extra NIC (ens801f0np0) | created: 2026-06-11
network:
version: 2
ethernets:
ens801f0np0: # ← the exact name confirmed in [01]
addresses:
- 192.168.10.50/24 # desired IP / prefix length
nameservers:
addresses: [8.8.8.8, 1.1.1.1]
routes:
- to: default
via: 192.168.10.1 # gateway
Keep Only One default Route (Gateway)
The default gateway (to: default) should live on only one interface. If ens259f0 already has a default route and you add another on ens801f0np0, routing can break.
If the extra NIC is only for traffic to a specific subnet, give it a specific route instead of a default.
1
2
3
4
5
6
ens801f0np0:
addresses:
- 192.168.10.50/24
routes:
- to: 192.168.20.0/24 # only this subnet goes out this NIC
via: 192.168.10.1
If you truly need a default on both interfaces, distinguish priority with metric (lower wins).
1
2
3
4
routes:
- to: default
via: 192.168.10.1
metric: 200
[05] (Key) Should You Delete the Existing 50-cloud-init.yaml? — Three Options
Now that cloud-init is off, it’s tempting to just delete the old file. Don’t delete it outright. It contains the IP/gateway/DNS of your current management network (ens259f0), so deleting it carelessly can drop your SSH session the moment you run netplan apply. Pick one of the three options below based on your situation.
Option 1 — Keep the Existing File, Add a New One (Safest ✅, Recommended for Remote Servers)
1
2
3
/etc/netplan/
├── 50-cloud-init.yaml ← left as-is (keeps the ens259f0 mgmt config)
└── 60-custom.yaml ← adds only ens801f0np0
netplan merges both files, so your management network is never touched. There’s no risk of losing your connection, so this is recommended for remote servers. Because cloud-init was disabled in [03], 50-cloud-init.yaml won’t be overwritten on reboot either.
Option 2 — Consolidate Into One File and Delete the Old One (Tidy First)
If you want all config in one place, copy the existing ens259f0 config into the new file first, then delete the old file. Order matters.
1
2
3
4
5
# 1) Back up first
sudo cp /etc/netplan/50-cloud-init.yaml /root/50-cloud-init.yaml.bak
# 2) Write both ens259f0 and ens801f0np0 in the new file
sudo vim /etc/netplan/60-custom.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 60-custom.yaml: consolidated static IP config for all NICs | created: 2026-06-11
network:
version: 2
ethernets:
ens259f0: # existing mgmt net — copied verbatim from 50-cloud-init.yaml
addresses:
- 192.168.0.108/24
nameservers:
addresses: [192.168.0.10]
routes:
- to: default
via: 192.168.0.1
ens801f0np0: # the NIC being added
addresses:
- 192.168.10.50/24
nameservers:
addresses: [8.8.8.8, 1.1.1.1]
routes:
- to: 192.168.20.0/24
via: 192.168.10.1
1
2
# 3) Delete the old file ONLY after confirming both interfaces are in the new file
sudo rm /etc/netplan/50-cloud-init.yaml
Option 3 — Disable by Renaming the Extension Instead of Deleting (Easiest to Revert)
netplan ignores any file that doesn’t end in .yaml. So instead of deleting, you can disable it by renaming.
1
sudo mv /etc/netplan/50-cloud-init.yaml /etc/netplan/50-cloud-init.yaml.disabled
If something breaks, just rename it back to .yaml to restore the original. Handy when you keep the consolidated file (the 60-custom.yaml from Option 2) and want to tidy up safely.
| Option | Existing file | Best when | Risk |
|---|---|---|---|
| 1. Add a new file | left as-is | Remote servers, don’t want to touch the mgmt net | Lowest |
| 2. Consolidate then delete | copied over, then deleted | You want everything in one file | Medium (mind the order) |
| 3. Rename extension | disabled as .disabled
|
Deletion feels risky, want a way back | Low |
[06] Set Permissions and Validate Syntax
netplan warns if the yaml permissions are too loose. Restrict it to owner-only read.
1
2
sudo chmod 600 /etc/netplan/60-custom.yaml
sudo netplan generate # syntax validation (errors print here)
[07] Apply Safely — netplan try
On a remote server, use netplan try before netplan apply. It applies the config and, if you don’t press Enter within a timeout (120s by default), automatically rolls back to the previous config. Even if a mistake drops your SSH session, it self-recovers — so it’s safe.
1
2
sudo netplan try
# Follow the on-screen prompt; if the connection holds, press Enter to confirm
Once you’ve confirmed it works, apply it.
1
sudo netplan apply
[08] Verify the Result
1
2
3
4
5
6
7
8
9
10
11
# Did the IP attach?
ip -br addr show ens801f0np0
# Check routes/gateway
ip route
# Check DNS
resolvectl status ens801f0np0
# Can you reach the gateway?
ping -c2 192.168.10.1
If ip -br addr shows the interface UP with the IP you assigned, you’re done.
[09] Troubleshooting
| Symptom | What to check |
|---|---|
| Config won’t apply | Check for a typo in the interface name ([01]); check yaml syntax/indentation with netplan generate
|
| Disappears after reboot | Did you disable cloud-init with 99-disable-network-config.cfg? ([03]) |
| Interface stays DOWN | Cable/transceiver, ip link set ens801f0np0 up, and the link partner (switch port) state |
| No internet | Check with ip route whether the default route landed on the wrong NIC; confirm the gateway is on the same subnet |
| DNS only fails | Check nameservers.addresses; verify the applied DNS with resolvectl status
|
| SSH dropped after apply | Restore the backup from the console, then use netplan try going forward |
| Permission warning | Tighten yaml permissions with chmod 600 ([06]) |
[10] Summary
| Step | Action | What |
|---|---|---|
| STEP 01 | Confirm | Pin the exact interface name with ip -br link
|
| STEP 03 | cloud-init | Create 99-disable-network-config.cfg to stop auto-generation |
| STEP 04 | netplan | Write IP/gateway/DNS in a separate yaml (only one default route) |
| STEP 05 | Existing file | Choose: add / consolidate then delete / rename extension (remote → add) |
| STEP 06 | Validate |
chmod 600 + netplan generate to check syntax |
| STEP 07 | Apply | Apply safely with netplan try, then netplan apply
|
| STEP 08 | Verify | Check with ip -br addr / ip route / resolvectl / ping
|