June 23, 2020 / Reading time: 8m

How to flash and setup a headless Raspberry Pi



If you don't need a GUI don't waste resources with it

Some early warnings ⚠️

  • "Headless" means with no UI. While this process is fairly simple, the only way to access your device (with this installation) is through a shell, if you are not comfortable with the terminal this is most likely not for you.
  • We're gonna flash a fresh installation, this means all the data on your SD will be wiped, make sure to backup if needed.

Why going headless?

A lot of the Raspberry Pi projects use it mostly as a controller, server or just another piece on a larger system. Most of these applications don’t require or have a use for a GUI.

A headless system still allows you to configure, access and monitor the device, but you do it so with a console. Besides having a much lighter underlying operating system, leaving more CPU and RAM available for your app(s), you also remove a lot of variables that can (possibly) cause some problems/bugs/crashes.

For example, you wouldn’t want a webserver to go down because a keyboard driver stopped working.


Download Raspberry Pi Imager utility, why?

  • It is the official method for flashing your SDs
  • Always up to date with the latest OS version(s)

Let's get to it

Insert your SD card on your computer

(Once again, a word of caution, all data on this SD will be lost, so backup first)

Open Raspberry Pi Imager & Select Choose OS

In the Operating System menu select Raspberry Pi OS (other)

Now select Raspberry Pi OS Lite (32-bit) - There’s currently a beta 64-bit version but at the time of this writing it isn’t stable therefore we won’t be using it just yet.

Finally click WRITE to start the flashing process (Warning: Once again, all data in the SD card will be lost, make sure to backup if you need to)

Your password will be requested by the system (at least on macOS), provide the root password so the flashing process can start.

After the writing & verification completes, your SD card will be unmounted.

Remove and re-insert the SD card on your computer

You can now close the Raspberry Pi Imager software.


Now that our card is flashed, let’s do some basic setup, with the SD still on your computer, open up the terminal.

Note: In this section you’ll see the path:


This is the default macOS path for the SD and boot is the name the raspberry pi imager sets by default, adjust accordingly if you are on windows and/or your SD has a different name.

Enabling SSH

Since our OS is headless (no GUI) we need a way to access our RaspberryPi, let’s use SSH:

touch /Volumes/boot/ssh

Verify the file was created successfully:

ls /Volumes/boot/

Check if a file called ssh exists, or you can grep for its name:

ls /Volumes/boot/ | grep '^ssh'

There should be a ssh output in the terminal

Add WIFI details

Is it important that our RaspberryPi connects to the same WIFI as the computer you want to access it

Official documentation: https://www.raspberrypi.org/documentation/configuration/wireless/headless.md

Adjusting for your ISO 3166 alpha-2 country code, network name and network password:Open up your editor of choice, I’m using VSCode:

code /Volumes/boot/wpa_supplicant.conf

Add to the top of the file

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev

I’m in Portugal, that’s why I have country=PT don’t forget to adjust to your use case.  Now for each wifi connection you want your Pi to have just write an object for each like this:


priority: Lower the number the higher the priority your Pi tries to connect to

id_str: Should be unique for each network you have

For example, if we had 3 wi-fi connection(s) our wpa_supplicant.conf file could look like this:

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev




Verify all went well

cat /Volumes/boot/wpa_supplicant.conf

Double check the structure matches the above example with your own details.

Boot up

Now that we’ve enabled SSH and added some WIFI details we can finally boot up our RaspberryPi (!!) and continue the configuration process via SSH.

  1. Eject the SD card from your computer
  2. Insert the SD card into your Raspberry Pi
  3. Connect a power source to the Pi, the LEDs should star flashing
  4. Wait until the OS finishes booting (LEDs stop blinking)


With the raspberrypi’s defaults in mind, we can SSH into our device:

  • hostname: raspberrypi
  • user:  pi
  • password: raspberry

Let’s SSH

On your computer open up the terminal and type

ssh pi@raspberrypi.local

When prompted add the new fingerprint write yes

