It's Pi all the way down...


In the previous post we saw how to configure multiple different users via user-data, one of the cloud-init configuration files. This time, we’ll turn our attention to network-config which is probably the most important configuration file aside from user-data as it tells Netplan what to do when setting up the network.


What’s Netplan? It’s a tool used on Ubuntu used to present a common interface to whatever happens to manage the network. For instance, on desktops this is typically Network Manager, while servers tend to use systemd’s networkd service. Netplan can “render” a configuration to work with either of these systems.


This file is basically just a typical Netplan configuration minus the root “network:” value. By default it contains the following on the Pi images:


 1 version: 2
 2 ethernets:
 3   eth0:
 4     dhcp4: true
 5     optional: true
 6 #wifis:
 7 #  wlan0:
 8 #    dhcp4: true
 9 #    optional: true
10 #    access-points:
11 #      myhomewifi:
12 #        password: "S3kr1t"
13 #      myworkwifi:
14 #        password: "correct battery horse staple"
15 #      workssid:
16 #        auth:
17 #          key-management: eap
18 #          method: peap
19 #          identity: ""
20 #          password: "passw0rd"
21 #          ca-certificate: /etc/my_ca.pem

On line 1, “version:” just declares the version of the Netplan schema that the file conforms to (this should be “2”).

On line 2, the “ethernets:” value starts which sets up the “eth0” interface to use DHCP for IPv4 (we haven’t specified anything for IPv6) and marks the interface optional (indicating we shouldn’t wait for it to come up on boot, just in case there’s no cable plugged in).

On line 6 onwards is a big “wifis:” section which is commented out (the “#” prefix), and which contains several examples of common WiFi configurations. We’ll explore this in the next section.

What should we do if we wanted to use a static IP configuration for eth0 instead of DHCP? The following is an example block which should be reasonably obvious to anyone familiar with IP networking.

version: 2
      search: [mydomain]
      addresses: [,]
    optional: true

It is important to remember that “addresses:” takes a list of addresses (as an interface can have multiple).

wifi configuration

This is much the same as ethernet (as you can probably see from the commented out example in the default file). The only major difference is the extra “access-points” sub-value. Under this, you can list all the wifi access points you regularly connect to, and the credentials required for each.

For example, let’s assume your home router is called “BT-1234” with password “a very long password”, but you also have an extender called “wifi_ex” which has the (slightly less secure) password “passw0rd”. In this case you might use the following configuration:

version: 2
    dhcp4: true
    optional: true
        password: "a very long password"
        password: "passw0rd"
    dhcp4: true
    optional: true

Note that it doesn’t matter what order the top-level values appear in. I tend to write “version” first, followed by “ethernets” but it really doesn’t matter. The same goes for sub-values of values; place them in whatever order you want.

Later changes

What does cloud-init do with the network-config file? Roughly speaking, it copies it (with an additional root “network:” value) to /etc/netplan/50-cloud-init.yaml (the Netplan configuration consists of all YAML files under /etc/netplan) and then applies it.


Unfortunately, there’s currently a bug here. While cloud-init will happily copy your WiFi configuration to Netplan, it won’t (currently) apply it automatically. To do that, you need to reboot your Pi afterwards (or run sudo netplan apply from the command prompt, assuming you have a keyboard attached).

The issue is being tracked under LP: #1870346 for those interested.

For users of Raspbian this probably feels similar to its facility of copying a file named wpa_supplicant.conf on the boot partition. The main difference is that this deals with all interfaces rather than just wifi.

Remember that cloud-init only deals with the very first boot. What happens if you want to change your network configuration later? In this case simply edit the file cloud-init created, /etc/netplan/50-cloud-init.yaml, and run sudo netplan apply (or reboot).

Back to user-data

While we’re looking at network related stuff, there’s a couple of settings in user-data we should cover. First is “hostname” which can be used to set the hostname of a freshly minted machine. It’s as simple as specifying this at the top level:

hostname: waldorf

Whether this is honoured by the local DNS server will depend on its configuration. If you use dnsmasq as your local DHCP/DNS server (as I do) then it should work just fine.

System time can often be an issue on Pis, which lack a RTC. NTP is the usual solution to this for any Pi connected to a network. Often, the DHCP server will supply the address of an NTP server, or the NTP’s default configuration will be sufficient. However in some cases you may need to configure the NTP servers to query manually. Again, you can use cloud-init to set NTP up:

  enabled: true
  - ntp.server.local

Cloud-init knows how to configure a reasonable variety of NTP clients and can adapt the configuration above to their particular format. But how to get such a client installed on the very first boot? That’s a topic we’ll leave for next time…