Ubuntu Server 16.04 on Raspberry Pi 3 via Terraform
In this tutorial you will find how to setup latest Ubuntu Classic server 16.04 and automate process as much as possible. Solve two issues related to upgrade packages and kernel.
Hardware and software requirements:
-
Raspberry Pi 3
-
A microSD card with adapter
-
A monitor with an HDMI interface
-
A USB keyboard
-
Ethernet cable with Internet connection
-
Terraform (Getting Started)
-
(Optional) Terraform example of resources repo
Install Ubuntu
First step is to download the latest Ubuntu Classic Server 16.04 image from the download page of Ubuntu Pi Flavour Maker.
There are many solutions to burn an image on a microSD you can find on official ubuntu page, but I suggest to use Etcher from Resin.io team. It is easy and faster for all OS.
First boot and steps
-
Connect the device to local network and boot it.
-
If you have already DHCP server setup in the local network, than you would get the IP address through booting output. Otherwise you need to manually login to the device and setup network. Default login and password is ubuntu. It would ask you to change the password after first login.
-
Update authorize keys of the user to access the host without password. Some solutions:
ssh-copy-id ubuntu@<ip>
. Or import Github’s public keys:
# Updated 2017.07.05 Thanks to https://www.reddit.com/user/xeoomd for the url
# from comment https://www.reddit.com/r/devops/comments/6l6uhm/ubuntu_server_1606_on_raspberry_pi_3_via_terraform/djsf1ai/
# Replace GTIHUB_USER with your username in Github
curl -s https://github.com/GTIHUB_USER.keys >> ~/.ssh/authorized_keys
# First version
# curl -s https://api.github.com/users/GTIHUB_USER/keys | grep key | sed 's/.*"key":\s*"\([^\"]*\)"/\1/g' >> ~/.ssh/authorized_keys
Automation
I choose Terraform, because it is easy to read and fast learning. The main purpose of Terraform to work with Cloud/Hosting providers and setup resources via API calls. To provision hosts I use null_resource
. It allows to connect to the host and run different scripts. More information you can find in official documentation Provisioners: null_resource and Provisioner Connections.
Upgrade packages
So you have kernel version 4.4.0–1009-raspi2
. There are few bugs that blocks simple upgrading:
The upgrade packages, create a resource:
variable "server_ip" {
default = "10.0.0.2"
}
# Terraform documentation
# * Provisioner null_resource: https://www.terraform.io/docs/provisioners/null_resource.html
# * Provisioner Connections: https://www.terraform.io/docs/provisioners/null_resource.html
# Ubuntu issues:
# https://bugs.launchpad.net/ubuntu/+source/linux-raspi2/+bug/1652270
# https://bugs.launchpad.net/ubuntu/+source/linux-raspi2/+bug/1652270/comments/44
# https://bugs.launchpad.net/ubuntu/+source/linux-firmware-raspi2/+bug/1691729
resource "null_resource" "upgrade-packages" {
connection {
type = "ssh"
user = "ubuntu"
host = "${var.server_ip}"
}
provisioner "remote-exec" {
inline = [
"sudo apt-mark hold linux-raspi2 linux-image-raspi2 linux-headers-raspi2",
"sudo dpkg-divert --divert /lib/firmware/brcm/brcmfmac43430-sdio-2.bin --package linux-firmware-raspi2 --rename --add /lib/firmware/brcm/brcmfmac43430-sdio.bin",
"sudo apt-get update && sudo apt-get upgrade -y && sudo apt-get dist-upgrade -y",
"sudo apt-mark unhold linux-raspi2 linux-image-raspi2 linux-headers-raspi2",
"sudo apt-get update && sudo apt-get upgrade -y && sudo apt-get dist-upgrade -y",
"sudo sed 's/device_tree_address.*/device_tree_address=0x02008000/g; s/^.*device_tree_end.*//g;' -i /boot/firmware/config.txt",
"sudo reboot"
]
}
}
Where var.server_ip
is your Raspberry Pi’s ip address. To apply changes run command:
$ terraform apply -target=null_resource.upgrade-packages
Change Hostname
By default the server’s hostname is ubuntu
. It could be changed via resource:
variable "server_ip" {
default = "10.0.0.2"
}
variable "server_hostname" {
default = "node01"
}
# Ubuntu reference for hostnamectl: http://manpages.ubuntu.com/manpages/trusty/man1/hostnamectl.1.html
resource "null_resource" "set-hostname" {
connection {
type = "ssh"
user = "ubuntu"
host = "${var.server_ip}"
}
provisioner "remote-exec" {
inline = [
"sudo hostnamectl set-hostname ${var.server_hostname}",
"echo '127.0.0.1 ${var.server_hostname}' | sudo tee -a /etc/hosts",
"sudo reboot"
]
}
}
Update variables server_ip
and server_hostname
to your needs and apply changes:
$ terraform apply -target=null_resource.set-hostname
Wifi
After upgrade the packages the wifi device was disappeared. Ubuntu issue:
In same thread you can find the solution. After fix the problem you need to setup connection to your WiFi. Also you can find more information how to setup Raspberry Pi with WiFi in How to setup your Raspberry Pi 2/3 with Ubuntu 16.04, without cables (headlessly).
variable "server_ip" {
default = "10.0.0.2"
}
variable "wlan_ssid" {
default = "free wifi hotspot"
}
variable "wlan_psk" {
default = "changeme"
}
# https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=141834
# https://medium.com/a-swift-misadventure/how-to-setup-your-raspberry-pi-2-3-with-ubuntu-16-04-without-cables-headlessly-9e3eaad32c01
# https://wiki.debian.org/WiFi/HowToUse
resource "null_resource" "wifi" {
depends_on = ["null_resource.upgrade-packages"]
connection {
type = "ssh"
user = "ubuntu"
host = "${var.server_ip}"
}
provisioner "remote-exec" {
inline = [
"sudo apt-get install -y wireless-tools wpasupplicant",
"cd /lib/firmware/brcm/",
"sudo wget https://github.com/RPi-Distro/firmware-nonfree/raw/master/brcm80211/brcm/brcmfmac43430-sdio.bin",
"sudo wget https://github.com/RPi-Distro/firmware-nonfree/raw/master/brcm80211/brcm/brcmfmac43430-sdio.txt",
"echo \"allow-hotplug wlan0\niface wlan0 inet dhcp\nwpa-conf /etc/wpa_supplicant/wpa_supplicant.conf\" | sudo tee /etc/network/interfaces.d/10-wlan.cfg",
"echo \"network={\\nssid=\\\"${var.wlan_ssid}\\\"\\npsk=\\\"${var.wlan_psk}\\\"\\n}\" | sudo tee /etc/wpa_supplicant/wpa_supplicant.conf",
"sudo reboot"
]
}
}
$ terraform apply -target=null_resource.wifi
Summary
Now you can access to your Raspberry Pi via WiFi or Ethernet. You can modify terraform resource to install avahi
to detect the IP addresses of the device. Another solution to scan local network for hosts with open 22 port via:
$ nmap -sV -p 22 10.0.0.0/24
In the output would get a detail information about your local network, and choose ip similar to:
Nmap scan report for 10.0.0.2
Host is up (0.012s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Michael Nikitochkin is a Lead Software Engineer. Follow him on LinkedIn or GitHub.
If you enjoyed this story, we recommend reading our latest tech stories and trending tech stories.