# syntax=docker/dockerfile:1.7 # ============================================================================= # Versions # ============================================================================= ARG SUNSHINE_VERSION=v2025.924.154138 # Update these values whenever the NVIDIA GPU Operator driver changes. ARG NVIDIA_DRIVER_BRANCH=580 ARG NVIDIA_DRIVER_VERSION=580.126.20 ARG NVIDIA_DRIVER_PACKAGE_VERSION=580.126.20-1ubuntu1 # ============================================================================= # Sunshine package source # ============================================================================= FROM ghcr.io/lizardbyte/sunshine:${SUNSHINE_VERSION}-ubuntu-24.04 AS sunshine # ============================================================================= # Main image # ============================================================================= FROM docker.io/library/ubuntu:24.04 ARG NVIDIA_DRIVER_BRANCH ARG NVIDIA_DRIVER_VERSION ARG NVIDIA_DRIVER_PACKAGE_VERSION ARG USER_NAME=ubuntu ARG USER_UID=1000 ARG USER_GID=1000 ENV DEBIAN_FRONTEND=noninteractive \ HOME=/home/ubuntu \ USER=ubuntu \ DISPLAY=:20 \ DISPLAY_SIZEW=1920 \ DISPLAY_SIZEH=1080 \ DISPLAY_REFRESH=120 \ DISPLAY_DPI=96 \ DISPLAY_CDEPTH=24 \ VIDEO_PORT=HDMI-0 \ TZ=Europe/Paris \ LANG=fr_FR.UTF-8 \ LANGUAGE=fr_FR:fr \ LC_ALL=fr_FR.UTF-8 \ 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 \ NVIDIA_VISIBLE_DEVICES=all \ NVIDIA_DRIVER_CAPABILITIES=all \ EXPECTED_NVIDIA_DRIVER_VERSION=${NVIDIA_DRIVER_VERSION} \ NVIDIA_I386_PACKAGE_VERSION=${NVIDIA_DRIVER_PACKAGE_VERSION} SHELL ["/bin/bash", "-o", "pipefail", "-c"] USER root # ============================================================================= # Base desktop / gaming environment # ============================================================================= RUN dpkg --add-architecture i386 \ && apt-get update \ && apt-get install --no-install-recommends -y \ btop fonts-noto-cjk fonts-ubuntu mousepad nano ristretto thunar \ ubuntu-wallpapers \ adwaita-icon-theme \ elementary-xfce-icon-theme \ greybird-gtk-theme \ hicolor-icon-theme \ humanity-icon-theme \ keyboard-configuration \ tango-icon-theme \ xfce4-goodies \ xfce4-notifyd \ xfce4-pulseaudio-plugin \ xfonts-base \ xfonts-scalable \ alsa-utils \ ca-certificates \ curl \ dbus \ dbus-user-session \ dbus-x11 \ file \ fonts-dejavu \ fonts-liberation \ fonts-noto \ fonts-noto-color-emoji \ kmod \ libasound2-plugins \ libcap2-bin \ libegl1 \ libgbm1 \ libgl1 \ libglvnd0 \ libglx0 \ libpciaccess0 \ libpulse0 \ libvulkan1 \ libx11-6 \ libx11-xcb1 \ libxdamage1 \ libxext6 \ libxfixes3 \ libxinerama1 \ libxrandr2 \ libxss1 \ libxtst6 \ locales \ mesa-utils \ pciutils \ pipewire \ pipewire-pulse \ procps \ psmisc \ pulseaudio-utils \ sudo \ supervisor \ tzdata \ udev \ vulkan-tools \ wireplumber \ x11-utils \ x11-xserver-utils \ xauth \ xcvt \ xdg-user-dirs \ xdg-utils \ xfce4 \ xfce4-terminal \ xkb-data \ xserver-xorg-core \ xserver-xorg-input-libinput \ xserver-xorg-legacy \ xz-utils \ && sed -i \ -e 's/^# *fr_FR.UTF-8 UTF-8/fr_FR.UTF-8 UTF-8/' \ -e 's/^# *en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' \ /etc/locale.gen \ && locale-gen \ && apt-get clean \ && rm -rf \ /var/lib/apt/lists/* \ /var/cache/apt/* \ /var/cache/debconf/* \ /tmp/* \ /var/tmp/* # ============================================================================= # Desktop user # ============================================================================= RUN set -eux; \ if ! getent group "${USER_GID}" >/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_GID}" \ --create-home \ --shell /bin/bash \ "${USER_NAME}"; \ else \ usermod --shell /bin/bash "${USER_NAME}"; \ fi; \ for group in \ audio \ games \ input \ render \ tty \ video; \ 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}"; \ install \ -d \ -o "${USER_UID}" \ -g "${USER_GID}" \ -m 0700 \ /tmp/runtime-ubuntu; \ install \ -d \ -o "${USER_UID}" \ -g "${USER_GID}" \ /home/${USER_NAME}/.config/sunshine \ /games # ============================================================================= # NVIDIA repository + nvidia-xconfig # # Only the userspace Xorg configuration utility is installed here. # The kernel driver remains fully managed by the NVIDIA GPU Operator. # ============================================================================= RUN curl -fsSLO \ https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/cuda-keyring_1.1-1_all.deb \ && dpkg -i cuda-keyring_1.1-1_all.deb \ && rm -f cuda-keyring_1.1-1_all.deb \ && apt-get update \ && apt-get install --no-install-recommends -y \ "nvidia-xconfig=${NVIDIA_DRIVER_PACKAGE_VERSION}" \ && nvidia-xconfig --version \ && apt-get clean \ && rm -rf \ /var/lib/apt/lists/* \ /var/cache/apt/* # ============================================================================= # NVIDIA Xorg driver modules # # Extract only the Xorg-side NVIDIA modules matching the host driver. # Do not install the whole amd64 NVIDIA userspace stack with APT. # ============================================================================= RUN cd /tmp \ && apt-get update \ && apt-get download \ "xserver-xorg-video-nvidia-${NVIDIA_DRIVER_BRANCH}=${NVIDIA_DRIVER_PACKAGE_VERSION}" \ && mkdir -p /tmp/nvidia-xorg \ && dpkg-deb -x \ "xserver-xorg-video-nvidia-${NVIDIA_DRIVER_BRANCH}_${NVIDIA_DRIVER_PACKAGE_VERSION}_amd64.deb" \ /tmp/nvidia-xorg \ && install -D -m 0755 \ /tmp/nvidia-xorg/usr/lib/xorg/modules/drivers/nvidia_drv.so \ /usr/lib/xorg/modules/drivers/nvidia_drv.so \ && cp -a \ /tmp/nvidia-xorg/usr/lib/xorg/modules/extensions/libglxserver_nvidia.so* \ /usr/lib/xorg/modules/extensions/ \ && rm -rf \ /tmp/nvidia-xorg \ /tmp/xserver-xorg-video-nvidia-*.deb \ /var/lib/apt/lists/* # ============================================================================= # NVIDIA GLVND / Vulkan configuration # # Actual 64-bit NVIDIA libraries are injected at runtime by the GPU Operator / # NVIDIA 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/vulkan/icd.d \ /usr/share/glvnd/egl_vendor.d \ && cat > /etc/vulkan/icd.d/nvidia_icd.json <<'EOF' { "file_format_version": "1.0.0", "ICD": { "library_path": "libGLX_nvidia.so.0", "api_version": "1.3.0" } } EOF RUN cat > /usr/share/glvnd/egl_vendor.d/10_nvidia.json <<'EOF' { "file_format_version": "1.0.0", "ICD": { "library_path": "libEGL_nvidia.so.0" } } EOF # ============================================================================= # Sunshine # ============================================================================= COPY --from=sunshine /sunshine.deb /tmp/sunshine.deb RUN apt-get update \ && apt-get install --no-install-recommends -y \ /tmp/sunshine.deb \ && setcap cap_sys_admin,cap_dac_override=ep \ /usr/bin/sunshine-2025.924.154138 \ && rm -f /tmp/sunshine.deb \ && apt-get clean \ && rm -rf \ /var/lib/apt/lists/* \ /var/cache/apt/* # ============================================================================= # Steam + 32-bit Linux gaming runtime # ============================================================================= RUN dpkg --add-architecture i386 \ && apt-get update \ && apt-get install --no-install-recommends -y \ ca-certificates \ curl \ && curl -fsSL \ https://repo.steampowered.com/steam/archive/stable/steam.gpg \ -o /usr/share/keyrings/steam.gpg \ && printf '%s\n' \ 'deb [arch=amd64,i386 signed-by=/usr/share/keyrings/steam.gpg] https://repo.steampowered.com/steam/ stable steam' \ > /etc/apt/sources.list.d/steam-bootstrap.list \ && apt-get update \ && apt-get install --no-install-recommends -y \ steam-launcher \ steam-libs-amd64 \ steam-libs-i386 \ libegl1:amd64 \ libegl1:i386 \ libgbm1:amd64 \ libgbm1:i386 \ libgl1:amd64 \ libgl1:i386 \ libgl1-mesa-dri:amd64 \ libgl1-mesa-dri:i386 \ libglx-mesa0:amd64 \ libglx-mesa0:i386 \ libvulkan1:amd64 \ libvulkan1:i386 \ xdg-desktop-portal \ xdg-desktop-portal-gtk \ && rm -f /etc/apt/sources.list.d/steam-bootstrap.list \ && apt-get clean \ && rm -rf \ /var/lib/apt/lists/* \ /var/cache/apt/* # ============================================================================= # Non-snap Firefox # ============================================================================= RUN install -d -m 0755 /etc/apt/keyrings \ && curl -fsSL https://packages.mozilla.org/apt/repo-signing-key.gpg \ -o /etc/apt/keyrings/packages.mozilla.org.asc \ && echo "deb [signed-by=/etc/apt/keyrings/packages.mozilla.org.asc] https://packages.mozilla.org/apt mozilla main" \ > /etc/apt/sources.list.d/mozilla.list \ && printf '%s\n' \ 'Package: *' \ 'Pin: origin packages.mozilla.org' \ 'Pin-Priority: 1000' \ > /etc/apt/preferences.d/mozilla \ && apt-get update \ && apt-get install --no-install-recommends -y \ firefox \ firefox-l10n-fr \ && apt-get clean # ============================================================================= # NVIDIA 32-bit userspace # # The GPU Operator currently does not provide the compat32 libraries required # by 32-bit OpenGL applications and Proton/DXVK. # # Install the exact userspace version matching the host driver, then keep a # protected copy under /opt. The NVIDIA runtime can remove/mask the files in # /usr/lib/i386-linux-gnu when the pod starts; sunshine-entrypoint.sh restores # them afterwards. # ============================================================================= RUN dpkg --add-architecture i386 \ && apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ "libnvidia-common-${NVIDIA_DRIVER_BRANCH}=${NVIDIA_DRIVER_PACKAGE_VERSION}" \ "libnvidia-gpucomp-${NVIDIA_DRIVER_BRANCH}:i386=${NVIDIA_DRIVER_PACKAGE_VERSION}" \ "libnvidia-decode-${NVIDIA_DRIVER_BRANCH}:i386=${NVIDIA_DRIVER_PACKAGE_VERSION}" \ "libnvidia-compute-${NVIDIA_DRIVER_BRANCH}:i386=${NVIDIA_DRIVER_PACKAGE_VERSION}" \ "libnvidia-gl-${NVIDIA_DRIVER_BRANCH}:i386=${NVIDIA_DRIVER_PACKAGE_VERSION}" \ && mkdir -p /opt/nvidia-i386 \ && for file in $( \ dpkg -L \ "libnvidia-gl-${NVIDIA_DRIVER_BRANCH}:i386" \ "libnvidia-compute-${NVIDIA_DRIVER_BRANCH}:i386" \ "libnvidia-decode-${NVIDIA_DRIVER_BRANCH}:i386" \ "libnvidia-gpucomp-${NVIDIA_DRIVER_BRANCH}:i386" \ | grep '^/usr/lib/i386-linux-gnu/' \ | sort -u \ ); do \ if [[ -e "${file}" || -L "${file}" ]]; then \ cp -a --parents "${file}" /opt/nvidia-i386/; \ fi; \ done \ && test -e \ /opt/nvidia-i386/usr/lib/i386-linux-gnu/libGLX_nvidia.so.0 \ && test -e \ "/opt/nvidia-i386/usr/lib/i386-linux-gnu/libnvidia-glcore.so.${NVIDIA_DRIVER_VERSION}" \ && ldconfig \ && apt-get clean \ && rm -rf \ /var/lib/apt/lists/* \ /var/cache/apt/* # Keep APT package indexes available for Steam's dependency checker. RUN apt-get update \ && apt-get clean # ============================================================================= # Runtime scripts # ============================================================================= COPY desktop-entrypoint.sh /etc/desktop-entrypoint.sh COPY sunshine-entrypoint.sh /etc/sunshine-entrypoint.sh COPY supervisord.conf /etc/supervisord.conf RUN sed -i 's/\r$//' \ /etc/desktop-entrypoint.sh \ /etc/sunshine-entrypoint.sh \ /etc/supervisord.conf \ && chmod 0755 \ /etc/desktop-entrypoint.sh \ /etc/sunshine-entrypoint.sh \ && chmod 0644 \ /etc/supervisord.conf # ============================================================================= # Final filesystem permissions # ============================================================================= RUN chown -R \ "${USER_UID}:${USER_GID}" \ "/home/${USER_NAME}" \ /tmp/runtime-ubuntu # ============================================================================= # Sanity checks # ============================================================================= RUN command -v \ steam \ && command -v \ nvidia-xconfig \ && command -v \ supervisord \ && command -v \ pipewire \ && command -v \ wireplumber \ && command -v \ Xorg \ && command -v \ xfce4-session \ && test -x \ /etc/sunshine-entrypoint.sh \ && test -x \ /etc/desktop-entrypoint.sh # ============================================================================= # Runtime # ============================================================================= USER 1000:1000 WORKDIR /home/ubuntu STOPSIGNAL SIGTERM ENTRYPOINT ["/etc/sunshine-entrypoint.sh"]