Ubuntu Server - Configuring Network Settings with Netplan

If you’ve been using Ubuntu Server for a while, you’ve probably noticed that the old /etc/network/interfaces method for configuring network settings is gone. Ubuntu replaced it with Netplan starting with Ubuntu 18.04, and it’s been the default ever since. I’ll be honest — when I first ran into Netplan I found the YAML syntax a little unfamiliar, but once it clicks it’s actually pretty clean to work with.

This post covers everything I’ve needed for network configuration on Ubuntu Server: setting a static IP, configuring DNS servers and search domains, setting a default gateway, adding static routes, VLAN tagging, NIC bonding, and bridge interfaces. I’m writing this mainly as a reference for myself and anyone else who finds themselves Googling these options every time they spin up a new server.

I’m running Ubuntu Server 24.04 LTS for this post, but the Netplan syntax has been consistent for several major versions so this should apply equally well to 22.04 and 20.04.


Prerequisites

  • A running Ubuntu Server instance with SSH access
  • A user with sudo privileges

How Netplan Works

Netplan reads YAML configuration files from /etc/netplan/ and uses them as the source of truth for network configuration. On Ubuntu Server the renderer is typically networkd (systemd-networkd), while Ubuntu Desktop uses NetworkManager. For servers we’ll always be working with networkd.

When you install Ubuntu Server, it creates a default config file in /etc/netplan/. The filename varies — it’s usually something like 00-installer-config.yaml or 50-cloud-init.yaml depending on how the system was installed. You edit that file (or create a new one) and then run netplan apply to push the changes live.

A quick note on file naming: Netplan processes files in lexicographical order, and later files override earlier ones for conflicting settings. For most single-server setups this doesn’t matter, but it’s good to know.


Finding Your Network Interface Name

Before writing any config, you need to know the name of your network interface. Run:

ip link show

You’ll see output like this:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 ...
2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 ...

Ignore lo — that’s the loopback interface. Your real interface will be something like ens18, eth0, enp3s0, or similar. Note the name, you’ll need it in every config block.


Finding the Existing Config File

ls /etc/netplan/

Open whichever file is there:

sudo nano /etc/netplan/00-installer-config.yaml

If the server was set to DHCP during install, it’ll look something like this:

network:
  version: 2
  ethernets:
    ens18:
      dhcp4: true

This is what we’ll be replacing or expanding.


Static IP Configuration

To assign a static IP, disable DHCP and set the address manually. The address must be written in CIDR notation (e.g., /24 for a 255.255.255.0 subnet mask).

network:
  version: 2
  renderer: networkd
  ethernets:
    ens18:
      dhcp4: false
      addresses:
        - 192.168.1.50/24
      routes:
        - to: default
          via: 192.168.1.1
      nameservers:
        addresses:
          - 1.1.1.1
          - 8.8.8.8

Breaking down the key fields:

  • dhcp4: false — disables DHCP; the interface will use only what you define here
  • addresses — list of IP addresses in CIDR notation; you can have more than one
  • routes — defines routing; to: default is your default gateway, via is the next hop IP
  • nameservers.addresses — DNS resolvers, in order of preference

DNS Search Domains

DNS search domains let you resolve short hostnames without typing the full FQDN. For example, if your domain is lab.local and you add it as a search domain, you can SSH to server01 instead of server01.lab.local.

Add a search list under nameservers:

network:
  version: 2
  renderer: networkd
  ethernets:
    ens18:
      dhcp4: false
      addresses:
        - 192.168.1.50/24
      routes:
        - to: default
          via: 192.168.1.1
      nameservers:
        addresses:
          - 192.168.1.1
          - 1.1.1.1
        search:
          - lab.local
          - chns.local

You can list as many search domains as you need. The system will try each in order when resolving a short name.


Adding Static Routes

Static routes let you direct traffic for specific networks through a particular gateway — useful when you have multiple subnets, a VPN gateway on a separate interface, or a management VLAN that routes differently from your default gateway.

Routes are defined as a list under the interface, each with a to (destination network) and via (next hop):

network:
  version: 2
  renderer: networkd
  ethernets:
    ens18:
      dhcp4: false
      addresses:
        - 192.168.1.50/24
      routes:
        - to: default
          via: 192.168.1.1
        - to: 10.10.0.0/16
          via: 192.168.1.254
        - to: 172.16.5.0/24
          via: 192.168.1.253
      nameservers:
        addresses:
          - 192.168.1.1
          - 1.1.1.1
        search:
          - lab.local

In this example:

  • All internet-bound traffic routes through 192.168.1.1 (the default gateway)
  • Traffic destined for the 10.10.0.0/16 network is sent to 192.168.1.254
  • Traffic for 172.16.5.0/24 is sent to 192.168.1.253

