diff --git a/.github/workflows/container-publish.yml b/.github/workflows/container-publish.yml index 5eb2850..dadbe66 100644 --- a/.github/workflows/container-publish.yml +++ b/.github/workflows/container-publish.yml @@ -23,6 +23,7 @@ jobs: include: - os_version: "20.04" - os_version: "22.04" + - os_version: "24.04" latest_tag: true steps: - name: Checkout repository diff --git a/Dockerfile b/Dockerfile index a16ade9..391f6e4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,50 +2,67 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at https://mozilla.org/MPL/2.0/. -# Ubuntu release versions 22.04, and 20.04 are supported -ARG DISTRIB_RELEASE=22.04 +# Supported base images: Ubuntu 24.04, 22.04, 20.04 +ARG DISTRIB_RELEASE=24.04 FROM ubuntu:${DISTRIB_RELEASE} +ARG DISTRIB_RELEASE LABEL maintainer "https://github.com/ehfd,https://github.com/danisla" -ARG DISTRIB_RELEASE -# Use noninteractive mode to skip confirmation when installing packages ARG DEBIAN_FRONTEND=noninteractive -# System defaults that should not be changed -ENV DISPLAY :0 -ENV XDG_RUNTIME_DIR /tmp/runtime-user -ENV PULSE_SERVER unix:/run/pulse/native +# Configure rootless user environment for constrained conditions without escalated root privileges inside containers +ARG TZ=UTC +ARG PASSWD=mypasswd +RUN apt-get clean && apt-get update && apt-get dist-upgrade -y && apt-get install --no-install-recommends -y \ + apt-utils \ + dbus-user-session \ + fakeroot \ + fuse \ + locales \ + ssl-cert \ + sudo \ + udev \ + tzdata && \ + apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/debconf/* /var/log/* /tmp/* /var/tmp/* && \ + locale-gen en_US.UTF-8 && \ + ln -snf "/usr/share/zoneinfo/$TZ" /etc/localtime && echo "$TZ" > /etc/timezone && \ + # Only use sudo-root for root-owned directory (/dev, /proc, /sys) or user/group permission operations, not for apt-get installation or file/directory operations + mv -f /usr/bin/sudo /usr/bin/sudo-root && \ + ln -snf /usr/bin/fakeroot /usr/bin/sudo && \ + groupadd -g 1000 ubuntu || true && \ + useradd -ms /bin/bash ubuntu -u 1000 -g 1000 || true && \ + usermod -a -G adm,audio,cdrom,dialout,dip,fax,floppy,games,input,lp,plugdev,render,ssl-cert,sudo,tape,tty,video,voice ubuntu && \ + echo "ubuntu ALL=(ALL:ALL) NOPASSWD: ALL" >> /etc/sudoers && \ + echo "ubuntu:${PASSWD}" | chpasswd && \ + chown -R -f --no-preserve-root ubuntu:ubuntu / || true && \ + chown -R -f --no-preserve-root root:root /usr/bin/sudo-root /etc/sudo.conf /etc/sudoers /etc/sudoers.d /etc/sudo_logsrvd.conf /usr/libexec/sudo || true && chmod -f 4755 /usr/bin/sudo-root || true -# Install fundamental packages -RUN apt-get clean && apt-get update && apt-get upgrade -y && apt-get install --no-install-recommends -y \ - apt-transport-https \ - apt-utils \ - build-essential \ - ca-certificates \ - curl \ - gnupg \ - locales \ - make \ - software-properties-common \ - wget && \ - rm -rf /var/lib/apt/lists/* && \ - locale-gen en_US.UTF-8 # Set locales ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 +USER 1000 +# Use BUILDAH_FORMAT=docker in buildah +SHELL ["/usr/bin/fakeroot", "--", "/bin/sh", "-c"] + # Install operating system libraries or packages -RUN dpkg --add-architecture i386 && \ - apt-get update && apt-get install --no-install-recommends -y \ - alsa-base \ - alsa-utils \ +RUN apt-get update && apt-get install --no-install-recommends -y \ + # Operating system packages + software-properties-common \ + build-essential \ + ca-certificates \ cups-browsed \ cups-bsd \ cups-common \ cups-filters \ printer-driver-cups-pdf \ + alsa-base \ + alsa-utils \ file \ + gnupg \ + curl \ + wget \ bzip2 \ gzip \ xz-utils \ @@ -57,15 +74,14 @@ RUN dpkg --add-architecture i386 && \ zstd \ gcc \ git \ + coturn \ jq \ python3 \ python3-cups \ python3-numpy \ - ssl-cert \ nano \ vim \ htop \ - fakeroot \ fonts-dejavu \ fonts-freefont-ttf \ fonts-hack \ @@ -86,32 +102,23 @@ RUN dpkg --add-architecture i386 && \ less \ libavcodec-extra \ libpulse0 \ - pulseaudio \ supervisor \ net-tools \ packagekit-tools \ pkg-config \ mesa-utils \ - va-driver-all \ - va-driver-all:i386 \ - i965-va-driver-shaders \ - i965-va-driver-shaders:i386 \ - intel-media-va-driver-non-free \ - intel-media-va-driver-non-free:i386 \ + mesa-va-drivers \ libva2 \ - libva2:i386 \ vainfo \ vdpau-driver-all \ - vdpau-driver-all:i386 \ + libvdpau-va-gl1 \ vdpauinfo \ mesa-vulkan-drivers \ - mesa-vulkan-drivers:i386 \ - libvulkan-dev \ - libvulkan-dev:i386 \ vulkan-tools \ + radeontop \ + libvulkan-dev \ ocl-icd-libopencl1 \ clinfo \ - dbus-user-session \ dbus-x11 \ libdbus-c++-1-0v5 \ xkb-data \ @@ -133,36 +140,77 @@ RUN dpkg --add-architecture i386 && \ xserver-xorg-video-all \ xserver-xorg-video-intel \ xserver-xorg-video-qxl \ - # Install OpenGL libraries + # OpenGL libraries libxau6 \ - libxau6:i386 \ libxdmcp6 \ - libxdmcp6:i386 \ libxcb1 \ - libxcb1:i386 \ libxext6 \ - libxext6:i386 \ libx11-6 \ - libx11-6:i386 \ libxv1 \ - libxv1:i386 \ libxtst6 \ - libxtst6:i386 \ - libglvnd0 \ - libglvnd0:i386 \ + libdrm2 \ + libegl1 \ libgl1 \ - libgl1:i386 \ + libopengl0 \ + libgles1 \ + libgles2 \ + libglvnd0 \ libglx0 \ - libglx0:i386 \ - libegl1 \ + libglu1 \ + libsm6 && \ + # PipeWire and WirePlumber + mkdir -pm755 /etc/apt/trusted.gpg.d && curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xFC43B7352BCC0EC8AF2EEB8B25088A0359807596" | gpg --dearmor -o /etc/apt/trusted.gpg.d/pipewire-debian-ubuntu-pipewire-upstream.gpg && \ + mkdir -pm755 /etc/apt/sources.list.d && echo "deb https://ppa.launchpadcontent.net/pipewire-debian/pipewire-upstream/ubuntu $(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"') main" > "/etc/apt/sources.list.d/pipewire-debian-ubuntu-pipewire-upstream-$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"').list" && \ + mkdir -pm755 /etc/apt/sources.list.d && echo "deb https://ppa.launchpadcontent.net/pipewire-debian/wireplumber-upstream/ubuntu $(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"') main" > "/etc/apt/sources.list.d/pipewire-debian-ubuntu-wireplumber-upstream-$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"').list" && \ + apt-get update && apt-get install --no-install-recommends -y \ + pipewire \ + pipewire-alsa \ + pipewire-audio-client-libraries \ + pipewire-jack \ + pipewire-locales \ + pipewire-v4l2 \ + pipewire-libcamera \ + gstreamer1.0-pipewire \ + libpipewire-0.3-modules \ + libpipewire-module-x11-bell \ + libspa-0.2-jack \ + libspa-0.2-modules \ + wireplumber \ + wireplumber-locales \ + gir1.2-wp-0.4 && \ + # Packages only meant for x86_64 + if [ "$(dpkg --print-architecture)" = "amd64" ]; then \ + dpkg --add-architecture i386 && apt-get update && apt-get install --no-install-recommends -y \ + intel-gpu-tools \ + nvtop \ + va-driver-all \ + i965-va-driver-shaders \ + intel-media-va-driver-non-free \ + va-driver-all:i386 \ + i965-va-driver-shaders:i386 \ + intel-media-va-driver-non-free:i386 \ + libva2:i386 \ + vdpau-driver-all:i386 \ + mesa-vulkan-drivers:i386 \ + libvulkan-dev:i386 \ + libxau6:i386 \ + libxdmcp6:i386 \ + libxcb1:i386 \ + libxext6:i386 \ + libx11-6:i386 \ + libxv1:i386 \ + libxtst6:i386 \ + libdrm2:i386 \ libegl1:i386 \ - libgles2 \ + libgl1:i386 \ + libopengl0:i386 \ + libgles1:i386 \ libgles2:i386 \ - libglu1 \ + libglvnd0:i386 \ + libglx0:i386 \ libglu1:i386 \ - libsm6 \ - libsm6:i386 && \ - rm -rf /var/lib/apt/lists/* && \ + libsm6:i386; fi && \ + apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/debconf/* /var/log/* /tmp/* /var/tmp/* && \ echo "/usr/local/nvidia/lib" >> /etc/ld.so.conf.d/nvidia.conf && \ echo "/usr/local/nvidia/lib64" >> /etc/ld.so.conf.d/nvidia.conf && \ # Configure OpenCL manually @@ -192,33 +240,33 @@ ENV NVIDIA_VISIBLE_DEVICES all ENV NVIDIA_DRIVER_CAPABILITIES all # Disable VSYNC for NVIDIA GPUs ENV __GL_SYNC_TO_VBLANK 0 +# Set default DISPLAY environment +ENV DISPLAY ":0" # Anything above this line should always be kept the same between docker-nvidia-glx-desktop and docker-nvidia-egl-desktop # Default environment variables (password is "mypasswd") -ENV TZ UTC -ENV SIZEW 1920 -ENV SIZEH 1080 -ENV REFRESH 60 -ENV DPI 96 -ENV CDEPTH 24 +ENV DESKTOP_SIZEW 1920 +ENV DESKTOP_SIZEH 1080 +ENV DESKTOP_REFRESH 60 +ENV DESKTOP_DPI 96 +ENV DESKTOP_CDEPTH 24 ENV VGL_DISPLAY egl -ENV PASSWD mypasswd ENV NOVNC_ENABLE false -ENV WEBRTC_ENCODER nvh264enc -ENV WEBRTC_ENABLE_RESIZE false -ENV ENABLE_BASIC_AUTH true +ENV SELKIES_ENCODER nvh264enc +ENV SELKIES_ENABLE_RESIZE false +ENV SELKIES_ENABLE_BASIC_AUTH true # Set versions for components that should be manually checked before upgrading, other component versions are automatically determined by fetching the version online -ARG NOVNC_VERSION=1.4.0 +ARG NOVNC_VERSION=1.5.0 # Install Xvfb RUN apt-get update && apt-get install --no-install-recommends -y \ xvfb && \ - rm -rf /var/lib/apt/lists/* + apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/debconf/* /var/log/* /tmp/* /var/tmp/* && \ # Install VirtualGL and make libraries available for preload -RUN VIRTUALGL_VERSION="$(curl -fsSL "https://api.github.com/repos/VirtualGL/virtualgl/releases/latest" | jq -r '.tag_name' | sed 's/[^0-9\.\-]*//g')" && \ +RUN cd /tmp && VIRTUALGL_VERSION="$(curl -fsSL "https://api.github.com/repos/VirtualGL/virtualgl/releases/latest" | jq -r '.tag_name' | sed 's/[^0-9\.\-]*//g')" && \ if [ "$(dpkg --print-architecture)" = "amd64" ]; then \ dpkg --add-architecture i386 && \ curl -fsSL -O "https://github.com/VirtualGL/virtualgl/releases/download/${VIRTUALGL_VERSION}/virtualgl_${VIRTUALGL_VERSION}_amd64.deb" && \ @@ -233,16 +281,18 @@ RUN VIRTUALGL_VERSION="$(curl -fsSL "https://api.github.com/repos/VirtualGL/virt apt-get update && apt-get install -y --no-install-recommends ./virtualgl_${VIRTUALGL_VERSION}_arm64.deb && \ rm -f "virtualgl_${VIRTUALGL_VERSION}_arm64.deb" && \ chmod u+s /usr/lib/libvglfaker.so /usr/lib/libvglfaker-nodl.so /usr/lib/libdlfaker.so /usr/lib/libgefaker.so; fi && \ - rm -rf /var/lib/apt/lists/* + apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/debconf/* /var/log/* /tmp/* /var/tmp/* # Anything below this line should always be kept the same between docker-nvidia-glx-desktop and docker-nvidia-egl-desktop # Install KDE and other GUI packages -ENV XDG_CURRENT_DESKTOP KDE +ENV DESKTOP_SESSION plasma ENV XDG_SESSION_DESKTOP KDE +ENV XDG_CURRENT_DESKTOP KDE ENV XDG_SESSION_TYPE x11 -ENV DESKTOP_SESSION plasma +ENV XDG_SESSION_ID ${DISPLAY#*:} ENV KDE_FULL_SESSION true +ENV KDE_APPLICATIONS_AS_SCOPE 1 ENV KWIN_COMPOSE N ENV KWIN_X11_NO_SYNC_TO_VBLANK 1 # Use sudoedit to change protected files instead of using sudo on kate @@ -378,14 +428,13 @@ Pin-Priority: -1" > /etc/apt/preferences.d/firefox-nosnap && \ xdg-desktop-portal-kde \ xdg-user-dirs \ firefox \ - pavucontrol-qt \ transmission-qt && \ apt-get install --install-recommends -y \ libreoffice \ libreoffice-kf5 \ libreoffice-plasma \ libreoffice-style-breeze && \ - rm -rf /var/lib/apt/lists/* && \ + apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/debconf/* /var/log/* /tmp/* /var/tmp/* && \ # Fix KDE startup permissions issues in containers MULTI_ARCH=$(dpkg --print-architecture | sed -e 's/arm64/aarch64-linux-gnu/' -e 's/armhf/arm-linux-gnueabihf/' -e 's/riscv64/riscv64-linux-gnu/' -e 's/ppc64el/powerpc64le-linux-gnu/' -e 's/s390x/s390x-linux-gnu/' -e 's/i.*86/i386-linux-gnu/' -e 's/amd64/x86_64-linux-gnu/' -e 's/unknown/x86_64-linux-gnu/') && \ cp -f /usr/lib/${MULTI_ARCH}/libexec/kf5/start_kdeinit /tmp/ && \ @@ -405,7 +454,8 @@ logout=false" > /etc/xdg/kdeglobals # Wine, Winetricks, Lutris, and PlayOnLinux, this process must be consistent with https://wiki.winehq.org/Ubuntu ARG WINE_BRANCH=staging -RUN mkdir -pm755 /etc/apt/keyrings && curl -fsSL -o /etc/apt/keyrings/winehq-archive.key "https://dl.winehq.org/wine-builds/winehq.key" && \ +RUN if [ "$(dpkg --print-architecture)" = "amd64" ]; then \ + mkdir -pm755 /etc/apt/keyrings && curl -fsSL -o /etc/apt/keyrings/winehq-archive.key "https://dl.winehq.org/wine-builds/winehq.key" && \ curl -fsSL -o "/etc/apt/sources.list.d/winehq-$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"').sources" "https://dl.winehq.org/wine-builds/ubuntu/dists/$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"')/winehq-$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"').sources" && \ apt-get update && apt-get install --install-recommends -y \ winehq-${WINE_BRANCH} && \ @@ -415,12 +465,13 @@ RUN mkdir -pm755 /etc/apt/keyrings && curl -fsSL -o /etc/apt/keyrings/winehq-arc LUTRIS_VERSION="$(curl -fsSL "https://api.github.com/repos/lutris/lutris/releases/latest" | jq -r '.tag_name' | sed 's/[^0-9\.\-]*//g')" && \ curl -fsSL -O "https://github.com/lutris/lutris/releases/download/v${LUTRIS_VERSION}/lutris_${LUTRIS_VERSION}_all.deb" && \ apt-get install --no-install-recommends -y ./lutris_${LUTRIS_VERSION}_all.deb && rm -f "./lutris_${LUTRIS_VERSION}_all.deb" && \ - rm -rf /var/lib/apt/lists/* && \ + apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/debconf/* /var/log/* /tmp/* /var/tmp/* && \ curl -fsSL -o /usr/bin/winetricks "https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks" && \ chmod 755 /usr/bin/winetricks && \ - curl -fsSL -o /usr/share/bash-completion/completions/winetricks "https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks.bash-completion" + curl -fsSL -o /usr/share/bash-completion/completions/winetricks "https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks.bash-completion"; fi -# Install latest Selkies-GStreamer (https://github.com/selkies-project/selkies-gstreamer) build, Python application, and web application, should be consistent with selkies-gstreamer documentation +# Install latest Selkies-GStreamer (https://github.com/selkies-project/selkies-gstreamer) build, Python application, and web application, should be consistent with Selkies-GStreamer documentation +ARG PIP_BREAK_SYSTEM_PACKAGES=1 RUN apt-get update && apt-get install --no-install-recommends -y \ # GStreamer dependencies python3-pip \ @@ -428,66 +479,68 @@ RUN apt-get update && apt-get install --no-install-recommends -y \ python3-gi \ python3-setuptools \ python3-wheel \ - udev \ - wmctrl \ - jq \ - gdebi-core \ + libaa1 \ + bzip2 \ + libgcrypt20 \ + libcairo-gobject2 \ + libpangocairo-1.0-0 \ libgdk-pixbuf2.0-0 \ - libgtk2.0-bin \ - libgl-dev \ - libgles-dev \ - libglvnd-dev \ + libsoup2.4-1 \ + libsoup-gnome2.4-1 \ + libgirepository-1.0-1 \ + glib-networking \ + libglib2.0-0 \ + libjson-glib-1.0-0 \ libgudev-1.0-0 \ - xclip \ - x11-utils \ - xdotool \ - x11-xserver-utils \ - xserver-xorg-core \ + alsa-utils \ + jackd2 \ + libjack-jackd2-0 \ + libpulse0 \ + libogg0 \ + libopus0 \ + libvorbis-dev \ + libjpeg-turbo8 \ + libopenjp2-7 \ + libvpx-dev \ + libwebp-dev \ + x264 \ + x265 \ + libdrm2 \ + libegl1 \ + libgl1 \ + libopengl0 \ + libgles1 \ + libgles2 \ + libglvnd0 \ + libglx0 \ wayland-protocols \ libwayland-dev \ libwayland-egl1 \ + wmctrl \ + xsel \ + xdotool \ + x11-utils \ + x11-xserver-utils \ + xserver-xorg-core \ libx11-xcb1 \ + libxcb-dri3-0 \ libxkbcommon0 \ libxdamage1 \ - libsoup2.4-1 \ - libsoup-gnome2.4-1 \ - libsrtp2-1 \ - lame \ - libopus0 \ - libwebrtc-audio-processing1 \ - pulseaudio \ - libpulse0 \ - libcairo-gobject2 \ - libpangocairo-1.0-0 \ - libgirepository-1.0-1 \ - libopenjp2-7 \ - libjpeg-dev \ - libwebp-dev \ - libvpx-dev \ - zlib1g-dev \ - x264 \ - # AMD/Intel graphics driver dependencies - va-driver-all \ - i965-va-driver-shaders \ - intel-media-va-driver-non-free \ - libva2 \ - vainfo \ - intel-gpu-tools \ - radeontop && \ - if [ "$(grep VERSION_ID= /etc/os-release | cut -d= -f2 | tr -d '\"')" \> "20.04" ]; then apt-get install --no-install-recommends -y xcvt; else apt-get install --no-install-recommends -y mesa-utils-extra; fi && \ - rm -rf /var/lib/apt/lists/* && \ + libxfixes3 \ + libxv1 \ + libxtst6 \ + libxext6 && \ + if [ "$(grep VERSION_ID= /etc/os-release | cut -d= -f2 | tr -d '\"')" \> "20.04" ]; then apt-get install --no-install-recommends -y xcvt libopenh264-dev libde265-0 svt-av1 aom-tools; else apt-get install --no-install-recommends -y mesa-utils-extra; fi && \ # Automatically fetch the latest selkies-gstreamer version and install the components - SELKIES_VERSION="1.5.2" && \ - cd /opt && curl -fsSL "https://github.com/selkies-project/selkies-gstreamer/releases/download/v${SELKIES_VERSION}/selkies-gstreamer-v${SELKIES_VERSION}-ubuntu$(grep VERSION_ID= /etc/os-release | cut -d= -f2 | tr -d '\"').tgz" | tar -zxf - && \ - # Extract NVRTC dependency, https://developer.download.nvidia.com/compute/cuda/redist/cuda_nvrtc/LICENSE.txt - NVRTC_VERSION="11.4.152" && \ - NVRTC_ARCH="$(dpkg --print-architecture | sed -e 's/arm64/sbsa/' -e 's/ppc64el/ppc64le/' -e 's/i.*86/x86/' -e 's/amd64/x86_64/' -e 's/unknown/x86_64/')" && \ - cd /tmp && curl -fsSL "https://developer.download.nvidia.com/compute/cuda/redist/cuda_nvrtc/linux-${NVRTC_ARCH}/cuda_nvrtc-linux-${NVRTC_ARCH}-${NVRTC_VERSION}-archive.tar.xz" | tar -xJf - -C /tmp && mv -f cuda_nvrtc* cuda_nvrtc && cd cuda_nvrtc/lib && chmod 755 libnvrtc* && mv -f libnvrtc* /opt/gstreamer/lib/$(dpkg --print-architecture | sed -e 's/arm64/aarch64-linux-gnu/' -e 's/armhf/arm-linux-gnueabihf/' -e 's/riscv64/riscv64-linux-gnu/' -e 's/ppc64el/powerpc64le-linux-gnu/' -e 's/s390x/s390x-linux-gnu/' -e 's/i.*86/i386-linux-gnu/' -e 's/amd64/x86_64-linux-gnu/' -e 's/unknown/x86_64-linux-gnu/')/ && cd /tmp && rm -rf /tmp/cuda_nvrtc && \ - cd /tmp && curl -fsSL -O "https://github.com/selkies-project/selkies-gstreamer/releases/download/v${SELKIES_VERSION}/selkies_gstreamer-${SELKIES_VERSION}-py3-none-any.whl" && pip3 install "selkies_gstreamer-${SELKIES_VERSION}-py3-none-any.whl" && rm -f "selkies_gstreamer-${SELKIES_VERSION}-py3-none-any.whl" && \ - cd /opt && curl -fsSL "https://github.com/selkies-project/selkies-gstreamer/releases/download/v${SELKIES_VERSION}/selkies-gstreamer-web-v${SELKIES_VERSION}.tgz" | tar -zxf - && \ - cd /tmp && curl -fsSL -o selkies-js-interposer.deb "https://github.com/selkies-project/selkies-gstreamer/releases/download/v${SELKIES_VERSION}/selkies-js-interposer-v${SELKIES_VERSION}-ubuntu$(grep VERSION_ID= /etc/os-release | cut -d= -f2 | tr -d '\"').deb" && apt-get update && apt-get install --no-install-recommends -y ./selkies-js-interposer.deb && rm -f ./selkies-js-interposer.deb && rm -rf /var/lib/apt/lists/* /tmp/* + SELKIES_VERSION="$(curl -fsSL "https://api.github.com/repos/selkies-project/selkies-gstreamer/releases/latest" | jq -r '.tag_name' | sed 's/[^0-9\.\-]*//g')" && \ + cd /opt && curl -fsSL "https://github.com/selkies-project/selkies-gstreamer/releases/download/v${SELKIES_VERSION}/gstreamer-selkies_gpl_v${SELKIES_VERSION}_ubuntu$(grep VERSION_ID= /etc/os-release | cut -d= -f2 | tr -d '\"')_$(dpkg --print-architecture).tar.gz" | tar -xzf - && \ + cd /tmp && curl -O -fsSL "https://github.com/selkies-project/selkies-gstreamer/releases/download/v${SELKIES_VERSION}/selkies_gstreamer-${SELKIES_VERSION}-py3-none-any.whl" && pip3 install --no-cache-dir --force-reinstall "selkies_gstreamer-${SELKIES_VERSION}-py3-none-any.whl" && rm -f "selkies_gstreamer-${SELKIES_VERSION}-py3-none-any.whl" && \ + cd /opt && curl -fsSL "https://github.com/selkies-project/selkies-gstreamer/releases/download/v${SELKIES_VERSION}/selkies-gstreamer-web_v${SELKIES_VERSION}.tar.gz" | tar -xzf - && \ + cd /tmp && curl -o selkies-js-interposer.deb -fsSL "https://github.com/selkies-project/selkies-gstreamer/releases/download/v${SELKIES_VERSION}/selkies-js-interposer_v${SELKIES_VERSION}_ubuntu$(grep VERSION_ID= /etc/os-release | cut -d= -f2 | tr -d '\"')_$(dpkg --print-architecture).deb" && sudo apt-get update && sudo apt-get install --no-install-recommends -y ./selkies-js-interposer.deb && rm -f selkies-js-interposer.deb && \ + apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/debconf/* /var/log/* /tmp/* /var/tmp/* # Add configuration for Selkies-GStreamer Joystick interposer -ENV LD_PRELOAD /usr/local/lib/selkies-js-interposer/joystick_interposer.so${LD_PRELOAD:+:${LD_PRELOAD}} +ENV SELKIES_INTERPOSER '/usr/$LIB/selkies_joystick_interposer.so' +ENV LD_PRELOAD "${SELKIES_INTERPOSER}${LD_PRELOAD:+:${LD_PRELOAD}}" ENV SDL_JOYSTICK_DEVICE /dev/input/js0 # Install the noVNC web interface and the latest x11vnc for fallback @@ -514,7 +567,7 @@ RUN apt-get update && apt-get install --no-install-recommends -y \ libxss-dev \ libxtst-dev \ libavahi-client-dev && \ - rm -rf /var/lib/apt/lists/* && \ + apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/debconf/* /var/log/* /tmp/* /var/tmp/* && \ # Build the latest x11vnc source to avoid various errors git clone "https://github.com/LibVNC/x11vnc.git" /tmp/x11vnc && \ cd /tmp/x11vnc && autoreconf -fi && ./configure && make install && cd / && rm -rf /tmp/* && \ @@ -526,32 +579,46 @@ RUN apt-get update && apt-get install --no-install-recommends -y \ # Add custom packages right below this comment, or use FROM in a new container and replace entrypoint.sh or supervisord.conf, and set ENTRYPOINT to /usr/bin/supervisord -# Create user with password ${PASSWD} and assign adequate groups -RUN apt-get update && apt-get install --no-install-recommends -y \ - sudo \ - tzdata && \ - rm -rf /var/lib/apt/lists/* && \ - groupadd -g 1000 user && \ - useradd -ms /bin/bash user -u 1000 -g 1000 && \ - usermod -a -G adm,audio,cdrom,dialout,dip,fax,floppy,input,lp,lpadmin,plugdev,pulse-access,render,scanner,ssl-cert,sudo,tape,tty,video,voice user && \ - echo "user ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \ - chown user:user /home/user && \ - echo "user:${PASSWD}" | chpasswd && \ - ln -snf "/usr/share/zoneinfo/$TZ" /etc/localtime && echo "$TZ" > /etc/timezone - -# Copy scripts and configurations used to start the container -COPY entrypoint.sh /etc/entrypoint.sh +# Copy scripts and configurations used to start the container with `--chown=1000:1000` +COPY --chown=1000:1000 entrypoint.sh /etc/entrypoint.sh RUN chmod 755 /etc/entrypoint.sh -COPY selkies-gstreamer-entrypoint.sh /etc/selkies-gstreamer-entrypoint.sh +COPY --chown=1000:1000 selkies-gstreamer-entrypoint.sh /etc/selkies-gstreamer-entrypoint.sh RUN chmod 755 /etc/selkies-gstreamer-entrypoint.sh -COPY supervisord.conf /etc/supervisord.conf +COPY --chown=1000:1000 supervisord.conf /etc/supervisord.conf RUN chmod 755 /etc/supervisord.conf -EXPOSE 8080 +# Configure coTURN script +RUN echo "#!/bin/bash\n\ +set -e\n\ +exec turnserver\n\ + --verbose\n\ + --listening-ip=0.0.0.0\n\ + --listening-ip=::\n\ + --listening-port=\${SELKIES_TURN_PORT:-3478}\n\ + --realm=\${TURN_REALM:-example.com}\n\ + --min-port=\${TURN_MIN_PORT:-49152}\n\ + --max-port=\${TURN_MAX_PORT:-65535}\n\ + --lt-cred-mech\n\ + --user selkies:\${TURN_RANDOM_PASSWORD}\n\ + --no-cli\n\ + --allow-loopback-peers\n\ + --db /tmp/coturn-turndb\n\ + \${TURN_EXTRA_ARGS} \$@\ +" > /etc/start-turnserver.sh && chmod 755 /etc/start-turnserver.sh + +SHELL ["/bin/sh", "-c"] + +ENV PIPEWIRE_LATENCY "32/48000" +ENV XDG_RUNTIME_DIR /tmp/runtime-ubuntu +ENV PIPEWIRE_RUNTIME_DIR "${PIPEWIRE_RUNTIME_DIR:-${XDG_RUNTIME_DIR:-/tmp}}" +ENV PULSE_RUNTIME_PATH "${PULSE_RUNTIME_PATH:-${XDG_RUNTIME_DIR:-/tmp}/pulse}" +ENV PULSE_SERVER "${PULSE_SERVER:-unix:${PULSE_RUNTIME_PATH:-${XDG_RUNTIME_DIR:-/tmp}/pulse}/native}" USER 1000 ENV SHELL /bin/bash -ENV USER user -WORKDIR /home/user +ENV USER ubuntu +WORKDIR /home/ubuntu + +EXPOSE 8080 ENTRYPOINT ["/usr/bin/supervisord"] diff --git a/README.md b/README.md index f8b5c82..4e540f8 100644 --- a/README.md +++ b/README.md @@ -8,19 +8,19 @@ Use [docker-nvidia-glx-desktop](https://github.com/selkies-project/docker-nvidia ## Usage -This container is composed fully of vendor-neutral applications and protocols except the NVIDIA base container itself, meaning that **there is nothing stopping you from using this container with GPUs of other vendors including AMD and Intel**. Use the respective vendor's container toolkit/runtime or Kubernetes device plugin and make sure that it provisions `/dev/dri/card[n]` devices, then set the environment variable `WEBRTC_ENCODER` to the value `x264enc`, `vp8enc`, or `vp9enc` if using the selkies-gstreamer WebRTC interface. However, this is not officially supported and you must solve your own problems. This container also supports running without any GPUs with software fallback (set `WEBRTC_ENCODER` to the value `x264enc`, `vp8enc`, or `vp9enc` if using the selkies-gstreamer WebRTC interface). +This container is composed fully of vendor-neutral applications and protocols except the NVIDIA base container itself, meaning that **there is nothing stopping you from using this container with GPUs of other vendors including AMD and Intel**. Use the respective vendor's container toolkit/runtime or Kubernetes device plugin and make sure that it provisions `/dev/dri/card[n]` devices, then set the environment variable `SELKIES_ENCODER` to the value `x264enc`, `vp8enc`, or `vp9enc` if using the selkies-gstreamer WebRTC interface. However, this is not officially supported and you must solve your own problems. This container also supports running without any GPUs with software fallback (set `SELKIES_ENCODER` to the value `x264enc`, `vp8enc`, or `vp9enc` if using the selkies-gstreamer WebRTC interface). Wine, Winetricks, Lutris, and PlayOnLinux are bundled by default. Comment out the section where it is installed within `Dockerfile` if the user wants to remove them from the container. There are two web interfaces that can be chosen in this container, the first being the default [selkies-gstreamer](https://github.com/selkies-project/selkies-gstreamer) WebRTC HTML5 interface (requires a TURN server or host networking), and the second being the fallback [noVNC](https://github.com/novnc/noVNC) WebSocket HTML5 interface. While the noVNC interface does not support audio forwarding and remote cursors for gaming, it can be useful for troubleshooting the selkies-gstreamer WebRTC interface or using this container with low bandwidth environments. -The noVNC interface can be enabled by setting `NOVNC_ENABLE` to `true`. When using the noVNC interface, all environment variables related to the selkies-gstreamer WebRTC interface are ignored, with the exception of `BASIC_AUTH_PASSWORD`. As with the selkies-gstreamer WebRTC interface, the noVNC interface password will be set to `BASIC_AUTH_PASSWORD`, and uses `PASSWD` by default if not set. The noVNC interface also additionally accepts the `NOVNC_VIEWPASS` environment variable, where a view only password with only the ability to observe the desktop without controlling can also be set. +The noVNC interface can be enabled by setting `NOVNC_ENABLE` to `true`. When using the noVNC interface, all environment variables related to the selkies-gstreamer WebRTC interface are ignored, with the exception of `SELKIES_BASIC_AUTH_PASSWORD`. As with the selkies-gstreamer WebRTC interface, the noVNC interface password will be set to `SELKIES_BASIC_AUTH_PASSWORD`, and uses `PASSWD` by default if not set. The noVNC interface also additionally accepts the `NOVNC_VIEWPASS` environment variable, where a view only password with only the ability to observe the desktop without controlling can also be set. The container requires host NVIDIA GPU driver versions of at least **450.80.02** and preferably **470.42.01**, with the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html) to be also configured on the host for allocating GPUs. All Maxwell or later generation GPUs in the consumer, professional, or datacenter lineups will not have significant issues running this container, although the selkies-gstreamer high-performance NVENC backend may not be available (see the next paragraph). Kepler GPUs are untested and likely does not support the NVENC backend, but can be mostly functional using fallback software acceleration. -The high-performance NVENC backend for the selkies-gstreamer WebRTC interface is only supported in GPUs listed as supporting `H.264 (AVCHD)` under the `NVENC - Encoding` section of NVIDIA's [Video Encode and Decode GPU Support Matrix](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new). If you are using software fallback without allocated GPUs or your GPU is not listed as supporting `H.264 (AVCHD)`, add the environment variable `WEBRTC_ENCODER` with the value `x264enc`, `vp8enc`, or `vp9enc` in your container configuration for falling back to software acceleration, which also has a very good performance depending on your CPU. +The high-performance NVENC backend for the selkies-gstreamer WebRTC interface is only supported in GPUs listed as supporting `H.264 (AVCHD)` under the `NVENC - Encoding` section of NVIDIA's [Video Encode and Decode GPU Support Matrix](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new). If you are using software fallback without allocated GPUs or your GPU is not listed as supporting `H.264 (AVCHD)`, add the environment variable `SELKIES_ENCODER` with the value `x264enc`, `vp8enc`, or `vp9enc` in your container configuration for falling back to software acceleration, which also has a very good performance depending on your CPU. -The username is `user` in both the container user account and the web authentication prompt. The environment variable `PASSWD` is the password of the container user account, and `BASIC_AUTH_PASSWORD` is the password for the HTML5 interface authentication prompt. If `ENABLE_BASIC_AUTH` is set to `true` for selkies-gstreamer (not required for noVNC) but `BASIC_AUTH_PASSWORD` is unspecified, the HTML5 interface password will default to `PASSWD`. +The username is `user` in both the container user account and the web authentication prompt. The environment variable `PASSWD` is the password of the container user account, and `SELKIES_BASIC_AUTH_PASSWORD` is the password for the HTML5 interface authentication prompt. If `SELKIES_ENABLE_BASIC_AUTH` is set to `true` for selkies-gstreamer (not required for noVNC) but `SELKIES_BASIC_AUTH_PASSWORD` is unspecified, the HTML5 interface password will default to `PASSWD`. > NOTES: Only one web browser can be connected at a time with the selkies-gstreamer WebRTC interface. If the signaling connection works, but the WebRTC connection fails, read the [Using a TURN Server](#using-a-turn-server) section. ### Running with Docker @@ -28,18 +28,18 @@ The username is `user` in both the container user account and the web authentica 1. Run the container with Docker (or other similar container CLIs like Podman): ``` -docker run --gpus 1 -it --tmpfs /dev/shm:rw -e TZ=UTC -e SIZEW=1920 -e SIZEH=1080 -e REFRESH=60 -e DPI=96 -e CDEPTH=24 -e PASSWD=mypasswd -e WEBRTC_ENCODER=nvh264enc -e BASIC_AUTH_PASSWORD=mypasswd -p 8080:8080 ghcr.io/selkies-project/nvidia-egl-desktop:latest +docker run --gpus 1 -it --tmpfs /dev/shm:rw -e TZ=UTC -e DESKTOP_SIZEW=1920 -e DESKTOP_SIZEH=1080 -e DESKTOP_REFRESH=60 -e DESKTOP_DPI=96 -e DESKTOP_CDEPTH=24 -e PASSWD=mypasswd -e SELKIES_ENCODER=nvh264enc -e SELKIES_BASIC_AUTH_PASSWORD=mypasswd -p 8080:8080 ghcr.io/selkies-project/nvidia-egl-desktop:latest ``` -> NOTES: The container tags available are `latest` and `22.04` for Ubuntu 22.04, and `20.04` for Ubuntu 20.04. [Persistent container tags](https://github.com/selkies-project/docker-nvidia-egl-desktop/pkgs/container/nvidia-egl-desktop) are available in the form `22.04-20210101010101`. Replace all instances of `mypasswd` with your desired password. `BASIC_AUTH_PASSWORD` will default to `PASSWD` if unspecified. The container must not be run in privileged mode. +> NOTES: The container tags available are `latest` and `22.04` for Ubuntu 22.04, and `20.04` for Ubuntu 20.04. [Persistent container tags](https://github.com/selkies-project/docker-nvidia-egl-desktop/pkgs/container/nvidia-egl-desktop) are available in the form `22.04-20210101010101`. Replace all instances of `mypasswd` with your desired password. `SELKIES_BASIC_AUTH_PASSWORD` will default to `PASSWD` if unspecified. The container must not be run in privileged mode. The environment variable `VGL_DISPLAY` can also be passed to the container, but only do so after you understand what it implicates with VirtualGL, valid values being either `egl[n]`, or `/dev/dri/card[n]` only when `--device=/dev/dri` was used for the container. -Change `WEBRTC_ENCODER` to `x264enc`, `vp8enc`, or `vp9enc` when using the selkies-gstreamer interface if you are using software fallback without allocated GPUs or your GPU does not support `H.264 (AVCHD)` under the `NVENC - Encoding` section in NVIDIA's [Video Encode and Decode GPU Support Matrix](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new). +Change `SELKIES_ENCODER` to `x264enc`, `vp8enc`, or `vp9enc` when using the selkies-gstreamer interface if you are using software fallback without allocated GPUs or your GPU does not support `H.264 (AVCHD)` under the `NVENC - Encoding` section in NVIDIA's [Video Encode and Decode GPU Support Matrix](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new). 2. Connect to the web server with a browser on port 8080. You may also separately configure a reverse proxy to this port for external connectivity. > NOTES: Additional configurations and environment variables for the selkies-gstreamer WebRTC HTML5 interface are listed in lines that start with `parser.add_argument` within the [selkies-gstreamer main script](https://github.com/selkies-project/selkies-gstreamer/blob/master/src/selkies_gstreamer/__main__.py). -3. (Not Applicable for noVNC) **Read carefully if the selkies-gstreamer WebRTC HTML5 interface does not connect.** Choose whether to use host networking or a TURN server. The selkies-gstreamer WebRTC HTML5 interface will likely just start working if you add `--network host` to the above `docker run` command. However, this may be restricted or be undesired because of security reasons. If so, check if the container starts working after omitting `--network host`. If it does not work, you need a TURN server. Read the [Using a TURN Server](#using-a-turn-server) section and add the environment variables `-e TURN_HOST=`, `-e TURN_PORT=`, and pick one of `-e TURN_SHARED_SECRET=` or both `-e TURN_USERNAME=` and `-e TURN_PASSWORD=` environment variables to the `docker run` command based on your authentication method. +3. (Not Applicable for noVNC) **Read carefully if the selkies-gstreamer WebRTC HTML5 interface does not connect.** Choose whether to use host networking or a TURN server. The selkies-gstreamer WebRTC HTML5 interface will likely just start working if you add `--network host` to the above `docker run` command. However, this may be restricted or be undesired because of security reasons. If so, check if the container starts working after omitting `--network host`. If it does not work, you need a TURN server. Read the [Using a TURN Server](#using-a-turn-server) section and add the environment variables `-e SELKIES_TURN_HOST=`, `-e SELKIES_TURN_PORT=`, and pick one of `-e SELKIES_TURN_SHARED_SECRET=` or both `-e SELKIES_TURN_USERNAME=` and `-e SELKIES_TURN_PASSWORD=` environment variables to the `docker run` command based on your authentication method. ### Running with Kubernetes @@ -55,14 +55,14 @@ kubectl create secret generic my-pass --from-literal=my-pass=YOUR_PASSWORD ```bash kubectl create -f egl.yml ``` -> NOTES: The container tags available are `latest` and `22.04` for Ubuntu 22.04, and `20.04` for Ubuntu 20.04. [Persistent container tags](https://github.com/selkies-project/docker-nvidia-egl-desktop/pkgs/container/nvidia-egl-desktop) are available in the form `22.04-20210101010101`. `BASIC_AUTH_PASSWORD` will default to `PASSWD` if unspecified. +> NOTES: The container tags available are `latest` and `22.04` for Ubuntu 22.04, and `20.04` for Ubuntu 20.04. [Persistent container tags](https://github.com/selkies-project/docker-nvidia-egl-desktop/pkgs/container/nvidia-egl-desktop) are available in the form `22.04-20210101010101`. `SELKIES_BASIC_AUTH_PASSWORD` will default to `PASSWD` if unspecified. -Change `WEBRTC_ENCODER` to `x264enc`, `vp8enc`, or `vp9enc` when using the selkies-gstreamer interface if you are using software fallback without allocated GPUs or your GPU does not support `H.264 (AVCHD)` under the `NVENC - Encoding` section in NVIDIA's [Video Encode and Decode GPU Support Matrix](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new). +Change `SELKIES_ENCODER` to `x264enc`, `vp8enc`, or `vp9enc` when using the selkies-gstreamer interface if you are using software fallback without allocated GPUs or your GPU does not support `H.264 (AVCHD)` under the `NVENC - Encoding` section in NVIDIA's [Video Encode and Decode GPU Support Matrix](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new). 3. Connect to the web server spawned at port 8080. You may configure the ingress endpoint or reverse proxy that your Kubernetes cluster provides to this port for external connectivity. > NOTES: Additional configurations and environment variables for the selkies-gstreamer WebRTC HTML5 interface are listed in lines that start with `parser.add_argument` within the [selkies-gstreamer main script](https://github.com/selkies-project/selkies-gstreamer/blob/master/src/selkies_gstreamer/__main__.py). -4. (Not Applicable for noVNC) **Read carefully if the selkies-gstreamer WebRTC HTML5 interface does not connect.** Choose whether to use host networking or a TURN server. The selkies-gstreamer WebRTC HTML5 interface will likely just start working if you uncomment `hostNetwork: true` in `egl.yml`. However, this may be restricted or be undesired because of security reasons. If so, check if the container starts working after commenting out `hostNetwork: true`. If it does not work, you need a TURN server. Read the [Using a TURN Server](#using-a-turn-server) section and fill in the environment variables `TURN_HOST` and `TURN_PORT`, then pick one of `TURN_SHARED_SECRET` or both `TURN_USERNAME` and `TURN_PASSWORD` environment variables based on your authentication method. +4. (Not Applicable for noVNC) **Read carefully if the selkies-gstreamer WebRTC HTML5 interface does not connect.** Choose whether to use host networking or a TURN server. The selkies-gstreamer WebRTC HTML5 interface will likely just start working if you uncomment `hostNetwork: true` in `egl.yml`. However, this may be restricted or be undesired because of security reasons. If so, check if the container starts working after commenting out `hostNetwork: true`. If it does not work, you need a TURN server. Read the [Using a TURN Server](#using-a-turn-server) section and fill in the environment variables `SELKIES_TURN_HOST` and `SELKIES_TURN_PORT`, then pick one of `SELKIES_TURN_SHARED_SECRET` or both `SELKIES_TURN_USERNAME` and `SELKIES_TURN_PASSWORD` environment variables based on your authentication method. ## Using a TURN server @@ -76,73 +76,73 @@ In most cases when either of your server or client has a permissive firewall, th ### Configuring with Docker -With Docker (or Podman), use the `-e` option to add the `TURN_HOST`, `TURN_PORT` environment variables. This is the hostname or IP and the port of the TURN server (3478 in most cases). +With Docker (or Podman), use the `-e` option to add the `SELKIES_TURN_HOST`, `SELKIES_TURN_PORT` environment variables. This is the hostname or IP and the port of the TURN server (3478 in most cases). -You may set `TURN_PROTOCOL` to `tcp` if you are only able to open TCP ports for the coTURN container to the internet, or if the UDP protocol is blocked or throttled in your client network. You may also set `TURN_TLS` to `true` with the `-e` option if TURN over TLS/DTLS was properly configured. +You may set `SELKIES_TURN_PROTOCOL` to `tcp` if you are only able to open TCP ports for the coTURN container to the internet, or if the UDP protocol is blocked or throttled in your client network. You may also set `SELKIES_TURN_TLS` to `true` with the `-e` option if TURN over TLS/DTLS was properly configured. -You also require to provide either just `TURN_SHARED_SECRET` for time-limited shared secret TURN authentication, or both `TURN_USERNAME` and `TURN_PASSWORD` for legacy long-term TURN authentication, depending on your TURN server configuration. Provide just one of these authentication methods, not both. +You also require to provide either just `SELKIES_TURN_SHARED_SECRET` for time-limited shared secret TURN authentication, or both `SELKIES_TURN_USERNAME` and `SELKIES_TURN_PASSWORD` for legacy long-term TURN authentication, depending on your TURN server configuration. Provide just one of these authentication methods, not both. ### Configuring with Kubernetes -Your TURN server will use only one out of two ways to authenticate the client, so only provide one type of authentication method. The time-limited shared secret TURN authentication requires to only provide the Base64 encoded `TURN_SHARED_SECRET`. The legacy long-term TURN authentication requires to provide both `TURN_USERNAME` and `TURN_PASSWORD` credentials. +Your TURN server will use only one out of two ways to authenticate the client, so only provide one type of authentication method. The time-limited shared secret TURN authentication requires to only provide the Base64 encoded `SELKIES_TURN_SHARED_SECRET`. The legacy long-term TURN authentication requires to provide both `SELKIES_TURN_USERNAME` and `SELKIES_TURN_PASSWORD` credentials. #### Time-limited shared secret authentication 1. Create a secret containing the TURN shared secret: ```bash -kubectl create secret generic turn-shared-secret --from-literal=turn-shared-secret=MY_TURN_SHARED_SECRET +kubectl create secret generic turn-shared-secret --from-literal=turn-shared-secret=MY_SELKIES_TURN_SHARED_SECRET ``` -> NOTES: Replace `MY_TURN_SHARED_SECRET` with the shared secret of the TURN server, then changing the name `turn-shared-secret` to your preferred name of the Kubernetes secret, with the `egl.yml` file also being changed accordingly. +> NOTES: Replace `MY_SELKIES_TURN_SHARED_SECRET` with the shared secret of the TURN server, then changing the name `turn-shared-secret` to your preferred name of the Kubernetes secret, with the `egl.yml` file also being changed accordingly. -2. Uncomment the lines in the `egl.yml` file related to TURN server usage, updating the `TURN_HOST` and `TURN_PORT` environment variable as needed: +2. Uncomment the lines in the `egl.yml` file related to TURN server usage, updating the `SELKIES_TURN_HOST` and `SELKIES_TURN_PORT` environment variable as needed: ```yaml -- name: TURN_HOST +- name: SELKIES_TURN_HOST value: "turn.example.com" -- name: TURN_PORT +- name: SELKIES_TURN_PORT value: "3478" -- name: TURN_SHARED_SECRET +- name: SELKIES_TURN_SHARED_SECRET valueFrom: secretKeyRef: name: turn-shared-secret key: turn-shared-secret -- name: TURN_PROTOCOL +- name: SELKIES_TURN_PROTOCOL value: "udp" -- name: TURN_TLS +- name: SELKIES_TURN_TLS value: "false" ``` -> NOTES: It is possible to skip the first step and directly provide the shared secret with `value:`, but this exposes the shared secret in plain text. Set `TURN_PROTOCOL` to `tcp` if you were able to only open TCP ports while creating your own coTURN Deployment/DaemonSet, or if your client network throttles or blocks the UDP protocol. +> NOTES: It is possible to skip the first step and directly provide the shared secret with `value:`, but this exposes the shared secret in plain text. Set `SELKIES_TURN_PROTOCOL` to `tcp` if you were able to only open TCP ports while creating your own coTURN Deployment/DaemonSet, or if your client network throttles or blocks the UDP protocol. #### Legacy long-term authentication 1. Create a secret containing the TURN password: ```bash -kubectl create secret generic turn-password --from-literal=turn-password=MY_TURN_PASSWORD +kubectl create secret generic turn-password --from-literal=turn-password=MY_SELKIES_TURN_PASSWORD ``` -> NOTES: Replace `MY_TURN_PASSWORD` with the password of the TURN server, then changing the name `turn-password` to your preferred name of the Kubernetes secret, with the `egl.yml` file also being changed accordingly. +> NOTES: Replace `MY_SELKIES_TURN_PASSWORD` with the password of the TURN server, then changing the name `turn-password` to your preferred name of the Kubernetes secret, with the `egl.yml` file also being changed accordingly. -2. Uncomment the lines in the `egl.yml` file related to TURN server usage, updating the `TURN_HOST`, `TURN_PORT`, and `TURN_USERNAME` environment variable as needed: +2. Uncomment the lines in the `egl.yml` file related to TURN server usage, updating the `SELKIES_TURN_HOST`, `SELKIES_TURN_PORT`, and `SELKIES_TURN_USERNAME` environment variable as needed: ```yaml -- name: TURN_HOST +- name: SELKIES_TURN_HOST value: "turn.example.com" -- name: TURN_PORT +- name: SELKIES_TURN_PORT value: "3478" -- name: TURN_USERNAME +- name: SELKIES_TURN_USERNAME value: "username" -- name: TURN_PASSWORD +- name: SELKIES_TURN_PASSWORD valueFrom: secretKeyRef: name: turn-password key: turn-password -- name: TURN_PROTOCOL +- name: SELKIES_TURN_PROTOCOL value: "udp" -- name: TURN_TLS +- name: SELKIES_TURN_TLS value: "false" ``` -> NOTES: It is possible to skip the first step and directly provide the TURN password with `value:`, but this exposes the TURN password in plain text. Set `TURN_PROTOCOL` to `tcp` if you were able to only open TCP ports while creating your own coTURN Deployment/DaemonSet, or if your client network throttles or blocks the UDP protocol. +> NOTES: It is possible to skip the first step and directly provide the TURN password with `value:`, but this exposes the TURN password in plain text. Set `SELKIES_TURN_PROTOCOL` to `tcp` if you were able to only open TCP ports while creating your own coTURN Deployment/DaemonSet, or if your client network throttles or blocks the UDP protocol. ## Troubleshooting diff --git a/egl.yml b/egl.yml index 9754800..16a9933 100644 --- a/egl.yml +++ b/egl.yml @@ -25,15 +25,15 @@ spec: env: - name: TZ value: "UTC" - - name: SIZEW + - name: DESKTOP_SIZEW value: "1920" - - name: SIZEH + - name: DESKTOP_SIZEH value: "1080" - - name: REFRESH + - name: DESKTOP_REFRESH value: "60" - - name: DPI + - name: DESKTOP_DPI value: "96" - - name: CDEPTH + - name: DESKTOP_CDEPTH value: "24" # Keep to default unless you know what you are doing with VirtualGL, `VGL_DISPLAY` should be set to either `egl[n]`, or `/dev/dri/card[n]` only when the device was passed to the container # - name: VGL_DISPLAY @@ -45,7 +45,7 @@ spec: # secretKeyRef: # name: my-pass # key: my-pass - # Uncomment this to enable noVNC, disabing selkies-gstreamer and ignoring all its parameters except `BASIC_AUTH_PASSWORD`, which will be used for authentication with noVNC, `BASIC_AUTH_PASSWORD` defaults to `PASSWD` if not provided + # Uncomment this to enable noVNC, disabing Selkies-GStreamer and ignoring all its parameters except `SELKIES_BASIC_AUTH_PASSWORD`, which will be used for authentication with noVNC, `SELKIES_BASIC_AUTH_PASSWORD` defaults to `PASSWD` if not provided # - name: NOVNC_ENABLE # value: "true" # Additional view-only password only applicable to the noVNC interface, choose either `value:` or `secretKeyRef:` but not both at the same time @@ -56,24 +56,24 @@ spec: # name: my-pass # key: my-pass ### - # selkies-gstreamer parameters, for additional configurations see lines that start with "parser.add_argument" in https://github.com/selkies-project/selkies-gstreamer/blob/master/src/selkies_gstreamer/__main__.py + # Selkies-GStreamer parameters, for additional configurations see `selkies-gstreamer --help` ### - # Change `WEBRTC_ENCODER` to `x264enc`, `vp8enc`, or `vp9enc` if you are using software fallback without allocated GPUs or your GPU doesn't support `H.264 (AVCHD)` under the `NVENC - Encoding` section in https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new - - name: WEBRTC_ENCODER + # Change `SELKIES_ENCODER` to `x264enc`, `vp8enc`, or `vp9enc` if you are using software fallback without allocated GPUs or your GPU doesn't support `H.264 (AVCHD)` under the `NVENC - Encoding` section in https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new + - name: SELKIES_ENCODER value: "nvh264enc" - - name: WEBRTC_ENABLE_RESIZE + - name: SELKIES_ENABLE_RESIZE value: "false" - - name: ENABLE_BASIC_AUTH + - name: SELKIES_ENABLE_BASIC_AUTH value: "true" - - name: ENABLE_HTTPS_WEB + - name: SELKIES_ENABLE_HTTPS_WEB value: "false" # Volume mount trusted HTTPS certificate to new path for no web browser warnings -# - name: HTTPS_WEB_CERT +# - name: SELKIES_HTTPS_WEB_CERT # value: /etc/ssl/certs/ssl-cert-snakeoil.pem -# - name: HTTPS_WEB_KEY +# - name: SELKIES_HTTPS_WEB_KEY # value: /etc/ssl/private/ssl-cert-snakeoil.key # Defaults to `PASSWD` if unspecified, choose either `value:` or `secretKeyRef:` but not both at the same time -# - name: BASIC_AUTH_PASSWORD +# - name: SELKIES_BASIC_AUTH_PASSWORD # value: "mypasswd" # valueFrom: # secretKeyRef: @@ -82,30 +82,30 @@ spec: ### # Uncomment below to use a TURN server for improved network compatibility ### -# - name: TURN_HOST +# - name: SELKIES_TURN_HOST # value: "turn.example.com" -# - name: TURN_PORT +# - name: SELKIES_TURN_PORT # value: "3478" - # Provide only `TURN_SHARED_SECRET` for time-limited shared secret authentication or both `TURN_USERNAME` and `TURN_PASSWORD` for legacy long-term authentication, but do not provide both authentication methods at the same time -# - name: TURN_SHARED_SECRET + # Provide only `SELKIES_TURN_SHARED_SECRET` for time-limited shared secret authentication or both `SELKIES_TURN_USERNAME` and `SELKIES_TURN_PASSWORD` for legacy long-term authentication, but do not provide both authentication methods at the same time +# - name: SELKIES_TURN_SHARED_SECRET # valueFrom: # secretKeyRef: # name: turn-shared-secret # key: turn-shared-secret -# - name: TURN_USERNAME +# - name: SELKIES_TURN_USERNAME # value: "username" # Choose either `value:` or `secretKeyRef:` but not both at the same time -# - name: TURN_PASSWORD +# - name: SELKIES_TURN_PASSWORD # value: "mypasswd" # valueFrom: # secretKeyRef: # name: turn-password # key: turn-password # Change to `tcp` if the UDP protocol is throttled or blocked in your client network, or when the TURN server does not support UDP -# - name: TURN_PROTOCOL +# - name: SELKIES_TURN_PROTOCOL # value: "udp" # You need a valid hostname and a certificate from authorities such as ZeroSSL (Let's Encrypt may have issues) to enable this -# - name: TURN_TLS +# - name: SELKIES_TURN_TLS # value: "false" stdin: true tty: true @@ -126,7 +126,7 @@ spec: name: dshm - mountPath: /cache name: egl-cache-vol - - mountPath: /home/user + - mountPath: /home/ubuntu name: egl-root-vol volumes: - name: dshm diff --git a/entrypoint.sh b/entrypoint.sh index 4a214c4..69a0e00 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,57 +1,68 @@ -#!/bin/bash -e +#!/bin/bash # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at https://mozilla.org/MPL/2.0/. +set -e + trap "echo TRAPed signal" HUP INT QUIT TERM # Create and modify permissions of XDG_RUNTIME_DIR -sudo -u user mkdir -pm700 /tmp/runtime-user -sudo chown user:user /tmp/runtime-user -sudo -u user chmod 700 /tmp/runtime-user +mkdir -pm700 /tmp/runtime-ubuntu +chown ubuntu:ubuntu /tmp/runtime-ubuntu +chmod 700 /tmp/runtime-ubuntu # Make user directory owned by the user in case it is not -sudo chown user:user /home/user || sudo chown user:user /home/user/* || { echo "Failed to change user directory permissions. There may be permission issues."; } +chown ubuntu:ubuntu /home/ubuntu || sudo chown ubuntu:ubuntu /home/ubuntu || sudo-root chown ubuntu:ubuntu /home/ubuntu || chown user:user /home/ubuntu/* || sudo chown user:user /home/ubuntu/* || sudo-root chown user:user /home/ubuntu/* || echo 'Failed to change user directory permissions, there may be permission issues' # Change operating system password to environment variable -echo "user:$PASSWD" | sudo chpasswd +echo "ubuntu:$PASSWD" | chpasswd # Remove directories to make sure the desktop environment starts -sudo rm -rf /tmp/.X* ~/.cache +rm -rf /tmp/.X* ~/.cache # Change time zone from environment variable -sudo ln -snf "/usr/share/zoneinfo/$TZ" /etc/localtime && echo "$TZ" | sudo tee /etc/timezone > /dev/null +ln -snf "/usr/share/zoneinfo/$TZ" /etc/localtime && echo "$TZ" | tee /etc/timezone > /dev/null # Add Lutris directories to path export PATH="${PATH:+${PATH}:}/usr/local/games:/usr/games" # Add LibreOffice to library path export LD_LIBRARY_PATH="/usr/lib/libreoffice/program${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}" -# Start DBus without systemd -sudo /etc/init.d/dbus start +# Configure joystick interposer +export SELKIES_INTERPOSER='/usr/$LIB/selkies_joystick_interposer.so' +export LD_PRELOAD="${SELKIES_INTERPOSER}${LD_PRELOAD:+:${LD_PRELOAD}}" +export SDL_JOYSTICK_DEVICE=/dev/input/js0 +mkdir -pm777 /dev/input || sudo-root mkdir -pm777 /dev/input || echo 'Failed to create joystick interposer directory' +touch /dev/input/js0 /dev/input/js1 /dev/input/js2 /dev/input/js3 || sudo-root touch /dev/input/js0 /dev/input/js1 /dev/input/js2 /dev/input/js3 || echo 'Failed to create joystick interposer devices' + +# Set default display +export DISPLAY="${DISPLAY:-:0}" +# PipeWire-Pulse server socket location +export PIPEWIRE_LATENCY="32/48000" +export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/tmp}" +export PIPEWIRE_RUNTIME_DIR="${PIPEWIRE_RUNTIME_DIR:-${XDG_RUNTIME_DIR:-/tmp}}" +export PULSE_RUNTIME_PATH="${PULSE_RUNTIME_PATH:-${XDG_RUNTIME_DIR:-/tmp}/pulse}" +export PULSE_SERVER="${PULSE_SERVER:-unix:${PULSE_RUNTIME_PATH:-${XDG_RUNTIME_DIR:-/tmp}/pulse}/native}" -# Default display is :0 across the container -export DISPLAY=":0" # Run Xvfb server with required extensions -/usr/bin/Xvfb "${DISPLAY}" -ac -screen "0" "8192x4096x${CDEPTH}" -dpi "${DPI}" +extension "COMPOSITE" +extension "DAMAGE" +extension "GLX" +extension "RANDR" +extension "RENDER" +extension "MIT-SHM" +extension "XFIXES" +extension "XTEST" +iglx +render -nolisten "tcp" -noreset -shmem & +/usr/bin/Xvfb -screen "${DISPLAY}" "8192x4096x${DESKTOP_CDEPTH}" -dpi "${DESKTOP_DPI}" +extension "COMPOSITE" +extension "DAMAGE" +extension "GLX" +extension "RANDR" +extension "RENDER" +extension "MIT-SHM" +extension "XFIXES" +extension "XTEST" +iglx +render -nolisten "tcp" -noreset -shmem & -# Wait for X11 to start -echo "Waiting for X socket" -until [ -S "/tmp/.X11-unix/X${DISPLAY/:/}" ]; do sleep 1; done -echo "X socket is ready" +# Wait for X server to start +echo 'Waiting for X socket' && until [ -S "/tmp/.X11-unix/X${DISPLAY#*:}" ]; do sleep 0.5; done && echo 'X Server is ready' # Resize the screen to the provided size -bash -c ". /opt/gstreamer/gst-env && /usr/local/bin/selkies-gstreamer-resize ${SIZEW}x${SIZEH}" +/usr/local/bin/selkies-gstreamer-resize "${DESKTOP_SIZEW}x${DESKTOP_SIZEH}" # Run the x11vnc + noVNC fallback web interface if enabled if [ "${NOVNC_ENABLE,,}" = "true" ]; then if [ -n "$NOVNC_VIEWPASS" ]; then export NOVNC_VIEWONLY="-viewpasswd ${NOVNC_VIEWPASS}"; else unset NOVNC_VIEWONLY; fi - /usr/local/bin/x11vnc -display "${DISPLAY}" -passwd "${BASIC_AUTH_PASSWORD:-$PASSWD}" -shared -forever -repeat -xkb -snapfb -threads -xrandr "resize" -rfbport 5900 ${NOVNC_VIEWONLY} & + /usr/local/bin/x11vnc -display "${DISPLAY}" -passwd "${SELKIES_BASIC_AUTH_PASSWORD:-$PASSWD}" -shared -forever -repeat -xkb -snapfb -threads -xrandr "resize" -rfbport 5900 ${NOVNC_VIEWONLY} & /opt/noVNC/utils/novnc_proxy --vnc localhost:5900 --listen 8080 --heartbeat 10 & fi # Use VirtualGL to run the KDE desktop environment with OpenGL if the GPU is available, otherwise use OpenGL with llvmpipe if [ -n "$(nvidia-smi --query-gpu=uuid --format=csv | sed -n 2p)" ]; then - export VGL_REFRESHRATE="${REFRESH}" - /usr/bin/vglrun -d "${VGL_DISPLAY:-egl}" +wm /usr/bin/dbus-launch /usr/bin/startplasma-x11 & + export VGL_REFRESHRATE="${DESKTOP_REFRESH}" + /usr/bin/vglrun -d "${VGL_DISPLAY:-egl}" +wm /usr/bin/dbus-launch --exit-with-session /usr/bin/startplasma-x11 & else - /usr/bin/dbus-launch /usr/bin/startplasma-x11 & + /usr/bin/dbus-launch --exit-with-session /usr/bin/startplasma-x11 & fi # Start Fcitx input method framework diff --git a/selkies-gstreamer-entrypoint.sh b/selkies-gstreamer-entrypoint.sh index 9f98fa9..9bbf204 100755 --- a/selkies-gstreamer-entrypoint.sh +++ b/selkies-gstreamer-entrypoint.sh @@ -1,28 +1,44 @@ -#!/bin/bash -e +#!/bin/bash # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at https://mozilla.org/MPL/2.0/. -# Source environment for GStreamer -. /opt/gstreamer/gst-env +set -e + +# Set password for basic authentication +if [ "${SELKIES_ENABLE_BASIC_AUTH,,}" = "true" ] && [ -z "${SELKIES_BASIC_AUTH_PASSWORD}" ]; then export SELKIES_BASIC_AUTH_PASSWORD="${PASSWD}"; fi # Set default display export DISPLAY="${DISPLAY:-:0}" - -# Configure joystick interposer -sudo mkdir -pm755 /dev/input || true -sudo touch /dev/input/js0 /dev/input/js1 /dev/input/js2 /dev/input/js3 || true - -# Show debug logs for GStreamer +# PipeWire-Pulse server socket path +export PIPEWIRE_LATENCY="32/48000" +export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/tmp}" +export PIPEWIRE_RUNTIME_DIR="${PIPEWIRE_RUNTIME_DIR:-${XDG_RUNTIME_DIR:-/tmp}}" +export PULSE_RUNTIME_PATH="${PULSE_RUNTIME_PATH:-${XDG_RUNTIME_DIR:-/tmp}/pulse}" +export PULSE_SERVER="${PULSE_SERVER:-unix:${PULSE_RUNTIME_PATH:-${XDG_RUNTIME_DIR:-/tmp}/pulse}/native}" + +# Export environment variables required for Selkies-GStreamer export GST_DEBUG="${GST_DEBUG:-*:2}" -# Set password for basic authentication -if [ "${ENABLE_BASIC_AUTH,,}" = "true" ] && [ -z "${BASIC_AUTH_PASSWORD}" ]; then export BASIC_AUTH_PASSWORD="${PASSWD}"; fi +export GSTREAMER_PATH=/opt/gstreamer + +# Source environment for GStreamer +. /opt/gstreamer/gst-env -# Wait for X11 to start -echo "Waiting for X socket" -until [ -S "/tmp/.X11-unix/X${DISPLAY/:/}" ]; do sleep 1; done -echo "X socket is ready" +export SELKIES_ENCODER="${SELKIES_ENCODER:-x264enc}" +export SELKIES_ENABLE_RESIZE="${SELKIES_ENABLE_RESIZE:-false}" +if ( [ -z "${SELKIES_TURN_USERNAME}" ] || [ -z "${SELKIES_TURN_PASSWORD}" ] ) && [ -z "${SELKIES_TURN_SHARED_SECRET}" ] || [ -z "${SELKIES_TURN_HOST}" ] || [ -z "${SELKIES_TURN_PORT}" ]; then + export TURN_RANDOM_PASSWORD="$(tr -dc A-Za-z0-9 /dev/null 2>&1 || sudo /usr/bin/pulseaudio --system --verbose --log-target=stderr --realtime=true --disallow-exit -L 'module-native-protocol-tcp auth-ip-acl=127.0.0.0/8 port=4713 auth-anonymous=1'" -environment=DISPLAY=":0" -logfile=/tmp/pulseaudio.log -pidfile=/tmp/pulseaudio.pid +[program:selkies-gstreamer] +command=bash -c "if [ $(echo %(ENV_NOVNC_ENABLE)s | tr '[:upper:]' '[:lower:]') != true ]; then /etc/selkies-gstreamer-entrypoint.sh; else sleep infinity; fi" +stdout_logfile=/tmp/selkies-gstreamer-entrypoint.log +stdout_logfile_backups=0 +redirect_stderr=true +stopasgroup=true stopsignal=INT autostart=true autorestart=true -redirect_stderr=true +priority=20 + +[group:pipewire-group] +program=pipewire,wireplumber,pipewire-pulse priority=10 -[program:selkies-gstreamer] -user=user -command=bash -c "if [ $(echo %(ENV_NOVNC_ENABLE)s | tr '[:upper:]' '[:lower:]') != true ]; then /etc/selkies-gstreamer-entrypoint.sh; else sleep infinity; fi" -logfile=/tmp/selkies-gstreamer-entrypoint.log -pidfile=/tmp/selkies-gstreamer-entrypoint.pid +[program:pipewire] +command=bash -c "until [ -S \"/tmp/.X11-unix/X${DISPLAY#*:}\" ]; do sleep 0.5; done; /usr/bin/pipewire" +environment=PIPEWIRE_LATENCY="32/48000",DISPLAY=":0",DISABLE_RTKIT="y",XDG_RUNTIME_DIR="%(ENV_XDG_RUNTIME_DIR)s",PIPEWIRE_RUNTIME_DIR="%(ENV_XDG_RUNTIME_DIR)s",PULSE_RUNTIME_PATH="%(ENV_XDG_RUNTIME_DIR)s/pulse" +stdout_logfile=/tmp/pipewire.log +stdout_logfile_backups=0 +redirect_stderr=true +stopasgroup=true stopsignal=INT autostart=true autorestart=true + +[program:wireplumber] +command=bash -c "until [ \"$(echo ${XDG_RUNTIME_DIR}/pipewire-*.lock)\" != \"${XDG_RUNTIME_DIR}/pipewire-*.lock\" ]; do sleep 0.5; done; /usr/bin/wireplumber" +environment=PIPEWIRE_LATENCY="32/48000",DISPLAY=":0",DISABLE_RTKIT="y",XDG_RUNTIME_DIR="%(ENV_XDG_RUNTIME_DIR)s",PIPEWIRE_RUNTIME_DIR="%(ENV_XDG_RUNTIME_DIR)s",PULSE_RUNTIME_PATH="%(ENV_XDG_RUNTIME_DIR)s/pulse" +stdout_logfile=/tmp/wireplumber.log +stdout_logfile_backups=0 redirect_stderr=true -priority=20 +stopasgroup=true +stopsignal=INT +autostart=true +autorestart=true + +[program:pipewire-pulse] +command=bash -c "until [ \"$(echo ${XDG_RUNTIME_DIR}/pipewire-*.lock)\" != \"${XDG_RUNTIME_DIR}/pipewire-*.lock\" ]; do sleep 0.5; done; /usr/bin/pipewire-pulse" +environment=PIPEWIRE_LATENCY="32/48000",DISPLAY=":0",DISABLE_RTKIT="y",XDG_RUNTIME_DIR="%(ENV_XDG_RUNTIME_DIR)s",PIPEWIRE_RUNTIME_DIR="%(ENV_XDG_RUNTIME_DIR)s",PULSE_RUNTIME_PATH="%(ENV_XDG_RUNTIME_DIR)s/pulse" +stdout_logfile=/tmp/pipewire-pulse.log +stdout_logfile_backups=0 +redirect_stderr=true +stopasgroup=true +stopsignal=INT +autostart=true +autorestart=true