#!/bin/sh # Exit immediately if a command exits with a non-zero status. # We disable this ('+e') temporarily during the nomodeset check. set -u # --- Configuration --- # Set the URL you want the signage to display KIOSK_URL="https://example.com" # Set the user account to run the signage under SIGNAGE_USER="signage" # WayVNC Configuration # The script will create a ~/.profile for the SIGNAGE_USER # where this variable can be set. # For better security, leave it blank here and edit ~/.profile manually after setup. WAYVNC_PASSWORD_TO_SET="" # Example: "your_secure_password" WAYVNC_LISTEN_ADDRESS="0.0.0.0" # Listen on all interfaces WAYVNC_PORT="5900" # Default VNC port # --- End Configuration --- echo "Starting Alpine Linux Signage Setup (Using Sway, greetd, WayVNC)..." echo "Target URL: $KIOSK_URL" echo "Signage User: $SIGNAGE_USER" echo "WayVNC will listen on: $WAYVNC_LISTEN_ADDRESS:$WAYVNC_PORT" echo "-------------------------------------" # 1. Check if running as root if [ "$(id -u)" -ne 0 ]; then echo "ERROR: This script must be run as root" 1>&2 exit 1 fi # 2. Check for 'nomodeset' kernel parameter (early check) set +e # Temporarily disable exit-on-error KERNEL_CMDLINE=$(cat /proc/cmdline) echo "[Step 1/13] Checking kernel command line for 'nomodeset'..." echo "Command line: $KERNEL_CMDLINE" if echo "$KERNEL_CMDLINE" | grep -q -w 'nomodeset'; then echo "" echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" echo "!! WARNING: Kernel parameter 'nomodeset' detected in /proc/cmdline!" echo "!! This PREVENTS Wayland compositors (like Sway) from working correctly with DRM." echo "!! You MUST remove 'nomodeset' from your bootloader configuration" echo "!! (e.g., /etc/default/grub or /boot/extlinux.conf) and update/reboot" echo "!! for the graphical kiosk to function." echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" echo "" else echo "'nomodeset' not found. Proceeding..." fi set -e # Re-enable exit-on-error echo "-------------------------------------" # 3. Update repositories echo "[Step 2/13] Updating package repositories..." apk update echo "-------------------------------------" # 4. Setup base Wayland environment (includes enabling community repo) echo "[Step 3/13] Setting up base Wayland environment (elogind, eudev)..." apk add --no-cache alpine-conf setup-wayland-base # This enables community repository echo "-------------------------------------" # 5. Install necessary packages echo "[Step 4/13] Installing Sway, Chromium, Mesa, D-Bus, Fonts, Firmware, Greetd, WayVNC, swaybg, open-vm-tools..." apk add \ sway \ swayidle \ swaybg \ wl-clipboard \ xwayland \ chromium \ mesa-dri-gallium \ mesa-va-gallium \ mesa-egl \ dbus \ font-dejavu \ ttf-freefont \ util-linux \ linux-firmware \ greetd \ greetd-agreety \ wayvnc \ open-vm-tools # open-vm-tools-desktop has been removed echo "-------------------------------------" # 6. Enable & Start D-Bus service echo "[Step 5/13] Enabling and starting D-Bus service..." if ! rc-service dbus status > /dev/null 2>&1; then rc-update add dbus default rc-service dbus start else echo "D-Bus service already running or enabled." fi echo "-------------------------------------" # 7. Enable & Start open-vm-tools service (if installed) echo "[Step 6/13] Enabling and starting open-vm-tools service..." if apk info --installed open-vm-tools > /dev/null 2>&1; then if ! rc-service open-vm-tools status > /dev/null 2>&1; then echo "Enabling open-vm-tools service..." rc-update add open-vm-tools default echo "Starting open-vm-tools service..." rc-service open-vm-tools start else echo "open-vm-tools service already running or enabled." fi else echo "open-vm-tools not installed, skipping service setup." fi echo "-------------------------------------" # 8. Create the signage user and add to necessary groups echo "[Step 7/13] Creating signage user '$SIGNAGE_USER' and configuring groups..." if ! id -u "$SIGNAGE_USER" >/dev/null 2>&1; then echo "Creating group '$SIGNAGE_USER' (for primary group)..." addgroup "$SIGNAGE_USER" # Ensure primary group exists echo "Creating user '$SIGNAGE_USER' with shell /bin/sh..." # -D: no password, don't expire # -G group: add user to primary group 'group'. Uses existing or creates if not. adduser -D -G "$SIGNAGE_USER" -s /bin/sh -h "/home/$SIGNAGE_USER" "$SIGNAGE_USER" echo "Adding user '$SIGNAGE_USER' to 'video' supplementary group..." addgroup "$SIGNAGE_USER" video echo "Adding user '$SIGNAGE_USER' to 'input' supplementary group..." addgroup "$SIGNAGE_USER" input echo "User '$SIGNAGE_USER' created and added to video/input groups." else echo "User '$SIGNAGE_USER' already exists. Ensuring shell is /bin/sh and group memberships..." usermod -s /bin/sh "$SIGNAGE_USER" # Ensure primary group exists (original script's safeguard) if ! getent group "$SIGNAGE_USER" >/dev/null 2>&1; then echo "Primary group '$SIGNAGE_USER' not found, creating it." addgroup "$SIGNAGE_USER" # If primary group was missing, ensure user is member. # This typically means user's GID needs to be updated with usermod -g if primary group was truly lost and recreated. # For now, just ensuring membership in the group by name. if ! groups "$SIGNAGE_USER" | grep -q -w "$SIGNAGE_USER"; then addgroup "$SIGNAGE_USER" "$SIGNAGE_USER" fi fi echo "Ensuring $SIGNAGE_USER is in 'video' supplementary group..." if ! groups "$SIGNAGE_USER" | grep -q -w video; then addgroup "$SIGNAGE_USER" video echo "$SIGNAGE_USER added to 'video'." else echo "$SIGNAGE_USER already in 'video'." fi echo "Ensuring $SIGNAGE_USER is in 'input' supplementary group..." if ! groups "$SIGNAGE_USER" | grep -q -w input; then addgroup "$SIGNAGE_USER" input echo "$SIGNAGE_USER added to 'input'." else echo "$SIGNAGE_USER already in 'input'." fi fi SIGNAGE_HOME="/home/$SIGNAGE_USER" if [ ! -d "$SIGNAGE_HOME" ]; then echo "Creating home directory '$SIGNAGE_HOME'..." mkdir -p "$SIGNAGE_HOME" fi chown "$SIGNAGE_USER:$SIGNAGE_USER" "$SIGNAGE_HOME" chmod 750 "$SIGNAGE_HOME" # Create user's .local/share directory for logs SIGNAGE_LOCAL_SHARE="$SIGNAGE_HOME/.local/share" mkdir -p "$SIGNAGE_LOCAL_SHARE/sway" # For sway logs chown -R "$SIGNAGE_USER:$SIGNAGE_USER" "$SIGNAGE_HOME/.local" chmod 700 "$SIGNAGE_HOME/.local" # Restrict access chmod 700 "$SIGNAGE_LOCAL_SHARE" chmod 700 "$SIGNAGE_LOCAL_SHARE/sway" echo "-------------------------------------" # 9. Configure user's .profile for WayVNC password and other environment variables echo "[Step 8/13] Configuring $SIGNAGE_HOME/.profile for $SIGNAGE_USER..." SIGNAGE_PROFILE="$SIGNAGE_HOME/.profile" cat > "$SIGNAGE_PROFILE" << EOF # Profile for $SIGNAGE_USER executed by /bin/sh on login # --- WayVNC Configuration --- # IMPORTANT: Set a strong password for WayVNC if it's accessible from untrusted networks. # Uncomment and set your password: # export WAYVNC_PASSWORD="your_very_secure_password_here" EOF if [ -n "$WAYVNC_PASSWORD_TO_SET" ]; then echo "export WAYVNC_PASSWORD=\"$WAYVNC_PASSWORD_TO_SET\"" >> "$SIGNAGE_PROFILE" echo "WAYVNC_PASSWORD has been pre-set in $SIGNAGE_PROFILE. Review for security." else echo "INFO: WAYVNC_PASSWORD is not set. Edit $SIGNAGE_PROFILE to set it for WayVNC security." fi cat >> "$SIGNAGE_PROFILE" << EOF # --- Other Environment Variables (optional) --- # export XDG_CURRENT_DESKTOP=sway # Sway usually sets this # export MOZ_ENABLE_WAYLAND=1 # For Firefox, if used # export QT_QPA_PLATFORM=wayland # For Qt apps, if used # export ECORE_EVAS_ENGINE=wayland_shm # For EFL apps # export ELM_ACCEL=wayland # export SDL_VIDEODRIVER=wayland # export _JAVA_AWT_WM_NONREPARENTING=1 EOF chown "$SIGNAGE_USER:$SIGNAGE_USER" "$SIGNAGE_PROFILE" chmod 600 "$SIGNAGE_PROFILE" # User read/write only echo "-------------------------------------" # 10. Configure Sway echo "[Step 9/13] Configuring Sway..." SIGNAGE_CONFIG_DIR="$SIGNAGE_HOME/.config" SIGNAGE_SWAY_CONFIG_DIR="$SIGNAGE_CONFIG_DIR/sway" SIGNAGE_SWAY_CONFIG_FILE="$SIGNAGE_SWAY_CONFIG_DIR/config" echo "Creating Sway configuration directories..." mkdir -p "$SIGNAGE_SWAY_CONFIG_DIR" chown -R "$SIGNAGE_USER:$SIGNAGE_USER" "$SIGNAGE_CONFIG_DIR" || true chmod 700 "$SIGNAGE_CONFIG_DIR" # Restrict access chmod 700 "$SIGNAGE_SWAY_CONFIG_DIR" echo "Creating $SIGNAGE_SWAY_CONFIG_FILE..." cat > "$SIGNAGE_SWAY_CONFIG_FILE" << EOF # Sway configuration for Alpine Signage Kiosk # --- Basic Setup --- # Set the Super key as the modifier set \$mod Mod4 # Set default font font pango:DejaVu Sans Mono 10 # --- Output Configuration --- # Explicitly enable all outputs and set power state to on # This is important for ensuring the display activates correctly at boot. output * enable output * power on # The old 'output * dpms off' command is equivalent to 'output * power on'. # Adding 'output * enable' provides an extra layer of assurance. # To set a specific mode for an output (name from 'swaymsg -t get_outputs'): # output Virtual-1 mode 1280x800@60hz # Optional: set a background if swaybg is installed # output * bg /usr/share/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png fill # --- Input Configuration --- # Hide mouse cursor after 1000ms (1 second) of inactivity seat * hide_cursor 1000 # Alternative: always hide (uncomment below, comment line above) # seat * hide_cursor always # --- Autostart Applications --- # Chromium in Kiosk Mode # --disable-gpu is added as a safe default, especially for VMs. # Remove --disable-gpu if you confirm hardware acceleration works correctly. exec /usr/bin/chromium \\ --enable-features=UseOzonePlatform \\ --ozone-platform=wayland \\ --kiosk \\ --no-first-run \\ --disable-infobars \\ --disable-session-crashed-bubble \\ --disable-component-update \\ --disable-pinch \\ --app=$KIOSK_URL \\ --no-sandbox \\ --password-store=basic \\ --enable-zero-copy \\ --ignore-gpu-blocklist \\ --disable-gpu # --enable-unsafe-webgpu # --disable-gpu-vsync # --user-data-dir=/home/$SIGNAGE_USER/.config/chromium-kiosk # WayVNC for remote access # Password should be set via WAYVNC_PASSWORD environment variable (see ~/.profile) exec wayvnc --render-cursor $WAYVNC_LISTEN_ADDRESS $WAYVNC_PORT # --- Keybindings (Minimal, mostly for debugging) --- # Kill focused window bindsym \$mod+Shift+q kill # Reload sway config bindsym \$mod+Shift+c reload # Exit sway (logs out the user) bindsym \$mod+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end the kiosk session.' -B 'Yes, exit sway' 'swaymsg exit' # --- General Settings --- focus_follows_mouse no mouse_warping output EOF chown "$SIGNAGE_USER:$SIGNAGE_USER" "$SIGNAGE_SWAY_CONFIG_FILE" chmod 600 "$SIGNAGE_SWAY_CONFIG_FILE" # User read/write only echo "-------------------------------------" # 11. Configure greetd for Autologin and Sway Session echo "[Step 10/13] Configuring greetd..." GREETD_CONFIG_DIR="/etc/greetd" GREETD_CONFIG_FILE="$GREETD_CONFIG_DIR/config.toml" mkdir -p "$GREETD_CONFIG_DIR" SWAY_LOG_PATH_IN_GREETD="$SIGNAGE_LOCAL_SHARE/sway/sway-greetd.log" cat > "$GREETD_CONFIG_FILE" << EOF # Greetd configuration for signage kiosk with Sway [terminal] vt = 1 [default_session] user = "$SIGNAGE_USER" # Launch sway via dbus-run-session. User's .profile will be sourced. # Sway debug logs (-d) are redirected. -V (version) is also included. command = "/usr/bin/dbus-run-session /usr/bin/sway -V -d 2> $SWAY_LOG_PATH_IN_GREETD" # Simpler alternative if log redirection is problematic (logs go to greetd's output): # command = "/usr/bin/dbus-run-session /usr/bin/sway" EOF chmod 644 "$GREETD_CONFIG_FILE" echo "greetd config written to $GREETD_CONFIG_FILE" echo "Ensure $SIGNAGE_USER can write to $SWAY_LOG_PATH_IN_GREETD." echo "-------------------------------------" # 12. Configure inittab to start greetd echo "[Step 11/13] Configuring autologin via greetd in /etc/inittab..." if [ -f "/etc/inittab" ]; then if [ ! -f "/etc/inittab.bak.signage" ]; then # Create backup only once cp /etc/inittab /etc/inittab.bak.signage echo "Backed up /etc/inittab to /etc/inittab.bak.signage" fi echo "Commenting out ttys 2-6 in /etc/inittab..." sed -i -e '/^tty[2-6]:/s/^/#/' /etc/inittab echo "Modifying tty1 entry in /etc/inittab to start greetd..." GREETD_INITTAB_LINE="tty1::respawn:/usr/sbin/greetd" if grep -q "^tty1::respawn:" /etc/inittab && ! grep -Fxq "$GREETD_INITTAB_LINE" /etc/inittab; then sed -i "s|^tty1::respawn:.*|$GREETD_INITTAB_LINE|" /etc/inittab elif ! grep -Fxq "$GREETD_INITTAB_LINE" /etc/inittab; then echo "$GREETD_INITTAB_LINE" >> /etc/inittab echo "Added greetd line to /etc/inittab (fallback)." else echo "greetd line already seems to be present in /etc/inittab." fi else echo "Warning: /etc/inittab not found. Cannot configure greetd startup for sysvinit." fi echo "-------------------------------------" # 13. Attempt to Enable elogind PAM module for session management echo "[Step 12/13] Attempting to configure PAM for elogind session..." PAM_GREETD_FILE="/etc/pam.d/greetd" PAM_SYSTEM_LOGIN="/etc/pam.d/system-login" PAM_SYSTEM_AUTH="/etc/pam.d/system-auth" PAM_TARGET_FILE="" PAM_MODULE="pam_elogind.so" if [ -f "$PAM_GREETD_FILE" ]; then PAM_TARGET_FILE="$PAM_GREETD_FILE" elif [ -f "$PAM_SYSTEM_LOGIN" ]; then PAM_TARGET_FILE="$PAM_SYSTEM_LOGIN" elif [ -f "$PAM_SYSTEM_AUTH" ]; then PAM_TARGET_FILE="$PAM_SYSTEM_AUTH" fi if [ -n "$PAM_TARGET_FILE" ]; then echo "Using $PAM_TARGET_FILE for PAM configuration." if ! grep -q "$PAM_MODULE" "$PAM_TARGET_FILE"; then echo "Adding '$PAM_MODULE' to $PAM_TARGET_FILE..." if [ ! -f "$PAM_TARGET_FILE.bak.signage" ]; then cp "$PAM_TARGET_FILE" "$PAM_TARGET_FILE.bak.signage" echo "Backed up $PAM_TARGET_FILE to $PAM_TARGET_FILE.bak.signage" fi # Add pam_elogind.so after the first 'session' line, or as the first session line if none exist if grep -q "^session" "$PAM_TARGET_FILE"; then awk '/^session/{if(!p++) print; print "session optional pam_elogind.so"; next} 1' "$PAM_TARGET_FILE" > "$PAM_TARGET_FILE.tmp" && mv "$PAM_TARGET_FILE.tmp" "$PAM_TARGET_FILE" else echo "session optional pam_elogind.so" >> "$PAM_TARGET_FILE" # Fallback if no session lines fi echo "PAM module added." else echo "'$PAM_MODULE' already present in $PAM_TARGET_FILE." fi else echo "Warning: Could not find suitable PAM file (greetd, system-login, system-auth) to modify." echo " System relies on default PAM includes for elogind session setup." fi echo "-------------------------------------" echo "[Step 13/13] Final checks and information." echo "-----------------------------------------------------" echo " Alpine Linux Signage Setup Script Finished!" echo "-----------------------------------------------------" echo " SUMMARY:" echo " * Packages installed (Sway, Chromium, Greetd, WayVNC, open-vm-tools etc.)." echo " * User '$SIGNAGE_USER' created/configured with shell /bin/sh and added to 'video' and 'input' groups." echo " * Sway configured in $SIGNAGE_SWAY_CONFIG_FILE." echo " -> Output explicitly enabled, power state set to ON." echo " -> Chromium will start with --disable-gpu. Edit this file to change." echo " -> Mouse cursor configured to hide after 1s inactivity." echo " * WayVNC configured to launch via Sway, listening on $WAYVNC_LISTEN_ADDRESS:$WAYVNC_PORT." echo " * IMPORTANT: WayVNC password MUST be set in $SIGNAGE_PROFILE for security." echo " * Autologin configured via greetd ($GREETD_CONFIG_FILE)." echo " * /etc/inittab modified to launch greetd on tty1." echo " * Attempted to configure PAM for elogind." echo " * open-vm-tools service enabled (if applicable, open-vm-tools-desktop was NOT installed)." echo "" echo " !!! IMPORTANT !!!" echo " * If you saw a WARNING about 'nomodeset' earlier, the graphical kiosk" echo " WILL NOT WORK until you remove 'nomodeset' from your bootloader config and reboot." echo " * For WayVNC to be secure, you MUST set a strong WAYVNC_PASSWORD" echo " in $SIGNAGE_HOME/.profile for the user $SIGNAGE_USER." echo " Example: echo 'export WAYVNC_PASSWORD=\"your_secure_password\"' >> $SIGNAGE_HOME/.profile" echo " * Chromium is launched with --disable-gpu. If you have working 3D acceleration" echo " (especially on bare metal or with robust VM drivers), you can try removing" echo " this flag from $SIGNAGE_SWAY_CONFIG_FILE for better performance." echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" echo "" echo " Please REBOOT the system for changes to take effect." echo " Command: reboot" echo "" echo " TROUBLESHOOTING AFTER REBOOT (if it doesn't work):" echo " 1. Log in as root on TTY2 (Alt+F2) or SSH." echo " 2. Check greetd logs: grep greetd /var/log/messages | tail -n 20" echo " 3. Check Sway log: cat $SWAY_LOG_PATH_IN_GREETD" echo " 4. Check Sway config syntax (as root, or as user if paths adjusted):" echo " su - $SIGNAGE_USER -c \"export XDG_RUNTIME_DIR=/run/user/\$(id -u $SIGNAGE_USER) && sway -C -c $SIGNAGE_SWAY_CONFIG_FILE\"" echo " 5. Check XDG_RUNTIME_DIR: ls -ld /run/user/\$(id -u $SIGNAGE_USER)" echo " 6. Check services: rc-service elogind status && rc-service dbus status && rc-service open-vm-tools status" echo " 7. Check inittab: grep ^tty1 /etc/inittab" echo " 8. Check dmesg: dmesg | tail -n 50" echo " 9. Verify Chromium flags in: cat $SIGNAGE_SWAY_CONFIG_FILE" echo "10. Check WayVNC: ps aux | grep wayvnc ; netstat -tulnp | grep :$WAYVNC_PORT" echo " Ensure WAYVNC_PASSWORD is set in $SIGNAGE_PROFILE" echo "11. Manually test Sway as $SIGNAGE_USER on TTY2 (stop greetd first: rc-service greetd stop):" echo " su - $SIGNAGE_USER -c \"dbus-run-session sway -d\"" echo "12. Check user groups: groups $SIGNAGE_USER (should include 'video' and 'input')" echo "-----------------------------------------------------" exit 0