ECDSA key fingerprint is SHA256:RUFxSFNP6jBUntrxYa8EnYQt51L8o9wtWPp0fBgBje0.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

After that, the password will be requested, we write the default pi’s password (the terminal won’t write anything in the prompt):


Note: If you had previously SSH’ed into another pi you might get an error like this:

Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
Please contact your system administrator.

This is a security measure as this is another device (hardware) with the same name, this is to prevent you from SSH'ing in into a potentially malicious device.

Since we know this is another device controlled by us we can simply remove the old device from our known_hosts list, I’m using vscode

code /Users/YOUR_USERNAME/.ssh/known_hosts

Find the line with raspberrypi.local and remove it, save the file changes and try SSH once again.

And voilá we're in!

Now let’s start configure our raspberry pi via SSH.

One of the first things you'll see when first SSHing into your Pi is:

SSH is enabled and the default password for the 'pi' user has not been changed.
This is a security risk - please login as the 'pi' user and type 'passwd' to set

You should definitely do this, please change the default password, no need to leave a major security risk, even for the most trivial projects.

Remember your raspberry pi might be connected to your home network, a default password might be the point of entry to all the system connected to that same network, this is the default password for all Raspberry Pi OS pi users, don't be lazy and let’s fix that, while in the pi’s shell write:


Now we are prompted to change the password:

Changing password for pi.
Current password:

Our current password is the default one:


Now set the your new password and confirm

New password:
Retype new password: 
passwd: password updated successfully

Now whenever you want to SSH into your pi again you use your new password.

Note: If you get an error

passwd: Authentication token manipulation error
passwd: password unchanged

It means the filesystem was mounted as read-only, which prevents changing the password. A way to (try and) fix this issue is to remount the filesystem and then to check permissions of /etc/shadow file.

sudo mount -rw -o remount /


sudo mount -o remount,rw /

Expand your storage

sudo raspi-config


7. Advanced options


A1 Expand File System

Tab to finish, don’t reboot right now

Update and Cleanup

Remove Bloatware on the Raspberry Pi

This will remove a lot of utilities that come bundled with Raspberry Pi OS (libraoffice etc.) we'll most likely never user, we can always install these packages again if you need.

sudo curl -fsSL https://raw.githubusercontent.com/JoaquimLey/raspberrypi-headless-setup/master/pi_bloat_remove.sh

Update packages to the latest version

Finally let’s get our packages up to date before rebooting, this will install the latest versions of the bundled software

sudo apt-get update && sudo apt-full-upgrade

When prompted type say yes/y, the upgrade process might take a while.

Remove unused packages

sudo apt autoremove

Say yes/y when prompted.

Finally reboot

sudo reboot

Your connection will be closed as you pi restarts

Remember, if you want to SSH into your pi, you must use your newly set password.

We’re LIVE!

And that’s it, your headless RaspberryPi is ready!


SSH back into your Pi

Change your pi's hostname

This might come in handy for two reasons:

  1. Easily distinguish between multiple devices connected locally
  2. SSH locally with a specific device hostname with
ssh pi@your_custom_hostname.local

But first, to this we need to change it! Let's open up the config panel

sudo raspi-config

Now select:

1. Network Options
2. N1 Hostname -> OK
3. Set the new hostname

Now y ou can ssh locally with your custom name.

Setup ngrok

I use ngrok to remotely ssh to my pi's.

Ngrok provides a “tunneling” service, works as an abstraction for the constant ip changes, making it easier for me to connect to my devices while I'm not on the same location.

  1. Create a free account at https://ngrok.com/
  2. Download  ngrok for Linux ARM with
sudo wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-arm.zip

I’ve also created a self-sufficient script that installs a ngrok ssh tunnel service that runs on boot for the raspberry pi, you can check it here:

Install git

If you are planning on doing any kind of development you most likely wanna use git:

sudo apt-get install git

Find all the material associated with this article here:


While I don't implement a comments feature on this website. Feel free reach out to me on twitter for any questions or issues, and give a follow while you're at it.

Hope you enjoyed this article and it was helpful to you, cheers!