diff --git a/chromium-setup/emmc-provisioning/cloud-init/config-files/99-default-session.conf b/chromium-setup/emmc-provisioning/cloud-init/config-files/99-default-session.conf index 6f76496..53c6607 100644 --- a/chromium-setup/emmc-provisioning/cloud-init/config-files/99-default-session.conf +++ b/chromium-setup/emmc-provisioning/cloud-init/config-files/99-default-session.conf @@ -1,3 +1,3 @@ [Seat:*] -user-session=plasmax11 -autologin-session=plasmax11 +user-session=rpd-labwc +autologin-session=rpd-labwc diff --git a/chromium-setup/emmc-provisioning/cloud-init/config-files/README.md b/chromium-setup/emmc-provisioning/cloud-init/config-files/README.md index a34fd59..1707e3f 100644 --- a/chromium-setup/emmc-provisioning/cloud-init/config-files/README.md +++ b/chromium-setup/emmc-provisioning/cloud-init/config-files/README.md @@ -5,9 +5,7 @@ first-boot.sh downloads these from `FILE_SERVER` (e.g. `http://10.130.60.141:500 | File on server | Destination on device | |----------------|------------------------| | 99-wallpaper.conf | /etc/lightdm/lightdm.conf.d/99-wallpaper.conf | -| 99-default-session.conf | /etc/lightdm/lightdm.conf.d/99-default-session.conf | -| kdeglobals | /home/pi/.config/kdeglobals | -| kwinrc | /home/pi/.config/kwinrc | +| 99-default-session.conf | /etc/lightdm/lightdm.conf.d/99-default-session.conf (rpd-labwc) | | maliit-keyboard.desktop | /home/pi/.config/autostart/maliit-keyboard.desktop | | set-rotation-once.desktop | /home/pi/.config/autostart/set-rotation-once.desktop (with set-rotation-once.sh) | | set-wallpaper-once.desktop | /home/pi/.config/autostart/set-wallpaper-once.desktop (with set-wallpaper-once.sh) | diff --git a/chromium-setup/emmc-provisioning/cloud-init/files-from-guard/README.md b/chromium-setup/emmc-provisioning/cloud-init/files-from-guard/README.md index 3fbdc44..f4284f5 100644 --- a/chromium-setup/emmc-provisioning/cloud-init/files-from-guard/README.md +++ b/chromium-setup/emmc-provisioning/cloud-init/files-from-guard/README.md @@ -12,12 +12,10 @@ first-boot.sh downloads from **`.../files/first-boot/`** (e.g. `http://10.130.60 | **custom.plymouth** | Plymouth theme config (from `plymouth-custom/`). | | **custom.script** | Plymouth script that displays splash.png (from `plymouth-custom/`). | | **99-wallpaper.conf** | LightDM greeter wallpaper (from `config-files/`). | -| **99-default-session.conf** | LightDM default session plasmax11 (from `config-files/`). | -| **kdeglobals** | KDE font DPI (from `config-files/`). | -| **kwinrc** | KDE window/touch (from `config-files/`). | +| **99-default-session.conf** | LightDM default session rpd-labwc (from `config-files/`). | | **maliit-keyboard.desktop** | Maliit on-screen keyboard autostart (from `config-files/`). | -| **set-rotation-once.sh** + **.desktop** | One-shot: DSI-1 rotation at first login. | -| **set-wallpaper-once.sh** + **.desktop** | One-shot: desktop wallpaper at first login. | +| **set-rotation-once.sh** + **.desktop** | One-shot: wlr-randr rotation (Right) at first login. | +| **set-wallpaper-once.sh** + **.desktop** | One-shot: swaybg wallpaper + labwc autostart at first login. | --- diff --git a/chromium-setup/emmc-provisioning/cloud-init/first-boot.md b/chromium-setup/emmc-provisioning/cloud-init/first-boot.md index 2196975..6df2c4b 100644 --- a/chromium-setup/emmc-provisioning/cloud-init/first-boot.md +++ b/chromium-setup/emmc-provisioning/cloud-init/first-boot.md @@ -1,6 +1,6 @@ # first-boot.sh — Documentation -This script runs once on first boot via cloud-init (see `user-data-remote-gnss.example`). It installs packages, configures a Chromium kiosk with KDE Plasma and touch support, and installs the reTerminal DM display/touch drivers. It must run as **root**. +This script runs once on first boot via cloud-init (see `user-data-remote-gnss.example`). It installs packages, configures a Chromium kiosk with rpd-labwc (Raspberry Pi Desktop + labwc) and touch support, and installs the reTerminal DM display/touch drivers. It must run as **root**. --- @@ -9,14 +9,16 @@ This script runs once on first boot via cloud-init (see `user-data-remote-gnss.e 1. **Constants** — `FILE_SERVER`, `PI_USER`, paths, log file. 2. **Logging** — All output tee’d to `/var/log/first-boot.log`. 3. **Helpers** — `install_oneshot(name)` downloads `${name}.sh` from the file server and installs it as a one-shot autostart (runs once at pi’s first login, then deletes itself). -4. **Packages** — git, Chromium, wmctrl, SSH, KDE Plasma, kscreen, maliit, xinput-calibrator. +4. **Packages** — git, Chromium, wmctrl, SSH, swaybg, wlr-randr, maliit, xinput-calibrator. 5. **Kiosk files** — Download `start-chromium.sh` and `chromium-kiosk.desktop`; create autostart dir. 6. **Boot splash and wallpaper** — Download `splash.png`; install Plymouth custom theme; copy image for LightDM and desktop. -7. **LightDM** — Download `99-default-session.conf` and `99-wallpaper.conf` to `/etc/lightdm/lightdm.conf.d/`. -8. **KDE + Maliit** — Download `kdeglobals`, `kwinrc`, `maliit-keyboard.desktop` from file server to pi’s `.config` and autostart. +7. **LightDM** — Download `99-default-session.conf` (rpd-labwc) and `99-wallpaper.conf` to `/etc/lightdm/lightdm.conf.d/`. +8. **Maliit** — Download `maliit-keyboard.desktop` from file server to pi’s autostart. 9. **reTerminal DM drivers** — Seeed repo clone and `reTerminal.sh`. -10. **One-shots** — Download `set-rotation-once.sh` + `.desktop` and `set-wallpaper-once.sh` + `.desktop` from file server. -11. **Reboot.** +10. **Re-apply splash** — Set `disable_splash=0`, Plymouth theme to `custom` only, `update-initramfs`. +11. **Boot order** — If `rpi-eeprom-config` is available, set `BOOT_ORDER=0x21` (network first, then eMMC/SD) for future network boot / re-provisioning. +12. **One-shots** — Download `set-rotation-once.sh` + `.desktop` and `set-wallpaper-once.sh` + `.desktop` from file server (wlr-randr + swaybg for labwc). +13. **Reboot.** --- @@ -47,8 +49,8 @@ Installs the software needed for the rest of the script and for the kiosk: | **chromium-browser** | Full-screen kiosk browser. | | **wmctrl** | Window control; used to force Chromium into fullscreen. | | **openssh-server** | SSH access (often also enabled in user-data). | -| **kde-plasma-desktop** | KDE Plasma desktop (X11 session used for Chromium). | -| **kscreen** | KDE display control; provides `kscreen-doctor` for screen rotation (same as GUI “Right”). | +| **swaybg** | Wallpaper for labwc (Wayland); used by one-shot and labwc autostart. | +| **wlr-randr** | Display rotation for wlroots/labwc; one-shot sets “Right” (transform 90). | | **maliit-keyboard** | On-screen keyboard for touch input. | | **xinput-calibrator** | Touchscreen calibration (optional; run manually if needed). | @@ -78,24 +80,13 @@ A **single image** (`splash.png`) is used for the boot splash, login screen, and - **Plymouth (boot splash):** Downloads `splash.png`, `custom.plymouth`, and `custom.script` from the file server → installs to `/usr/share/plymouth/themes/custom/` → sets `Theme=custom` in `/etc/plymouth/plymouthd.conf` → runs `update-initramfs -u`. If any download fails, logs a warning and continues. - **LightDM (login screen):** Copies the same image to `/usr/share/rpd-wallpaper/splash.png` and writes `/etc/lightdm/lightdm.conf.d/99-wallpaper.conf` with `wallpaper=...` and `wallpaper_mode=crop`. -- **Desktop wallpaper:** A one-shot autostart runs when **pi** first logs in and runs `plasma-apply-wallpaperimage /usr/share/rpd-wallpaper/splash.png`. The script then deletes itself. If `plasma-apply-wallpaperimage` is not installed, the step no-ops and the one-shot still removes itself. +- **Desktop wallpaper:** A one-shot autostart runs when **pi** first logs in: it adds `swaybg -i /usr/share/rpd-wallpaper/splash.png -m fill` to `~/.config/labwc/autostart` (so it persists across logins) and runs swaybg for the current session. The one-shot then deletes itself. --- -## KDE Plasma: default session (X11) +## LightDM: default session (rpd-labwc) -Writes `/etc/lightdm/lightdm.conf.d/99-default-session.conf` so the display manager (LightDM) uses the **Plasma X11** session (`plasmax11`) instead of Wayland. Chromium kiosk is configured for X11, so this is required for it to run correctly. - ---- - -## KDE touch-friendly settings - -Two config files for user `pi` to improve touch and window behaviour: - -- **`/home/pi/.config/kdeglobals`** — `ForceFontDPI=120` for larger, more readable UI on the small screen. -- **`/home/pi/.config/kwinrc`** — `BorderlessMaximizedWindows=true` and `touchpointsEnabled=true` for better touch and fullscreen behaviour. - -Both are owned by `pi:pi` with mode 644. +Writes `/etc/lightdm/lightdm.conf.d/99-default-session.conf` so the display manager (LightDM) uses the **rpd-labwc** session (Raspberry Pi Desktop with labwc Wayland compositor). The script also patches `/etc/lightdm/lightdm.conf` so `user-session` and `autologin-session` are `rpd-labwc`. --- @@ -111,12 +102,6 @@ Runs `chown -R pi:pi /home/pi/.config` so all files under `pi`’s config direct --- -## Default X session manager - -Runs `update-alternatives --set x-session-manager /usr/bin/startplasma-x11` so the default graphical session is KDE Plasma on X11. Matches the LightDM setting above and ensures the kiosk and Maliit run in the same X11 session. - ---- - ## reTerminal DM: Seeed display/touch drivers Installs the official Seeed drivers for the reTerminal DM so the display and touch work: @@ -131,15 +116,19 @@ These changes take effect after a reboot. ## Screen rotation (portrait → landscape, “Right”) -The reTerminal DM default is portrait. Rotation is set the **same way as in the GUI** (Display settings → Orientation → Right), using KDE’s **kscreen-doctor**, so nothing is written to `/boot/firmware/config.txt`. +The reTerminal DM default is portrait. Rotation is set using **wlr-randr** (labwc/Wayland), so nothing is written to `/boot/firmware/config.txt`. - **One-shot autostart** — A small script runs once when user `pi` first logs into the graphical session: - - **`/home/pi/set-rotation-once.sh`** — Waits 5 seconds, then runs `kscreen-doctor output.DSI-1.rotation.right` (only the reTerminal DM DSI-1 display; no other screen is used). + - **`/home/pi/set-rotation-once.sh`** — Waits 5 seconds, detects the output name with `wlr-randr`, then runs `wlr-randr --output --transform 90` (Right / 90° clockwise). Falls back to `DSI-1` if detection fails. - **`/home/pi/.config/autostart/set-rotation-once.desktop`** — Autostart entry that runs the script. Both the script and this desktop file **delete themselves** after a successful run, so rotation is applied only once. -- **Effect** — Same as choosing “Right” in System Settings → Display → Orientation. Rotation applies after the first login; no reboot needed for rotation (only for the Seeed drivers). +- **Effect** — Same as choosing “Right” in display settings. Rotation applies after the first login; no reboot needed for rotation (only for the Seeed drivers). --- +## Boot order (network first, then eMMC/SD) + +If **`rpi-eeprom-config`** and **`rpi-eeprom-update`** are present (Pi 4/CM4), the script sets the EEPROM **`BOOT_ORDER=0x21`**: try **network** first (0x2), then **SD/eMMC** (0x1). This allows future network boot or re-provisioning (e.g. PXE or USB gadget) before falling back to local storage. The EEPROM update is scheduled for the next reboot; no second reboot is required. If the tools are not available, the step is skipped. + ## Reboot Runs **`reboot`** so the kernel and display stack load the new Seeed drivers. After reboot, the screen and touch work; on **pi**’s first login the one-shot sets rotation to “Right” (landscape), and the Chromium kiosk and Maliit start via autostart. @@ -148,7 +137,7 @@ Runs **`reboot`** so the kernel and display stack load the new Seeed drivers. Af ## Customisation -- **File server** — Edit `FILE_SERVER` if your assets are served from another host/port. Host all files listed in **`files-from-guard/README.md`** and **`config-files/README.md`** (kiosk, splash, Plymouth, LightDM, KDE, Maliit, one-shots and their .desktop files). +- **File server** — Edit `FILE_SERVER` if your assets are served from another host/port. Host all files listed in **`files-from-guard/README.md`** and **`config-files/README.md`** (kiosk, splash, Plymouth, LightDM, Maliit, one-shots and their .desktop files). - **Kiosk URL** — The URL Chromium opens is defined in `start-chromium.sh` on your file server (e.g. `--app=http://127.0.0.1:8080`); change it there. - **User** — If you use a user other than `pi`, replace `pi` in this script and in the files on the file server (paths and ownership). -- **Screen rotation** — The one-shot runs `kscreen-doctor output.DSI-1.rotation.right`. To use another orientation, edit the script and change `rotation.right` to `rotation.left`, `rotation.inverted`, or `rotation.none`. +- **Screen rotation** — The one-shot runs `wlr-randr --output --transform 90`. To use another orientation, change `90` to `270` (left), `180` (inverted), or `normal`. diff --git a/chromium-setup/emmc-provisioning/cloud-init/first-boot.sh b/chromium-setup/emmc-provisioning/cloud-init/first-boot.sh index f49b6ce..3ecc649 100644 --- a/chromium-setup/emmc-provisioning/cloud-init/first-boot.sh +++ b/chromium-setup/emmc-provisioning/cloud-init/first-boot.sh @@ -1,5 +1,5 @@ #!/bin/bash -# First-boot: packages, Chromium kiosk, KDE Plasma + touch, reTerminal DM drivers. +# First-boot: packages, Chromium kiosk, rpd-labwc + touch, reTerminal DM drivers. # Run by cloud-init (user-data-remote-gnss.example). Run as root. set -e @@ -57,9 +57,9 @@ install_oneshot() { log "--- Installing packages ---" log "Running apt-get update ..." apt-get update -qq -log "Installing: git chromium wmctrl openssh-server kde-plasma-desktop kscreen maliit-keyboard xinput-calibrator" +log "Installing: git chromium wmctrl openssh-server swaybg wlr-randr maliit-keyboard xinput-calibrator" apt-get install -y -qq git chromium wmctrl openssh-server \ - kde-plasma-desktop kscreen maliit-keyboard xinput-calibrator + swaybg wlr-randr maliit-keyboard xinput-calibrator log "Packages installed successfully" # --- 2. Dirs and kiosk files from file server --- @@ -99,8 +99,8 @@ else log "WARNING: Could not download splash.png" fi -# --- 4. LightDM: KDE Plasma X11 session + configs from file server --- -log "--- LightDM session ---" +# --- 4. LightDM: rpd-labwc session + configs from file server --- +log "--- LightDM session (rpd-labwc) ---" mkdir -p /etc/lightdm/lightdm.conf.d if curl -fsSL "${FILE_SERVER}/99-default-session.conf" -o /etc/lightdm/lightdm.conf.d/99-default-session.conf 2>/dev/null; then log "99-default-session.conf installed" @@ -109,19 +109,16 @@ else fi # Raspberry Pi OS may apply main lightdm.conf after .conf.d; force session in main config too if [[ -f /etc/lightdm/lightdm.conf ]]; then - sed -i 's/^user-session=.*/user-session=plasmax11/' /etc/lightdm/lightdm.conf - sed -i 's/^autologin-session=.*/autologin-session=plasmax11/' /etc/lightdm/lightdm.conf - log "Patched /etc/lightdm/lightdm.conf to use plasmax11" + sed -i 's/^user-session=.*/user-session=rpd-labwc/' /etc/lightdm/lightdm.conf + sed -i 's/^autologin-session=.*/autologin-session=rpd-labwc/' /etc/lightdm/lightdm.conf + log "Patched /etc/lightdm/lightdm.conf to use rpd-labwc" fi -# --- 5. KDE touch-friendly + Maliit (from file server) --- -log "--- KDE and Maliit ---" +# --- 5. Maliit on-screen keyboard (from file server) --- +log "--- Maliit ---" mkdir -p "$AUTOSTART" "$PI_HOME/.config" -curl -fsSL "${FILE_SERVER}/kdeglobals" -o "$PI_HOME/.config/kdeglobals" 2>/dev/null && log "kdeglobals installed" || log "WARNING: Could not download kdeglobals" -curl -fsSL "${FILE_SERVER}/kwinrc" -o "$PI_HOME/.config/kwinrc" 2>/dev/null && log "kwinrc installed" || log "WARNING: Could not download kwinrc" curl -fsSL "${FILE_SERVER}/maliit-keyboard.desktop" -o "$AUTOSTART/maliit-keyboard.desktop" 2>/dev/null && log "maliit-keyboard.desktop installed" || log "WARNING: Could not download maliit-keyboard.desktop" chown -R "$PI_USER:$PI_USER" "$PI_HOME/.config" -update-alternatives --set x-session-manager /usr/bin/startplasma-x11 2>/dev/null && log "Default x-session-manager set to startplasma-x11" || true # --- 6. reTerminal DM drivers (Seeed) --- log "--- reTerminal DM drivers ---" @@ -158,6 +155,30 @@ fi log "Running update-initramfs to apply Plymouth theme ..." update-initramfs -u -k all 2>/dev/null || true +# --- 6c. Boot order: network first, then eMMC/SD (for future network boot / re-provisioning) --- +# BOOT_ORDER: 0x2 = network, 0x1 = SD/eMMC. 0x21 = try network first, then local storage. +log "--- Boot order (network first, then eMMC/SD) ---" +if command -v rpi-eeprom-config >/dev/null 2>&1 && command -v rpi-eeprom-update >/dev/null 2>&1; then + BOOTCONF="/tmp/first-boot-eeprom-conf.txt" + if PEE="$(rpi-eeprom-update -l 2>/dev/null)" && [[ -n "$PEE" ]] && [[ -f "$PEE" ]]; then + rpi-eeprom-config "$PEE" > "$BOOTCONF" 2>/dev/null || true + fi + if [[ -s "$BOOTCONF" ]]; then + sed -i 's/^BOOT_ORDER=.*/BOOT_ORDER=0x21/' "$BOOTCONF" + grep -q '^BOOT_ORDER=' "$BOOTCONF" || echo 'BOOT_ORDER=0x21' >> "$BOOTCONF" + if rpi-eeprom-config --apply "$BOOTCONF" 2>/dev/null; then + log "Boot order set to 0x21 (network first, then eMMC/SD); EEPROM update scheduled for next reboot" + else + log "WARNING: rpi-eeprom-config --apply failed; boot order unchanged" + fi + else + log "WARNING: Could not read current EEPROM config; skipping boot order change" + fi + rm -f "$BOOTCONF" +else + log "rpi-eeprom-config/rpi-eeprom-update not found; skipping boot order (not a Pi4/CM4 or package missing)" +fi + # --- 7. One-shots (rotation + wallpaper at first login) --- log "--- One-shot scripts (run at pi first login) ---" install_oneshot set-rotation-once || true diff --git a/chromium-setup/emmc-provisioning/cloud-init/fix-reterminal-display.sh b/chromium-setup/emmc-provisioning/cloud-init/fix-reterminal-display.sh index ecc9ffa..e335729 100644 --- a/chromium-setup/emmc-provisioning/cloud-init/fix-reterminal-display.sh +++ b/chromium-setup/emmc-provisioning/cloud-init/fix-reterminal-display.sh @@ -25,11 +25,10 @@ if [[ -f /etc/plymouth/plymouthd.conf ]]; then fi update-initramfs -u -k all 2>/dev/null || true -echo "=== Rotation and wallpaper (run as $PI_USER at next login or now via sudo -u) ===" -echo "To set rotation and wallpaper now (with X running), run as $PI_USER:" -echo " export DISPLAY=:0" -echo " kscreen-doctor output.DSI-1.rotation.right" -echo " plasma-apply-wallpaperimage /usr/share/rpd-wallpaper/splash.png" +echo "=== Rotation and wallpaper (rpd-labwc / labwc Wayland) ===" +echo "To set rotation and wallpaper now (in a labwc session), run as $PI_USER:" +echo " wlr-randr --output \$(wlr-randr | awk '/^[A-Za-z0-9_-]+ /{print \$1; exit}') --transform 90" +echo " swaybg -i /usr/share/rpd-wallpaper/splash.png -m fill &" echo "" echo "Or ensure one-shots run at next login (they are in autostart if still present)." echo "=== Reboot to apply splash and initramfs ===" diff --git a/chromium-setup/emmc-provisioning/cloud-init/set-rotation-once.sh b/chromium-setup/emmc-provisioning/cloud-init/set-rotation-once.sh index d9403d5..c8efc6a 100644 --- a/chromium-setup/emmc-provisioning/cloud-init/set-rotation-once.sh +++ b/chromium-setup/emmc-provisioning/cloud-init/set-rotation-once.sh @@ -1,15 +1,29 @@ #!/bin/bash -# One-shot: set DSI-1 (reTerminal DM) rotation to Right, then remove self. Runs as user pi at first login. -# Logs to /var/log/first-boot.log (same as first-boot.sh). +# One-shot: set reTerminal DM (labwc/Wayland) rotation to Right via wlr-randr, then remove self. +# Runs as user pi at first login. Logs to /var/log/first-boot.log. FIRST_BOOT_LOG="/var/log/first-boot.log" log() { echo "[$(date -Iseconds)] [set-rotation-once] $*" >> "$FIRST_BOOT_LOG" 2>/dev/null || true; } -export DISPLAY=:0 -log "started (DISPLAY=$DISPLAY)" -log "waiting 5s for display ..." +log "started (labwc/wlr-randr)" +log "waiting 5s for compositor ..." sleep 5 -log "running kscreen-doctor output.DSI-1.rotation.right" -kscreen-doctor output.DSI-1.rotation.right 2>&1 | while read -r line; do log "$line"; done + +OUTPUT="" +if command -v wlr-randr &>/dev/null; then + OUTPUT=$(wlr-randr 2>/dev/null | awk '/^[A-Za-z0-9_-]+ /{print $1; exit}') +fi +if [[ -z "$OUTPUT" ]]; then + OUTPUT="DSI-1" + log "using default output: $OUTPUT" +fi + +if [[ -n "$OUTPUT" ]] && command -v wlr-randr &>/dev/null; then + log "applying rotation right (transform 90) on $OUTPUT" + wlr-randr --output "$OUTPUT" --transform 90 2>&1 | while read -r line; do log "$line"; done +else + log "WARNING: wlr-randr not found or no output" +fi + log "removing one-shot desktop and script" rm -f /home/pi/.config/autostart/set-rotation-once.desktop /home/pi/set-rotation-once.sh log "finished" diff --git a/chromium-setup/emmc-provisioning/cloud-init/set-wallpaper-once.sh b/chromium-setup/emmc-provisioning/cloud-init/set-wallpaper-once.sh index c7f623f..ae39c4f 100644 --- a/chromium-setup/emmc-provisioning/cloud-init/set-wallpaper-once.sh +++ b/chromium-setup/emmc-provisioning/cloud-init/set-wallpaper-once.sh @@ -1,20 +1,36 @@ #!/bin/bash -# One-shot: set desktop wallpaper to splash image, then remove self. Runs as user pi at first login. -# Logs to /var/log/first-boot.log (same as first-boot.sh). +# One-shot: set desktop wallpaper for labwc (swaybg) and persist via labwc autostart, then remove self. +# Runs as user pi at first login. Logs to /var/log/first-boot.log. FIRST_BOOT_LOG="/var/log/first-boot.log" log() { echo "[$(date -Iseconds)] [set-wallpaper-once] $*" >> "$FIRST_BOOT_LOG" 2>/dev/null || true; } -export DISPLAY=:0 -log "started (DISPLAY=$DISPLAY)" -log "waiting 8s for desktop ..." -sleep 8 WALLPAPER="/usr/share/rpd-wallpaper/splash.png" -if [[ -f "$WALLPAPER" ]]; then - log "applying wallpaper $WALLPAPER" - plasma-apply-wallpaperimage "$WALLPAPER" 2>&1 | while read -r line; do log "$line"; done -else +LABWC_AUTOSTART="$HOME/.config/labwc/autostart" + +log "started (labwc/swaybg)" +log "waiting 8s for compositor ..." +sleep 8 + +if [[ ! -f "$WALLPAPER" ]]; then log "WARNING: wallpaper not found $WALLPAPER" +else + mkdir -p "$(dirname "$LABWC_AUTOSTART")" + if [[ ! -f "$LABWC_AUTOSTART" ]]; then + echo '#!/bin/sh' > "$LABWC_AUTOSTART" + chmod +x "$LABWC_AUTOSTART" + fi + if ! grep -q 'swaybg.*splash.png' "$LABWC_AUTOSTART" 2>/dev/null; then + echo "swaybg -i $WALLPAPER -m fill &" >> "$LABWC_AUTOSTART" + log "added swaybg to labwc autostart" + fi + if command -v swaybg &>/dev/null; then + log "applying wallpaper now: $WALLPAPER" + swaybg -i "$WALLPAPER" -m fill & + else + log "WARNING: swaybg not installed" + fi fi + log "removing one-shot desktop and script" rm -f /home/pi/.config/autostart/set-wallpaper-once.desktop /home/pi/set-wallpaper-once.sh log "finished" diff --git a/chromium-setup/emmc-provisioning/cloud-init/user-data-remote-gnss.example b/chromium-setup/emmc-provisioning/cloud-init/user-data-remote-gnss.example index e9b0080..6c7510f 100644 --- a/chromium-setup/emmc-provisioning/cloud-init/user-data-remote-gnss.example +++ b/chromium-setup/emmc-provisioning/cloud-init/user-data-remote-gnss.example @@ -1,6 +1,6 @@ #cloud-config # Example: create user (pi), enable SSH, then download and run first-boot.sh to install -# Chromium kiosk, KDE Plasma, and touch options. Edit FIRST_BOOT_URL to point to your +# Chromium kiosk, rpd-labwc, and touch options. Edit FIRST_BOOT_URL to point to your # hosted first-boot.sh (e.g. file server or raw GitHub). # # 1. Generate a password hash: mkpasswd -m sha-512 'YourPassword' or openssl passwd -6 'YourPassword' diff --git a/chromium-setup/emmc-provisioning/docs/NETWORK-BOOT-LXC.md b/chromium-setup/emmc-provisioning/docs/NETWORK-BOOT-LXC.md new file mode 100644 index 0000000..7b038fd --- /dev/null +++ b/chromium-setup/emmc-provisioning/docs/NETWORK-BOOT-LXC.md @@ -0,0 +1,96 @@ +# Network boot on the provisioning LXC (eth1 = LAN, eth0 = WAN) + +The provisioning LXC can provide **network boot** (PXE-style) and **internet access** to devices connected on **eth1**, while **eth0** is used as WAN for the LXC itself. + +## Roles + +| Interface | Role | Typical config | +|-----------|------|-----------------| +| **eth0** | WAN | DHCP or static; default route; internet for the LXC | +| **eth1** | LAN (provisioning) | Static e.g. `10.20.50.1/24`; DHCP server + TFTP server; NAT so clients get internet via eth0 | + +Devices plugged into the same network as **eth1** (e.g. reTerminals with network boot enabled) will: + +1. Get an IP via **DHCP** (from the LXC on eth1). +2. Get **TFTP** boot files (Raspberry Pi firmware: `start4.elf`, `fixup4.dat`, kernel, etc.) for network boot. +3. Have **internet** via NAT through the LXC (eth0). + +## What you need on the LXC + +1. **DHCP server** on eth1 only (e.g. **dnsmasq**), handing out addresses in e.g. `10.20.50.100`–`10.20.50.200` and advertising the TFTP server (next-server = LXC’s eth1 IP). +2. **TFTP server** (dnsmasq can provide this) with **TFTP root** containing Raspberry Pi 4 / CM4 boot files. +3. **IP forwarding** and **NAT** (nftables or iptables) so traffic from `10.20.50.0/24` is masqueraded out **eth0**. + +## One-time setup (inside the LXC) + +From your machine, run the setup script **on the LXC** (replace with your LXC IP if different): + +```bash +# From the repo (script runs inside the LXC) +./chromium-setup/emmc-provisioning/scripts/setup-network-boot-on-lxc.sh root@10.130.60.141 +``` + +Or SSH into the LXC and run the script there: + +```bash +ssh root@10.130.60.141 +# Copy or rsync the emmc-provisioning tree into the container, then: +bash /path/to/setup-network-boot-on-lxc.sh +``` + +The script will: + +- Install **dnsmasq** (DHCP + TFTP). +- Configure dnsmasq to listen only on **eth1**, with a DHCP range and TFTP root. +- Create `/srv/tftpboot` and optionally fetch Raspberry Pi boot files (or tell you how). +- Enable **IPv4 forwarding** and **NAT** (nftables) so clients on eth1 use eth0 for internet. +- Enable and start the **dnsmasq** and **nftables** (or apply rules) services. + +## Proxmox: adding eth1 to the LXC + +If you create the container by hand or want a second interface: + +1. On the **Proxmox host**, add a second network device to the container, e.g.: + ```bash + pct set --net1 name=eth1,bridge=vmbr1,ip=10.20.50.1/24 + ``` + Use the bridge that corresponds to the physical LAN where reTerminals are connected (e.g. `vmbr1` or a dedicated provisioning bridge). + +2. Inside the LXC, ensure **eth1** has a static address (e.g. in `/etc/network/interfaces`): + ``` + auto eth1 + iface eth1 inet static + address 10.20.50.1/24 + ``` + +Your current LXC already has eth0 (10.130.60.141) and eth1 (10.20.50.1); the setup script only adds DHCP, TFTP, and NAT. + +## After setup: reTerminal network boot + +1. Set the reTerminal **boot order** to try network first (e.g. `BOOT_ORDER=0x21`; see cloud-init/first-boot). +2. Connect the reTerminal to the **same network as the LXC’s eth1** (e.g. 10.20.50.0/24). +3. Power on; it will get an IP via DHCP and load boot files via TFTP from the LXC. +4. For **provisioning** (Backup/Deploy), the netboot environment must run **network-client/provisioning-client.sh** with `PROVISIONING_SERVER=http://10.20.50.1:5000` so it talks to the dashboard on the LXC. + +## TFTP boot files (Raspberry Pi 4 / CM4) + +The TFTP root (e.g. `/srv/tftpboot`) must contain the Raspberry Pi firmware boot files, for example: + +- `start4.elf`, `fixup4.dat` (or `start4cd.elf`, `fixup4cd.dat`) +- `config.txt`, `cmdline.txt` +- `kernel8.img` (64-bit) or `kernel7l.img` (32-bit) + +You can: + +- Run the script’s step that downloads the boot files from the official Raspberry Pi firmware repo, or +- Copy them from a Raspberry Pi OS `/boot/firmware` (or `/boot`) into `/srv/tftpboot` on the LXC. + +## Summary + +| Component | Where | Purpose | +|-------------|--------|--------| +| eth0 | LXC | WAN; LXC’s internet | +| eth1 | LXC | LAN; 10.20.50.1/24; DHCP + TFTP | +| dnsmasq | LXC | DHCP (on eth1) + TFTP | +| TFTP root | LXC | e.g. `/srv/tftpboot` with RPi boot files | +| NAT | LXC | 10.20.50.0/24 → eth0 so LAN has internet | diff --git a/chromium-setup/emmc-provisioning/docs/PROXMOX-LXC-DEPLOYMENT.md b/chromium-setup/emmc-provisioning/docs/PROXMOX-LXC-DEPLOYMENT.md index 633e05c..041a2ef 100644 --- a/chromium-setup/emmc-provisioning/docs/PROXMOX-LXC-DEPLOYMENT.md +++ b/chromium-setup/emmc-provisioning/docs/PROXMOX-LXC-DEPLOYMENT.md @@ -245,3 +245,4 @@ That script syncs the repo to the host and reinstalls scripts on both the host a | Dashboard | Flask app in LXC at `http://:5000`; switch Flash/Backup mode, list and download backups; see **dashboard/README.md** and section 3 above | | Backups | Saved under `/var/lib/cm4-provisioning/backups/` (optionally a host path bind-mounted into the LXC — set `CM4_BACKUPS_HOST_PATH` at deploy). When a device is detected, choose **Backup** or **Deploy** in the dashboard. | | Network deploy/backup | Network-booted devices run **network-client/provisioning-client.sh** and register with the dashboard; they then appear under "Device detected (Network)" and you choose Backup or Deploy. See **network-client/README.md**. | +| Network boot (DHCP + TFTP on eth1) | If the LXC has a second interface **eth1** as provisioning LAN (e.g. 10.20.50.1/24), run **scripts/setup-network-boot-on-lxc.sh root@<LXC-IP>** to install dnsmasq (DHCP+TFTP) on eth1 and NAT so LAN clients get internet via eth0. See **docs/NETWORK-BOOT-LXC.md**. | diff --git a/chromium-setup/emmc-provisioning/lxc/README.md b/chromium-setup/emmc-provisioning/lxc/README.md new file mode 100644 index 0000000..0e052dd --- /dev/null +++ b/chromium-setup/emmc-provisioning/lxc/README.md @@ -0,0 +1,16 @@ +# LXC config (network boot: eth1 = LAN, eth0 = WAN) + +Config files for the **provisioning LXC** when using **eth1** as a provisioning LAN (DHCP + TFTP for network boot, NAT for internet). + +| File | Purpose | +|------|--------| +| **dnsmasq-network-boot.conf** | dnsmasq: DHCP + TFTP on eth1 only. Copied to `/etc/dnsmasq.d/` by `scripts/setup-network-boot-on-lxc.sh`. | +| **nft-nat-lan.conf** | nftables NAT so 10.20.50.0/24 uses eth0 for internet. Applied by the setup script to `/etc/nftables.d/nat-lan.conf`. | + +Setup is done by running (from your machine): + +```bash +./chromium-setup/emmc-provisioning/scripts/setup-network-boot-on-lxc.sh root@ +``` + +See [../docs/NETWORK-BOOT-LXC.md](../docs/NETWORK-BOOT-LXC.md) for full documentation. diff --git a/chromium-setup/emmc-provisioning/lxc/dnsmasq-network-boot.conf b/chromium-setup/emmc-provisioning/lxc/dnsmasq-network-boot.conf new file mode 100644 index 0000000..33a2779 --- /dev/null +++ b/chromium-setup/emmc-provisioning/lxc/dnsmasq-network-boot.conf @@ -0,0 +1,26 @@ +# dnsmasq: DHCP + TFTP on eth1 only (provisioning LAN). +# Install to /etc/dnsmasq.d/network-boot.conf on the LXC. +# Restrict to eth1 so we don't interfere with host/other DHCP. + +# Listen only on eth1 (provisioning LAN) +interface=eth1 +bind-interfaces + +# DHCP range for devices on eth1 (adjust if you use a different subnet) +dhcp-range=10.20.50.100,10.20.50.200,12h + +# TFTP for Raspberry Pi / CM4 network boot +enable-tftp +tftp-root=/srv/tftpboot + +# RPi 4 netboot: next-server is this host; boot filename (Pi firmware uses this) +# Option 66 = next-server (TFTP), 67 = boot filename +dhcp-option=66,10.20.50.1 +dhcp-option=67,start4cd.elf + +# Logging (optional; disable in production if too noisy) +log-dhcp +log-queries + +# Do not use /etc/resolv.conf or act as DNS if you only want DHCP+TFTP +port=0 diff --git a/chromium-setup/emmc-provisioning/lxc/nft-nat-lan.conf b/chromium-setup/emmc-provisioning/lxc/nft-nat-lan.conf new file mode 100644 index 0000000..9f6cea3 --- /dev/null +++ b/chromium-setup/emmc-provisioning/lxc/nft-nat-lan.conf @@ -0,0 +1,10 @@ +# nftables: NAT for LAN (eth1) so clients use WAN (eth0) for internet. +# Load with: nft -f /etc/nftables.d/nat-lan.conf +# Or use the inline rules in setup-network-boot-on-lxc.sh (no separate file dependency). + +table ip nat { + chain postrouting { + type nat hook postrouting priority srcnat; policy accept; + ip saddr 10.20.50.0/24 oifname "eth0" masquerade + } +} diff --git a/chromium-setup/emmc-provisioning/scripts/deploy-to-proxmox.sh b/chromium-setup/emmc-provisioning/scripts/deploy-to-proxmox.sh index 0aaaf73..63a2254 100755 --- a/chromium-setup/emmc-provisioning/scripts/deploy-to-proxmox.sh +++ b/chromium-setup/emmc-provisioning/scripts/deploy-to-proxmox.sh @@ -184,9 +184,14 @@ else fi [[ -z "$DEBIAN12_TMPL" ]] && { log "Error: no Debian 12 template found"; exit 1; } TMPL_NAME=$(basename "$DEBIAN12_TMPL") + # Optional: add eth1 for network-boot LAN (DHCP+TFTP). Set DEPLOY_LXC_NET1 e.g. "name=eth1,bridge=vmbr1,ip=10.20.50.1/24" + NET1_OPT="" + if [[ -n "${DEPLOY_LXC_NET1:-}" ]]; then + NET1_OPT="--net1 $DEPLOY_LXC_NET1" + fi pct create "$CTID" "local:vztmpl/${TMPL_NAME}" \ --hostname "$LXC_HOSTNAME" --memory 1024 --swap 0 --cores 1 \ - --rootfs "${ROOTFS_STORAGE}:8" --net0 name=eth0,bridge=vmbr0,ip=dhcp \ + --rootfs "${ROOTFS_STORAGE}:8" --net0 name=eth0,bridge=vmbr0,ip=dhcp $NET1_OPT \ --unprivileged 0 --features nesting=1 -tag cm4-provisioning mkdir -p /var/lib/cm4-provisioning pct set "$CTID" -mp0 /var/lib/cm4-provisioning,mp=/var/lib/cm4-provisioning diff --git a/chromium-setup/emmc-provisioning/scripts/setup-network-boot-on-lxc.sh b/chromium-setup/emmc-provisioning/scripts/setup-network-boot-on-lxc.sh new file mode 100755 index 0000000..2beee2d --- /dev/null +++ b/chromium-setup/emmc-provisioning/scripts/setup-network-boot-on-lxc.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash +# Setup network boot on the provisioning LXC: DHCP + TFTP on eth1, NAT so LAN uses eth0 for internet. +# Run inside the LXC (as root), or from your machine: ./setup-network-boot-on-lxc.sh root@10.130.60.141 +# When run with ssh target, rsyncs lxc/ and runs this script inside the container. + +set -e +TARGET="${1:-}" + +if [[ -n "$TARGET" ]]; then + # Run remotely: sync lxc/ and script, then execute inside LXC + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + REPO_DIR="$(dirname "$SCRIPT_DIR")" + echo "Syncing lxc config and script to $TARGET ..." + rsync -a "$REPO_DIR/lxc/" "$TARGET:/tmp/cm4-network-boot-lxc/" --exclude='.git' + scp "$SCRIPT_DIR/setup-network-boot-on-lxc.sh" "$TARGET:/tmp/cm4-network-boot-lxc/setup.sh" + ssh "$TARGET" "bash /tmp/cm4-network-boot-lxc/setup.sh" + echo "Done. Next: ensure /srv/tftpboot has RPi boot files (see docs/NETWORK-BOOT-LXC.md)." + exit 0 +fi + +# --- Running inside the LXC from here --- +echo "Configuring network boot (DHCP + TFTP on eth1, NAT via eth0) ..." + +# 1) Install dnsmasq +if ! command -v dnsmasq >/dev/null 2>&1; then + apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get install -y -qq dnsmasq +fi + +# 2) dnsmasq config for eth1 only (DHCP + TFTP) +mkdir -p /etc/dnsmasq.d +cat > /etc/dnsmasq.d/network-boot.conf << 'DNSMASQ' +# DHCP + TFTP on eth1 only (provisioning LAN) +interface=eth1 +bind-interfaces +dhcp-range=10.20.50.100,10.20.50.200,12h +enable-tftp +tftp-root=/srv/tftpboot +dhcp-option=66,10.20.50.1 +dhcp-option=67,start4cd.elf +log-dhcp +log-queries +port=0 +DNSMASQ + +# 3) TFTP root and minimal placeholder so TFTP serves something +mkdir -p /srv/tftpboot +if [[ ! -f /srv/tftpboot/start4cd.elf ]]; then + echo "TFTP root /srv/tftpboot is empty. You need Raspberry Pi 4 boot files (start4cd.elf, fixup4cd.dat, config.txt, cmdline.txt, kernel8.img)." + echo "Download from: https://github.com/raspberrypi/firmware/ (branch master, boot/ folder) and copy into /srv/tftpboot" + echo "Or from a Pi: scp -r pi@:/boot/firmware/* root@:/srv/tftpboot/" +fi + +# 4) IP forwarding (LAN clients use WAN) +echo 'net.ipv4.ip_forward=1' > /etc/sysctl.d/99-cm4-network-boot.conf +sysctl -p /etc/sysctl.d/99-cm4-network-boot.conf 2>/dev/null || sysctl -w net.ipv4.ip_forward=1 + +# 5) NAT: 10.20.50.0/24 -> eth0 (masquerade) +if command -v nft >/dev/null 2>&1; then + mkdir -p /etc/nftables.d + cat > /etc/nftables.d/nat-lan.conf << 'NFT' +table ip nat { + chain postrouting { + type nat hook postrouting priority srcnat; policy accept; + ip saddr 10.20.50.0/24 oifname "eth0" masquerade + } +} +NFT + if ! nft list table ip nat 2>/dev/null | grep -q postrouting; then + nft -f /etc/nftables.d/nat-lan.conf + fi + # Ensure main config includes our drop-in (Debian) + if [[ -f /etc/nftables.conf ]] && ! grep -q 'nftables.d/nat-lan' /etc/nftables.conf 2>/dev/null; then + echo 'include "/etc/nftables.d/nat-lan.conf"' >> /etc/nftables.conf + fi + echo "NAT rule added (nftables) and saved to /etc/nftables.d/nat-lan.conf" +else + # Fallback iptables + iptables -t nat -C POSTROUTING -s 10.20.50.0/24 -o eth0 -j MASQUERADE 2>/dev/null || \ + iptables -t nat -A POSTROUTING -s 10.20.50.0/24 -o eth0 -j MASQUERADE + echo "NAT rule added (iptables)." +fi + +# 6) Enable and start dnsmasq +systemctl enable dnsmasq +systemctl restart dnsmasq + +echo "Network boot setup done." +echo " - DHCP + TFTP on eth1 (10.20.50.1), range 10.20.50.100-200" +echo " - NAT: 10.20.50.0/24 -> eth0 (internet)" +echo " - Put RPi 4 boot files in /srv/tftpboot (see above or docs/NETWORK-BOOT-LXC.md)"