Headless Raspberry Pi Setup
Preparing the SD card
First we need grab ourselves an OS image.
While that’s downloading, we can list the attached drives before and after inserting our SD card, to find it’s device name.
> lsblk -p
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
/dev/mmcblk0 179:0 0 14.9G 0 disk
└─/dev/mmcblk0p1 179:1 0 14.9G 0 part /media/aaron/9016-4EF8
Once the image is downloaded, we can decompress it and write it to the SD card.
unzip ~/Downloads/2022-01-28-raspios-bullseye-armhf-lite.zip
sudo dd if=./2022-01-28-raspios-bullseye-armhf-lite.img \
of=/dev/mmcblk0 bs=4M conv=fsync status=progress
This might take a minute or two. -p
pipes the contents to stdout rather than disk, and fsync
ensure dd flushes writes to the SD card on completion.
After it’s finished, we can remove and re-insert the card to see the new partitions.
> lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
mmcblk0 179:0 0 14.9G 0 disk
├─mmcblk0p1 179:1 0 256M 0 part /media/aaron/boot
└─mmcblk0p2 179:2 0 1.6G 0 part /media/aaron/rootfs
My OS has handily mounted this for me, you may have to do that manually.
> cd /media/aaron
> ls
boot
rootfs
To enable ssh
on boot we can create the below empty file.
> touch boot/ssh
And configure the WiFi connection.
> vim boot/wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
country=<Insert 2 letter ISO 3166-1 country code here>
update_config=1
network={
ssid="<Name of your wireless LAN>"
psk="<Password for your wireless LAN>"
}
Note that you are writing your WiFi password in plaintext on an unencrypted filesystem, so don’t leave this pi anywhere bad actors might have physical access.
If you want to add multiple networks add id_str
with a unique name like
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
country=<Insert 2 letter ISO 3166-1 country code here>
update_config=1
network={
ssid="<Name of your wireless LAN>"
psk="<Password for your wireless LAN>"
id_str="Home_2.4GHz"
}
network={
ssid="<Name of your wireless LAN>"
psk="<Password for your wireless LAN>"
id_str="Home_5GHz"
}
We want our pi to have a predictable IP. This can be done though DHCP reservation if your router supports it, but raspberry pis have a habit of randomising their MAC address which makes that tricky.
A more reliable solution is to assign a static IP address on the pi itself. Check your router settings to ensure you pick an IP address that won’t be assigned to another device via DHCP.
Pick a hostname and IP address. You can get inspiration from any ordered set, chemical elements, roman emperors, I usually use pokemon.
This device will be named zenigame
and have IP address 192.168.1.7
.
Open rootfs/etc/dhcpcd.conf
and append the following lines. Your router address may vary, try sudo arp-scan --localnet
if you’re not sure.
static ip_address=192.168.1.7/24
static routers=192.168.1.254
static domain_name_servers=192.168.1.254
Note that this sets the same IP address for both the WiFi and ethernet interfaces, so you may not be able to use both at once.
To set the hostname, edit rootfs/etc/hostname
and rootfs/etc/hosts
and change the default raspberrypi
to your chosen name, I’m using zenigame
.
I also like to customise rootfs/etc/motd
with some ascii art, I’m going to be using this by Maija Haavisto.
This is about as far as we can get with the pi offline, so let’s unmount the SD card.
> sudo umount boot
> sudo umount rootfs
Insert the SD card in to the raspberry pi and power it on.
Pi Online
The only indication we get from the pi directly is the power LED, but we can run arp-scan
and wait for it’s IP to show up.
> sudo arp-scan --localnet
192.168.1.7 dc:a6:32:a4:ad:bb Raspberry Pi Trading Ltd
We can add an entry to our .ssh/config
like below
Host zenigame
Hostname 192.168.0.9
User pi
and attempt to connect with the default password ‘raspberry’
> ssh zenigame
Press ctrl-d to logout.
Assuming you have your ssh keys setup locally you can run
> ssh-copy-id zenigame
Once complete you should be able to run ssh zenigame
without being asked for a password.
Now we’re not at risk of locking ourselves out we can change the password. We won’t be using it much so I’d suggest making it random and keeping it in a password manager.
> ssh zenigame
pi> passwd
vim
is not installed by default, only vi
. You may wish to install vim or simply alias to vi.
Let’s update the system, which will also test our network connection.
pi> sudo apt update
pi> sudo apt upgrade
Let’s also set up the system to automatically install it’s own security updates.
pi> sudo apt install unattended-upgrades apt-listchanges
Open the config
pi> vi /etc/apt/apt.conf.d/50unattended-upgrades
and uncomment and set
Unattended-Upgrade::Mail "root";
Future Exploration
How best to check this mail? Can we install a web mail interface? Or forward the mail to another email address? Is there a client I can run from my main machine that will connect over ssh?
Does unattended upgrades work out of the box for raspberry pi systems? Some suggest that we need to also edit the sources in that config file, some do not. I’ll leave it as default for now and monitor. https://raspberrypi.stackexchange.com/questions/38931/how-do-i-set-my-raspberry-pi-to-automatically-update-upgrade
You can monitor these files to check on the automation
/var/log/unattended-upgrades/unattended-upgrades.log
/var/log/unattended-upgrades/unattended-upgrades-dpkg.log
/var/log/dpkg.log
/var/log/apt/history.log