You can also set a metric on routes to influence preference when multiple routes exist for the same destination:

      routes:
        - to: default
          via: 192.168.1.1
          metric: 100
        - to: default
          via: 10.0.0.1
          metric: 200

Lower metric = higher priority. This is useful if you have a failover path and want the primary route always preferred.


Multiple Network Interfaces

If your server has more than one NIC — common for servers that need to be on two different VLANs or subnets — you define each interface as its own block under ethernets:

network:
  version: 2
  renderer: networkd
  ethernets:
    ens18:
      dhcp4: false
      addresses:
        - 192.168.1.50/24
      routes:
        - to: default
          via: 192.168.1.1
      nameservers:
        addresses:
          - 192.168.1.1
          - 1.1.1.1
        search:
          - lab.local
    ens19:
      dhcp4: false
      addresses:
        - 10.10.0.50/24

A couple of things to watch here:

  • Only one interface should have a default route (to: default). Having two default routes on two different interfaces causes routing confusion.
  • The second interface ens19 doesn’t need DNS or a default gateway — it just needs an IP so the host can communicate on that subnet. Add a specific static route if traffic for certain networks should go out that interface.

VLAN Tagging

VLAN tagging lets a single physical NIC carry traffic for multiple VLANs simultaneously. Each VLAN gets its own virtual interface, identified by the parent interface name and the VLAN ID (e.g., ens18.10 for VLAN 10 on ens18). The switch port the NIC connects to needs to be configured as a trunk port passing those VLANs.

Netplan handles this with a vlans block. You still define the parent interface under ethernets, but you leave it with no IP — the IP goes on the VLAN interface:

network:
  version: 2
  renderer: networkd
  ethernets:
    ens18:
      dhcp4: false
  vlans:
    ens18.10:
      id: 10
      link: ens18
      dhcp4: false
      addresses:
        - 192.168.10.50/24
      routes:
        - to: default
          via: 192.168.10.1
      nameservers:
        addresses:
          - 192.168.10.1
          - 1.1.1.1
        search:
          - lab.local
    ens18.20:
      id: 20
      link: ens18
      dhcp4: false
      addresses:
        - 192.168.20.50/24

Breaking it down:

  • ethernets.ens18 — the parent physical interface with no IP assigned; it just needs to be present
  • vlans — top-level block, separate from ethernets
  • id — the 802.1Q VLAN ID (1–4094)
  • link — the parent physical interface this VLAN rides on
  • Everything else (addresses, routes, nameservers) works exactly the same as a regular interface

In this example, ens18.10 handles traffic for VLAN 10 and is the primary interface with a default gateway. ens18.20 is on VLAN 20 with just an IP — you’d add static routes if you need to reach other networks through it.

You can combine this with the static routes section above — just add a routes block to whichever VLAN interface needs it.


NIC Bonding

Bonding (also called link aggregation or LAG) combines multiple physical NICs into one logical interface. The main reasons to do this are redundancy (if one NIC fails, the other keeps traffic flowing) or increased throughput (traffic is distributed across both NICs). Your switch needs to support and be configured for the bonding mode you choose.

Netplan handles bonding with a bonds block. The physical NICs become members of the bond and get no IP of their own:

network:
  version: 2
  renderer: networkd
  ethernets:
    ens18:
      dhcp4: false
    ens19:
      dhcp4: false
  bonds:
    bond0:
      interfaces:
        - ens18
        - ens19
      dhcp4: false
      addresses:
        - 192.168.1.50/24
      routes:
        - to: default
          via: 192.168.1.1
      nameservers:
        addresses:
          - 192.168.1.1
          - 1.1.1.1
        search:
          - lab.local
      parameters:
        mode: active-backup
        primary: ens18
        mii-monitor-interval: 100

Key fields under parameters:

  • mode — the bonding mode (see below)
  • primary — for active-backup mode, which NIC to prefer as the active one
  • mii-monitor-interval — how often (in milliseconds) to check if a link is up; 100 is a common value

Bonding Modes

Mode Name Description
active-backup Active/Backup One NIC active, one standby. Failover only. No switch config needed.
balance-rr Round Robin Alternates packets across NICs. Requires switch-side LAG config.
802.3ad LACP Industry standard dynamic LAG. Requires switch support. Recommended for throughput + redundancy.
balance-alb Adaptive Load Balancing Distributes outgoing traffic by load; no special switch config needed.
balance-tlb Transmit Load Balancing Distributes outgoing by load, all incoming on one NIC; no special switch config.

For a homelab or basic redundancy without touching switch config, active-backup is the easiest choice. For a proper aggregated uplink with a managed switch, 802.3ad (LACP) is what you want — just make sure the switch port channel is configured to match.

