Setting up Ubuntu 20.04 Server on Raspberry 4B

Ubuntu now supports a flavor that runs in the Raspberry Pi platform, unfortunately as of the time of writing there is still a fair bit of configuration needed by the user to use the Pi beyond a generic use case. This series of posts is a culmination of the lessons learned of many dead ends that I have experienced. I attempt to be both minimalistic in configurations but explanatory so, if you are so inclined, you can better understand the why and how of what configurations have been made.

That said, if there any surprises or if the code doesn’t work off the shelf, then please leave a comment.

Download Ubuntu Image

Ubuntu have done an excellent job to provide a flavor in support of Raspberry Pi, ranging from Pi 2 through to Pi 400 as well as supporting 32bit and 64bit architectures as of the time of writing this. Images are available for download here.

I have a Raspberry Pi 4B with 8GB of RAM and though the recommendation is to use the 64bit architecture I have chosen Ubuntu Server 20.04 LTS 32bit for the Raspberry 4 as my OS.

  • Why Ubuntu Server? I intend to use the Pi headerless (i.e. without a screen) so all the bells and whistles that come with Ubuntu Desktop are superfluous to my needs.
  • Why the LTS version? Because I want to avoid doing a Linux distribution upgrade as far as I can and possibly brake elements of my prior work.
  • Why the 32bit? Some libraries don’t fully support 64bit (e.g. userland) and hence to save a lot of wasted effort I chose the 32bit.


I’m assuming you have chosen Ubuntu Server. In which case just follow the excellent instructions by Ubuntu here. However, I’d add that it is recommended that you use a SD micro card that has a speed class of 10 (looks like a 10 within a C) or better. C10 indicates that the card is possible to write at 10MB/s. For a great overview of SD cards I refer to a explanation provided by

If you can’t find the Raspberry Pi’s IP address even after a few minutes then it is either that you made a typo when modifying /system-boot/network-config, or that the Pi has the right network information but for some reason doesn’t make the connection. Obviously in the first instance you need to double check but removing the SD card from the Pi and connecting it back to your main computer. In the second instance, especially if the Pi’s activity green LED is not showing any signs of life, then simply unplug the Pi and re-plug it (on my second attempts the Pi connects to the network).

If you follow the Ubuntu set up guide you will be familiar with how to use ssh . The rest of the guide assumes you are already logged in with secure shell protocol.

House Cleaning

Keeping OS up to date

Keeping your OS in order is important. As soon as you logged in via ssh do the following:

$ sudo apt update
$ sudo apt upgrade -y
  • apt is a tool to manage the many different packages you have. To use it you need to have sudo priveledges
  • update updates the lists of packages with new versions, new packages whilst upgrade upgrades the versions you already have to new versions
  • the -y argument gives an automatic confirmation that all upgraded revisions are to be accepted. If you want to review the upgrades before they are executed then remove -y from the above snippet
  • The | (vertical bar) in command1 | command2 seralizes commands on the same line.

Customising user configurations

~/.bashrc holds user configurations which you don’t want to change manually. Cleverly it makes a reference to another configuration file that you are able to modify, which is ~/.bash_aliases. Open ~/.bashrc and find the following block which does the referencing

if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
  • Essentially the above snippets asks “If ~/.bash_aliases does exist then includes its contents”. By default ~/.bash_aliases does not exist. To create the file then do

$ touch ~/.bash_aliases

  • The touch command either creates a file if it does not exist or updates the access and modification times of the file if it does exist.

Now we want to populate it with custom configurations. The below are just some ideas

$ echo "alias ls='ls -la --color=auto'" >> ~/.bash_aliases

  • The command goes like this echo [STRING] >> [FILE] and is typically used to append a string to the end of a file. Be careful, if you swapped >> with > then the string will overwrite the file with the new string.

Now we want to replace the current shell with a new bash shell so that we can use the new alias.

$ exec bash

Folder Structure

Purely optional but I prefer to have a lean Home folder. To this end I create a folder called repositories by typing $ mkdir ~/repositories . Similar line to create a folder to hold all the virtual environments $ mkdir ~/environments


Frustratingly Ubuntu Server 20.04 does not bundle the tools to use the camera off the shelf. This is the plan of attack:

  1. Configure boot to enable the camera port
  2. Install tools that we will need to build from source.
  3. Download and build userland repository from source. This will give use tools such as raspistill and raspivid. If you’ve skipped the beginning of this post to get here then note that I’m running 32bit architecture. If you are running 64bit architecture and are coming across other errors not shown below the bad news is that it may be because userland doesn’t 100% support 64bit architecture yet.
  4. Enable configuration to be able to use raspistill without an absolute path
  5. Give rights to the user to be able to use raspistill without needing sudo
  6. Reboot and test

