Ubuntu 18.04 Ignored /etc/network/interfaces: A Netplan Static IP That Works
New server, fresh 18.04 install, and a task I have done since I was a teenager: give it a static IP. I edited /etc/network/interfaces, restarted networking, and the machine kept its DHCP address as if I had written the file to a diary. No error. No warning. The file was simply not consulted by anything.
Ubuntu 18.04 configures networking with Netplan. You write a small YAML file describing what you want, and Netplan generates configuration for the backend that actually does the work, which on a server is systemd-networkd. The ifupdown package that owned /etc/network/interfaces is not installed by default, so the file is inert.
My honest opinion after a year of both: the YAML is better. It is declarative, it is the same on every cloud image, and netplan try has saved me from locking myself out of a remote machine more than once, which ifdown eth0 never did for anybody. The annoyance is real but it is one afternoon, and the file is twelve lines.
Create /etc/netplan/60-static.yaml, using your real interface name from ip link show:
network:
version: 2
renderer: networkd
ethernets:
enp0s3:
dhcp4: no
addresses: [192.168.1.50/24]
gateway4: 192.168.1.1
nameservers:
addresses: [1.1.1.1, 8.8.8.8]
Then apply it with the safety net, not without:
sudo netplan try # rolls back in 120s unless you confirm
sudo netplan apply # only once try has proved it
Step 1: Find the interface's real name
It is probably not eth0. Predictable interface names have been the default for several releases, so you get names derived from the hardware path:
ip -br link show
lo UNKNOWN 00:00:00:00:00:00
enp0s3 UP 08:00:27:1f:3a:9c
Use that name exactly. A Netplan file that names an interface which does not exist is not an error: it is a valid description of a device that is absent, so it applies cleanly and changes nothing. That silence is why people conclude Netplan is broken.
Step 2: Write your own file, do not edit theirs
ls -1 /etc/netplan/
On a cloud server you will usually find 50-cloud-init.yaml. Netplan reads every .yaml file in that directory in lexical order and later files win, so add 60-static.yaml rather than editing the generated one. Then stop cloud-init from rewriting networking on the next boot:
echo 'network: {config: disabled}' | \
sudo tee /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg
Skip that and your careful static address survives until the machine reboots, at which point cloud-init regenerates its own file and you are back on DHCP with no memory of why.
Step 3: Apply it without losing the server
sudo netplan try
Do you want to keep these settings?
Press ENTER before the timeout to accept the new configuration
Changes will revert in 120 seconds
This is the command that matters when the machine is in a data centre and you are on a different continent. It applies the configuration, waits for you to press enter, and reverts if you cannot, because the reason you cannot is usually that you just cut your own SSH session. Once try has been accepted, netplan apply is safe.
The errors, and what they actually mean
Two shapes of failure, and they are different problems:
Invalid YAML at /etc/netplan/60-static.yaml line 6 column 8: did not find expected key
The file is not valid YAML at all, before Netplan has looked at the meaning. Ninety per cent of the time it is a tab character. YAML forbids tabs for indentation, and most editors will happily insert one. Two spaces per level, always. The other frequent cause is a missing space after a colon: dhcp4:no is a string, dhcp4: no is a boolean.
Error in network definition /etc/netplan/60-static.yaml line 7 column 6: unknown key gateway
This one is valid YAML that Netplan does not understand. The key is misspelled or belongs somewhere else in the tree. Common examples: gateway instead of gateway4, nameserver instead of nameservers, or addresses given as a bare string rather than a list. Addresses are always a list of CIDR strings, including the prefix length, and 192.168.1.50 without /24 is rejected.
When neither message is enough, ask for the working:
sudo netplan --debug apply
It prints the parse, the files it generated, and the backend it chose, which settles the frequent confusion about whether networkd or NetworkManager is in charge. A desktop install uses NetworkManager and a server uses networkd, and a machine that had a desktop installed on it once can be either.
Two things the YAML makes easier
Since you are here anyway, these are the cases that used to mean looking up ifupdown syntax every single time.
A second address on the same interface is one more list entry, not a virtual eth0:1 device:
addresses:
- 192.168.1.50/24
- 192.168.1.51/24
And a route to one internal network through a different gateway, without disturbing the default route:
routes:
- to: 10.20.0.0/16
via: 192.168.1.254
Both take effect on netplan apply with no interface flapping in between, which matters when the machine you are reconfiguring is the one carrying your SSH session.
The related trap is a server with two interfaces, a public one and a private one, which most providers now hand you by default. Give gateway4 to exactly one of them, the public interface, and give the private interface an address and nothing else:
ethernets:
ens3:
addresses: [102.x.x.x/24]
gateway4: 102.x.x.1
nameservers:
addresses: [1.1.1.1, 8.8.8.8]
ens4:
addresses: [10.10.0.7/16]
Two default gateways on one machine produces traffic that leaves by whichever route the kernel prefers at that moment, which looks exactly like an intermittent network fault and is diagnosed as one for days. If the private network needs to reach beyond its own subnet, add an explicit routes: entry for it as above rather than a second default.
Verification
ip -br addr show enp0s3
ip route | head -n 3
systemd-resolve --status | grep -A2 'DNS Servers'
ping -c 2 1.1.1.1
ping -c 2 ubuntu.com
Run all five, in that order, because each one fails differently. An address but no route is a missing gateway4. A working ping to an IP but not to a name is DNS, and on 18.04 that means systemd-resolved: /etc/resolv.conf is now a symlink to a stub file containing 127.0.0.53, which is correct and confuses everyone who greps it looking for their nameserver.
Then reboot. Networking that survives netplan apply but not a restart is the cloud-init problem from step two, and it is better to find that out now than during the next power cut.
What people get wrong
Installing ifupdown to bring back the old file. It mostly works, and it leaves you with one machine configured unlike every other machine you own, including the images your provider builds. You will forget which is which at the worst moment.
Editing files under /run/systemd/network. They are regenerated from the YAML on every apply and lost on every boot. If a setting cannot be expressed in Netplan, put a real file in /etc/systemd/network/ instead, and know that you now have two sources of truth.
Disabling systemd-resolved because resolv.conf looks wrong. The stub resolver is deliberate. Point your nameservers at the interface in Netplan and check them with systemd-resolve --status, rather than hand editing a file that is regenerated.
Running netplan apply on a remote machine without a console. Use try. If your provider gives you a web console, open it in another tab first. Both cost nothing until the day they cost nothing.
When it is still broken
- Nothing changes and no error appears. The interface name in the YAML does not match a real device. Check
ip -br link showagain. - The address is set but traffic does not leave. Look for two files both defining the same interface, one of them still asking for DHCP. Lexical order decides, and
50-loses to60-. - It works, then reverts after a reboot. cloud-init. Disable its network configuration as in step two.
- The backend is not running at all.
systemctl status systemd-networkdand read the journal for it. It is an ordinary systemd unit like any other, and the diagnostic habits from moving services to systemd apply here unchanged.
Frequently asked questions
- Can I go back to /etc/network/interfaces on Ubuntu 18.04?
- You can install ifupdown and it will mostly work, but it is a dead end: the installer, cloud images and future releases all assume Netplan. Learning the twelve lines of YAML once is cheaper than maintaining a machine that is configured differently from every other machine you own.
- Why does netplan apply say my YAML is invalid when it looks fine?
- Netplan YAML is indentation sensitive and rejects tabs outright. Use two spaces per level and never a tab character. Also check that addresses is a list of strings in CIDR form, and that the interface name matches what ip link show reports, not eth0 out of habit.
- How do I avoid locking myself out when changing a remote server's IP?
- Use netplan try. It applies the configuration, waits for you to confirm, and rolls back automatically if you do not, which saves the SSH session that just went dark. Where the provider offers a console, have it open in another tab before you touch networking at all.
- Which file should I edit when there are several in /etc/netplan?
- Netplan reads every .yaml file in the directory in lexical order, and later files override earlier keys. On cloud servers the installer writes 50-cloud-init.yaml. Add your own file with a higher number, such as 60-static.yaml, so an image update does not overwrite your settings.