For LACP, the parameters block looks like this:

      parameters:
        mode: 802.3ad
        lacp-rate: fast
        mii-monitor-interval: 100
  • lacp-rate: fast — sends LACP PDUs every second instead of every 30 seconds; recommended for faster failover detection

Bridge Interfaces

A bridge makes your server act like a virtual switch, connecting physical interfaces and virtual interfaces (like VM NICs or containers) at Layer 2. This is commonly used on hypervisor hosts — Proxmox does this automatically, but if you’re running KVM/QEMU manually on Ubuntu Server, you’ll need to set it up yourself.

Like bonding, bridge members (the physical NICs) carry no IP — the IP lives on the bridge interface:

network:
  version: 2
  renderer: networkd
  ethernets:
    ens18:
      dhcp4: false
  bridges:
    br0:
      interfaces:
        - ens18
      dhcp4: false
      addresses:
        - 192.168.1.50/24
      routes:
        - to: default
          via: 192.168.1.1
      nameservers:
        addresses:
          - 192.168.1.1
          - 1.1.1.1
        search:
          - lab.local
      parameters:
        stp: false
        forward-delay: 0

Key parameters for bridges:

  • stp — Spanning Tree Protocol. Disable it (false) in simple homelab setups where there are no loops. Enable it if you have redundant switch paths.
  • forward-delay — how long (in seconds) the bridge waits before forwarding traffic after a link comes up. Set to 0 for faster boot; leave at the default 15 if STP is enabled (STP needs the delay to converge).

Once the bridge is up, VMs created with virt-manager or virsh can use br0 as their network interface and will get addresses from your physical network as if they were plugged in directly — no NAT required.

Combining a Bridge with a Bond

For a production-style setup — bonded uplinks bridged for VM access — you can stack these together. The bond becomes a member of the bridge:

network:
  version: 2
  renderer: networkd
  ethernets:
    ens18:
      dhcp4: false
    ens19:
      dhcp4: false
  bonds:
    bond0:
      interfaces:
        - ens18
        - ens19
      dhcp4: false
      parameters:
        mode: active-backup
        mii-monitor-interval: 100
  bridges:
    br0:
      interfaces:
        - bond0
      dhcp4: false
      addresses:
        - 192.168.1.50/24
      routes:
        - to: default
          via: 192.168.1.1
      nameservers:
        addresses:
          - 192.168.1.1
          - 1.1.1.1
      parameters:
        stp: false
        forward-delay: 0

The physical NICs have no IP, the bond has no IP, and the bridge is the only thing with an address. VMs attach to br0 and get full Layer 2 access to the physical network through the bonded uplink.


Applying the Configuration

Once you’ve saved your YAML file, you have two options for applying it.

netplan try — applies the config temporarily and reverts automatically after 120 seconds unless you confirm. This is the safer option when working remotely over SSH — if you make a mistake and lose connectivity, it rolls back on its own.

sudo netplan try

If everything looks good, press Enter to confirm and keep the changes.

netplan apply — applies the config immediately and permanently, no rollback.

sudo netplan apply

I use netplan try any time I’m touching a production server or anything I can’t physically access. For a local lab VM it doesn’t matter much, but it’s a good habit.


Verifying the Configuration

After applying, confirm the settings are active:

ip addr show ens18

Check your routing table:

ip route show

Test DNS resolution:

resolvectl status

This shows which DNS servers are assigned to each interface, what search domains are configured, and whether systemd-resolved is picking up your settings correctly. If DNS isn’t working after applying changes, resolvectl status is the first place I look.


A Note on Permissions and Syntax

Netplan is strict about YAML indentation — use spaces, not tabs, and be consistent. A mis-indented line will either cause netplan apply to error out or silently apply the wrong settings.

Netplan also enforces file permissions. Config files should be owned by root and not world-readable:

sudo chmod 600 /etc/netplan/00-installer-config.yaml

If you see a warning like Permissions for /etc/netplan/*.yaml are too open when running netplan apply, that command fixes it.


Wrapping Up

Netplan is one of those tools that seems overly complicated at first glance but ends up being pretty straightforward once you’ve worked through it a couple of times. The YAML format makes configs readable and easy to version-control, which is something I appreciate when managing multiple servers.

The config patterns above cover everything you’re likely to need for Ubuntu Server network setup — static IPs, DNS, search domains, routing, VLANs, bonding, and bridges. You can mix and match these blocks in a single Netplan file to build up whatever topology your environment requires.

If you run into issues, netplan generate --debug is a useful command that shows exactly what systemd-networkd config Netplan would produce from your YAML — handy for diagnosing unexpected behavior.