:bulb: 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).

:warning: 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

:bulb: 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)

:warning: 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.

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