How to use a Raspberry Pi in kiosk mode

All tutorials

Kiosks are designed to offer users specific information or a specific experience, while preventing access to any other activities on the device. They are often found in airports, shops, hospitals, cafes, and museums — any location where people need easy access to information or services like timetables, waiting times, product information, directions, self check-in machines, and so on. Kiosk mode on your Raspberry Pi allows you to boot straight into a full‑screen web page or an application without using the desktop environment. It’s the foundation for many different projects where you want to display information for a dedicated interaction with a user. To demonstrate kiosk mode we are going to set up our Raspberry Pi to boot automatically to a full‑screen raspberrypi.com web page, which will rotate with the time.is/London web page.

Supplies

For the initial SD card setup, you will need:

  • Another computer connected to your network. We’ll refer to this as your usual computer to distinguish it from the Raspberry Pi computer you are setting up as the ambient lighting controller.

Choose the right Raspberry Pi

Kiosk mode works on all Raspberry Pi models. For this tutorial, we’ll be using a Raspberry Pi 4 Model B.

Configure your Raspberry Pi

To begin, follow the Getting Started documentation to set up your Raspberry Pi. For your operating system, choose Raspberry Pi OS (32-bit) to run headless (without a mouse and keyboard).

During the OS customisation stage, edit settings as follows:

  • Enter a hostname of your choice (we suggest pi-kiosk for this tutorial)

  • Enter a username and password; you’ll need these later to authenticate

  • Check the box next to Configure wireless LAN so your Pi can automatically connect to Wi-Fi

    • Enter your network SSID (name) and password; you can find these in your Wi-Fi settings or on a sticker on your router

  • Check the box next to Enable SSH so we can connect to the Pi without a mouse and keyboard

Remotely connect to your Raspberry Pi

SSH allows you to wirelessly connect to your Raspberry Pi, eliminating the need for a keyboard and mouse. It’s perfect if your Raspberry Pi is located in a hard-to-reach location, like the back of your television.

note

To SSH into the Raspberry Pi, you’ll use the hostname you set in Imager. If you have issues connecting using this method, you may want to use the Raspberry Pi’s IP address instead.

For more information about finding your IP address and remote accessing your Raspberry Pi, see the remote access documentation.

Connect via SSH

Open a terminal session on your usual computer. To access your Raspberry Pi via SSH, run the following command, replacing <username> with the username you chose in Imager:

$ ssh <username>@pi-kiosk.local
$ ssh <username>@pi-kiosk.local
The authenticity of host 'pi-kiosk.local (fd81:b8a1:261d:1:acd4:610c:b069:ac16)' can't be established.
ED25519 key fingerprint is SHA256:s6aWAEe8xrbPmJzhctei7/gEQitO9mj2ilXigelBm04.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/
[fingerprint])? yes
Warning: Permanently added 'pi-kiosk.local' (ED25519) to the list of known hosts.

<username>@pi-kiosk.local's password:
Linux pi-kiosk 6.1.21-v8+ #1642 SMP PREEMPT Mon Apr  3 17:24:16 BST 2023 aarch64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Oct 24 09:41:00 2023
<username>@pi-kiosk:~ $

When asked for your password, use the password you created in Raspberry Pi Imager.

Set up kiosk mode

This tutorial requires one additional piece of software, wtype, which simulates keyboard activity. To install it, run the following command:

$ sudo apt install wtype

To ensure your Raspberry Pi boots straight into the desktop environment when it’s powered up, use raspi-config:

$ sudo raspi-config
System Options in raspi-config

Select System Options > Boot / Auto Login > Desktop Autologin: Desktop GUI, automatically logged in as 'pi' user.

Configuring automatic login in raspi-config

Press Enter and Finish to save this setting. When prompted, reboot again. Once you have rebooted your Raspberry Pi, you should see the desktop environment on your monitor.

Next, we’ll instruct your Raspberry Pi what to present in kiosk mode and how to present it. In this tutorial, we’ll display the Raspberry Pi home page and a page displaying the time in London, switching between these two pages every few seconds.

To achieve this, we will edit .config/wayfire.ini. .config/wayfire.ini is a configuration file used to modify the behaviour and appearance of Wayfire, which is used to render the desktop in Raspberry Pi OS.

To open the file for editing in nano, a text editor, run the following command:

$ sudo nano .config/wayfire.ini

Take a look at the section titled [autostart]. At the moment, it reads like this:

[autostart]
panel = wfrespawn wf-panel-pi
background = wfrespawn pcmanfm --desktop --profile LXDE-pi
xdg-autostart = lxsession-xdg-autostart

Let’s append a few lines to this section to automatically start kiosk mode whenever your Raspberry Pi powers on:

