Headless setup of Raspberry Pi — once and for all

How to reduce headaches when configuring all those million options.

Image Source.

Every time I set up a Raspberry Pi it feels like I am starting again for the first time. Why are there so many options? And so many places to set them? I find myself shutting down, mounting, editing, un-mounting, rebooting over and over and over.

After exhausting Google, here is my contribution to getting a headless setup (i.e. without monitor/keyboard) of a Raspberry Pi going. This entails flashing an SD card and getting started with Raspberry Pi OS, and enabling all the nice hardware that we like.

We will be using a Raspberry Pi Zero WiFi running Raspberry Pi OS (32-bit) Lite (Raspbian? When did they rename it?!).

Table of contents:

  1. Flash the SD card.
  2. Headless setup of RPi — WiFi / SSH / SSH over USB port / Enable SPI / I2C communication / UART / LCD via fbtft.
  3. Connecting to your device.
  4. Setup important features — WiFi / New user / Change hostname / Python / Pip.
  5. Enable optional features — Enable LCD screen over SPI via fbtft / Enable I2C / Enable NFC / Install Docker / Install apt-file.

I labeled each section with


so you can pick and choose.

Flash the SD card (required)

Get the latest Raspberry Pi OS Lite image here. I used:

Raspberry Pi OS (32-bit) Lite  
Minimal image based on Debian Buster  
Version: May 2020  
Release date: 2020–05–27  
Kernel version: 4.19  
Size: 432 MB

Get balenaEtcher here and flash an SD card with the image.

Headless setup of RPi (required)

Headless setup. Image source: author.

We will now setup your Pi without a monitor or keyboard.

Mount the SD card on your computer, and navigate to the boot partition.

Then we can set up the Pi as follows.

WiFi (required)

You can edit WiFi by making a file called wpa\_supplicant.conf with contents:

ctrl\_interface=DIR=/var/run/wpa\_supplicant GROUP=netdev  

NOTE: this didn’t work for me. I had to set it up later by editing sudo nano /etc/wpa_supplicant/wpa_supplicant.conf directly as described below. But you can connect to pi using SSH over USB without setting up networking to begin.

NOTE NOTE: The correct way to restart the WiFi is:

sudo wpa\_cli -i wlan0 reconfigure

SSH (required) ————–

To enable ssh, make empty file simply titled ssh (no extension) in the boot partition. You can use the command touch ssh to do this.

SSH over port USB (required)

To enable USB connection, add to the bottom of config.txt:

# Enable USB OTG like ethernet  

and to the end of cmdline.txt after rootwait such that it reads:

… rootwait modules-load=dwc2,g\_ether

Make sure you connect the USB cable to the USB port — not the power port on the Raspberry Pi Zero WiFi!

If ssh still does not work later (ugh!) you will have to use a keyboard to enter to pi and run:

sudo systemctl enable ssh.service

which should do it.

Enable SPI (optional)

To enableSPI, edit config.txt and uncomment:


I2C communication (optional) —————————-

To enable I2C devices, edit config.txt and ADD the following line:


Note: this is not done, see more directions below — there is further setup required later when you connect over ssh.

UART (optional)

You can enable UART by adding to config.txt:

# Enable UART  

Enable LCD via fbtft (optional) ——————————-

To enable an LCD screen over SPI, edit config.txt and enable SPI as discussed above. We can also disable overscan by uncommenting:


To enable the LCD to show the boot process, append to /boot/cmdline.txt:


Note: this is not done, see more directions below — there is further setup required later when you connect over ssh.

Connecting to your device (required)

Now you can connect — find the address:

ping raspberrypi.local

which should give e.g., then:

ssh pi@  
password: raspberry

Setup important features (required)

Idea! The think you know. Image source: author.

WiFi (required)

  • Check WiFi connects:
  • If not, edit sudo nano /etc/wpa_supplicant/wpa_supplicant.conf:
ctrl\_interface=DIR=/var/run/wpa\_supplicant GROUP=netdev  
sudo wpa\_cli -i wlan0 reconfigure

New user (recommended) ———————-

  • Make a new user called joehisashi with password abc123:
sudo adduser joehisashi  
password: abc123
  • Add to sudo:
sudo adduser joehisashi sudo
  • Now log out and back in as joehisashi.
  • Delete the pi user
sudo userdel -r pi
  • We can add ourselves to sudo so we don’t need sudo for a command like some_command:
joehisashi ALL=(ALL) NOPASSWD: some\_command

at the bottom.

  • Change the hostname so instead of ping raspberrypi.local we can ping ghibli.local .
  • Edit:
sudo nano /etc/hostname

such that it reads simply

  • This requires a restart to work:
sudo reboot -h now

Now we can ping the device with simply

ping ghibli.local

Python (recommended) ——————–

  • Both python 2.7.16 and python 3.7.3 come installed.
  • Make alias so python3 is default because what even is Python 2 good for at this point:
nano ~/.bashrc

Add the line

