Skip to content

PiPiece Setup Guide

This guide explains how to set up a Raspberry Pi for PiPiece using the automation in setup-pi.sh and the scripts in the setup/ directory.

It supports two installation modes:

  • Remote mode: run the setup from another machine over SSH
  • Local mode: SSH into the Pi first, then run the setup scripts directly on the Pi
  • Automated local mode (recommended): a single command downloads the latest release and runs setup/install.sh which auto-detects hardware, configures the display, installs everything, and optionally reboots

It also supports two ways to get the PiPiece code onto the Pi:

  • Release tarball (recommended for production): download a pre-built release that includes the compiled Vue UI. No git or build tooling required on the Pi.
  • Clone from source: clone the repository and build locally. Required for development.

Overview

The setup flow uses SSH to run shell scripts on the Raspberry Pi remotely. The main script is:

bash
./setup-pi.sh [-u username] <hostname> <command>

Example:

bash
./setup-pi.sh pipiece new

Example with a custom SSH username:

bash
./setup-pi.sh -u john pipiece.local new

Local example:

bash
./setup-pi.sh pipiece local

Important behavior:

  • The Raspberry Pi hostname is expected to be reachable as <hostname>.local
  • The script connects as user pi by default
  • Use -u <username> to connect as a different SSH user
  • The script uses the local SSH key ~/.ssh/id_rsa
  • Each selected script in setup/ is piped over SSH and executed on the Raspberry Pi
  • The local command runs the same setup sequence directly on the Pi without SSH
  • The current argument parser still expects a first argument before local, so use ./setup-pi.sh pipiece local rather than ./setup-pi.sh local

Before You Start

Make sure all of these are true before running setup:

  1. Raspberry Pi OS is installed on the microSD card.
  2. The Pi is on your network and reachable with the hostname pipiece.local or your chosen hostname.
  3. SSH is enabled on the Pi.
  4. Your local machine has a working private key at ~/.ssh/id_rsa.
  5. The matching public key is already installed for the remote user you plan to connect as.
  6. The PiPiece repository exists on the Raspberry Pi at ~/src/pipiece-ui.

The last item matters because setup/server.sh does not clone the repository. It expects the code to already be present.

Quick Start

Run the full default setup sequence:

bash
cd ~/src/rpi/pipiece-ui
./setup-pi.sh pipiece new

If your remote SSH user is not pi, use:

bash
./setup-pi.sh -u <username> pipiece.local new

Run the same sequence locally after SSHing into the Pi:

bash
cd ~/src/pipiece
./setup-pi.sh pipiece local

The new command runs these scripts in order:

  1. update
  2. hyperpixel
  3. node
  4. tools
  5. ssh
  6. server
  7. ui

Command Reference

List available setup commands:

bash
./setup-pi.sh pipiece

List commands for a custom SSH user:

bash
./setup-pi.sh -u <username> pipiece.local

Run a single step manually:

bash
./setup-pi.sh pipiece update
./setup-pi.sh pipiece node
./setup-pi.sh pipiece server

Remote examples with a custom SSH user:

bash
./setup-pi.sh -u <username> pipiece.local update
./setup-pi.sh -u <username> pipiece.local server

When you are already SSHed into the Pi, individual scripts can be run directly:

bash
bash ./setup/update.sh
bash ./setup/node.sh
bash ./setup/server.sh

Useful optional scripts:

  • doctor checks whether the Pi matches the expected configuration
  • raspi enables camera support and screen blanking settings using raspi-config
  • reboot reboots the Raspberry Pi
  • no-ui removes the Labwc Chromium autostart entry

Automated Local Setup (setup/install.sh)

The install.sh script is an all-in-one orchestrator designed to run directly on the Pi. It replaces the need to use setup-pi.sh from a remote machine.

bash
cd ~/pipiece-ui && bash setup/install.sh

What it does:

  1. Detects hardware — runs doctor.sh --emit to identify the attached display and write a machine-readable state file (setup-state.env)
  2. Updates system packages — runs update.sh
  3. Configures the display — auto-selects the correct display script based on detection:
    • HyperPixel4 → hyperpixel.sh
    • TouchDisplay 1 → touchdisplay1.sh
    • TouchDisplay 2 → touchdisplay2.sh
    • PiTFT 2.4" → pitft24.sh
    • No screen detected → warns and continues
  4. Installs Node.js and tools — runs node.sh and tools.sh
  5. Hardens SSH — runs ssh.sh
  6. Starts the server — runs server.sh
  7. Configures the kiosk — runs ui.sh
  8. Optional packages — prompts for astrometry.net and LiteRT/ML inference
  9. Validates — runs doctor.sh to show final system state
  10. Reboot prompt — offers to reboot to apply display changes

