$linuxjunkies
>

Build a Raspberry Pi Kiosk

Boot a Raspberry Pi straight into full-screen Chromium with no desktop, no cursor, and no screen blanking using labwc, systemd autologin, and Wayland.

IntermediateUbuntuDebianFedoraArch9 min readUpdated June 7, 2026

Before you start

  • Raspberry Pi 4 or 5 with a microSD card (16 GB minimum) and HDMI display
  • Raspberry Pi OS Lite (64-bit, Bookworm) flashed and booted with SSH enabled
  • Admin user account with sudo access on the Pi
  • Network connectivity on the Pi for package installation

A Raspberry Pi kiosk turns a $35 board into a locked-down display that boots straight into a full-screen browser — no taskbar, no cursor, no escape. This guide covers the complete stack: a lightweight Wayland compositor, autologin via systemd, Chromium in kiosk mode, and disabling screen blanking so the display never goes dark. Steps are written for Raspberry Pi OS (Bookworm, 64-bit), which is Debian-based, but the same logic applies to Ubuntu Server for Pi with minor package name changes.

1. Start With a Lean Base

Flash Raspberry Pi OS Lite (64-bit) using Raspberry Pi Imager. Lite has no desktop environment installed, which gives you a clean slate. Enable SSH and set your hostname in the imager before writing the card.

After first boot, update the system:

sudo apt update && sudo apt full-upgrade -y

Install the packages you need. labwc is a lightweight, wlroots-based Wayland compositor well-suited for kiosk use. cage is an even simpler single-app Wayland compositor — either works, but labwc gives you more flexibility if you ever want a second app.

sudo apt install --no-install-recommends \
  labwc \
  chromium-browser \
  xwayland \
  fonts-liberation \
  unclutter-xfixes

If you prefer the absolute minimum, replace labwc with cage and skip the labwc config below — cage takes a single command as its argument and runs nothing else.

2. Create a Dedicated Kiosk User

Running the kiosk as a restricted user reduces the blast radius if the browser is exploited.

sudo useradd -m -G video,input,render kiosk
sudo passwd -l kiosk

passwd -l locks password login. The account can still be used by systemd for autologin. Add it to the seat group if seatd is managing device access:

sudo usermod -aG seat kiosk

3. Configure labwc for Kiosk Mode

Create the labwc config directory for the kiosk user and write a minimal config that hides all decorations and disables the compositor's built-in screen-saver.

sudo -u kiosk mkdir -p /home/kiosk/.config/labwc
sudo -u kiosk tee /home/kiosk/.config/labwc/rc.xml <<'EOF'
<?xml version="1.0"?>
<labwc_config>
  <core>
    <decoration>server</decoration>
  </core>
  <screen>
    <screensaver enabled="false" />
  </screen>
</labwc_config>
EOF

Write the autostart file that labwc executes on startup. This launches Chromium and hides the cursor with unclutter:

sudo -u kiosk tee /home/kiosk/.config/labwc/autostart <<'EOF'
chromium-browser \
  --kiosk \
  --noerrdialogs \
  --disable-infobars \
  --no-first-run \
  --disable-translate \
  --disable-features=TranslateUI \
  --disable-session-crashed-bubble \
  --check-for-update-interval=31536000 \
  --app=https://your-kiosk-url.example.com &
unclutter --hide-on-touch --start-hidden &
EOF

Replace https://your-kiosk-url.example.com with your actual URL. The --app flag strips the browser chrome (address bar, tab strip) automatically — use it instead of passing the URL as a bare argument.

4. Autologin and Autostart via systemd

Override the getty service for TTY1 to autologin as the kiosk user:

sudo mkdir -p /etc/systemd/system/[email protected]
sudo tee /etc/systemd/system/[email protected]/autologin.conf <<'EOF'
[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin kiosk --noclear %I $TERM
EOF

Now configure the kiosk user's shell profile to launch labwc automatically on TTY1. We do this in .bash_profile so it only fires on a real login shell, not on every bash invocation:

sudo -u kiosk tee /home/kiosk/.bash_profile <<'EOF'
# Only start compositor on TTY1
if [ "$(tty)" = "/dev/tty1" ]; then
  exec labwc
fi
EOF

If you chose cage instead of labwc, replace exec labwc with:

exec cage -- chromium-browser --kiosk --noerrdialogs --app=https://your-kiosk-url.example.com

Reload systemd and enable the override:

sudo systemctl daemon-reload
sudo systemctl enable getty@tty1

5. Disable Screen Blanking and DPMS

Three separate layers can blank your display: the kernel console, the Wayland compositor, and the monitor's DPMS. Silence all three.

Kernel Console Blanking

Edit /boot/firmware/cmdline.txt (Raspberry Pi OS Bookworm path — older releases use /boot/cmdline.txt). Add the following to the end of the existing single line:

sudo sed -i 's/$/ consoleblank=0 logo.nologo=1/' /boot/firmware/cmdline.txt

DPMS via wlr-randr or Chromium Flag

labwc respects the WAYLAND_DISPLAY variable. You can disable DPMS by adding a wlr-randr call to the autostart file, or by passing Chromium's flag. Install the tool first:

sudo apt install wlr-randr

Then append to the labwc autostart file:

sudo -u kiosk tee -a /home/kiosk/.config/labwc/autostart <<'EOF'
wlr-randr --output HDMI-A-1 --on &
xset -dpms s off s noblank && xset s 0 0 &
EOF

The xset call handles any XWayland-inherited DPMS settings. If your HDMI output name differs, check it later with wlr-randr (no arguments) once the compositor is running.

Raspberry Pi-Specific Blanking (vc4 driver)

Add these lines to /boot/firmware/config.txt under the [all] section:

sudo tee -a /boot/firmware/config.txt <<'EOF'
# Kiosk: prevent blanking
[all]
hdmi_blanking=1
EOF

hdmi_blanking=1 allows software to control HDMI power (the default, 0, can override and blank regardless).

6. Harden and Lock Down the Kiosk

Prevent users from reaching a shell or changing configuration:

  • Set kiosk's shell to /usr/sbin/nologin as an extra measure: sudo chsh -s /usr/sbin/nologin kiosk — but note this conflicts with .bash_profile if you use agetty. Keep bash as the shell; the lock is the locked password.
  • Disable SSH password auth in /etc/ssh/sshd_config (PasswordAuthentication no) and manage the Pi over key-based SSH from your workstation.
  • Mount /home/kiosk read-only with a tmpfs overlay if you want to prevent any local writes — though Chromium needs a writable cache, so point --user-data-dir at a tmpfs instead: add --user-data-dir=/tmp/chromium-kiosk to the Chromium flags.

7. Verify

Reboot and confirm the kiosk comes up cleanly:

sudo reboot

After the Pi restarts, the display should show your URL in full-screen Chromium with no cursor within about 15–20 seconds. SSH in from another machine and check:

# Confirm labwc is running as kiosk
ps aux | grep labwc

# Confirm Chromium is running
ps aux | grep chromium

Output will vary but you should see both processes owned by the kiosk user.

Troubleshooting

Blank screen after boot

SSH in and check the kiosk user's journal: sudo journalctl --user -b -u labwc. Usually the cause is a missing group (video, render, or seat) or a typo in the autostart path.

Chromium shows "crashed" dialog on next boot

Add --disable-session-crashed-bubble and --restore-last-session flags, or point --user-data-dir at /tmp so the profile resets on every boot.

Screen still blanks after 10 minutes

Run wlr-randr with no arguments inside a compositor session to confirm your output name, then add an explicit DPMS-off call. Also double-check cmdline.txt has consoleblank=0 on one unbroken line — a stray newline breaks the kernel parameter parsing.

Wrong resolution

Set hdmi_group and hdmi_mode in config.txt, or use wlr-randr --output HDMI-A-1 --mode 1920x1080@60 in the autostart file.

tested on:Debian 12 (Bookworm) — Raspberry Pi OS 64-bitUbuntu 24.04 LTS — Ubuntu Server for Raspberry Pi

Frequently asked questions

Can I use X11 instead of Wayland on Raspberry Pi OS Bookworm?
Yes — install openbox and xorg, use lightdm for autologin, and set DISPLAY in your autostart. However, Bookworm defaults to Wayland and the Chromium package is optimised for it; stick with Wayland unless you have a specific reason not to.
How do I update the kiosk URL without rebuilding the SD card?
SSH into the Pi as your admin user, edit /home/kiosk/.config/labwc/autostart with the new URL, then run sudo systemctl restart getty@tty1 to restart the session.
Will the kiosk recover automatically after a network outage?
Chromium will show its offline page. Add a simple watchdog script using a systemd timer that checks connectivity and reloads Chromium if needed, or set --app to a local HTML fallback page that auto-refreshes when the network returns.
How do I prevent Chromium from showing update or permission prompts?
Use --no-first-run, --disable-infobars, and --check-for-update-interval=31536000 (one year). Also point --user-data-dir at /tmp/chromium-kiosk so the profile is wiped on each reboot, eliminating accumulated prompts.
Does this work on a Pi Zero 2 W or only Pi 4/5?
labwc and Chromium run on Pi Zero 2 W (which is 64-bit capable) but expect slower startup — around 45–60 seconds to first paint. Pi 4 or 5 with 2 GB+ RAM is strongly recommended for smooth kiosk operation.

Related guides