alias python3=python
  • Log out and in or source ~/.bashrc
  • Check that python — version gives 3.7.3 .
  • First you need python3-distutils else the Pip install will fail:
sudo apt-get install python3-distutils
  • Get pip following directions here:
curl <https://bootstrap.pypa.io/get-pip.py> -o get-pip.py  
python get-pip.py
  • Remove the script when done
rm get-pip.py

Enable optional features (optional) ===================================

So many options, what do they all do? Image source: author.

Enable LCD screen over SPI via fbtft (optional)

  • Enable SPI on the SD card in/boot/config.txt as discussed above, and the LCD section above.
  • Back on the Pi, create /etc/modules-load.d/fbtft.conf:

(The Broadcom BCM 2835 chip is a chip on the Pi).

  • Find your device here of supported fbtft devices, or you can use a custom one. I will use the example for fb_ili9341 as shown in the link under Custom display.
  • Create /etc/modprobe.d/fbtft.conf:
options fbtft\_device custom name=fb\_ili9341 gpios=reset:25,dc:24,led:18 speed=16000000 rotate=270 bgr=1

Obviously, edit your GPIO numbers as necessary.

  • Reboot
sudo reboot -h now
  • Check dmesg that it worked — you should see something about fb_ili9341 or whatever your device is.
  • Note: to get pygame to work, you also need:
sudo apt-get install python-pygame

and to run the python script that will control the LCD with sudo.

Sources and more information here and extra details here.

Enable I2C (optional)

  • Enable I2C in /boot/config.txt as described above.
  • On the Pi, check: lsmod|grep i2c . There should only be one line:
i2c\_bcm2835 16384 0
  • Run:
sudo modprobe i2c-dev

Now checking lsmod|grep i2c should give:

i2c\_dev 16384 0  
i2c\_bcm2835 16384 0
  • Make it so this happens automatically at startup: edit sudo nano /etc/modules and add the line:

and reboot

sudo reboot -h now

Enable NFC (optional) ———————

  • To use NFC devices as discussed here, install libnfc-bin:
sudo apt-get install libnfc-bin
  • Find your device here. You can use UART or I2C or SPI. I will use PN532 device on R-Pi connected using I2C just for example.
  • Edit sudo nano /etc/nfc/libnfc.conf such that it reads:
# Allow device auto-detection (default: true)  
# Note: if this auto-detection is disabled, user has to set manually a device  
# configuration using file or environment variable  
allow\_autoscan = true
# Allow intrusive auto-detection (default: false)  
# Warning: intrusive auto-detection can seriously disturb other devices  
# This option is not recommended, user should prefer to add manually his device.  
allow\_intrusive\_scan = false
# Set log level (default: error)  
# Valid log levels are (in order of verbosity): 0 (none), 1 (error), 2 (info), 3 (debug)  
# Note: if you compiled with — enable-debug option, the default log level is “debug”  
log\_level = 1
# Manually set default device (no default)  
# To set a default device, you must set both name and connstring for your device  
# Note: if autoscan is enabled, default device will be the first device available in device list.  
device.name = “\_PN532\_I2c”  
device.connstring = “pn532\_i2c:/dev/i2c-1”
  • Later you need to run the command that will run the NFC as sudo: sudo my_nfc_command .

Install Docker (optional)

  • Install docker:

NOTE: do NOT run sudo apt-get install docker. It doesn’t work as stated here.

Follow the exact instructions here. Also do not use the regular instructions! On Raspberry Pi OS, only the Install using the convenience script works.

The commands are just:

curl -fsSL <https://get.docker.com> -o get-docker.sh  
sudo sh get-docker.sh

After which you can remove the script

rm get-docker.sh
  • Add yourself to docker group so we don’t need sudo for every command
sudo usermod -aG docker joehisashi

You have to log out and in again for it to work.

  • Validate:
docker run hypriot/armhf-hello-world

Note that sudo docker run hello-world won’t work because Pi is armhf. For Raspberry Pi Zero WiFi you must use armhf. It should say Hello from Docker buried somewhere in the middle and a bunch of other stuff.

  • Clean up: You can see the image when you run
docker image ls

You can see the stopped container by

docker container ls --all

Note that you need --all to see stopped container.

Remove it by

docker container rm CONTAINER\_ID

and the image by

docker image rm IMAGE\_ID

where CONTAINER_ID and IMAGE_ID come from those previous commands.

Install apt-file (optional)

apt-file is great for searching for missing library dependencies:

sudo apt-get install apt-file

Then for example, upon:

ImportError: libSDL-1.2.so.0: cannot open shared object file: No such file or directory


apt-file search libSDL-1.2.so.0


libsdl1.2debian: /usr/lib/arm-linux-gnueabihf/libSDL-1.2.so.0  
libsdl1.2debian: /usr/lib/arm-linux-gnueabihf/libSDL-1.2.so.0.11.4

So install:

sudo apt-get install libsdl1.2debian

Final thoughts

That’s it! It should be enough to get your Raspberry Pi going for your next project, with only major headaches.


Oliver K. Ernst
July 9, 2020

Read this on Medium