Headless Raspberry Pi Installation

I seem to enjoy buying Raspberry Pis, as I find myself setting a new one up often enough that I made a small checklist for a headless setup.

UPDATE (2024): These days, the RaspberryPi Imager allows pre-configuring most of the settings (ssh, default user, hostname, locale) when copying an image to the SD card. Prefer this, as it’s less work and avoids connecting an RPi with a well-known default user/password to the network. You will still need to grow partitions and might want to update the system.

Let’s go headless

It’s great getting a new Raspberry Pi, but I really don’t care for connecting monitors, keyboards, etc. What am I, a farmer? I just want to hook up the Pi to Power and Network in a basement and ssh to the box. Turns out, this is easy. After copying the Raspian / Raspberry Pi OS image to your SD card, you can configure it to boot the Pi with DHCP and ssh enabled.

TIP: If you plan to run the RPi as a pure server, consider installing the Raspberry Pi OS Lite image, which doesn’t bring all the Desktop and visual applications and is much smaller.

To do so, you create an empty file called ssh in the boot partition.

Jam the card in the Pi, connect it to power and the network and it should pick up an IP address from DHCP and should have ssh enabled. Look up the IP in your DHCP server (or do a netscan) and log in to the Pi using the default credentials:

$ ssh pi@<IP Address>
# Default password should be 'raspberry'

NOTE: The ssh file will only enable ssh for a single boot (the file automatically gets deleted afterwards), so don’t reboot before you…

Permanently enable ssh

To permanently enable ssh, you can use:

$ sudo raspi-config
# Select “Interface Options” > SSH
# reboot

Grow Partitions

A very common step in every Raspberry Pi setup is to grow the partitions.

By default the OS only “sees” the size of the image you copied on the SD card and ignores the space “after” the image. You can use raspi-config to extend the OS partitions to the full size of the SD card making that space available to use.

sudo raspi-config
# Select “Expand Filesystem”
# reboot

Change timezone & locale

Update the timezone & locale:

$ sudo raspi-config
# Update Timezone

Change the hostname

If you happen to have more than one Pi, it’s a good idea to modify the hostname so you can tell them apart. Replace the system default in two places:

$ sudo vi /etc/hosts
...
127.0.1.1	<new hostname>
$ sudo vi /etc/hostname
<new hostname>
$ sudo reboot

NOTE: 127.0.0.1 is the so called loopback address, which you can think of roughly “this machine”.

“Replace” the pi user

It’s good safety practice to replace default users and passwords, so let’s get rid of the pi/raspberry login we used so far. We will add a new <user>, grant that user sudo powers, i.e., the power to run commands as root with sudo (this is important, as you won’t have root access otherwise) and will then remove the pi user.

# In case you don’t want to edit files with nano (ugh):
$ sudo update-alternatives --set editor /usr/bin/vim.tiny

# As the pi user:
$ sudo adduser <user>
$ sudo cp /etc/sudoers.d/010_pi-nopasswd \
  /etc/sudoers.d/010_<user>-nopasswd 
# Edit 010_<user>-nopasswd to give <user> sudo powers

# Log out, ssh back in using the new <user>
$ sudo userdel -r pi

TIP: Given some software tends to install on a per-user basis, it makes sense to do this before installing stuff.

Updating the system

As a last step, let’s make sure pick up updates published after the image you installed from was cut:

$ sudo apt-get update
$ sudo apt-get upgrade

At this point you should have the RPi up and ready to customize to whatever job it’s supposed to do in your network.