From 85decda2a1e6c6c171a2749e3469333cf44d75f7 Mon Sep 17 00:00:00 2001 From: Manawyrm Date: Thu, 29 Jun 2023 22:14:05 +0200 Subject: [PATCH] Initial commit --- .github/workflows/main.yml | 39 ++++ .gitignore | 3 + README.md | 31 ++++ build_raspberry_pi.sh | 66 +++++++ kiosk_skeleton/build.sh | 61 +++++++ kiosk_skeleton/etc/lightdm/lightdm.conf | 169 ++++++++++++++++++ kiosk_skeleton/etc/nginx/nginx.conf | 61 +++++++ .../etc/nginx/sites-enabled/default | 19 ++ kiosk_skeleton/etc/php/8.2/fpm/php-fpm.conf | 145 +++++++++++++++ .../etc/php/8.2/fpm/pool.d/www.conf | 14 ++ .../etc/ssh/sshd_config.d/kiosk.conf | 2 + kiosk_skeleton/etc/sudoers.d/090-php-nopasswd | 1 + .../etc/systemd/system/kiosk-autossh.service | 10 ++ .../systemd/system/kiosk-set-hostname.service | 10 ++ .../etc/systemd/system/kiosk-watchdog.service | 10 ++ .../etc/systemd/system/kiosk-wifi.service | 10 ++ .../etc/systemd/system/ntpdate.service | 12 ++ .../home/pi/.config/openbox/autostart | 36 ++++ kiosk_skeleton/home/pi/.ssh/authorized_keys | 1 + kiosk_skeleton/usr/bin/cache-clear-timer | 6 + kiosk_skeleton/usr/bin/get-ini | 22 +++ kiosk_skeleton/usr/bin/kiosk-autossh | 10 ++ kiosk_skeleton/usr/bin/kiosk-set-hostname | 15 ++ kiosk_skeleton/usr/bin/kiosk-watchdog | 33 ++++ kiosk_skeleton/usr/bin/kiosk-wifi | 27 +++ kiosk_skeleton/var/www/html/heartbeat.php | 8 + kiosk_skeleton/var/www/html/index.php | 17 ++ kiosk_skeleton/var/www/html/screenshot.php | 3 + raspberry_pi_skeleton/boot/cmdline.txt | 1 + raspberry_pi_skeleton/boot/config.txt | 55 ++++++ raspberry_pi_skeleton/boot/kioskbrowser.ini | 43 +++++ raspberry_pi_skeleton/boot/ssh | 0 .../raspberry_pi_bullseye.sh | 9 + .../rfkill/platform-3f300000.mmcnr:wlan | 1 + .../rfkill/platform-fe300000.mmcnr:wlan | 1 + 35 files changed, 951 insertions(+) create mode 100644 .github/workflows/main.yml create mode 100644 .gitignore create mode 100644 README.md create mode 100755 build_raspberry_pi.sh create mode 100755 kiosk_skeleton/build.sh create mode 100644 kiosk_skeleton/etc/lightdm/lightdm.conf create mode 100644 kiosk_skeleton/etc/nginx/nginx.conf create mode 100644 kiosk_skeleton/etc/nginx/sites-enabled/default create mode 100644 kiosk_skeleton/etc/php/8.2/fpm/php-fpm.conf create mode 100644 kiosk_skeleton/etc/php/8.2/fpm/pool.d/www.conf create mode 100644 kiosk_skeleton/etc/ssh/sshd_config.d/kiosk.conf create mode 100644 kiosk_skeleton/etc/sudoers.d/090-php-nopasswd create mode 100644 kiosk_skeleton/etc/systemd/system/kiosk-autossh.service create mode 100644 kiosk_skeleton/etc/systemd/system/kiosk-set-hostname.service create mode 100644 kiosk_skeleton/etc/systemd/system/kiosk-watchdog.service create mode 100644 kiosk_skeleton/etc/systemd/system/kiosk-wifi.service create mode 100644 kiosk_skeleton/etc/systemd/system/ntpdate.service create mode 100755 kiosk_skeleton/home/pi/.config/openbox/autostart create mode 100755 kiosk_skeleton/home/pi/.ssh/authorized_keys create mode 100755 kiosk_skeleton/usr/bin/cache-clear-timer create mode 100755 kiosk_skeleton/usr/bin/get-ini create mode 100755 kiosk_skeleton/usr/bin/kiosk-autossh create mode 100644 kiosk_skeleton/usr/bin/kiosk-set-hostname create mode 100644 kiosk_skeleton/usr/bin/kiosk-watchdog create mode 100755 kiosk_skeleton/usr/bin/kiosk-wifi create mode 100644 kiosk_skeleton/var/www/html/heartbeat.php create mode 100644 kiosk_skeleton/var/www/html/index.php create mode 100644 kiosk_skeleton/var/www/html/screenshot.php create mode 100644 raspberry_pi_skeleton/boot/cmdline.txt create mode 100755 raspberry_pi_skeleton/boot/config.txt create mode 100644 raspberry_pi_skeleton/boot/kioskbrowser.ini create mode 100644 raspberry_pi_skeleton/boot/ssh create mode 100755 raspberry_pi_skeleton/raspberry_pi_bullseye.sh create mode 100644 raspberry_pi_skeleton/var/lib/systemd/rfkill/platform-3f300000.mmcnr:wlan create mode 100644 raspberry_pi_skeleton/var/lib/systemd/rfkill/platform-fe300000.mmcnr:wlan diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..23c9a8f --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,39 @@ +name: CI + +on: + create: { } + push: { } + pull_request: { } + +jobs: + build: + runs-on: [self-hosted, hetzner-cax21] + + outputs: + pkgfile: ${{ steps.pkgname.outputs.pkgfile }} + + steps: + - name: Check out repo + uses: actions/checkout@v2 + + - name: Install dependencies + run: | + sudo apt update -qq + sudo apt install -yqq libguestfs-tools qemu-utils rsync sudo wget xz pigz + + - name: Build firmware + run: | + ./build_raspberry_pi.sh + + - name: Compress firmware + run: | + pigz -9 raspikiosk.img + + - name: Release build artifacts + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') + with: + files: | + ./raspikiosk.img.gz + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e0ae4de --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +raspikiosk.img +raspios.img.xz +work/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..c7a8c77 --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +Another kiosk browser OS? + +Yes, this one is a little bit opinionated :) +The author ran several similar setups in production for years and has seen a lot of problems and strange failure modes. +This project aims to solve a lot of those (at least for the author), it might also be useful for others :) + +Key features: +- Images built via CI +- WiFi connection support +- Raspberry Pi (Arm64) compatibility +- USB flash drive, USB SSD, etc. compatible +- aarch64 mode for Raspberry Pis (_significant_ performance improvements over armv7/32bit ARM) +- Read-only filesystem handling (no more broken SD cards) +- Configurable cache clear functionality +- HTTP watchdog (website needs to send heartbeat messages via XHR/AJAX to localhost) +- Force specific resolution (1080p on 4k screens, broken EDID, etc.) +- Hard NTP handling (will wait for NTP at boot) +- SSH support +- VNC support +- SSH tunneling support (for remote-access without port-forwarding, etc.) + +Planned features: +- PC (x86) compatibility +- Raspberry Pi PXE/network boot support +- Network connectivity watchdog (configurable ping, etc. timeout) +- Automatic reboot at specified time + +Security considerations: +- Autossh does not check SSH host keys. This is okay-ish as long as the target server only allows tunneling, nothing else. +- nginx/PHP are allowed to use sudo/NOPASSWD (because it needs to query the VideoCore, manage service, etc.), more priviledge seperation would be nice +- due to the skeleton mechanism, the system has some ... creative permissions. some cleanup required. \ No newline at end of file diff --git a/build_raspberry_pi.sh b/build_raspberry_pi.sh new file mode 100755 index 0000000..f13951a --- /dev/null +++ b/build_raspberry_pi.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +SCRIPT_DIR="$(dirname "$(realpath "$0")")" +BUILD_DIR="${SCRIPT_DIR}/work/root/" + +umount -fl "${BUILD_DIR}" || true +losetup -D /dev/loop0 || true +rm -rf "${BUILD_DIR}" || true +mkdir -p "${BUILD_DIR}" + +if [ ! -f raspios.img.xz ] +then + wget -O raspios.img.xz "https://downloads.raspberrypi.org/raspios_lite_arm64/images/raspios_lite_arm64-2023-05-03/2023-05-03-raspios-bullseye-arm64-lite.img.xz" + echo "bf982e56b0374712d93e185780d121e3f5c3d5e33052a95f72f9aed468d58fa7 raspios.img.xz" | sha256sum --check --status + if [ $? -ne 0 ]; + echo "downloaded raspios does not match checksum"; + return -1; + fi +fi + +rm -f raspios.img +xz -kd raspios.img.xz + +# Repartition image +virt-filesystems --long -h --all -a raspios.img + +truncate -r raspios.img raspikiosk.img +truncate -s +3G raspikiosk.img + +virt-resize --expand /dev/sda2 raspios.img raspikiosk.img +rm -f raspios.img + +# Setup loop device for Raspberry Pi image (with partition scanning) +sudo losetup -P /dev/loop0 raspikiosk.img + +# Mount partitions +sudo mount /dev/loop0p2 "${BUILD_DIR}" +sudo mount /dev/loop0p1 "${BUILD_DIR}/boot" + +# Copy the (raspberry pi-specific) skeleton files +rsync -a "${SCRIPT_DIR}/raspberry_pi_skeleton/." "${BUILD_DIR}" +rsync -a "${SCRIPT_DIR}/kiosk_skeleton/." "${BUILD_DIR}/kiosk_skeleton" + +# Mount system partitions (from the build host) +sudo mount -t proc /proc "${BUILD_DIR}/proc/" +sudo mount --rbind /sys "${BUILD_DIR}/sys/" +sudo mount --rbind /dev "${BUILD_DIR}/dev/" + +sudo chroot "${BUILD_DIR}" /raspberry_pi_bullseye.sh +sudo chroot "${BUILD_DIR}" /kiosk_skeleton/build.sh + +sudo rm -r "${BUILD_DIR}/kiosk_skeleton" +sudo rm "${BUILD_DIR}/raspberry_pi_bullseye.sh" + +sudo umount -fl "${BUILD_DIR}/proc" +sudo umount -fl "${BUILD_DIR}/sys" +sudo umount -fl "${BUILD_DIR}/dev" + +sudo umount "${BUILD_DIR}/proc" +sudo umount "${BUILD_DIR}/sys" +sudo umount "${BUILD_DIR}/dev" + +sudo umount "${BUILD_DIR}/boot" +sudo umount "${BUILD_DIR}" + +sudo losetup -D /dev/loop0 diff --git a/kiosk_skeleton/build.sh b/kiosk_skeleton/build.sh new file mode 100755 index 0000000..287a51e --- /dev/null +++ b/kiosk_skeleton/build.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# This script is being run on the target debian platform + +apt update +APT_LISTCHANGES_FRONTEND=none DEBIAN_FRONTEND=noninteractive apt dist-upgrade -y +DEBIAN_FRONTEND=noninteractive apt install -y lightdm openbox nginx php-fpm php-cli chromium autossh unclutter x11-xserver-utils xdotool htop nano openssh-server rsync x11vnc lm-sensors ntpdate scrot + +rsync -a --chown=root:root "/kiosk_skeleton/." "/" +chown -hR pi:pi /home/pi + +# Raspberry Pi specific modifications +# raspberrypi-net-mods does things like copying /boot/wpa_supplicant.conf to the root FS +apt remove -y raspberrypi-net-mods || true +# userconf-pi prevents lightdm from starting unless the default "pi" user is changed +apt remove -y userconf-pi || true +# RF emissions are blocked by default +rfkill unblock wlan || true + +# fix file system permissions +chown -hR 0:0 /etc/sudoers.d/ +chown -hR www-data:www-data /var/www/html/ + +mkdir -p /home/pi/.config/chromium/ +chown -hR 1000:1000 /home/pi/.config/chromium/ + +mkdir -p /home/pi/.pki/ +chown -hR 1000:1000 /home/pi/.pki/ + +# FIXME: readonly in /etc/fstab +echo "tmpfs /dev/shm tmpfs mode=0777 0 0" >> /etc/fstab +echo "tmpfs /tmp tmpfs mode=1777 0 0" >> /etc/fstab +echo "tmpfs /run tmpfs mode=0755,nosuid,nodev 0 0" >> /etc/fstab +echo "tmpfs /var/log tmpfs defaults,noatime,nosuid,mode=0755,size=100m 0 0" >> /etc/fstab +echo "tmpfs /var/lib/lightdm tmpfs defaults,noatime,nosuid,size=30m 0 0" >> /etc/fstab +echo "tmpfs /home/pi/.cache tmpfs mode=0755,nosuid,nodev,uid=1000,gid=1000 0 0" >> /etc/fstab +echo "tmpfs /home/pi/.config/chromium/ tmpfs mode=0755,nosuid,nodev,uid=1000,gid=1000 0 0" >> /etc/fstab +echo "tmpfs /home/pi/.pki/ tmpfs mode=0755,nosuid,nodev,uid=1000,gid=1000 0 0" >> /etc/fstab + +# Create symlinks for configuration files which will later get created at runtime (in /tmp) +rm /etc/hosts +rm /etc/hostname +mkdir -p /etc/wpa_supplicant/ +ln -sf /tmp/hosts /etc/hosts +ln -sf /tmp/hostname /etc/hostname +ln -sf /tmp/wpa_supplicant.conf /etc/wpa_supplicant/wpa_supplicant.conf + +systemctl daemon-reload + +# remove unneccessary clutter +systemctl disable dphys-swapfile +systemctl disable ModemManager +systemctl disable avahi-daemon +systemctl disable bluetooth + +systemctl enable kiosk-wifi +systemctl enable kiosk-autossh +systemctl enable kiosk-watchdog +systemctl enable kiosk-set-hostname +systemctl enable ntpdate +systemctl enable lightdm +systemctl enable nginx diff --git a/kiosk_skeleton/etc/lightdm/lightdm.conf b/kiosk_skeleton/etc/lightdm/lightdm.conf new file mode 100644 index 0000000..134ea0c --- /dev/null +++ b/kiosk_skeleton/etc/lightdm/lightdm.conf @@ -0,0 +1,169 @@ +# +# General configuration +# +# start-default-seat = True to always start one seat if none are defined in the configuration +# greeter-user = User to run greeter as +# minimum-display-number = Minimum display number to use for X servers +# minimum-vt = First VT to run displays on +# lock-memory = True to prevent memory from being paged to disk +# user-authority-in-system-dir = True if session authority should be in the system location +# guest-account-script = Script to be run to setup guest account +# logind-check-graphical = True to on start seats that are marked as graphical by logind +# log-directory = Directory to log information to +# run-directory = Directory to put running state in +# cache-directory = Directory to cache to +# sessions-directory = Directory to find sessions +# remote-sessions-directory = Directory to find remote sessions +# greeters-directory = Directory to find greeters +# backup-logs = True to move add a .old suffix to old log files when opening new ones +# dbus-service = True if LightDM provides a D-Bus service to control it +# +[LightDM] +#start-default-seat=true +#greeter-user=lightdm +#minimum-display-number=0 +#minimum-vt=7 +#lock-memory=true +user-authority-in-system-dir=true +#guest-account-script=guest-account +#logind-check-graphical=false +#log-directory=/var/log/lightdm +#run-directory=/var/run/lightdm +#cache-directory=/var/cache/lightdm +#sessions-directory=/usr/share/lightdm/sessions:/usr/share/xsessions:/usr/share/wayland-sessions +#remote-sessions-directory=/usr/share/lightdm/remote-sessions +#greeters-directory=$XDG_DATA_DIRS/lightdm/greeters:$XDG_DATA_DIRS/xgreeters +#backup-logs=true +#dbus-service=true + +# +# Seat configuration +# +# Seat configuration is matched against the seat name glob in the section, for example: +# [Seat:*] matches all seats and is applied first. +# [Seat:seat0] matches the seat named "seat0". +# [Seat:seat-thin-client*] matches all seats that have names that start with "seat-thin-client". +# +# type = Seat type (local, xremote, unity) +# pam-service = PAM service to use for login +# pam-autologin-service = PAM service to use for autologin +# pam-greeter-service = PAM service to use for greeters +# xserver-backend = X backend to use (mir) +# xserver-command = X server command to run (can also contain arguments e.g. X -special-option) +# xmir-command = Xmir server command to run (can also contain arguments e.g. Xmir -special-option) +# xserver-config = Config file to pass to X server +# xserver-layout = Layout to pass to X server +# xserver-allow-tcp = True if TCP/IP connections are allowed to this X server +# xserver-share = True if the X server is shared for both greeter and session +# xserver-hostname = Hostname of X server (only for type=xremote) +# xserver-display-number = Display number of X server (only for type=xremote) +# xdmcp-manager = XDMCP manager to connect to (implies xserver-allow-tcp=true) +# xdmcp-port = XDMCP UDP/IP port to communicate on +# xdmcp-key = Authentication key to use for XDM-AUTHENTICATION-1 (stored in keys.conf) +# unity-compositor-command = Unity compositor command to run (can also contain arguments e.g. unity-system-compositor -special-option) +# unity-compositor-timeout = Number of seconds to wait for compositor to start +# greeter-session = Session to load for greeter +# greeter-hide-users = True to hide the user list +# greeter-allow-guest = True if the greeter should show a guest login option +# greeter-show-manual-login = True if the greeter should offer a manual login option +# greeter-show-remote-login = True if the greeter should offer a remote login option +# user-session = Session to load for users +# allow-user-switching = True if allowed to switch users +# allow-guest = True if guest login is allowed +# guest-session = Session to load for guests (overrides user-session) +# session-wrapper = Wrapper script to run session with +# greeter-wrapper = Wrapper script to run greeter with +# guest-wrapper = Wrapper script to run guest sessions with +# display-setup-script = Script to run when starting a greeter session (runs as root) +# display-stopped-script = Script to run after stopping the display server (runs as root) +# greeter-setup-script = Script to run when starting a greeter (runs as root) +# session-setup-script = Script to run when starting a user session (runs as root) +# session-cleanup-script = Script to run when quitting a user session (runs as root) +# autologin-guest = True to log in as guest by default +# autologin-user = User to log in with by default (overrides autologin-guest) +# autologin-user-timeout = Number of seconds to wait before loading default user +# autologin-session = Session to load for automatic login (overrides user-session) +# autologin-in-background = True if autologin session should not be immediately activated +# exit-on-failure = True if the daemon should exit if this seat fails +# +[Seat:*] +#type=local +#pam-service=lightdm +#pam-autologin-service=lightdm-autologin +#pam-greeter-service=lightdm-greeter +#xserver-backend= +#xserver-command=X +#xmir-command=Xmir +#xserver-config= +#xserver-layout= +#xserver-allow-tcp=false +#xserver-share=true +#xserver-hostname= +#xserver-display-number= +#xdmcp-manager= +#xdmcp-port=177 +#xdmcp-key= +#unity-compositor-command=unity-system-compositor +#unity-compositor-timeout=60 +#greeter-session=example-gtk-gnome +#greeter-hide-users=false +#greeter-allow-guest=true +#greeter-show-manual-login=false +#greeter-show-remote-login=true +#user-session=default +#allow-user-switching=true +#allow-guest=true +#guest-session= +#session-wrapper=lightdm-session +#greeter-wrapper= +#guest-wrapper= +#display-setup-script= +#display-stopped-script= +#greeter-setup-script= +#session-setup-script= +#session-cleanup-script= +#autologin-guest=false +autologin-user=pi +#autologin-user-timeout=0 +#autologin-in-background=false +#autologin-session= +#exit-on-failure=false + +# +# XDMCP Server configuration +# +# enabled = True if XDMCP connections should be allowed +# port = UDP/IP port to listen for connections on +# listen-address = Host/address to listen for XDMCP connections (use all addresses if not present) +# key = Authentication key to use for XDM-AUTHENTICATION-1 or blank to not use authentication (stored in keys.conf) +# hostname = Hostname to report to XDMCP clients (defaults to system hostname if unset) +# +# The authentication key is a 56 bit DES key specified in hex as 0xnnnnnnnnnnnnnn. Alternatively +# it can be a word and the first 7 characters are used as the key. +# +[XDMCPServer] +#enabled=false +#port=177 +#listen-address= +#key= +#hostname= + +# +# VNC Server configuration +# +# enabled = True if VNC connections should be allowed +# command = Command to run Xvnc server with +# port = TCP/IP port to listen for connections on +# listen-address = Host/address to listen for VNC connections (use all addresses if not present) +# width = Width of display to use +# height = Height of display to use +# depth = Color depth of display to use +# +[VNCServer] +#enabled=false +#command=Xvnc +#port=5900 +#listen-address= +#width=1024 +#height=768 +#depth=8 \ No newline at end of file diff --git a/kiosk_skeleton/etc/nginx/nginx.conf b/kiosk_skeleton/etc/nginx/nginx.conf new file mode 100644 index 0000000..33aac2b --- /dev/null +++ b/kiosk_skeleton/etc/nginx/nginx.conf @@ -0,0 +1,61 @@ +user www-data; +worker_processes auto; +pid /run/nginx.pid; +include /etc/nginx/modules-enabled/*.conf; + +events { + worker_connections 768; + # multi_accept on; +} + +http { + + ## + # Basic Settings + ## + + sendfile on; + tcp_nopush on; + types_hash_max_size 2048; + # server_tokens off; + + # server_names_hash_bucket_size 64; + # server_name_in_redirect off; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + ## + # SSL Settings + ## + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE + ssl_prefer_server_ciphers on; + + ## + # Logging Settings + ## + + access_log /dev/null; + error_log /dev/null; + + ## + # Gzip Settings + ## + + gzip on; + + # gzip_vary on; + # gzip_proxied any; + # gzip_comp_level 6; + # gzip_buffers 16 8k; + # gzip_http_version 1.1; + # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + + ## + # Virtual Host Configs + ## + + include /etc/nginx/conf.d/*.conf; + include /etc/nginx/sites-enabled/*; +} \ No newline at end of file diff --git a/kiosk_skeleton/etc/nginx/sites-enabled/default b/kiosk_skeleton/etc/nginx/sites-enabled/default new file mode 100644 index 0000000..dd9589c --- /dev/null +++ b/kiosk_skeleton/etc/nginx/sites-enabled/default @@ -0,0 +1,19 @@ +server { + listen 80 default_server; + listen [::]:80 default_server; + + root /var/www/html; + + index index.php; + + server_name _; + + location / { + try_files $uri $uri/ =404; + } + + location ~ \.php$ { + include snippets/fastcgi-php.conf; + fastcgi_pass unix:/run/php-fpm.sock; + } +} \ No newline at end of file diff --git a/kiosk_skeleton/etc/php/8.2/fpm/php-fpm.conf b/kiosk_skeleton/etc/php/8.2/fpm/php-fpm.conf new file mode 100644 index 0000000..244b6ec --- /dev/null +++ b/kiosk_skeleton/etc/php/8.2/fpm/php-fpm.conf @@ -0,0 +1,145 @@ +;;;;;;;;;;;;;;;;;;;;; +; FPM Configuration ; +;;;;;;;;;;;;;;;;;;;;; + +; All relative paths in this configuration file are relative to PHP's install +; prefix (/usr). This prefix can be dynamically changed by using the +; '-p' argument from the command line. + +;;;;;;;;;;;;;;;;;; +; Global Options ; +;;;;;;;;;;;;;;;;;; + +[global] +; Pid file +; Note: the default prefix is /var +; Default Value: none +; Warning: if you change the value here, you need to modify systemd +; service PIDFile= setting to match the value here. +pid = /run/php8.2-fpm.pid + +; Error log file +; If it's set to "syslog", log is sent to syslogd instead of being written +; into a local file. +; Note: the default prefix is /var +; Default Value: log/php-fpm.log +error_log = syslog + +; syslog_facility is used to specify what type of program is logging the +; message. This lets syslogd specify that messages from different facilities +; will be handled differently. +; See syslog(3) for possible values (ex daemon equiv LOG_DAEMON) +; Default Value: daemon +;syslog.facility = daemon + +; syslog_ident is prepended to every message. If you have multiple FPM +; instances running on the same server, you can change the default value +; which must suit common needs. +; Default Value: php-fpm +;syslog.ident = php-fpm + +; Log level +; Possible Values: alert, error, warning, notice, debug +; Default Value: notice +;log_level = notice + +; Log limit on number of characters in the single line (log entry). If the +; line is over the limit, it is wrapped on multiple lines. The limit is for +; all logged characters including message prefix and suffix if present. However +; the new line character does not count into it as it is present only when +; logging to a file descriptor. It means the new line character is not present +; when logging to syslog. +; Default Value: 1024 +;log_limit = 4096 + +; Log buffering specifies if the log line is buffered which means that the +; line is written in a single write operation. If the value is false, then the +; data is written directly into the file descriptor. It is an experimental +; option that can potentially improve logging performance and memory usage +; for some heavy logging scenarios. This option is ignored if logging to syslog +; as it has to be always buffered. +; Default value: yes +;log_buffering = no + +; If this number of child processes exit with SIGSEGV or SIGBUS within the time +; interval set by emergency_restart_interval then FPM will restart. A value +; of '0' means 'Off'. +; Default Value: 0 +;emergency_restart_threshold = 0 + +; Interval of time used by emergency_restart_interval to determine when +; a graceful restart will be initiated. This can be useful to work around +; accidental corruptions in an accelerator's shared memory. +; Available Units: s(econds), m(inutes), h(ours), or d(ays) +; Default Unit: seconds +; Default Value: 0 +;emergency_restart_interval = 0 + +; Time limit for child processes to wait for a reaction on signals from master. +; Available units: s(econds), m(inutes), h(ours), or d(ays) +; Default Unit: seconds +; Default Value: 0 +;process_control_timeout = 0 + +; The maximum number of processes FPM will fork. This has been designed to control +; the global number of processes when using dynamic PM within a lot of pools. +; Use it with caution. +; Note: A value of 0 indicates no limit +; Default Value: 0 +; process.max = 128 + +; Specify the nice(2) priority to apply to the master process (only if set) +; The value can vary from -19 (highest priority) to 20 (lowest priority) +; Note: - It will only work if the FPM master process is launched as root +; - The pool process will inherit the master process priority +; unless specified otherwise +; Default Value: no set +; process.priority = -19 + +; Send FPM to background. Set to 'no' to keep FPM in foreground for debugging. +; Default Value: yes +;daemonize = yes + +; Set open file descriptor rlimit for the master process. +; Default Value: system defined value +;rlimit_files = 1024 + +; Set max core size rlimit for the master process. +; Possible Values: 'unlimited' or an integer greater or equal to 0 +; Default Value: system defined value +;rlimit_core = 0 + +; Specify the event mechanism FPM will use. The following is available: +; - select (any POSIX os) +; - poll (any POSIX os) +; - epoll (linux >= 2.5.44) +; - kqueue (FreeBSD >= 4.1, OpenBSD >= 2.9, NetBSD >= 2.0) +; - /dev/poll (Solaris >= 7) +; - port (Solaris >= 10) +; Default Value: not set (auto detection) +;events.mechanism = epoll + +; When FPM is built with systemd integration, specify the interval, +; in seconds, between health report notification to systemd. +; Set to 0 to disable. +; Available Units: s(econds), m(inutes), h(ours) +; Default Unit: seconds +; Default value: 10 +;systemd_interval = 10 + +;;;;;;;;;;;;;;;;;;;; +; Pool Definitions ; +;;;;;;;;;;;;;;;;;;;; + +; Multiple pools of child processes may be started with different listening +; ports and different management options. The name of the pool will be +; used in logs and stats. There is no limitation on the number of pools which +; FPM can handle. Your system will tell you anyway :) + +; Include one or more files. If glob(3) exists, it is used to include a bunch of +; files from a glob(3) pattern. This directive can be used everywhere in the +; file. +; Relative path can also be used. They will be prefixed by: +; - the global prefix if it's been set (-p argument) +; - /usr otherwise +include=/etc/php/8.2/fpm/pool.d/*.conf \ No newline at end of file diff --git a/kiosk_skeleton/etc/php/8.2/fpm/pool.d/www.conf b/kiosk_skeleton/etc/php/8.2/fpm/pool.d/www.conf new file mode 100644 index 0000000..6884536 --- /dev/null +++ b/kiosk_skeleton/etc/php/8.2/fpm/pool.d/www.conf @@ -0,0 +1,14 @@ +[www] +user = www-data +group = www-data + +listen = /run/php-fpm.sock + +listen.owner = www-data +listen.group = www-data + +pm = dynamic +pm.max_children = 5 +pm.start_servers = 2 +pm.min_spare_servers = 1 +pm.max_spare_servers = 3 diff --git a/kiosk_skeleton/etc/ssh/sshd_config.d/kiosk.conf b/kiosk_skeleton/etc/ssh/sshd_config.d/kiosk.conf new file mode 100644 index 0000000..f742952 --- /dev/null +++ b/kiosk_skeleton/etc/ssh/sshd_config.d/kiosk.conf @@ -0,0 +1,2 @@ +PermitRootLogin prohibit-password +PasswordAuthentication no diff --git a/kiosk_skeleton/etc/sudoers.d/090-php-nopasswd b/kiosk_skeleton/etc/sudoers.d/090-php-nopasswd new file mode 100644 index 0000000..67fb143 --- /dev/null +++ b/kiosk_skeleton/etc/sudoers.d/090-php-nopasswd @@ -0,0 +1 @@ +www-data ALL=(ALL) NOPASSWD: ALL \ No newline at end of file diff --git a/kiosk_skeleton/etc/systemd/system/kiosk-autossh.service b/kiosk_skeleton/etc/systemd/system/kiosk-autossh.service new file mode 100644 index 0000000..a34ebf4 --- /dev/null +++ b/kiosk_skeleton/etc/systemd/system/kiosk-autossh.service @@ -0,0 +1,10 @@ +[Unit] +Description=Keeps an SSH tunnel open +After=network.target + +[Service] +User=root +ExecStart=/usr/bin/kiosk-autossh + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/kiosk_skeleton/etc/systemd/system/kiosk-set-hostname.service b/kiosk_skeleton/etc/systemd/system/kiosk-set-hostname.service new file mode 100644 index 0000000..50e9ab7 --- /dev/null +++ b/kiosk_skeleton/etc/systemd/system/kiosk-set-hostname.service @@ -0,0 +1,10 @@ +[Unit] +Description=Set hostname to the one from kioskbrowser.ini +Before=networking.service + +[Service] +Type=oneshot +ExecStart=/usr/bin/kiosk-set-hostname + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/kiosk_skeleton/etc/systemd/system/kiosk-watchdog.service b/kiosk_skeleton/etc/systemd/system/kiosk-watchdog.service new file mode 100644 index 0000000..380a5eb --- /dev/null +++ b/kiosk_skeleton/etc/systemd/system/kiosk-watchdog.service @@ -0,0 +1,10 @@ +[Unit] +Description=HTTP based watchdog +After=lightdm.service + +[Service] +Type=simple +ExecStart=/usr/bin/kiosk-watchdog + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/kiosk_skeleton/etc/systemd/system/kiosk-wifi.service b/kiosk_skeleton/etc/systemd/system/kiosk-wifi.service new file mode 100644 index 0000000..d936510 --- /dev/null +++ b/kiosk_skeleton/etc/systemd/system/kiosk-wifi.service @@ -0,0 +1,10 @@ +[Unit] +Description=Generate wpa_supplicant.conf from kioskbrowser.ini +Before=wpa_supplicant.service + +[Service] +Type=oneshot +ExecStart=/usr/bin/kiosk-wifi + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/kiosk_skeleton/etc/systemd/system/ntpdate.service b/kiosk_skeleton/etc/systemd/system/ntpdate.service new file mode 100644 index 0000000..0f9ab03 --- /dev/null +++ b/kiosk_skeleton/etc/systemd/system/ntpdate.service @@ -0,0 +1,12 @@ +[Unit] +Description=Force ntpdate to synchronise clock +Requires=networking.service +After=syslog.target networking.service dhcpcd.service +Before=lightdm.service + +[Service] +Type=oneshot +ExecStart=ntpdate ptbtime2.ptb.de ptbtime3.ptb.de + +[Install] +WantedBy=multi-user.target diff --git a/kiosk_skeleton/home/pi/.config/openbox/autostart b/kiosk_skeleton/home/pi/.config/openbox/autostart new file mode 100755 index 0000000..7710df8 --- /dev/null +++ b/kiosk_skeleton/home/pi/.config/openbox/autostart @@ -0,0 +1,36 @@ +#!/bin/bash + +VNC_ENABLED=$(get-ini /boot/kioskbrowser.ini vnc enabled) +if [ "${VNC_ENABLED}" -eq 1 ] +then + x11vnc -localhost & +fi + +# move the cursor out of the way +xdotool mousemove 0 0 + +xset s off # don't activate screensaver +xset -dpms # disable DPMS (Energy Star) features. +xset s noblank # don't blank the video device + +# hide mouse cursor after 1 second +unclutter -idle 1 -root & + +# set a custom resolution (if specified) +RESOLUTION=$(get-ini /boot/kioskbrowser.ini screen force_resolution) +if [ -n "${RESOLUTION}" ] +then + MONITOR=$(xrandr -q | grep " connected" | awk '{ print $1; }') + xrandr --output "${MONITOR}" --mode "${RESOLUTION}" +fi + +# start chromium +URL=$(get-ini /boot/kioskbrowser.ini browser url) +chromium --start-fullscreen --check-for-update-interval=1 --simulate-critical-update --noerrdialogs --disable-infobars --kiosk --allow-insecure-localhost ${URL} & + +# if a cache clearing interval is specified, launch the cache-clear-timer (while true, sleep, rm -rf) +CACHE_CLEAR=$(get-ini /boot/kioskbrowser.ini browser cache_clear_interval) +if [ -n "${CACHE_CLEAR}" ] +then + /usr/bin/cache-clear-timer "${CACHE_CLEAR}" & +fi diff --git a/kiosk_skeleton/home/pi/.ssh/authorized_keys b/kiosk_skeleton/home/pi/.ssh/authorized_keys new file mode 100755 index 0000000..4574257 --- /dev/null +++ b/kiosk_skeleton/home/pi/.ssh/authorized_keys @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDMEtunV3AKNmKM3NeK5ZERUiQRKtpqFcmbH8ubNPy+zp7MfKiWwypltc5CStA95av76WeFHOQhRC75mjE98HOsyAgx9dgq4KvqSnqPu5j3hQI/BA0kp9a1oC+8DvoqWqrSop5+BPIQp23a0ILjlRsJ/JWfGTOp+4WAk9QEbQ4IBTDa/htMnI6/BYJHpvYB5QxT3BhjPCe00mCAvLIuO5xYwMDi1zl+VHsLjheSRjNku46Ivfgec8FFQVG9f5OTCT86TNWxO63Nvyk275JvyVRZdk8GfBS/tB9t2/JXCIPuEiE4p1VYHLcoGtNz6WLo8LNxQ8upmsMgXI6oX12Zysxnqsyt/L1YpD72rR3MLTdhLFrZO6EVFnzU9rqfx5Nr4krw+vuDx4LQ6sFc/IaCEmPwclgILFZi/zKNyypjRkuT1F3ejjoSkq3CA/WrEwWNVR/vOGbqQjkJ9eZJ6v3771bAbfY6yJOYjhRgDpaF4AUtYBDunOAaw0aEbopOqISzIZ0KydHQ/KAlNxPzWpIVVjvz8eqGTTy/xDggCddOTaj9mt6BeLK/xUyqu0gh/OD8ZqgNmyeNYfkAtV4mfrSV3MiwpJG2ItgMsPUZt8L87e0//s6K2XOZ0Dx3OeZyXdMLzwG+YR6Bj+qKG5TMPw5YKFfmVBxcwDNovthapOKkPT3fhw== Manawyrm \ No newline at end of file diff --git a/kiosk_skeleton/usr/bin/cache-clear-timer b/kiosk_skeleton/usr/bin/cache-clear-timer new file mode 100755 index 0000000..0ff8f0a --- /dev/null +++ b/kiosk_skeleton/usr/bin/cache-clear-timer @@ -0,0 +1,6 @@ +#!/bin/bash +while true +do + sleep $1 + rm -r /home/pi/.cache/chromium/Default || true +done \ No newline at end of file diff --git a/kiosk_skeleton/usr/bin/get-ini b/kiosk_skeleton/usr/bin/get-ini new file mode 100755 index 0000000..9a9d17d --- /dev/null +++ b/kiosk_skeleton/usr/bin/get-ini @@ -0,0 +1,22 @@ +#!/usr/bin/env php + /tmp/hostname + hostnamectl --transient hostname "${HOSTNAME}" + + echo "127.0.0.1 localhost" > /tmp/hosts + echo "::1 localhost ip6-localhost ip6-loopback" >> /tmp/hosts + echo "ff02::1 ip6-allnodes" >> /tmp/hosts + echo "ff02::2 ip6-allrouters" >> /tmp/hosts + echo "" >> /tmp/hosts + echo "127.0.1.1 ${HOSTNAME}" >> /tmp/hosts +fi \ No newline at end of file diff --git a/kiosk_skeleton/usr/bin/kiosk-watchdog b/kiosk_skeleton/usr/bin/kiosk-watchdog new file mode 100644 index 0000000..1314dac --- /dev/null +++ b/kiosk_skeleton/usr/bin/kiosk-watchdog @@ -0,0 +1,33 @@ +#!/usr/bin/env php + $config["watchdog"]["timeout"]) + { + error_log("Exceeded timeout! Restarting lightdm."); + exec("systemctl restart lightdm"); + // Cooldown delay (give the system time to reinitialize) + sleep(60); + } + if ((time() - $last_heartbeat) > $config["watchdog"]["timeout_reboot"]) + { + error_log("Exceeded timeout_reboot! Rebooting system."); + exec("reboot"); + } + + sleep(5); + } + } +} \ No newline at end of file diff --git a/kiosk_skeleton/usr/bin/kiosk-wifi b/kiosk_skeleton/usr/bin/kiosk-wifi new file mode 100755 index 0000000..941f806 --- /dev/null +++ b/kiosk_skeleton/usr/bin/kiosk-wifi @@ -0,0 +1,27 @@ +#!/bin/bash + +if [ -f "/boot/wpa_supplicant.conf" ]; then + ln -s /boot/wpa_supplicant.conf /tmp/wpa_supplicant.conf + exit +fi + +WIFI_SSID=$(get-ini /boot/kioskbrowser.ini wifi ssid) +WIFI_PSK=$(get-ini /boot/kioskbrowser.ini wifi psk) +WIFI_COUNTRY=$(get-ini /boot/kioskbrowser.ini wifi country) + +if [ -n "${WIFI_SSID}" ] +then + echo "country=${WIFI_COUNTRY}" > /tmp/wpa_supplicant.conf + echo "ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev" >> /tmp/wpa_supplicant.conf + echo "update_config=1" >> /tmp/wpa_supplicant.conf + echo "network={" >> /tmp/wpa_supplicant.conf + echo " ssid=\"${WIFI_SSID}\"" >> /tmp/wpa_supplicant.conf + if [ -n "${WIFI_PSK}" ] + then + echo " psk=\"${WIFI_PSK}\"" >> /tmp/wpa_supplicant.conf + else + echo " key_mgmt=NONE" >> /tmp/wpa_supplicant.conf + fi + echo "}" >> /tmp/wpa_supplicant.conf +fi + diff --git a/kiosk_skeleton/var/www/html/heartbeat.php b/kiosk_skeleton/var/www/html/heartbeat.php new file mode 100644 index 0000000..9429479 --- /dev/null +++ b/kiosk_skeleton/var/www/html/heartbeat.php @@ -0,0 +1,8 @@ +Kioskbrowser + +CPU temperature:
+ +
+CPU voltage:
+ +
+Throttling status (everything except 0x0 means throttling, get a better power supply!):
+ +
+Last heartbeat: + +
+ +

