| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546 |
- # syntax=docker/dockerfile:1.7
- # Ubuntu 24.04 + NVIDIA GLX + XFCE + PipeWire + Firefox.
- #
- # Important: the Selkies GStreamer runtime, Python wheel, web client and
- # joystick interposer all come from the SAME published Selkies release.
- # Do not mix these assets with py-build:main or a frontend built from main.
- ARG DISTRIB_RELEASE=24.04
- ARG SELKIES_VERSION=1.6.2
- ARG NVIDIA_VAAPI_DRIVER_VERSION=latest
- # -----------------------------------------------------------------------------
- # Build nvidia-vaapi-driver without retaining its build dependencies
- # -----------------------------------------------------------------------------
- FROM docker.io/library/ubuntu:${DISTRIB_RELEASE} AS nvidia-vaapi-builder
- ARG DEBIAN_FRONTEND=noninteractive
- ARG NVIDIA_VAAPI_DRIVER_VERSION
- SHELL ["/bin/bash", "-o", "pipefail", "-c"]
- RUN apt-get update \
- && apt-get install --no-install-recommends -y \
- ca-certificates \
- curl \
- gcc \
- jq \
- meson \
- ninja-build \
- pkg-config \
- libdrm-dev \
- libegl-dev \
- libffmpeg-nvenc-dev \
- libgstreamer-plugins-bad1.0-dev \
- libva-dev \
- && rm -rf /var/lib/apt/lists/*
- RUN set -eux; \
- version="${NVIDIA_VAAPI_DRIVER_VERSION}"; \
- if [[ "${version}" == "latest" ]]; then \
- version="$(curl -fsSL https://api.github.com/repos/elFarto/nvidia-vaapi-driver/releases/latest \
- | jq -r '.tag_name' \
- | sed 's/^v//')"; \
- fi; \
- curl -fsSL \
- "https://github.com/elFarto/nvidia-vaapi-driver/archive/refs/tags/v${version}.tar.gz" \
- -o /tmp/nvidia-vaapi-driver.tar.gz; \
- install -d -m 0755 /tmp/nvidia-vaapi-driver; \
- tar -xzf /tmp/nvidia-vaapi-driver.tar.gz \
- --strip-components=1 \
- -C /tmp/nvidia-vaapi-driver; \
- cd /tmp/nvidia-vaapi-driver; \
- meson setup build --prefix=/usr --buildtype=release; \
- meson compile -C build; \
- DESTDIR=/out meson install -C build
- # -----------------------------------------------------------------------------
- # Final image
- # -----------------------------------------------------------------------------
- FROM docker.io/library/ubuntu:${DISTRIB_RELEASE}
- ARG DEBIAN_FRONTEND=noninteractive
- ARG DISTRIB_RELEASE
- ARG SELKIES_VERSION
- ARG TZ=Europe/Paris
- ARG USER_NAME=ubuntu
- ARG USER_UID=1000
- ARG USER_GID=1000
- LABEL org.opencontainers.image.title="Selkies NVIDIA XFCE Desktop" \
- org.opencontainers.image.description="XFCE remote desktop using the stable Selkies GStreamer release stack" \
- org.opencontainers.image.source="https://github.com/selkies-project/docker-selkies-glx-desktop"
- SHELL ["/bin/bash", "-o", "pipefail", "-c"]
- ENV TZ="${TZ}" \
- LANG="en_US.UTF-8" \
- LANGUAGE="en_US:en" \
- LC_ALL="en_US.UTF-8" \
- PASSWD="mypasswd" \
- DISPLAY=":20" \
- DISPLAY_SIZEW="1920" \
- DISPLAY_SIZEH="1080" \
- DISPLAY_REFRESH="60" \
- DISPLAY_DPI="96" \
- DISPLAY_CDEPTH="24" \
- VIDEO_PORT="DFP" \
- DESKTOP_SESSION="xfce" \
- XDG_SESSION_DESKTOP="xfce" \
- XDG_CURRENT_DESKTOP="XFCE" \
- XDG_SESSION_TYPE="x11" \
- NGINX_PORT="8080" \
- SELKIES_PORT="8081" \
- SELKIES_ENCODER="nvh264enc" \
- SELKIES_ENABLE_HTTPS="false" \
- SELKIES_ENABLE_RESIZE="false" \
- SELKIES_ENABLE_BASIC_AUTH="true" \
- NVIDIA_VISIBLE_DEVICES="all" \
- NVIDIA_DRIVER_CAPABILITIES="all" \
- __GL_SYNC_TO_VBLANK="0" \
- __GLX_VENDOR_LIBRARY_NAME="nvidia" \
- LIBVA_DRIVER_NAME="nvidia" \
- NVD_BACKEND="direct" \
- MOZ_DISABLE_RDD_SANDBOX="1" \
- MOZ_X11_EGL="1" \
- PIPEWIRE_LATENCY="128/48000" \
- XDG_RUNTIME_DIR="/tmp/runtime-ubuntu" \
- PIPEWIRE_RUNTIME_DIR="/tmp/runtime-ubuntu" \
- PULSE_RUNTIME_PATH="/tmp/runtime-ubuntu/pulse" \
- PULSE_SERVER="unix:/tmp/runtime-ubuntu/pulse/native" \
- DBUS_SYSTEM_BUS_ADDRESS="unix:path=/tmp/runtime-ubuntu/dbus-system-bus" \
- APPIMAGE_EXTRACT_AND_RUN="1" \
- SUDO_EDITOR="mousepad" \
- PIP_BREAK_SYSTEM_PACKAGES="1"
- # Bootstrap APT and locales.
- RUN apt-get update \
- && apt-get install --no-install-recommends -y \
- ca-certificates \
- curl \
- gnupg \
- locales \
- ssl-cert \
- tzdata \
- && locale-gen en_US.UTF-8 fr_FR.UTF-8 \
- && ln -snf "/usr/share/zoneinfo/${TZ}" /etc/localtime \
- && echo "${TZ}" > /etc/timezone \
- && rm -rf /var/lib/apt/lists/*
- # Firefox DEB and the same PipeWire/WirePlumber PPAs as the original image.
- RUN install -d -m 0755 \
- /etc/apt/preferences.d \
- /etc/apt/sources.list.d \
- /etc/apt/trusted.gpg.d \
- && printf '%s\n' \
- 'Package: firefox*' \
- 'Pin: version 1:1snap*' \
- 'Pin-Priority: -1' \
- > /etc/apt/preferences.d/firefox-nosnap \
- && curl -fsSL \
- 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x738BEB9321D1AAEC13EA9391AEBDF4819BE21867' \
- | gpg --dearmor \
- > /etc/apt/trusted.gpg.d/mozillateam-ubuntu-ppa.gpg \
- && echo \
- "deb https://ppa.launchpadcontent.net/mozillateam/ppa/ubuntu noble main" \
- > /etc/apt/sources.list.d/mozillateam-ubuntu-ppa.list \
- && curl -fsSL \
- 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xFC43B7352BCC0EC8AF2EEB8B25088A0359807596' \
- | gpg --dearmor \
- > /etc/apt/trusted.gpg.d/pipewire-debian-ubuntu.gpg \
- && echo \
- "deb https://ppa.launchpadcontent.net/pipewire-debian/pipewire-upstream/ubuntu noble main" \
- > /etc/apt/sources.list.d/pipewire-upstream.list \
- && echo \
- "deb https://ppa.launchpadcontent.net/pipewire-debian/wireplumber-upstream/ubuntu noble main" \
- > /etc/apt/sources.list.d/wireplumber-upstream.list
- # Desktop, Xorg, NVIDIA interfaces, PipeWire and the dependencies used by the
- # original Selkies GStreamer release. No KDE, Chrome, Wine, KasmVNC, RustDesk,
- # i386 stack, Intel VA-API stack or AMD/Mesa Vulkan stack.
- RUN apt-get update \
- && apt-get install --no-install-recommends -y \
- apache2-utils \
- apt-utils \
- alsa-utils \
- aom-tools \
- bash-completion \
- binutils \
- btop \
- bzip2 \
- clinfo \
- coturn \
- dbus-user-session \
- dbus-x11 \
- desktop-file-utils \
- dnsutils \
- file \
- firefox \
- fonts-dejavu \
- fonts-liberation \
- fonts-noto \
- fonts-noto-cjk \
- fonts-noto-color-emoji \
- fonts-noto-mono \
- fonts-ubuntu \
- fuse \
- git \
- glib-networking \
- gstreamer1.0-libcamera \
- gstreamer1.0-pipewire \
- gstreamer1.0-plugins-bad \
- gvfs \
- jackd2 \
- jq \
- kmod \
- less \
- libdrm2 \
- libegl1 \
- libelf-dev \
- libgcrypt20 \
- libgirepository-1.0-1 \
- libgl1 \
- libgles1 \
- libgles2 \
- libglib2.0-0 \
- libglvnd-dev \
- libglvnd0 \
- libglx0 \
- libgstreamer-plugins-bad1.0-0 \
- libgudev-1.0-0 \
- libjack-jackd2-0 \
- libopenh264-dev \
- libopengl0 \
- libopus0 \
- libpci3 \
- libpipewire-0.3-modules \
- libpipewire-module-x11-bell \
- libpulse0 \
- libsm6 \
- libspa-0.2-bluetooth \
- libspa-0.2-jack \
- libspa-0.2-modules \
- libva-drm2 \
- libva-x11-2 \
- libva2 \
- libvpx-dev \
- libvulkan1 \
- libwayland-dev \
- libwayland-egl1 \
- libx11-6 \
- libx11-xcb1 \
- libxau6 \
- libxcb-dri3-0 \
- libxcb1 \
- libxdamage1 \
- libxdmcp6 \
- libxext6 \
- libxfixes3 \
- libxkbcommon0 \
- libxtst6 \
- libxv1 \
- mousepad \
- nano \
- neofetch \
- net-tools \
- netcat-openbsd \
- nginx \
- ocl-icd-libopencl1 \
- pavucontrol \
- pciutils \
- pipewire \
- pipewire-alsa \
- pipewire-audio-client-libraries \
- pipewire-jack \
- pipewire-libcamera \
- pipewire-locales \
- pipewire-v4l2 \
- pipewire-vulkan \
- procps \
- psmisc \
- python3 \
- python3-dev \
- python3-gi \
- python3-pip \
- python3-setuptools \
- python3-venv \
- python3-wheel \
- ristretto \
- sudo \
- supervisor \
- svt-av1 \
- thunar \
- tumbler \
- udev \
- unzip \
- vainfo \
- vim \
- vulkan-tools \
- wayland-protocols \
- wget \
- wireplumber \
- wireplumber-locales \
- wmctrl \
- x11-apps \
- x11-utils \
- x11-xkb-utils \
- x11-xserver-utils \
- x264 \
- x265 \
- xauth \
- xbitmaps \
- xclip \
- xcvt \
- xdg-user-dirs \
- xdg-utils \
- xfce4 \
- xfce4-goodies \
- xfce4-notifyd \
- xfce4-pulseaudio-plugin \
- xfce4-terminal \
- xfonts-base \
- xfonts-scalable \
- xinit \
- xkb-data \
- xsel \
- xserver-xorg-core \
- xserver-xorg-input-libinput \
- xserver-xorg-legacy \
- xsettingsd \
- xterm \
- xdotool \
- xz-utils \
- zip \
- zstd \
- gir1.2-wp-0.5 \
- && sed -i \
- -e 's#/var/log/nginx/access\.log#/dev/stdout#g' \
- -e 's#/var/log/nginx/error\.log#/dev/stderr#g' \
- -e 's#/run/nginx\.pid#/tmp/nginx.pid#g' \
- /etc/nginx/nginx.conf \
- && printf '\nerror_log /dev/stderr;\n' >> /etc/nginx/nginx.conf \
- && apt-get clean \
- && rm -rf \
- /var/lib/apt/lists/* \
- /var/cache/apt/* \
- /var/cache/debconf/* \
- /var/log/* \
- /tmp/* \
- /var/tmp/*
- # Keep only the compiled NVIDIA VA-API runtime.
- COPY --from=nvidia-vaapi-builder /out/usr/ /usr/
- # NVIDIA libraries are injected by the NVIDIA GPU Operator / Container Toolkit.
- RUN printf '%s\n' \
- '/usr/local/nvidia/lib' \
- '/usr/local/nvidia/lib64' \
- > /etc/ld.so.conf.d/nvidia.conf \
- && install -d -m 0755 \
- /etc/OpenCL/vendors \
- /etc/vulkan/icd.d \
- /usr/share/glvnd/egl_vendor.d \
- && echo 'libnvidia-opencl.so.1' \
- > /etc/OpenCL/vendors/nvidia.icd \
- && cat > /etc/vulkan/icd.d/nvidia_icd.json <<'JSON'
- {
- "file_format_version": "1.0.0",
- "ICD": {
- "library_path": "libGLX_nvidia.so.0",
- "api_version": "1.3.0"
- }
- }
- JSON
- RUN cat > /usr/share/glvnd/egl_vendor.d/10_nvidia.json <<'JSON'
- {
- "file_format_version": "1.0.0",
- "ICD": {
- "library_path": "libEGL_nvidia.so.0"
- }
- }
- JSON
- ENV PATH="/usr/local/nvidia/bin:${PATH}" \
- LD_LIBRARY_PATH="/usr/local/nvidia/lib:/usr/local/nvidia/lib64"
- # Install every Selkies component from the same stable v1.6.2 release.
- # evdev is built from source on Python 3.12, so gcc is needed only for this step.
- RUN set -eux; \
- apt-get update; \
- apt-get install --no-install-recommends -y gcc; \
- ubuntu_version="$(. /etc/os-release; printf '%s' "${VERSION_ID}")"; \
- arch="$(dpkg --print-architecture)"; \
- release_url="https://github.com/selkies-project/selkies/releases/download/v${SELKIES_VERSION}"; \
- curl -fsSL \
- "${release_url}/gstreamer-selkies_gpl_v${SELKIES_VERSION}_ubuntu${ubuntu_version}_${arch}.tar.gz" \
- | tar -xzf - -C /opt; \
- wheel_path="/tmp/selkies_gstreamer-${SELKIES_VERSION}-py3-none-any.whl"; \
- curl -fsSL \
- "${release_url}/selkies_gstreamer-${SELKIES_VERSION}-py3-none-any.whl" \
- -o "${wheel_path}"; \
- python3 -m pip install \
- --break-system-packages \
- --no-cache-dir \
- --force-reinstall \
- "${wheel_path}" \
- 'websockets<14.0'; \
- curl -fsSL \
- "${release_url}/selkies-gstreamer-web_v${SELKIES_VERSION}.tar.gz" \
- | tar -xzf - -C /opt; \
- curl -fsSL \
- "${release_url}/selkies-js-interposer_v${SELKIES_VERSION}_ubuntu${ubuntu_version}_${arch}.deb" \
- -o /tmp/selkies-js-interposer.deb; \
- apt-get update; \
- apt-get install --no-install-recommends -y \
- /tmp/selkies-js-interposer.deb; \
- test -f /opt/gst-web/index.html; \
- test -f /opt/gstreamer/gst-env; \
- command -v selkies-gstreamer; \
- rm -f \
- "${wheel_path}" \
- /tmp/selkies-js-interposer.deb; \
- apt-get purge -y gcc; \
- apt-get autoremove -y; \
- apt-get clean; \
- rm -rf /var/lib/apt/lists/* /var/cache/apt/* /tmp/* /var/tmp/*
- # Regular desktop user and the permissions required by the original entrypoints.
- RUN set -eux; \
- if ! getent group "${USER_NAME}" >/dev/null; then \
- groupadd --gid "${USER_GID}" "${USER_NAME}"; \
- fi; \
- if ! id -u "${USER_NAME}" >/dev/null 2>&1; then \
- useradd \
- --uid "${USER_UID}" \
- --gid "${USER_NAME}" \
- --create-home \
- --shell /bin/bash \
- "${USER_NAME}"; \
- else \
- usermod --shell /bin/bash "${USER_NAME}"; \
- fi; \
- for group in \
- adm audio cdrom dialout dip fax floppy games input lp plugdev render \
- ssl-cert sudo tape tty video voice; \
- do \
- getent group "${group}" >/dev/null \
- && usermod -aG "${group}" "${USER_NAME}" \
- || true; \
- done; \
- echo "${USER_NAME} ALL=(ALL:ALL) NOPASSWD: ALL" \
- > "/etc/sudoers.d/${USER_NAME}"; \
- chmod 0440 "/etc/sudoers.d/${USER_NAME}"; \
- echo "${USER_NAME}:${PASSWD}" | chpasswd; \
- cp -a /usr/bin/sudo /usr/bin/sudo-root; \
- chown root:root /usr/bin/sudo-root; \
- chmod 4755 /usr/bin/sudo-root; \
- install -d -o "${USER_UID}" -g "${USER_GID}" -m 0700 \
- /tmp/runtime-ubuntu; \
- chown -R \
- "${USER_UID}:${USER_GID}" \
- "/home/${USER_NAME}" \
- /etc/X11 \
- /etc/nginx \
- /opt/gstreamer \
- /opt/gst-web \
- /var/lib/nginx
- # XFCE defaults for a permanently streamed desktop.
- RUN install -d -m 0755 \
- /etc/xdg/xfce4/xfconf/xfce-perchannel-xml \
- /etc/firefox/policies \
- && cat > /etc/xdg/xfce4/xfconf/xfce-perchannel-xml/xfce4-power-manager.xml <<'XML'
- <?xml version="1.0" encoding="UTF-8"?>
- <channel name="xfce4-power-manager" version="1.0">
- <property name="xfce4-power-manager" type="empty">
- <property name="blank-on-ac" type="int" value="0"/>
- <property name="dpms-enabled" type="bool" value="false"/>
- <property name="lock-screen-suspend-hibernate" type="bool" value="false"/>
- </property>
- </channel>
- XML
- RUN cat > /etc/firefox/policies/policies.json <<'JSON'
- {
- "policies": {
- "Preferences": {
- "gfx.x11-egl.force-enabled": {
- "Value": true,
- "Status": "default"
- },
- "media.ffmpeg.vaapi.enabled": {
- "Value": true,
- "Status": "default"
- },
- "media.hardware-video-decoding.force-enabled": {
- "Value": true,
- "Status": "default"
- },
- "media.rdd-ffmpeg.enabled": {
- "Value": true,
- "Status": "default"
- }
- }
- }
- }
- JSON
- RUN update-alternatives --set x-www-browser /usr/bin/firefox || true
- # Keep the ORIGINAL entrypoint and Selkies GStreamer entrypoint.
- # Replace supervisord.conf with the cleaned version supplied with this file.
- COPY --chown=${USER_UID}:${USER_GID} entrypoint.sh /etc/entrypoint.sh
- COPY --chown=${USER_UID}:${USER_GID} selkies-gstreamer-entrypoint.sh /etc/selkies-gstreamer-entrypoint.sh
- COPY --chown=${USER_UID}:${USER_GID} supervisord.conf /etc/supervisord.conf
- RUN sed -i 's/\r$//' \
- /etc/entrypoint.sh \
- /etc/selkies-gstreamer-entrypoint.sh \
- /etc/supervisord.conf \
- && chmod 0755 \
- /etc/entrypoint.sh \
- /etc/selkies-gstreamer-entrypoint.sh \
- /etc/supervisord.conf
- # Original coTURN helper used by selkies-gstreamer-entrypoint.sh.
- RUN cat > /etc/start-turnserver.sh <<'EOF_TURN'
- #!/bin/bash
- set -e
- exec turnserver \
- --verbose \
- --listening-ip="0.0.0.0" \
- --listening-ip="::" \
- --listening-port="${SELKIES_TURN_PORT:-3478}" \
- --realm="${TURN_REALM:-example.com}" \
- --external-ip="${TURN_EXTERNAL_IP:-127.0.0.1}" \
- --min-port="${TURN_MIN_PORT:-49152}" \
- --max-port="${TURN_MAX_PORT:-65535}" \
- --channel-lifetime="${TURN_CHANNEL_LIFETIME:--1}" \
- --lt-cred-mech \
- --user="selkies:${TURN_RANDOM_PASSWORD}" \
- --no-cli \
- --cli-password="${TURN_RANDOM_PASSWORD}" \
- --userdb="${XDG_RUNTIME_DIR:-/tmp}/turnserver-turndb" \
- --pidfile="${XDG_RUNTIME_DIR:-/tmp}/turnserver.pid" \
- --log-file="stdout" \
- --allow-loopback-peers \
- ${TURN_EXTRA_ARGS} "$@"
- EOF_TURN
- RUN chmod 0755 /etc/start-turnserver.sh
- USER ${USER_UID}:${USER_GID}
- ENV USER="${USER_NAME}" \
- HOME="/home/${USER_NAME}" \
- SHELL="/bin/bash"
- WORKDIR /home/${USER_NAME}
- EXPOSE 8080
- ENTRYPOINT ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
|