Flags:

  • --yes / -y — non-interactive mode: skips optional package prompts (declines them) and auto-reboots

The script tracks success/failure of each step and prints a summary at the end.

What Each Setup Step Does

1. update

Script: setup/update.sh

This step updates the APT package list and upgrades installed packages:

bash
sudo apt update
sudo apt upgrade -y

Why it matters:

  • Pulls in current package metadata
  • Installs the latest available security and system updates
  • Reduces avoidable issues later in the setup

2. hyperpixel

Script: setup/hyperpixel.sh

This step configures the HyperPixel4 display and display layout.

It does three things:

  1. Adds the HyperPixel4 overlay to /boot/firmware/config.txt
  2. Adds rotation and touchscreen parameters to /boot/firmware/config.txt
  3. Writes a kanshi display profile to ~/.config/kanshi/config

Why it matters:

  • Enables the HyperPixel hardware overlay
  • Rotates the display to the orientation expected by PiPiece
  • Ensures Wayland display layout is correct

A reboot is required after this step if the display overlay or rotation settings were newly added.

3. node

Script: setup/node.sh

This step installs Node.js, updates npm, installs PM2 globally, and configures PM2 to start at boot.

It uses the NodeSource setup script for Node 24.x, then installs:

  • nodejs
  • build-essential
  • pm2

It also runs:

bash
pm2 startup systemd -u pi --hp /home/pi

Why it matters:

  • The server requires Node.js
  • PM2 keeps the server running and restores it after reboot

4. tools

Script: setup/tools.sh

This installs supporting packages:

  • xdotool
  • entr
  • wtype
  • imagemagick

Why it matters:

  • imagemagick is used by image-processing utilities in the repo
  • wtype and xdotool support UI and automation workflows
  • entr is useful for file watching and utility scripting

5. ssh

Script: setup/ssh.sh

This disables password authentication in /etc/ssh/sshd_config by changing:

text
PasswordAuthentication no

Why it matters:

  • Moves the Pi toward key-only SSH access
  • Reduces attack surface compared to password logins

Do not run this step until you have confirmed that SSH public key authentication works.

6. server

Script: setup/server.sh

This step prepares directories and starts the PiPiece Express server with PM2.

It creates:

  • ~/photos
  • ~/pipiece-ui/config
  • ~/src

Then it expects the repo to already exist at:

bash
~/src/pipiece

Inside ~/src/pipiece-ui/server, it runs:

bash
npm ci
pm2 start bin/www.js --name "pipiece-ui"
pm2 restart pipiece-ui --watch
pm2 save

Why it matters:

  • Installs server dependencies cleanly from the lockfile
  • Starts the Express app under PM2
  • Saves the PM2 process list for reboot persistence

7. ui

Script: setup/ui.sh

This appends a Chromium kiosk launch command to:

bash
~/.config/labwc/autostart

The configured browser target is:

text
http://localhost

Why it matters:

  • Launches Chromium automatically in kiosk mode on login
  • Opens the local PiPiece UI without browser chrome
  • Forces dark-mode related Chromium flags used by this project

software-update

Script: setup/software-update.sh

This script checks for and applies PiPiece software updates from GitLab releases:

  1. Queries the GitLab Releases API for the latest version
  2. Compares against the currently installed version
  3. Downloads the release tarball
  4. Backs up the current installation to ~/pipiece-ui-backup/
  5. Extracts and rsyncs updated files (preserving config, photos, node_modules)
  6. Runs npm install for server dependencies
  7. Restarts the PM2 service

Use --check-only to check for updates without applying them.

Step 1. Prepare the Raspberry Pi OS image

Use Raspberry Pi Imager and make sure you configure:

  • Hostname: pipiece
  • SSH enabled
  • Public key authentication enabled
  • Your SSH public key installed for the user you will connect as
  • Wi-Fi credentials if needed

If you need a walk-through, see rpi-imager.md.

Step 2. Boot the Pi and verify SSH access

From your local machine:

bash
ssh -i ~/.ssh/id_rsa pi@pipiece.local

If you use a different account on the Pi:

bash
ssh -i ~/.ssh/id_rsa <username>@pipiece.local

If this fails, do not continue until SSH access is working.

Step 3. Get the PiPiece code onto the Raspberry Pi

This is the fastest way to get a fully configured Pi. A single command downloads the latest release, extracts it, and runs the automated setup which detects your display, installs all required software, and configures the kiosk.

SSH into the Pi and run:

bash
TAG=$(curl -s "https://gitlab.com/api/v4/projects/79538131/releases" | python3 -c "import sys,json; print(json.load(sys.stdin)[0]['tag_name'])") && curl -L "https://gitlab.com/api/v4/projects/79538131/packages/generic/pipiece/${TAG}/pipiece-${TAG}.tar.gz" -o pipiece-${TAG}.tar.gz && tar -xzf pipiece-${TAG}.tar.gz -C ~ && cd ~/pipiece-ui && bash setup/install.sh

This will:

  1. Fetch the latest release tag from the GitLab API
  2. Download the tarball
  3. Extract it to ~/pipiece-ui/
  4. Run setup/install.sh which automatically:
    • Detects the attached display (HyperPixel4, TouchDisplay 1/2, PiTFT 2.4")
    • Updates system packages
    • Configures the detected display
    • Installs Node.js, PM2, and system tools
    • Hardens SSH (disables password auth)
    • Starts the Express server under PM2
    • Configures Chromium kiosk autostart
    • Prompts to install optional packages (astrometry.net, LiteRT/ML)
    • Validates the installation with doctor.sh
    • Offers to reboot

For non-interactive installs (e.g. headless/automated), add --yes to skip all prompts, decline optional packages, and auto-reboot:

bash
TAG=$(curl -s "https://gitlab.com/api/v4/projects/79538131/releases" | python3 -c "import sys,json; print(json.load(sys.stdin)[0]['tag_name'])") && curl -L "https://gitlab.com/api/v4/projects/79538131/packages/generic/pipiece/${TAG}/pipiece-${TAG}.tar.gz" -o pipiece-${TAG}.tar.gz && tar -xzf pipiece-${TAG}.tar.gz -C ~ && cd ~/pipiece-ui && bash setup/install.sh --yes

After this, skip to Step 7 to validate the installation.

Option B — Download tarball only (manual setup)

If you prefer to run setup steps individually:

bash
TAG=$(curl -s "https://gitlab.com/api/v4/projects/79538131/releases" | python3 -c "import sys,json; print(json.load(sys.stdin)[0]['tag_name'])") && curl -L "https://gitlab.com/api/v4/projects/79538131/packages/generic/pipiece/${TAG}/pipiece-${TAG}.tar.gz" -o pipiece-${TAG}.tar.gz && tar -xzf pipiece-${TAG}.tar.gz -C ~

Then continue with Step 4 to run the remote or local setup.

Option C — Clone from source

Use this if you want to develop or build from source.

On the Pi:

bash
mkdir -p ~/src
git clone https://gitlab.com/johnwebbcole/pipiece-ui.git ~/src/pipiece

This is required before setup/server.sh can succeed.

Step 4. Run the automated setup

From your local machine in the repo root:

bash
./setup-pi.sh pipiece new

This runs the full setup sequence remotely over SSH.

If your Raspberry Pi account is not pi:

bash
./setup-pi.sh -u <username> pipiece.local new

Step 4a. Run the automated setup locally from an SSH session on the Pi

If you are already logged into the Pi over SSH and want to run the same setup directly on the device:

bash
cd ~/src/pipiece
./setup-pi.sh pipiece local

This runs the same sequence as new, but it executes each script locally instead of piping it over SSH.

Use this mode when:

  • .local name resolution is unreliable from your workstation
  • You want to watch output directly on the Pi
  • The remote SSH wrapper is getting in the way of debugging

Important note:

  • The current script still requires a placeholder first argument before local
  • In practice, use pipiece as that first argument even though local mode does not use it

Step 5. Apply Raspberry Pi configuration if needed

The new sequence does not run setup/raspi.sh. If camera support or screen blanking behavior is not correct, run:

bash
./setup-pi.sh pipiece raspi

This script enables:

  • Camera support
  • Screen blanking setting

Step 6. Reboot the Raspberry Pi

Some changes require a reboot, especially HyperPixel configuration.

Run:

bash
./setup-pi.sh pipiece reboot

Or reboot manually over SSH.

Step 7. Validate the installation

Run the doctor script:

bash
./setup-pi.sh pipiece doctor

This checks:

  • Raspberry Pi configuration values
  • HyperPixel overlay and rotation config
  • SSH password authentication state
  • kanshi display profile
  • node, pm2, xdotool, entr, wtype, and convert
  • Presence of expected directories
  • Labwc Chromium autostart entry
  • Whether the PM2 server process is running

Manual Verification Checklist

After setup and reboot, confirm the following:

  1. ssh pi@pipiece.local works with your SSH key.
  2. pm2 list on the Pi shows the pipiece-ui process.
  3. curl http://localhost/api/system/info on the Pi returns JSON.
  4. Chromium launches automatically in kiosk mode if the UI environment is enabled.
  5. The HyperPixel display is rotated correctly and touch input matches the screen orientation.

Troubleshooting

SSH cannot connect to pipiece.local

Checks:

  • Confirm the Pi is powered on and on the same network.
  • Confirm the hostname was set to pipiece during Raspberry Pi Imager setup.
  • Try ping pipiece.local.
  • If mDNS is unreliable on your network, connect by IP address instead.

The script itself assumes .local name resolution. If that does not work in your environment, either fix mDNS or update the script.

Workaround:

  • SSH to the Pi by IP address, then run ./setup-pi.sh pipiece local from ~/src/pipiece-ui

SSH key authentication fails

Checks:

  • Confirm your private key exists at ~/.ssh/id_rsa on the local machine.
  • Confirm the matching public key is in ~/.ssh/authorized_keys for the user you are connecting as on the Raspberry Pi.
  • Test manually:
bash
ssh -i ~/.ssh/id_rsa pi@pipiece.local

If you use a different user, test with that account name and pass the same username to setup-pi.sh with -u.

Do not run setup/ssh.sh until this works.

setup/server.sh says PiPiece is not found

Cause:

  • The repository is missing at ~/src/pipiece-ui on the Raspberry Pi.

Fix:

  • Clone the repo manually on the Pi before rerunning the server step.

./setup-pi.sh local only shows help

Cause:

  • The script parses the first positional argument as the hostname, so local by itself is treated as a hostname instead of a command.

Fix:

  • Run local setup as:
bash
./setup-pi.sh pipiece local
  • Or run individual scripts directly:
bash
bash ./setup/update.sh
bash ./setup/node.sh
bash ./setup/server.sh

Local setup fails because the repo path is wrong

Checks:

  • Confirm you are in ~/src/pipiece-ui
  • Confirm the setup/ directory exists under the current working directory

The local runner uses relative paths like ./setup/node.sh, so it must be launched from the repository root.

sudo commands fail during remote setup

Cause:

  • The setup scripts run non-interactively over SSH and may fail if sudo expects an interactive password prompt.

Fix:

  • Log in manually and run the failing step directly on the Pi.
  • Or configure your sudo policy appropriately for the setup workflow.

HyperPixel display does not rotate correctly

Checks:

  • Verify both lines exist in /boot/firmware/config.txt:
text
dtoverlay=vc4-kms-dpi-hyperpixel4
dtparam=rotate=90,touchscreen-swapped-x-y,touchscreen-inverted-y
  • Verify ~/.config/kanshi/config contains the DPI-1 profile.
  • Reboot after making changes.

Chromium does not start automatically

Checks:

  • Confirm ~/.config/labwc/autostart exists.
  • Confirm it contains the Chromium kiosk command added by setup/ui.sh.
  • If you want to remove kiosk startup, run:
bash
./setup-pi.sh pipiece no-ui

PM2 server is not running after reboot

Checks:

  • Run pm2 list
  • Run pm2 save
  • Re-run the PM2 startup command if necessary:
bash
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u pi --hp /home/pi
  • Then restart the server setup step:
bash
./setup-pi.sh pipiece server

Camera features do not work

Checks:

  • Run ./setup-pi.sh pipiece raspi
  • Reboot the Pi
  • Verify camera availability with Raspberry Pi camera tools installed on the device

Suggested Workflow for Re-runs

If you only need to fix one part of the system, rerun just that step instead of the whole new sequence.

Examples:

bash
./setup-pi.sh pipiece hyperpixel
./setup-pi.sh pipiece ssh
./setup-pi.sh pipiece server
./setup-pi.sh pipiece ui
./setup-pi.sh pipiece doctor

This is usually the safer approach once the initial installation is complete.