Ok, let’s get to work.

Step 1. Configure boot

In /boot/firmware/config.txt type the following text (note that for some reason if you followed the recommended practice of appending the below to /boot/firmware/usercfg.txt then the config.txt file doesn’t include it, hence the need to modify config.txt directly):

#enable camera port

Step 2. Install library dependencies

Now install cmake and build-essential:

$ sudo apt install cmake build-essential

Step 3. Clone userland

Now clone the userland repository and modify the build instructions slightly.

$ cd ~/repositories
$ git clone
$ cd userland
$ nano CMakeLists.txt

In CMakeLists.txt add the line SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-as-needed") this will allow us to use the picamera library that will later be installed. Now build from source. Note that there is no space after the comma in "-Wl,--no-as-needed" .

$ ./buildme

Step 4. Update your shell configuration

Update the configuration so that you can use the raspistill command

$ echo -e 'PATH=$PATH:/opt/vc/bin\nexport PATH' >> ~/.bash_aliases
$ echo -e 'LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/vc/lib\nexport LD_LIBRARY_PATH' >> ~/.bash_aliases
$ exec bash
$ sudo ldconfig

Step 5. Modify Permissions

Double check that the user is a member of the video group by typing $ groups ubuntu . If you see ‘video’ in the list you are good. If not then fix that by typing $ sudo usermod -aG video ubuntu. Note if we tried to run $ raspistill it will return a failed to open vchiq instance error. That’s why we need to change the read/write rights to the vchiq device.

$ sudo nano /etc/udev/rules.d/10-vchiq-permissions.rules

By default /dev/vchiq is owned by root the user and root the group but is read/write to the the root user only. We want it to be accessible to the group video and change its rights so that the group can read/write. Check this page by for a good introduction to chown and chmod. Note that if you didn’t create the above file but ran a line like $ sudo chown :video /dev/vchiq | sudo chmod 660 /dev/vchiq then it effectively assigns the same rights as those in the file but with the disadvantage of /dev/vchiq returning to the default setting after you reboot.

Step 6. Reboot and then test

$ sudo shutdown -r now

$ raspistill -o output.jpg

There should be no errors and a output.jpg file created in the folder you were in when you ran the above command


With Raspistill operational now we want to use the camera from inside a Python program. This is the plan of attack:

  1. Install tool to create a virtual environment (optional)
  2. Modify configuration
  3. Enable virtual environment and check dependencies
  4. Install PiCamera with pip
  5. Test

Step 1. Install Virtual Environments

I advocate the use of virtual environments for your different projects because you will find that different projects need different dependencies. If you tried to run all your projects from the globally available dependencies that you installed over time then you may find that there are conflicts and you will spend some time trying to untangle them. Using virtual environments allows you to compartmentalize these dependencies according to the specific needs of the project. The install then run $ sudo apt-get install python3-virtualenv

Step 2. Modifying configuration

When I try to install picamera with pip here it returns the following error: ValueError: This system does not appear to be a Raspberry Pi. To solve this error you need to add export READTHEDOCS=True to ~/.bash_aliases. Type:

$ echo 'export READTHEDOCS=True' >> ~/.bash_aliases

Step 3. Enable virtual environment and check dependencies

To create a virtual environment type the following:

$ cd ~/environments
$ python3 -m virtualenv testenv

Replace testenv with whatever name you want to call your new environment. The line to activate the new environment is $ source ~/environments/testenv/bin/activate which you would need to type each time. I think this is a bit unwieldy so you can make an alias in ~/.bash_aliases by typing:

$ echo "alias src_testenv='source ~/environments/testenv/bin/activate'" >> ~/.bash_aliases
$ exec bash
$ src_testenv

Check that you have wheel installed

(testenv) $ pip3 install wheel

Step 4. Install picamera

(testenv) $ pip3 install picamera

Step 5. Test picamera

In a folder of your choosing create a python file.

(testenv) $ touch

Populate the file with the following (taken from

from time import sleep
from picamera import PiCamera

camera = PiCamera()
camera.resolution = (1024, 768)
# Camera warm-up time

Test it with

(testenv) $ python3

If everything went well you will see that there is a file foo.jpg in the folder you ran the script. To deactivate the virtual environment then just type (testenv) $ deactivate

1 thought on “Setting up Ubuntu 20.04 Server on Raspberry 4B”

Leave a Reply

Your email address will not be published. Required fields are marked *