Configuring a Static IP with Netplan on Ubuntu 18.04
The first thing that catches people out on Ubuntu 18.04 Server is that /etc/network/interfaces is no longer where the network lives. It still exists, mostly empty, with a comment pointing you at Netplan. Netplan is a YAML front-end that generates configuration for a backend renderer, systemd-networkd on servers and NetworkManager on desktops. The upside is a much shorter config file; the downside is that YAML indentation errors give unhelpful messages and that the interface names are now things like ens160 or enp0s3.
I lost a bit of time to that on my first 18.04 box. Below is how I give a fresh server a static address now, using the netplan try safety net so a typo doesn't cut off my SSH session. Have console access (or some other way back in) and the address, prefix, gateway and DNS servers written down before you start.
Find the interface name and current config
ip -br addr
ip route
ls /etc/netplan/
ip -br addr (brief mode) prints one line per interface. On a VMware guest the NIC is usually ens160, on VirtualBox enp0s3, on KVM ens3. The existing Netplan file is typically /etc/netplan/50-cloud-init.yaml on cloud images and /etc/netplan/01-netcfg.yaml on installs from the ISO. Look at it:
cat /etc/netplan/50-cloud-init.yaml
A DHCP configuration looks like:
network:
version: 2
ethernets:
ens160:
dhcp4: true
Keep cloud-init from overwriting your changes
If the file is 50-cloud-init.yaml, cloud-init regenerates it on boot from the datasource. Disable that first or your static IP disappears on the next reboot:
sudo tee /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg <<'EOF'
network: {config: disabled}
EOF
Then create your own file rather than editing the cloud-init one. Netplan merges every *.yaml in /etc/netplan/ in lexical order, later files overriding earlier ones for the same interface.
The static configuration
sudo nano /etc/netplan/01-static.yaml
network:
version: 2
renderer: networkd
ethernets:
ens160:
dhcp4: no
addresses:
- 10.0.1.25/24
gateway4: 10.0.1.1
nameservers:
search: [example.internal]
addresses: [10.0.1.2, 10.0.1.3]
Points to get right:
- Indentation must be spaces, never tabs. Two or four is fine as long as it is consistent within the file.
addressestakes CIDR notation. There is no separatenetmaskkey.gateway4is a single address, not a list.renderer: networkdis the server default; state it explicitly so it is obvious later.
If the interface was in the cloud-init file, remove or empty that file so the two do not disagree:
sudo mv /etc/netplan/50-cloud-init.yaml /root/50-cloud-init.yaml.bak
Applying it, with a rollback
I never use netplan apply first on a remote box. netplan try applies the configuration and waits 120 seconds for you to press Enter to confirm. If you do not (because the connection dropped), it reverts automatically:
sudo netplan try
If you are on the console and confident, sudo netplan apply applies it immediately. netplan generate alone writes the backend files under /run/systemd/network/ without applying, which is useful for checking syntax.
Optional: a second interface and static routes
A storage or replication NIC on a private network without a gateway, plus a route to another subnet via that NIC:
ens192:
dhcp4: no
addresses: [192.168.50.25/24]
routes:
- to: 192.168.60.0/24
via: 192.168.50.1
Interfaces without gateway4 still get their directly connected route; only the default route comes from the interface that declares one.
Did it work?
ip -br addr show ens160
ip route show default
systemd-resolve --status | grep -A3 'Link 2'
ping -c 3 10.0.1.1
ping -c 3 archive.ubuntu.com
The DNS check matters because on 18.04 /etc/resolv.conf is a symlink to systemd-resolved's stub file and always shows 127.0.0.53. The real upstream servers are only visible through systemd-resolve --status. If names resolve and the default route is right, the configuration is complete. Reboot once to confirm it survives; that is the real test of the cloud-init change.
Errors and oddities
Error in network definition /etc/netplan/01-static.yaml line 6 column 8: expected mapping: YAML indentation problem, often a tab character or a list item at the wrong depth.cat -Ashows tabs as^I.Invalid YAML at ... found character that cannot start any token: same cause, almost always a tab.- Configuration applies but reverts after reboot: cloud-init rewrote the file. Confirm the
99-disable-network-config.cfgfile from earlier exists and that you did not leave adhcp4: truefor the same interface in another file. - Two default routes and flaky connectivity: both interfaces have
gateway4. Remove it from the private one. - Interface name changed after a hardware change: Netplan supports
match:by MAC address plusset-name:to pin a predictable name. Use it when the same YAML has to work across cloned VMs.
I still miss ifcfg-* files a little. But one short YAML file in version control is hard to argue with.