chromium = chromium-browser "https://realtime.nationalrail.co.uk/ldbcis/departures.aspx?u=039B1CD1-14D4-4CB9-83B1-A84CC3AEDF83&crs=CBG&H=1440" --kiosk --noerrdialogs --disable-infobars --no-first-run --ozone-platform=wayland --enable-features=OverlayScrollbar --start-maximized
switchtab = bash ~/switchtab.sh
screensaver = false
dpms = false

Add to the file directly below the existing contents of the [autostart] section. When you finish, you should end up with the following:

[autostart]
panel = wfrespawn wf-panel-pi
background = wfrespawn pcmanfm --desktop --profile LXDE-pi
xdg-autostart = lxsession-xdg-autostart
chromium = chromium-browser https://raspberrypi.com https://time.is/London --kiosk --noerrdialogs --disable-infobars --no-first-run --ozone-platform=wayland --enable-features=OverlayScrollbar --start-maximized
switchtab = bash ~/switchtab.sh
screensaver = false
dpms = false

This line opens the Chromium browser in kiosk mode, with two tabs open: raspberrypi.com and time.is. The extra options alter kiosk mode in the following ways:

--noerrdialogs

suppresses error messages

--disable-infobars

disables notification infobars

--no-first-run

skips the first-run setup experience that typically appears when launching for the first time

--ozone-platform=wayland

uses a Wayland-compatible Ozone platform

--enable-features=OverlayScrollbar

scrollbars appear only when necessary and overlay content instead of using a dedicated scroll gutter

--start-maximized

starts the browser in maximized fullscreen mode

Finally, the line switchtab = bash /home/kiosk/switchtab.sh executes a bash script which will automatically switch between the two tabs every ten seconds.

Press Ctrl+X, then Y, and finally Enter to save the edited file with nano. Next, we’ll write that bash script that switches viewing between the two tabs. Usually, the keyboard shortcut Ctrl+Tab cycles through the open browser tabs. Our script will use the program we installed, wtype, to simulate and automate keystrokes. To create the script and open it in nano, type:

$ nano ~/switchtab.sh

Add the following to the file:

#!/bin/bash

# Find Chromium browser process ID
chromium_pid=$(pgrep chromium | head -1)

# Check if Chromium is running
while
[
[ -z $chromium_pid ]]; do
  echo "Chromium browser is not running yet."
  sleep 5
  chromium_pid=$(pgrep chromium | head -1)
done

echo "Chromium browser process ID: $chromium_pid"

export XDG_RUNTIME_DIR=/run/user/1000

# Loop to send keyboard events
while true; do
  # Send Ctrl+Tab using `wtype` command
  wtype -M ctrl -P Tab

  # Send Ctrl+Tab using `wtype` command
  wtype -m ctrl -p Tab

  sleep 10
done

This script first checks that the Chromium browser is running. If not, it waits five seconds before trying again (this gives Chromium enough time to launch before moving on). To toggle between the two tabs, the script uses wtype to simulate Ctrl+Tab every ten seconds.

Press Ctrl+X, then Y, and finally Enter to save the new file with nano. Finally, reboot your Raspberry Pi:

$ sudo reboot

Your display should now be show Chrome in kiosk mode, toggling between raspberrypi.com and time.is every ten seconds.

Add security and fail-safe functionality

Kiosk mode devices run unattended for long periods of time. They frequently restart. They are left unattended in public places, making them vulnerable to unwanted attention or interference. None of this is conducive to a reliable long-term kiosk mode installation, and kiosks can also be a potential target for hackers. Although it’s not realistic to make them 100% secure, there are a number of things we can do to protect devices running in kiosk mode.

Disable ports

As this project currently stands, simply plugging a keyboard and mouse into the USB ports on our Raspberry Pi would give an attacker full control. Access to the Ethernet port is another weakness. To defend against this, disable all the unused ports. The following command disables all USB ports:

$ echo '1-1' | sudo tee /sys/bus/usb/drivers/usb/unbind
note

To enable USB ports again, run the following command:

$ echo '1-1' | sudo tee /sys/bus/usb/drivers/usb/bind

In order to disable the Ethernet port, enter the following command:

$ sudo ifconfig eth0 down
note

To enable the Ethernet port again, run the following command:

$ sudo ifconfig eth0 up

These disable commands are not persistent, so when power is cycled, the ports will work again. To disable them every time the device is powered on, we’ll make change to your /etc/rc.local file. This file runs at the end of every boot process. Open the file for editing using the following:

$ sudo nano /etc/rc.local

Add the two disable commands above the exit 0 line:

echo '1-1' | sudo tee /sys/bus/usb/drivers/usb/unbind
sudo ifconfig eth0 down

Press Ctrl+X, then Y, and finally Enter to save the new file with nano. The file should now look like this:

#!/bin/sh -e
#
*#* rc.local
#
*#* This script is executed at the end of each multiuser runlevel.
*#* Make sure that the script will "exit 0" on success or any other
*#* value on error.
#
*#* In order to enable or disable this script just change the execution
*#* bits.
#
*#* By default this script does nothing.

echo '1-1' | sudo tee /sys/bus/usb/drivers/usb/unbind
sudo ifconfig eth0 down

exit 0

Each time your Raspberry Pi boots up, this script will disable the Ethernet and USB ports.

Turn off Bluetooth

To turn Bluetooth off, edit the /boot/firmware/config.txt file:

$ sudo nano /boot/firmware/config.txt

Add the following line to the bottom of the file:

dtoverlay=disable-bt

Press Ctrl+X, then Y, and finally Enter to save the file with nano. Finally, reboot your Raspberry Pi:

$ sudo reboot

As long as the line you added remains there, Bluetooth will be disabled.

note
Remove dtoverlay=disable-bt from /boot/firmware/config.txt to enable Bluetooth again.

Set up SSH using keys rather than a password

Until now, you have connected to your Raspberry Pi with SSH using a password. We can provide an extra layer of security by connecting using pre-generated private-public RSA keys and removing the ability to log in with a username and password altogether. With key-based encryption, you’ll keep a private key on your usual computer and a public key on your Raspberry Pi. This variant of authentication is much harder to crack than a username and password. To create keys, open a terminal on your usual computer and run the following:

$ ssh-keygen

Accepting the defaults when prompted will create a private and a public key. The location of these saved files is also given:

$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/<username>/.ssh/id_rsa): Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/<username>/.ssh/id_rsa
Your public key has been saved in /Users/<username>/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:GYBHXNZrjEcDqqG0AV83V/yy8hI35F+8MDa+yWcN/Yo
<username>@<hostname>.local
The key's randomart image is:
+---
[RSA 3072]----+
|.   .+=.==.      |
| o ...o*  =      |
|  + ... .+ +     |
| . + o  .oB .    |
|  o .   S= o . . |
|        o = = + .|
|         = = = +.|
|        . ..oo+ o|
|         .  E+.. |
+----
[SHA256]-----+
$

The id_rsa file is your private key; do not share it. The id_rsa.pub file is your public key. To use key-based authentication, transfer the public key to your Raspberry Pi.

Run the following command to print your public key to your terminal:

$ cat ~/.ssh/id_rsa.pub

Copy the output of the command into your clipboard. Now, let’s move the public key onto your Raspberry Pi.

Connect to your Raspberry Pi over SSH:

$ ssh <username>@pi-kiosk.local

Then, create a folder called .ssh in your home directory:

$ mkdir ~/.ssh

Next, open a text editor for a new file named authorized_keys in the .ssh folder:

$ nano ~/.ssh/authorized_keys

Paste the contents of id_rsa.pub from your usual computer into this file. Press Ctrl+X, then Y, and finally Enter to save the file with nano. Finally, reboot your Raspberry Pi:

$ sudo reboot

Wait a few seconds for your Raspberry Pi to boot, then connect via SSH:

$ ssh <username>@pi-kiosk.local

If everything works as expected, you will no longer be prompted to enter a password. We can now disable password access completely by editing the /etc/ssh/sshd_config file:

$ sudo nano /etc/ssh/sshd_config

Find the line that reads #PasswordAuthentication yes. Uncomment it by removing the # to enable the line, and change yes to no, so it looks like this:

# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication no
#PermitEmptyPasswords no

Press Ctrl+X, then Y, and finally Enter to save the file with nano. Reboot your Raspberry Pi one more time:

$ sudo reboot

Now your Raspberry Pi is hardened against attackers over SSH.

SD card read-only mode

Unplugging your Raspberry Pi to shut it down can eventually result in system file corruption. Any operating system stored on an SD card may eventually fail if used for long periods of time. To reduce these risks, you can make your SD card read-only. Open the raspi-config tool with the following command:

$ sudo raspi-config

Navigate through the menu system as follows:

  1. Select Performance options

  2. Select Overlay File System

  3. Confirm that you would like to enable the overlay file system

  4. Confirm that you would like to write-protect the boot partition

  5. Confirm reboot

This whole process may take a few minutes to complete.

note

If you need to enable access again to carry out an update or adjust your scripts, SSH back into your Raspberry Pi and run this command to allow write access temporarily:

$ sudo mount -o remount,rw /boot

You can now carry out any work required. Another reboot will revert your SD card to a read-only state.

Take kiosk mode further

This guide explores the basics of setting up a simple web page viewer in kiosk mode. Building on this might take you on a journey to more complex projects, such as a CCTV viewing station, a home automation system, or perhaps the ultimate in kiosk mode projects: a magic mirror. Our tutorial is based on Magic Mirror2, the winner in the The MagPi magazine’s 50th issue celebration feature as voted by the Raspberry Pi community.