+ \ No newline at end of file diff --git a/kiosk_skeleton/var/www/html/screenshot.php b/kiosk_skeleton/var/www/html/screenshot.php new file mode 100644 index 0000000..c014a45 --- /dev/null +++ b/kiosk_skeleton/var/www/html/screenshot.php @@ -0,0 +1,3 @@ +&1"); diff --git a/raspberry_pi_skeleton/boot/cmdline.txt b/raspberry_pi_skeleton/boot/cmdline.txt new file mode 100644 index 0000000..c09b787 --- /dev/null +++ b/raspberry_pi_skeleton/boot/cmdline.txt @@ -0,0 +1 @@ +console=serial0,115200 console=tty1 root=PARTUUID=544c6228-02 rootfstype=ext4 ro rootwait quiet \ No newline at end of file diff --git a/raspberry_pi_skeleton/boot/config.txt b/raspberry_pi_skeleton/boot/config.txt new file mode 100755 index 0000000..56c8dfb --- /dev/null +++ b/raspberry_pi_skeleton/boot/config.txt @@ -0,0 +1,55 @@ +#hdmi_safe=1 + +#overscan_left=16 +#overscan_right=16 +#overscan_top=16 +#overscan_bottom=16 + +# uncomment to force a console size. By default it will be display's size minus +# overscan. +#framebuffer_width=1280 +#framebuffer_height=720 + +# uncomment if hdmi display is not detected and composite is being output +#hdmi_force_hotplug=1 + +# uncomment to force a specific HDMI mode (this will force VGA) +#hdmi_group=1 +#hdmi_mode=1 + +# uncomment to force a HDMI mode rather than DVI. This can make audio work in +# DMT (computer monitor) modes +#hdmi_drive=2 + +# uncomment to increase signal to HDMI, if you have interference, blanking, or +# no display +#config_hdmi_boost=4 + +enable_uart=1 +disable_splash=1 +dtparam=audio=on +gpu_mem=128 + +# Enable DRM VC4 V3D driver +dtoverlay=vc4-kms-v3d +max_framebuffers=2 + +# Run in 64-bit mode +arm_64bit=1 + +# Disable compensation for displays with overscan +disable_overscan=1 + +[cm4] +# Enable host mode on the 2711 built-in XHCI USB controller. +# This line should be removed if the legacy DWC2 controller is required +# (e.g. for USB device mode) or if USB support is not required. +otg_mode=1 + +[all] + +[pi4] +# Run as fast as firmware / board allows +arm_boost=1 + +[all] diff --git a/raspberry_pi_skeleton/boot/kioskbrowser.ini b/raspberry_pi_skeleton/boot/kioskbrowser.ini new file mode 100644 index 0000000..eb24179 --- /dev/null +++ b/raspberry_pi_skeleton/boot/kioskbrowser.ini @@ -0,0 +1,43 @@ +; KioskBrowser configuration file +[general] +hostname = "kioskpi" + +[screen] +; can be used to force 1080p on 4k screens or workaround broken EDID communication +;force_resolution = "1920x1080" + +[wifi] +; If you need more complex WiFi settings (like WPA2-Enterprise, hidden SSIDs, etc.) +; create a file called wpa_supplicant.conf on this partition. +country=DE +; Leave SSID empty to disable WiFi +ssid="My WiFi" +; Leave PSK empty (or comment) to use an open network +psk="My Passphrase" + +[browser] +url="https://tbspace.de/" +; clear the browser cache every 10 minutes +cache_clear_interval=600 + +[watchdog] +; The watchdog can be used to ensure that a website is always being displayed (and JS is running). +; Javascript needs to send regular XHR/AJAX/etc. requests to http://localhost/heartbeat.php +enabled=0 +; Seconds until the browser is restarted (to fix problems like error pages being displayed, temporary connection problems) +timeout=60 +; Seconds until the whole computer is restarted (to fix worse issues like crashed firmware, lost time sync, broken certificates, etc.) +timeout_reboot=600 + +[vnc] +; VNC is pretty insecure, so it's always bound to localhost. Use an SSH tunnel to connect via VNC. +enabled=0 + +[autossh] +; autossh can be used to keep a connection to a specified SSH server up-and-running to allow for remote access +; without the need for port forwarding, public IPv4 addressing, dynamic DNS, etc. +enabled=0 +args = "-p 22 -R 1234:127.0.0.1:22 tunnel@mydomain.de" +; security warning: ensure sshd_config "GatewayPorts" is set to "clientspecified" or "no". +; GatewayPorts=yes will cause the kioskpi to be globally bound (0.0.0.0, regardless of the bind-address specified above) and be reachable from the internet! +; This might be a huge risk. diff --git a/raspberry_pi_skeleton/boot/ssh b/raspberry_pi_skeleton/boot/ssh new file mode 100644 index 0000000..e69de29 diff --git a/raspberry_pi_skeleton/raspberry_pi_bullseye.sh b/raspberry_pi_skeleton/raspberry_pi_bullseye.sh new file mode 100755 index 0000000..ebec211 --- /dev/null +++ b/raspberry_pi_skeleton/raspberry_pi_bullseye.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +echo > /etc/apt/sources.list +echo "deb http://deb.debian.org/debian bookworm main contrib non-free" >> /etc/apt/sources.list +echo "deb http://security.debian.org/debian-security bookworm-security main contrib non-free" >> /etc/apt/sources.list +echo "deb http://deb.debian.org/debian bookworm-updates main contrib non-free" >> /etc/apt/sources.list + +apt update +APT_LISTCHANGES_FRONTEND=none DEBIAN_FRONTEND=noninteractive apt -o Dpkg::Options::="--force-confold" -f -y dist-upgrade diff --git a/raspberry_pi_skeleton/var/lib/systemd/rfkill/platform-3f300000.mmcnr:wlan b/raspberry_pi_skeleton/var/lib/systemd/rfkill/platform-3f300000.mmcnr:wlan new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/raspberry_pi_skeleton/var/lib/systemd/rfkill/platform-3f300000.mmcnr:wlan @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/raspberry_pi_skeleton/var/lib/systemd/rfkill/platform-fe300000.mmcnr:wlan b/raspberry_pi_skeleton/var/lib/systemd/rfkill/platform-fe300000.mmcnr:wlan new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/raspberry_pi_skeleton/var/lib/systemd/rfkill/platform-fe300000.mmcnr:wlan @@ -0,0 +1 @@ +0 \ No newline at end of file