From c93cc31d5714346ca61b8585c550919b06ddc859 Mon Sep 17 00:00:00 2001 From: billy Date: Wed, 1 Oct 2025 10:27:51 +0800 Subject: [PATCH 1/5] fix: nvidia-container-toolkit missing files when mounting to Docker Because NVIDIA never does it correctly, we have to do this ourselves. - NVIDIA doesn't provide DRI3 support - NVIDIA never fixes this issue properly - NVIDIA likes to do things their own way - Top 3 public clouds are obsessed with NVIDIA, so we have no choice but to support it Ported from: https://github.com/selkies-project/docker-selkies-egl-desktop/blob/8dd03fba2a33ac774d61f46375a19ed1d9c5b51a/Dockerfile#L248-L264 --- root/etc/s6-overlay/s6-rc.d/init-video/run | 45 ++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/root/etc/s6-overlay/s6-rc.d/init-video/run b/root/etc/s6-overlay/s6-rc.d/init-video/run index aaf9dfd7..b75f8e72 100755 --- a/root/etc/s6-overlay/s6-rc.d/init-video/run +++ b/root/etc/s6-overlay/s6-rc.d/init-video/run @@ -33,3 +33,48 @@ do fi fi done + +# check if nvidia gpu is present +if which nvidia-smi >/dev/null 2>&1; then + # nvidia-container-toolkit may not place files correctly, so we set them up here + echo "**** NVIDIA GPU detected ****" + + OPENCL_ICDS=$(find /etc/OpenCL/vendors -name '*nvidia*.icd' 2>/dev/null) + # if no opencl icd found + if [ -z "${OPENCL_ICDS}" ]; then + echo "**** Setting up OpenCL ICD for NVIDIA ****" + mkdir -pm755 /etc/OpenCL/vendors/ + echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd + fi + + # find vulkan icds + ICDS=$(find /usr/share/vulkan/icd.d /etc/vulkan/icd.d -name '*nvidia*.json' 2>/dev/null) + # if no icd found + if [ -z "${ICDS}" ]; then + echo "**** Setting up Vulkan ICD for NVIDIA ****" + # get vulkan api version + VULKAN_API_VERSION=$(ldconfig -p | grep "libvulkan.so" | awk '{print $NF}' | xargs readlink | grep -oE "[0-9]+\.[0-9]+\.[0-9]+") + mkdir -pm755 /etc/vulkan/icd.d/ + echo "{\n\ + \"file_format_version\" : \"1.0.0\",\n\ + \"ICD\": {\n\ + \"library_path\": \"libGLX_nvidia.so.0\",\n\ + \"api_version\" : \"${VULKAN_API_VERSION}\"\n\ + }\n\ +}" > /etc/vulkan/icd.d/nvidia_icd.json + fi + + # find glvnd egl_vendor files + EGLS=$(find /usr/share/glvnd/egl_vendor.d /etc/glvnd/egl_vendor.d -name '*nvidia*.json' 2>/dev/null) + # if no egl_vendor file found + if [ -z "${EGLS}" ]; then + echo "**** Setting up EGL vendor file for NVIDIA ****" + mkdir -pm755 /etc/glvnd/egl_vendor.d/ + echo "{\n\ + \"file_format_version\" : \"1.0.0\",\n\ + \"ICD\": {\n\ + \"library_path\": \"libEGL_nvidia.so.0\"\n\ + }\n\ +}" > /etc/glvnd/egl_vendor.d/10_nvidia.json + fi +fi From 4240d5bc2ed08b754931ce8a709e61d40e66c29d Mon Sep 17 00:00:00 2001 From: billy Date: Wed, 1 Oct 2025 11:28:17 +0800 Subject: [PATCH 2/5] fix: improve formatting for NVIDIA ICD and EGL vendor files --- root/etc/s6-overlay/s6-rc.d/init-video/run | 30 ++++++++++++---------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/root/etc/s6-overlay/s6-rc.d/init-video/run b/root/etc/s6-overlay/s6-rc.d/init-video/run index b75f8e72..e3ff2cba 100755 --- a/root/etc/s6-overlay/s6-rc.d/init-video/run +++ b/root/etc/s6-overlay/s6-rc.d/init-video/run @@ -55,13 +55,15 @@ if which nvidia-smi >/dev/null 2>&1; then # get vulkan api version VULKAN_API_VERSION=$(ldconfig -p | grep "libvulkan.so" | awk '{print $NF}' | xargs readlink | grep -oE "[0-9]+\.[0-9]+\.[0-9]+") mkdir -pm755 /etc/vulkan/icd.d/ - echo "{\n\ - \"file_format_version\" : \"1.0.0\",\n\ - \"ICD\": {\n\ - \"library_path\": \"libGLX_nvidia.so.0\",\n\ - \"api_version\" : \"${VULKAN_API_VERSION}\"\n\ - }\n\ -}" > /etc/vulkan/icd.d/nvidia_icd.json + cat > /etc/vulkan/icd.d/nvidia_icd.json << EOF +{ + "file_format_version" : "1.0.0", + "ICD": { + "library_path": "libGLX_nvidia.so.0", + "api_version" : "${VULKAN_API_VERSION}" + } +} +EOF fi # find glvnd egl_vendor files @@ -70,11 +72,13 @@ if which nvidia-smi >/dev/null 2>&1; then if [ -z "${EGLS}" ]; then echo "**** Setting up EGL vendor file for NVIDIA ****" mkdir -pm755 /etc/glvnd/egl_vendor.d/ - echo "{\n\ - \"file_format_version\" : \"1.0.0\",\n\ - \"ICD\": {\n\ - \"library_path\": \"libEGL_nvidia.so.0\"\n\ - }\n\ -}" > /etc/glvnd/egl_vendor.d/10_nvidia.json + cat > /etc/glvnd/egl_vendor.d/10_nvidia.json << EOF +{ + "file_format_version" : "1.0.0", + "ICD": { + "library_path": "libEGL_nvidia.so.0" + } +} +EOF fi fi From 9abc8e1201d66eec3abaf7d8ed650251e87575ed Mon Sep 17 00:00:00 2001 From: billy Date: Wed, 1 Oct 2025 11:59:07 +0800 Subject: [PATCH 3/5] fix: add fallback for Vulkan API version in NVIDIA setup --- root/etc/s6-overlay/s6-rc.d/init-video/run | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/root/etc/s6-overlay/s6-rc.d/init-video/run b/root/etc/s6-overlay/s6-rc.d/init-video/run index e3ff2cba..260bcb4b 100755 --- a/root/etc/s6-overlay/s6-rc.d/init-video/run +++ b/root/etc/s6-overlay/s6-rc.d/init-video/run @@ -54,6 +54,11 @@ if which nvidia-smi >/dev/null 2>&1; then echo "**** Setting up Vulkan ICD for NVIDIA ****" # get vulkan api version VULKAN_API_VERSION=$(ldconfig -p | grep "libvulkan.so" | awk '{print $NF}' | xargs readlink | grep -oE "[0-9]+\.[0-9]+\.[0-9]+") + # Fallback if pipeline fails + if [ -z "${VULKAN_API_VERSION}" ]; then + # version 1.1 or greater allows vulkan-loader to load the driver's dynamic library + VULKAN_API_VERSION="1.1.0" + fi mkdir -pm755 /etc/vulkan/icd.d/ cat > /etc/vulkan/icd.d/nvidia_icd.json << EOF { From c6c9726b08d0c5b36e86cfa26136c99bca60918a Mon Sep 17 00:00:00 2001 From: thelamer Date: Thu, 2 Oct 2025 09:47:48 -0400 Subject: [PATCH 4/5] add new container env vars and hardening setup bookworm --- Dockerfile | 38 +-- Dockerfile.aarch64 | 38 +-- README.md | 46 +++- readme-vars.yml | 46 +++- root/defaults/default.conf | 22 +- root/etc/s6-overlay/s6-rc.d/init-nginx/run | 42 +++- .../s6-rc.d/init-selkies-config/run | 236 +++++++++++++----- root/etc/s6-overlay/s6-rc.d/svc-de/run | 8 +- .../svc-watchdog/dependencies.d/init-services | 0 root/etc/s6-overlay/s6-rc.d/svc-watchdog/run | 32 +++ root/etc/s6-overlay/s6-rc.d/svc-watchdog/type | 1 + .../s6-rc.d/user/contents.d/svc-watchdog | 0 12 files changed, 388 insertions(+), 121 deletions(-) create mode 100644 root/etc/s6-overlay/s6-rc.d/svc-watchdog/dependencies.d/init-services create mode 100755 root/etc/s6-overlay/s6-rc.d/svc-watchdog/run create mode 100644 root/etc/s6-overlay/s6-rc.d/svc-watchdog/type create mode 100644 root/etc/s6-overlay/s6-rc.d/user/contents.d/svc-watchdog diff --git a/Dockerfile b/Dockerfile index 9cc6ce8d..af6e9958 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,24 +16,29 @@ RUN \ https://github.com/selkies-project/selkies.git \ /src && \ cd /src && \ - git checkout -f 89e39cf7d58c8f7c87ac5922b56b84f745ddeeab + git checkout -f 29466e687d2dbed57f657e47b69fab217a81ef1f RUN \ - echo "**** build frontend ****" && \ - cd /src && \ - cd addons/gst-web-core && \ - npm install && \ - npm run build && \ - cp dist/selkies-core.js ../selkies-dashboard/src && \ - cd ../selkies-dashboard && \ + echo "**** build shared core library ****" && \ + cd /src/addons/gst-web-core && \ npm install && \ npm run build && \ - mkdir dist/src dist/nginx && \ - cp ../universal-touch-gamepad/universalTouchGamepad.js dist/src/ && \ - cp ../gst-web-core/nginx/* dist/nginx/ && \ - cp -r ../gst-web-core/dist/jsdb dist/ && \ + echo "**** build multiple dashboards ****" && \ + DASHBOARDS="selkies-dashboard selkies-dashboard-zinc selkies-dashboard-wish" && \ mkdir /buildout && \ - cp -ar dist/* /buildout/ + for DASH in $DASHBOARDS; do \ + cd /src/addons/$DASH && \ + cp ../gst-web-core/dist/selkies-core.js src/ && \ + npm install && \ + npm run build && \ + mkdir -p dist/src dist/nginx && \ + cp ../gst-web-core/dist/selkies-core.js dist/src/ && \ + cp ../universal-touch-gamepad/universalTouchGamepad.js dist/src/ && \ + cp ../gst-web-core/nginx/* dist/nginx/ && \ + cp -r ../gst-web-core/dist/jsdb dist/ && \ + mkdir -p /buildout/$DASH && \ + cp -ar dist/* /buildout/$DASH/; \ + done # Runtime stage FROM ghcr.io/linuxserver/baseimage-debian:bookworm @@ -184,7 +189,7 @@ RUN \ | awk '/tag_name/{print $4;exit}' FS='[""]') && \ curl -o \ /tmp/selkies.tar.gz -L \ - "https://github.com/selkies-project/selkies/archive/89e39cf7d58c8f7c87ac5922b56b84f745ddeeab.tar.gz" && \ + "https://github.com/selkies-project/selkies/archive/29466e687d2dbed57f657e47b69fab217a81ef1f.tar.gz" && \ cd /tmp && \ tar xf selkies.tar.gz && \ cd selkies-* && \ @@ -226,6 +231,9 @@ RUN \ -e 's|| \n|' \ -e 's|4|1|' \ /etc/xdg/openbox/rc.xml && \ + sed -i \ + 's/--startup/--replace --startup/g' \ + /usr/bin/openbox-session && \ echo "**** user perms ****" && \ sed -e 's/%sudo ALL=(ALL:ALL) ALL/%sudo ALL=(ALL:ALL) NOPASSWD: ALL/g' \ -i /etc/sudoers && \ @@ -270,7 +278,7 @@ RUN \ # add local files COPY /root / -COPY --from=frontend /buildout /usr/share/selkies/www +COPY --from=frontend /buildout /usr/share/selkies COPY --from=xvfb / / # ports and volumes diff --git a/Dockerfile.aarch64 b/Dockerfile.aarch64 index 9a2c898d..c0ad14be 100644 --- a/Dockerfile.aarch64 +++ b/Dockerfile.aarch64 @@ -16,24 +16,29 @@ RUN \ https://github.com/selkies-project/selkies.git \ /src && \ cd /src && \ - git checkout -f 89e39cf7d58c8f7c87ac5922b56b84f745ddeeab + git checkout -f 29466e687d2dbed57f657e47b69fab217a81ef1f RUN \ - echo "**** build frontend ****" && \ - cd /src && \ - cd addons/gst-web-core && \ - npm install && \ - npm run build && \ - cp dist/selkies-core.js ../selkies-dashboard/src && \ - cd ../selkies-dashboard && \ + echo "**** build shared core library ****" && \ + cd /src/addons/gst-web-core && \ npm install && \ npm run build && \ - mkdir dist/src dist/nginx && \ - cp ../universal-touch-gamepad/universalTouchGamepad.js dist/src/ && \ - cp ../gst-web-core/nginx/* dist/nginx/ && \ - cp -r ../gst-web-core/dist/jsdb dist/ && \ + echo "**** build multiple dashboards ****" && \ + DASHBOARDS="selkies-dashboard selkies-dashboard-zinc selkies-dashboard-wish" && \ mkdir /buildout && \ - cp -ar dist/* /buildout/ + for DASH in $DASHBOARDS; do \ + cd /src/addons/$DASH && \ + cp ../gst-web-core/dist/selkies-core.js src/ && \ + npm install && \ + npm run build && \ + mkdir -p dist/src dist/nginx && \ + cp ../gst-web-core/dist/selkies-core.js dist/src/ && \ + cp ../universal-touch-gamepad/universalTouchGamepad.js dist/src/ && \ + cp ../gst-web-core/nginx/* dist/nginx/ && \ + cp -r ../gst-web-core/dist/jsdb dist/ && \ + mkdir -p /buildout/$DASH && \ + cp -ar dist/* /buildout/$DASH/; \ + done # Runtime stage FROM ghcr.io/linuxserver/baseimage-debian:arm64v8-bookworm @@ -182,7 +187,7 @@ RUN \ | awk '/tag_name/{print $4;exit}' FS='[""]') && \ curl -o \ /tmp/selkies.tar.gz -L \ - "https://github.com/selkies-project/selkies/archive/89e39cf7d58c8f7c87ac5922b56b84f745ddeeab.tar.gz" && \ + "https://github.com/selkies-project/selkies/archive/29466e687d2dbed57f657e47b69fab217a81ef1f.tar.gz" && \ cd /tmp && \ tar xf selkies.tar.gz && \ cd selkies-* && \ @@ -224,6 +229,9 @@ RUN \ -e 's|| \n|' \ -e 's|4|1|' \ /etc/xdg/openbox/rc.xml && \ + sed -i \ + 's/--startup/--replace --startup/g' \ + /usr/bin/openbox-session && \ echo "**** user perms ****" && \ sed -e 's/%sudo ALL=(ALL:ALL) ALL/%sudo ALL=(ALL:ALL) NOPASSWD: ALL/g' \ -i /etc/sudoers && \ @@ -268,7 +276,7 @@ RUN \ # add local files COPY /root / -COPY --from=frontend /buildout /usr/share/selkies/www +COPY --from=frontend /buildout /usr/share/selkies COPY --from=xvfb / / # ports and volumes diff --git a/README.md b/README.md index 40275895..b246128e 100644 --- a/README.md +++ b/README.md @@ -34,23 +34,51 @@ All application settings are passed via environment variables: | CUSTOM_USER | HTTP Basic auth username, abc is default. | | PASSWORD | HTTP Basic auth password, abc is default. If unset there will be no auth | | SUBFOLDER | Subfolder for the application if running a subfolder reverse proxy, need both slashes IE `/subfolder/` | -| TITLE | The page title displayed on the web browser, default "Selkies - webrtc". | +| TITLE | The page title displayed on the web browser, default "Selkies". | +| DASHBOARD | Allows the user to set their dashboard. Options: `selkies-dashboard`, `selkies-dashboard-zinc`, `selkies-dashboard-wish`. | +| FILE_MANAGER_PATH | Modifies the default upload/download file path, path must have proper permissions for abc user. | | START_DOCKER | If set to false a container with privilege will not automatically start the DinD Docker setup. | | DISABLE_IPV6 | If set to true or any value this will disable IPv6 | | LC_ALL | Set the Language for the container to run as IE `fr_FR.UTF-8` `ar_AE.UTF-8` | | NO_DECOR | If set the application will run without window borders for use as a PWA. (Decor can be enabled and disabled with Ctrl+Shift+d) | | NO_FULL | Do not autmatically fullscreen applications when using openbox. | | DISABLE_ZINK | Do not set the Zink environment variables if a video card is detected (userspace applications will use CPU rendering) | +| MAX_RES | Pass a larger maximum resolution for the container default is 16k `15360x8640` | | WATERMARK_PNG | Full path inside the container to a watermark png IE `/usr/share/selkies/www/icon.png` | | WATERMARK_LOCATION | Where to paint the image over the stream integer options below | -| MAX_RES | Pass a larger maximum resolution for the container default is 16k `15360x8640` | -* 1 - Top Left -* 2 - Top Right -* 3 - Bottom Left -* 4 - Bottom Right -* 5 - Centered -* 6 - Animated +**`WATERMARK_LOCATION` Options:** +- **1**: Top Left +- **2**: Top Right +- **3**: Bottom Left +- **4**: Bottom Right +- **5**: Centered +- **6**: Animated + +## Hardening + +These variables can be used to lock down the desktop environment for single-application use cases or to restrict user capabilities. + +### Meta Variables + +These variables act as presets, enabling multiple hardening options at once. Individual options can still be set to override the preset. + +| Variable | Description | +| :----: | --- | +| **`HARDEN_DESKTOP`** | Enables `DISABLE_OPEN_TOOLS`, `DISABLE_SUDO`, and `DISABLE_TERMINALS`. Also sets related Selkies UI settings (`SELKIES_FILE_TRANSFERS`, `SELKIES_COMMAND_ENABLED`, `SELKIES_UI_SIDEBAR_SHOW_FILES`, `SELKIES_UI_SIDEBAR_SHOW_APPS`) if they are not explicitly set by the user. | +| **`HARDEN_OPENBOX`** | Enables `DISABLE_CLOSE_BUTTON`, `DISABLE_MOUSE_BUTTONS`, and `HARDEN_KEYBINDS`. It also flags `RESTART_APP` if not set by the user, ensuring the primary application is automatically restarted if closed. | + +### Individual Hardening Variables + +| Variable | Description | +| :--- | --- | +| **`DISABLE_OPEN_TOOLS`** | If true, disables `xdg-open` and `exo-open` binaries by removing their execute permissions. | +| **`DISABLE_SUDO`** | If true, disables the `sudo` command by removing its execute permissions and invalidating the passwordless sudo configuration. | +| **`DISABLE_TERMINALS`** | If true, disables common terminal emulators by removing their execute permissions and hiding them from the Openbox right-click menu. | +| **`DISABLE_CLOSE_BUTTON`** | If true, removes the close button from window title bars in the Openbox window manager. | +| **`DISABLE_MOUSE_BUTTONS`** | If true, disables the right-click and middle-click context menus and actions within the Openbox window manager. | +| **`HARDEN_KEYBINDS`** | If true, disables default Openbox keybinds that can bypass other hardening options (e.g., `Alt+F4` to close windows, `Alt+Escape` to show the root menu). | +| **`RESTART_APP`** | If true, enables a watchdog service that automatically restarts the main application if it is closed. The user's autostart script is made read-only and root owned to prevent tampering. | ## Selkies application settings @@ -334,7 +362,7 @@ services: devices: - driver: nvidia count: 1 - capabilities: [compute,video,graphics,utility] + capabilities: [gpu] ``` # Development diff --git a/readme-vars.yml b/readme-vars.yml index 8c0a8a2f..60401149 100644 --- a/readme-vars.yml +++ b/readme-vars.yml @@ -38,23 +38,51 @@ full_custom_readme: | | CUSTOM_USER | HTTP Basic auth username, abc is default. | | PASSWORD | HTTP Basic auth password, abc is default. If unset there will be no auth | | SUBFOLDER | Subfolder for the application if running a subfolder reverse proxy, need both slashes IE `/subfolder/` | - | TITLE | The page title displayed on the web browser, default "Selkies - webrtc". | + | TITLE | The page title displayed on the web browser, default "Selkies". | + | DASHBOARD | Allows the user to set their dashboard. Options: `selkies-dashboard`, `selkies-dashboard-zinc`, `selkies-dashboard-wish`. | + | FILE_MANAGER_PATH | Modifies the default upload/download file path, path must have proper permissions for abc user. | | START_DOCKER | If set to false a container with privilege will not automatically start the DinD Docker setup. | | DISABLE_IPV6 | If set to true or any value this will disable IPv6 | | LC_ALL | Set the Language for the container to run as IE `fr_FR.UTF-8` `ar_AE.UTF-8` | | NO_DECOR | If set the application will run without window borders for use as a PWA. (Decor can be enabled and disabled with Ctrl+Shift+d) | | NO_FULL | Do not autmatically fullscreen applications when using openbox. | | DISABLE_ZINK | Do not set the Zink environment variables if a video card is detected (userspace applications will use CPU rendering) | + | MAX_RES | Pass a larger maximum resolution for the container default is 16k `15360x8640` | | WATERMARK_PNG | Full path inside the container to a watermark png IE `/usr/share/selkies/www/icon.png` | | WATERMARK_LOCATION | Where to paint the image over the stream integer options below | - | MAX_RES | Pass a larger maximum resolution for the container default is 16k `15360x8640` | - * 1 - Top Left - * 2 - Top Right - * 3 - Bottom Left - * 4 - Bottom Right - * 5 - Centered - * 6 - Animated + **`WATERMARK_LOCATION` Options:** + - **1**: Top Left + - **2**: Top Right + - **3**: Bottom Left + - **4**: Bottom Right + - **5**: Centered + - **6**: Animated + + ## Hardening + + These variables can be used to lock down the desktop environment for single-application use cases or to restrict user capabilities. + + ### Meta Variables + + These variables act as presets, enabling multiple hardening options at once. Individual options can still be set to override the preset. + + | Variable | Description | + | :----: | --- | + | **`HARDEN_DESKTOP`** | Enables `DISABLE_OPEN_TOOLS`, `DISABLE_SUDO`, and `DISABLE_TERMINALS`. Also sets related Selkies UI settings (`SELKIES_FILE_TRANSFERS`, `SELKIES_COMMAND_ENABLED`, `SELKIES_UI_SIDEBAR_SHOW_FILES`, `SELKIES_UI_SIDEBAR_SHOW_APPS`) if they are not explicitly set by the user. | + | **`HARDEN_OPENBOX`** | Enables `DISABLE_CLOSE_BUTTON`, `DISABLE_MOUSE_BUTTONS`, and `HARDEN_KEYBINDS`. It also flags `RESTART_APP` if not set by the user, ensuring the primary application is automatically restarted if closed. | + + ### Individual Hardening Variables + + | Variable | Description | + | :--- | --- | + | **`DISABLE_OPEN_TOOLS`** | If true, disables `xdg-open` and `exo-open` binaries by removing their execute permissions. | + | **`DISABLE_SUDO`** | If true, disables the `sudo` command by removing its execute permissions and invalidating the passwordless sudo configuration. | + | **`DISABLE_TERMINALS`** | If true, disables common terminal emulators by removing their execute permissions and hiding them from the Openbox right-click menu. | + | **`DISABLE_CLOSE_BUTTON`** | If true, removes the close button from window title bars in the Openbox window manager. | + | **`DISABLE_MOUSE_BUTTONS`** | If true, disables the right-click and middle-click context menus and actions within the Openbox window manager. | + | **`HARDEN_KEYBINDS`** | If true, disables default Openbox keybinds that can bypass other hardening options (e.g., `Alt+F4` to close windows, `Alt+Escape` to show the root menu). | + | **`RESTART_APP`** | If true, enables a watchdog service that automatically restarts the main application if it is closed. The user's autostart script is made read-only and root owned to prevent tampering. | ## Selkies application settings @@ -338,7 +366,7 @@ full_custom_readme: | devices: - driver: nvidia count: 1 - capabilities: [compute,video,graphics,utility] + capabilities: [gpu] ``` # Development diff --git a/root/defaults/default.conf b/root/defaults/default.conf index b82d5d6d..50c45c0f 100644 --- a/root/defaults/default.conf +++ b/root/defaults/default.conf @@ -4,7 +4,7 @@ server { listen 3000 default_server; listen [::]:3000 default_server; location SUBFOLDER { - alias /usr/share/selkies/www/; + alias /usr/share/selkies/web/; index index.html index.htm; try_files $uri $uri/ =404; } @@ -42,11 +42,15 @@ server { fancyindex on; fancyindex_footer SUBFOLDERnginx/footer.html; fancyindex_header SUBFOLDERnginx/header.html; - alias REPLACE_HOME/Desktop/; + alias REPLACE_DOWNLOADS_PATH/; + if (-f $request_filename) { + add_header Content-Disposition "attachment"; + add_header X-Content-Type-Options "nosniff"; + } } error_page 500 502 503 504 /50x.html; location = SUBFOLDER50x.html { - root /usr/share/selkies/www/; + root /usr/share/selkies/web/; } } @@ -58,7 +62,7 @@ server { ssl_certificate /config/ssl/cert.pem; ssl_certificate_key /config/ssl/cert.key; location SUBFOLDER { - alias /usr/share/selkies/www/; + alias /usr/share/selkies/web/; index index.html index.htm; try_files $uri $uri/ =404; } @@ -96,12 +100,14 @@ server { fancyindex on; fancyindex_footer SUBFOLDERnginx/footer.html; fancyindex_header SUBFOLDERnginx/header.html; - alias REPLACE_HOME/Desktop/; + alias REPLACE_DOWNLOADS_PATH/; + if (-f $request_filename) { + add_header Content-Disposition "attachment"; + add_header X-Content-Type-Options "nosniff"; + } } error_page 500 502 503 504 /50x.html; location = SUBFOLDER50x.html { - root /usr/share/selkies/www/; + root /usr/share/selkies/web/; } } - - diff --git a/root/etc/s6-overlay/s6-rc.d/init-nginx/run b/root/etc/s6-overlay/s6-rc.d/init-nginx/run index d8b5ab87..e1eaed6f 100755 --- a/root/etc/s6-overlay/s6-rc.d/init-nginx/run +++ b/root/etc/s6-overlay/s6-rc.d/init-nginx/run @@ -9,6 +9,10 @@ CHPORT="${CUSTOM_HTTPS_PORT:-3001}" CWS="${CUSTOM_WS_PORT:-8082}" CUSER="${CUSTOM_USER:-abc}" SFOLDER="${SUBFOLDER:-/}" +FILE_MANAGER_PATH="${FILE_MANAGER_PATH:-$HOME/Desktop}" +DASHBOARD="${DASHBOARD:-selkies-dashboard}" +SELKIES_FILE_TRANSFERS="${SELKIES_FILE_TRANSFERS:-upload,download}" +HARDEN_DESKTOP="${HARDEN_DESKTOP:-false}" # create self signed cert if [ ! -f "/config/ssl/cert.pem" ]; then @@ -28,8 +32,11 @@ sed -i "s/3000/$CPORT/g" ${NGINX_CONFIG} sed -i "s/3001/$CHPORT/g" ${NGINX_CONFIG} sed -i "s/CWS/$CWS/g" ${NGINX_CONFIG} sed -i "s|SUBFOLDER|$SFOLDER|g" ${NGINX_CONFIG} -sed -i "s|REPLACE_HOME|$HOME|g" ${NGINX_CONFIG} -s6-setuidgid abc mkdir -p $HOME/Desktop +sed -i "s|REPLACE_DOWNLOADS_PATH|$FILE_MANAGER_PATH|g" ${NGINX_CONFIG} +s6-setuidgid abc mkdir -p ${FILE_MANAGER_PATH} +if [[ $SELKIES_FILE_TRANSFERS != *"download"* ]] || [[ ${HARDEN_DESKTOP,,} == "true" ]]; then + sed -i '/files {/,/^ }/d' ${NGINX_CONFIG} +fi if [ ! -z ${DISABLE_IPV6+x} ]; then sed -i '/listen \[::\]/d' ${NGINX_CONFIG} fi @@ -44,7 +51,34 @@ if [ ! -z ${DEV_MODE+x} ]; then ${NGINX_CONFIG} fi -# copy favicon +# set dashboard and icon +rm -Rf \ + /usr/share/selkies/web +cp -a \ + /usr/share/selkies/$DASHBOARD \ + /usr/share/selkies/web +sed -i "s|REPLACE_DOWNLOADS_PATH|$FILE_MANAGER_PATH|g" /usr/share/selkies/web/nginx/footer.html +cp \ + /usr/share/selkies/www/icon.png \ + /usr/share/selkies/web/favicon.ico cp \ /usr/share/selkies/www/icon.png \ - /usr/share/selkies/www/favicon.ico + /usr/share/selkies/web/icon.png +# manifest creation +echo "{ + \"name\": \"${TITLE}\", + \"short_name\": \"${TITLE}\", + \"manifest_version\": 2, + \"version\": \"1.0.0\", + \"display\": \"fullscreen\", + \"background_color\": \"#000000\", + \"theme_color\": \"#000000\", + \"icons\": [ + { + \"src\": \"icon.png\", + \"type\": \"image/png\", + \"sizes\": \"180x180\" + } + ], + \"start_url\": \"/\" +}" > /usr/share/selkies/web/manifest.json diff --git a/root/etc/s6-overlay/s6-rc.d/init-selkies-config/run b/root/etc/s6-overlay/s6-rc.d/init-selkies-config/run index 146a3d26..ee31f48a 100755 --- a/root/etc/s6-overlay/s6-rc.d/init-selkies-config/run +++ b/root/etc/s6-overlay/s6-rc.d/init-selkies-config/run @@ -1,69 +1,208 @@ #!/usr/bin/with-contenv bash # default file copies first run -if [[ ! -f /config/.config/openbox/autostart ]]; then - mkdir -p /config/.config/openbox - cp /defaults/autostart /config/.config/openbox/autostart - chown -R abc:abc /config/.config/openbox +mkdir -p "$HOME/.config" +chown abc:abc "$HOME/.config" +if [[ ! -f "$HOME/.config/openbox/autostart" ]]; then + mkdir -p "$HOME/.config/openbox" + cp /defaults/autostart "$HOME/.config/openbox/autostart" + chown abc:abc "$HOME/.config/openbox" "$HOME/.config/openbox/autostart" fi -if [[ ! -f /config/.config/openbox/menu.xml ]]; then - mkdir -p /config/.config/openbox && \ - cp /defaults/menu.xml /config/.config/openbox/menu.xml && \ - chown -R abc:abc /config/.config +if [[ ! -f "$HOME/.config/openbox/menu.xml" ]]; then + mkdir -p "$HOME/.config/openbox" && \ + cp /defaults/menu.xml "$HOME/.config/openbox/menu.xml" + chown abc:abc "$HOME/.config/openbox" "$HOME/.config/openbox/menu.xml" fi # XDG Home -printf "${HOME}/.XDG" > /run/s6/container_environment/XDG_RUNTIME_DIR -if [ ! -d "${HOME}/.XDG" ]; then - mkdir -p ${HOME}/.XDG - chown abc:abc ${HOME}/.XDG +if [ ! -d "$HOME/.XDG" ]; then + mkdir -p "$HOME/.XDG" + chown abc:abc "$HOME/.XDG" fi +printf "$HOME/.XDG" > /run/s6/container_environment/XDG_RUNTIME_DIR -# Locale Support +# locale Support if [ ! -z ${LC_ALL+x} ]; then printf "${LC_ALL%.UTF-8}" > /run/s6/container_environment/LANGUAGE printf "${LC_ALL}" > /run/s6/container_environment/LANG fi -# Remove window borders -if [[ ! -z ${NO_DECOR+x} ]] && [[ ! -f /decorlock ]]; then - sed -i \ - 's|| no \n|' \ - /etc/xdg/openbox/rc.xml - touch /decorlock +# hardening flags +if [[ ${HARDEN_DESKTOP,,} == "true" ]]; then + export DISABLE_OPEN_TOOLS="true" + export DISABLE_SUDO="true" + export DISABLE_TERMINALS="true" + # application hardening if unset + if [ -z ${SELKIES_FILE_TRANSFERS+x} ]; then + printf "" > /run/s6/container_environment/SELKIES_FILE_TRANSFERS + fi + if [ -z ${SELKIES_COMMAND_ENABLED+x} ]; then + printf "false" > /run/s6/container_environment/SELKIES_COMMAND_ENABLED + fi + if [ -z ${SELKIES_UI_SIDEBAR_SHOW_FILES+x} ]; then + printf "false" > /run/s6/container_environment/SELKIES_UI_SIDEBAR_SHOW_FILES + fi + if [ -z ${SELKIES_UI_SIDEBAR_SHOW_APPS+x} ]; then + printf "false" > /run/s6/container_environment/SELKIES_UI_SIDEBAR_SHOW_APPS + fi +fi +if [[ ${HARDEN_OPENBOX,,} == "true" ]]; then + export DISABLE_CLOSE_BUTTON="true" + export DISABLE_MOUSE_BUTTONS="true" + export HARDEN_KEYBINDS="true" + if [ -z ${RESTART_APP+x} ]; then + export RESTART_APP=true + printf "true" > /run/s6/container_environment/RESTART_APP + fi fi -# Fullscreen everything in openbox unless the user explicitly disables it -if [[ ! -z ${NO_FULL+x} ]] && [[ ! -f /fulllock ]]; then - sed -i \ - 's|yes||g' \ - /etc/xdg/openbox/rc.xml - touch /fulllock +# disable open tools +xdg_open_path=$(which xdg-open 2>/dev/null) +exo_open_path=$(which exo-open 2>/dev/null) +if [[ ${DISABLE_OPEN_TOOLS,,} == "true" ]]; then + echo "[ls.io-init] Disabling xdg-open and exo-open" + [ -n "$xdg_open_path" ] && chmod 0000 "$xdg_open_path" + [ -n "$exo_open_path" ] && chmod 0000 "$exo_open_path" +else + [ -n "$xdg_open_path" ] && chmod 755 "$xdg_open_path" + [ -n "$exo_open_path" ] && chmod 755 "$exo_open_path" fi -# Add proot-apps -if [ ! -f "${HOME}/.local/bin/proot-apps" ]; then - mkdir -p ${HOME}/.local/bin/ - cp /proot-apps/* ${HOME}/.local/bin/ - echo 'export PATH="$HOME/.local/bin:$PATH"' >> $HOME/.bashrc - chown abc:abc \ - ${HOME}/.bashrc \ - ${HOME}/.local/ \ - ${HOME}/.local/bin \ - ${HOME}/.local/bin/{ncat,proot-apps,proot,jq,pversion} -elif ! diff -q /proot-apps/pversion ${HOME}/.local/bin/pversion > /dev/null; then - cp /proot-apps/* ${HOME}/.local/bin/ - chown abc:abc ${HOME}/.local/bin/{ncat,proot-apps,proot,jq,pversion} +# disable sudo +sudo_path=$(which sudo 2>/dev/null) +if [[ ${DISABLE_SUDO,,} == "true" ]]; then + echo "[ls.io-init] Disabling sudo binary and corrupting sudoers config" + [ -n "$sudo_path" ] && chmod 0000 "$sudo_path" + sed -i "s/NOPASSWD/CORRUPT_FILE/g" /etc/sudoers +else + [ -n "$sudo_path" ] && chmod 4755 "$sudo_path" + sed -i "s/CORRUPT_FILE/NOPASSWD/g" /etc/sudoers fi +# disable terminals and menu entries +USER_MENU_DIR="$HOME/.config/openbox" +USER_MENU_XML="$USER_MENU_DIR/menu.xml" +USER_MENU_BAK="$USER_MENU_DIR/menu.xml.bak" +TERMINAL_NAMES=("xterm" "st" "stterm" "uxterm" "lxterminal" "gnome-terminal" "konsole" "xfce4-terminal" "terminator") +if [ -f "$USER_MENU_XML" ] && [ ! -f "$USER_MENU_BAK" ]; then + echo "[ls.io-init] Creating initial backup of menu.xml" + cp "$USER_MENU_XML" "$USER_MENU_BAK" + chown abc:abc "$USER_MENU_BAK" +fi +if [[ ${DISABLE_TERMINALS,,} == "true" ]]; then + echo "[ls.io-init] Disabling terminal binaries and removing from menu" + [ -f "$USER_MENU_BAK" ] && cp "$USER_MENU_BAK" "$USER_MENU_XML" + for term_name in "${TERMINAL_NAMES[@]}"; do + term_path=$(which "$term_name" 2>/dev/null) + if [ -n "$term_path" ]; then + chmod 0000 "$term_path" + escaped_path=$(echo "$term_path" | sed 's/[&/\]/\\&/g') + sed -i "/${escaped_path}<\/command>/d" "$USER_MENU_XML" + fi + done + chown abc:abc "$USER_MENU_XML" +else + if [ -f "$USER_MENU_BAK" ]; then + cp "$USER_MENU_BAK" "$USER_MENU_XML" + chown abc:abc "$USER_MENU_XML" + fi + for term_name in "${TERMINAL_NAMES[@]}"; do + term_path=$(which "$term_name" 2>/dev/null) + if [ -n "$term_path" ] && [ ! -x "$term_path" ]; then + chmod 755 "$term_path" + fi + done +fi +# lock down autostart file if auto restart is enabled +AUTOSTART_SCRIPT="$HOME/.config/openbox/autostart" +if [ -f "$AUTOSTART_SCRIPT" ]; then + if [[ ${RESTART_APP,,} == "true" ]]; then + echo "[ls.io-init] RESTART_APP is set. Setting autostart owner to root and making read-only for user" + chown root:abc "$AUTOSTART_SCRIPT" + chmod 550 "$AUTOSTART_SCRIPT" + else + chown abc:abc "$AUTOSTART_SCRIPT" + chmod 644 "$AUTOSTART_SCRIPT" + fi +fi + +# openbox tweaks +SYS_RC_XML="/etc/xdg/openbox/rc.xml" +SYS_RC_BAK="/etc/xdg/openbox/rc.xml.bak" +if [ ! -f "$SYS_RC_BAK" ]; then + echo "[ls.io-init] Creating initial backup of system rc.xml" + cp "$SYS_RC_XML" "$SYS_RC_BAK" +fi +cp "$SYS_RC_BAK" "$SYS_RC_XML" +if [[ -n "${DISABLE_CLOSE_BUTTON}" ]]; then + echo "[ls.io-init] Disabling close button" + sed -i '//s/C//' "$SYS_RC_XML" +fi +if [[ ${DISABLE_MOUSE_BUTTONS,,} == "true" ]]; then + echo "[ls.io-init] Disabling right and middle mouse clicks" + sed -i -e '//d' \ + -e '//d' "$SYS_RC_XML" +fi +if [[ ! -z ${NO_DECOR+x} ]]; then + echo "[ls.io-init] Removing window decorations" + sed -i '//a \ no' "$SYS_RC_XML" +fi +if [[ ! -z ${NO_FULL+x} ]]; then + echo "[ls.io-init] Disabling maximization" + sed -i '/yes<\/maximized>/d' "$SYS_RC_XML" +fi +if [[ ${HARDEN_KEYBINDS,,} == "true" ]]; then + echo "[ls.io-init] Disabling dangerous keybinds" + KEYS_TO_DISABLE=( + "A-F4" + "A-Escape" + "A-space" + "W-e" + ) + for key in "${KEYS_TO_DISABLE[@]}"; do + sed -i "//{s/^/ /}" "$SYS_RC_XML" + done +fi + +# disable user rc path if config is hardened +USER_RC_XML="$HOME/.config/openbox/rc.xml" +if [[ ${DISABLE_MOUSE_BUTTONS,,} == "true" || ${HARDEN_KEYBINDS,,} == "true" ]]; then + echo "[ls.io-init] Locking user rc.xml to prevent security overrides" + mkdir -p "$(dirname $USER_RC_XML)" + chown abc:abc "$(dirname $USER_RC_XML)" + cp "$SYS_RC_XML" "$USER_RC_XML" + chown root:abc "$USER_RC_XML" + chmod 444 "$USER_RC_XML" +else + if [ -f "$USER_RC_XML" ] && [ "$(stat -c '%U' $USER_RC_XML)" == "root" ]; then + echo "[ls.io-init] Hardening disabled, removing locked user rc.xml" + rm -f "$USER_RC_XML" + fi +fi + +# add proot-apps +proot_updated=false +if [ ! -f "$HOME/.local/bin/proot-apps" ]; then + mkdir -p "$HOME/.local/bin/" + cp /proot-apps/* "$HOME/.local/bin/" + echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$HOME/.bashrc" + proot_updated=true +elif ! diff -q /proot-apps/pversion "$HOME/.local/bin/pversion" > /dev/null; then + cp /proot-apps/* "$HOME/.local/bin/" + proot_updated=true +fi +if [ "$proot_updated" = true ]; then + chown -R abc:abc "$HOME/.local" + [ -f "$HOME/.bashrc" ] && chown abc:abc "$HOME/.bashrc" +fi # set env based on vars if [[ -z ${NO_GAMEPAD+x} ]]; then printf "/usr/lib/selkies_joystick_interposer.so:/opt/lib/libudev.so.1.0.0-fake" > /run/s6/container_environment/LD_PRELOAD fi -# JS folder setup +# js folder setup mkdir -pm1777 /dev/input touch /tmp/selkies_js.log mknod /dev/input/js0 c 13 0 @@ -75,22 +214,3 @@ mknod /dev/input/event1001 c 13 1065 mknod /dev/input/event1002 c 13 1066 mknod /dev/input/event1003 c 13 1067 chmod 777 /dev/input/js* /dev/input/event* /tmp/selkies* - -# Manifest creation -echo "{ - \"name\": \"${TITLE}\", - \"short_name\": \"${TITLE}\", - \"manifest_version\": 2, - \"version\": \"1.0.0\", - \"display\": \"fullscreen\", - \"background_color\": \"#000000\", - \"theme_color\": \"#000000\", - \"icons\": [ - { - \"src\": \"icon.png\", - \"type\": \"image/png\", - \"sizes\": \"180x180\" - } - ], - \"start_url\": \"/\" -}" > /usr/share/selkies/www/manifest.json diff --git a/root/etc/s6-overlay/s6-rc.d/svc-de/run b/root/etc/s6-overlay/s6-rc.d/svc-de/run index 2a19c1bd..bf6a8260 100755 --- a/root/etc/s6-overlay/s6-rc.d/svc-de/run +++ b/root/etc/s6-overlay/s6-rc.d/svc-de/run @@ -9,9 +9,11 @@ while true; do done # set sane resolution before starting apps -s6-setuidgid abc xrandr --newmode "1024x768" 63.50 1024 1072 1176 1328 768 771 775 798 -hsync +vsync -s6-setuidgid abc xrandr --addmode screen "1024x768" -s6-setuidgid abc xrandr --output screen --mode "1024x768" --dpi 96 +if ! s6-setuidgid abc xrandr | grep -q "1024x768"; then + s6-setuidgid abc xrandr --newmode "1024x768" 63.50 1024 1072 1176 1328 768 771 775 798 -hsync +vsync + s6-setuidgid abc xrandr --addmode screen "1024x768" + s6-setuidgid abc xrandr --output screen --mode "1024x768" --dpi 96 +fi # set xresources if [ -f "${HOME}/.Xresources" ]; then diff --git a/root/etc/s6-overlay/s6-rc.d/svc-watchdog/dependencies.d/init-services b/root/etc/s6-overlay/s6-rc.d/svc-watchdog/dependencies.d/init-services new file mode 100644 index 00000000..e69de29b diff --git a/root/etc/s6-overlay/s6-rc.d/svc-watchdog/run b/root/etc/s6-overlay/s6-rc.d/svc-watchdog/run new file mode 100755 index 00000000..33056625 --- /dev/null +++ b/root/etc/s6-overlay/s6-rc.d/svc-watchdog/run @@ -0,0 +1,32 @@ +#!/usr/bin/with-contenv bash + +if [[ ${RESTART_APP,,} != "true" ]]; then + exec sleep infinity +fi + +# monitor loop for autostart +AUTOSTART_CMD="sh $HOME/.config/openbox/autostart" +while true; do + if pgrep -o -u abc -f "$AUTOSTART_CMD" > /dev/null; then + echo "SVC Watchdog: Initial process detected. Starting active monitoring." + break + fi + sleep 2 +done +last_known_pid="" +while true; do + current_pid=$(pgrep -o -u abc -f "$AUTOSTART_CMD") + if [ -z "$current_pid" ]; then + if [ -n "$last_known_pid" ]; then + echo "SVC Watchdog: Application process (PID: $last_known_pid) has terminated. Restarting..." + else + echo "SVC Watchdog: Application not running. Attempting to start..." + fi + s6-setuidgid abc $AUTOSTART_CMD & + last_known_pid="" + elif [ "$current_pid" != "$last_known_pid" ]; then + echo "SVC Watchdog: Application process found with PID: $current_pid. Monitoring..." + last_known_pid="$current_pid" + fi + sleep 1 +done diff --git a/root/etc/s6-overlay/s6-rc.d/svc-watchdog/type b/root/etc/s6-overlay/s6-rc.d/svc-watchdog/type new file mode 100644 index 00000000..5883cff0 --- /dev/null +++ b/root/etc/s6-overlay/s6-rc.d/svc-watchdog/type @@ -0,0 +1 @@ +longrun diff --git a/root/etc/s6-overlay/s6-rc.d/user/contents.d/svc-watchdog b/root/etc/s6-overlay/s6-rc.d/user/contents.d/svc-watchdog new file mode 100644 index 00000000..e69de29b From 3e3edbe034b3bbd4be74e4ebf2e59d47b754ff5e Mon Sep 17 00:00:00 2001 From: thelamer Date: Thu, 2 Oct 2025 10:53:29 -0400 Subject: [PATCH 5/5] update syntax and if statement to check for actual devices not just runtime --- root/etc/s6-overlay/s6-rc.d/init-video/run | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/root/etc/s6-overlay/s6-rc.d/init-video/run b/root/etc/s6-overlay/s6-rc.d/init-video/run index 260bcb4b..82213b08 100755 --- a/root/etc/s6-overlay/s6-rc.d/init-video/run +++ b/root/etc/s6-overlay/s6-rc.d/init-video/run @@ -35,10 +35,9 @@ do done # check if nvidia gpu is present -if which nvidia-smi >/dev/null 2>&1; then +if which nvidia-smi > /dev/null 2>&1 && ls -A /dev/dri 2>/dev/null; then # nvidia-container-toolkit may not place files correctly, so we set them up here echo "**** NVIDIA GPU detected ****" - OPENCL_ICDS=$(find /etc/OpenCL/vendors -name '*nvidia*.icd' 2>/dev/null) # if no opencl icd found if [ -z "${OPENCL_ICDS}" ]; then @@ -46,7 +45,6 @@ if which nvidia-smi >/dev/null 2>&1; then mkdir -pm755 /etc/OpenCL/vendors/ echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd fi - # find vulkan icds ICDS=$(find /usr/share/vulkan/icd.d /etc/vulkan/icd.d -name '*nvidia*.json' 2>/dev/null) # if no icd found @@ -70,7 +68,6 @@ if which nvidia-smi >/dev/null 2>&1; then } EOF fi - # find glvnd egl_vendor files EGLS=$(find /usr/share/glvnd/egl_vendor.d /etc/glvnd/egl_vendor.d -name '*nvidia*.json' 2>/dev/null) # if no egl_vendor file found