Dockerfile 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. # syntax=docker/dockerfile:1.7
  2. # Final target:
  3. # Ubuntu 24.04 + NVIDIA GLX + XFCE + PipeWire + Firefox + Selkies
  4. #
  5. # The build uses intermediate stages, but produces a single final image.
  6. ARG DISTRIB_RELEASE=24.04
  7. ARG SELKIES_IMAGE=ghcr.io/selkies-project/selkies/py-build:latest
  8. ARG SELKIES_JS_IMAGE=ghcr.io/selkies-project/selkies/js-interposer:latest-ubuntu24.04
  9. ARG NVIDIA_VAAPI_DRIVER_VERSION=latest
  10. # -----------------------------------------------------------------------------
  11. # Current Selkies wheel
  12. # -----------------------------------------------------------------------------
  13. FROM ${SELKIES_IMAGE} AS selkies-build
  14. # -----------------------------------------------------------------------------
  15. # Selkies joystick interposer
  16. # -----------------------------------------------------------------------------
  17. FROM ${SELKIES_JS_IMAGE} AS selkies-js-interposer
  18. # -----------------------------------------------------------------------------
  19. # Build the current nvidia-vaapi-driver without retaining build dependencies
  20. # -----------------------------------------------------------------------------
  21. FROM ubuntu:${DISTRIB_RELEASE} AS nvidia-vaapi-builder
  22. ARG DEBIAN_FRONTEND=noninteractive
  23. ARG NVIDIA_VAAPI_DRIVER_VERSION
  24. SHELL ["/bin/bash", "-o", "pipefail", "-c"]
  25. RUN apt-get update \
  26. && apt-get install --no-install-recommends -y \
  27. ca-certificates \
  28. curl \
  29. jq \
  30. meson \
  31. ninja-build \
  32. pkg-config \
  33. libdrm-dev \
  34. libegl-dev \
  35. libffmpeg-nvenc-dev \
  36. libgstreamer-plugins-bad1.0-dev \
  37. libva-dev \
  38. && rm -rf /var/lib/apt/lists/*
  39. RUN set -eux; \
  40. version="${NVIDIA_VAAPI_DRIVER_VERSION}"; \
  41. if [[ "${version}" == "latest" ]]; then \
  42. version="$(curl -fsSL https://api.github.com/repos/elFarto/nvidia-vaapi-driver/releases/latest \
  43. | jq -r '.tag_name' \
  44. | sed 's/^v//')"; \
  45. fi; \
  46. curl -fsSL \
  47. "https://github.com/elFarto/nvidia-vaapi-driver/archive/refs/tags/v${version}.tar.gz" \
  48. -o /tmp/nvidia-vaapi-driver.tar.gz; \
  49. mkdir -p /tmp/nvidia-vaapi-driver; \
  50. tar -xzf /tmp/nvidia-vaapi-driver.tar.gz \
  51. --strip-components=1 \
  52. -C /tmp/nvidia-vaapi-driver; \
  53. cd /tmp/nvidia-vaapi-driver; \
  54. meson setup build \
  55. --prefix=/usr \
  56. --buildtype=release; \
  57. meson compile -C build; \
  58. DESTDIR=/out meson install -C build
  59. # -----------------------------------------------------------------------------
  60. # Final image
  61. # -----------------------------------------------------------------------------
  62. FROM ubuntu:${DISTRIB_RELEASE}
  63. ARG DEBIAN_FRONTEND=noninteractive
  64. ARG DISTRIB_RELEASE
  65. ARG TZ=UTC
  66. ARG USER_NAME=ubuntu
  67. ARG USER_UID=1000
  68. ARG USER_GID=1000
  69. LABEL org.opencontainers.image.title="Selkies NVIDIA XFCE Desktop" \
  70. org.opencontainers.image.description="XFCE remote desktop with Selkies, PipeWire and NVIDIA acceleration" \
  71. org.opencontainers.image.source="https://github.com/selkies-project/selkies"
  72. SHELL ["/bin/bash", "-o", "pipefail", "-c"]
  73. ENV TZ="${TZ}" \
  74. LANG="en_US.UTF-8" \
  75. LANGUAGE="en_US:en" \
  76. LC_ALL="en_US.UTF-8" \
  77. PASSWD="mypasswd" \
  78. DISPLAY=":20" \
  79. DISPLAY_SIZEW="1920" \
  80. DISPLAY_SIZEH="1080" \
  81. DISPLAY_REFRESH="60" \
  82. DISPLAY_DPI="96" \
  83. DISPLAY_CDEPTH="24" \
  84. VIDEO_PORT="DFP" \
  85. DESKTOP_SESSION="xfce" \
  86. XDG_SESSION_DESKTOP="xfce" \
  87. XDG_CURRENT_DESKTOP="XFCE" \
  88. XDG_SESSION_TYPE="x11" \
  89. SELKIES_MODE="websockets" \
  90. SELKIES_PORT="8080" \
  91. SELKIES_ENCODER="h264enc" \
  92. SELKIES_ENABLE_RESIZE="false" \
  93. SELKIES_ENABLE_BASIC_AUTH="true" \
  94. NVIDIA_VISIBLE_DEVICES="all" \
  95. NVIDIA_DRIVER_CAPABILITIES="all" \
  96. __GL_SYNC_TO_VBLANK="0" \
  97. __GLX_VENDOR_LIBRARY_NAME="nvidia" \
  98. LIBVA_DRIVER_NAME="nvidia" \
  99. NVD_BACKEND="direct" \
  100. MOZ_DISABLE_RDD_SANDBOX="1" \
  101. MOZ_X11_EGL="1" \
  102. PIPEWIRE_LATENCY="128/48000" \
  103. XDG_RUNTIME_DIR="/tmp/runtime-ubuntu" \
  104. PIPEWIRE_RUNTIME_DIR="/tmp/runtime-ubuntu" \
  105. PULSE_RUNTIME_PATH="/tmp/runtime-ubuntu/pulse" \
  106. PULSE_SERVER="unix:/tmp/runtime-ubuntu/pulse/native" \
  107. DBUS_SYSTEM_BUS_ADDRESS="unix:path=/tmp/runtime-ubuntu/dbus-system-bus" \
  108. APPIMAGE_EXTRACT_AND_RUN="1" \
  109. SUDO_EDITOR="mousepad"
  110. # Bootstrap packages needed to configure APT repositories.
  111. RUN apt-get update \
  112. && apt-get install --no-install-recommends -y \
  113. ca-certificates \
  114. curl \
  115. gnupg \
  116. locales \
  117. ssl-cert \
  118. tzdata \
  119. && locale-gen en_US.UTF-8 \
  120. && ln -snf "/usr/share/zoneinfo/${TZ}" /etc/localtime \
  121. && echo "${TZ}" > /etc/timezone \
  122. && rm -rf /var/lib/apt/lists/*
  123. # Keep the same Mozilla and PipeWire repositories as the original image.
  124. RUN install -d -m 0755 \
  125. /etc/apt/preferences.d \
  126. /etc/apt/sources.list.d \
  127. /etc/apt/trusted.gpg.d \
  128. && printf '%s\n' \
  129. 'Package: firefox*' \
  130. 'Pin: version 1:1snap*' \
  131. 'Pin-Priority: -1' \
  132. > /etc/apt/preferences.d/firefox-nosnap \
  133. && curl -fsSL \
  134. 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x738BEB9321D1AAEC13EA9391AEBDF4819BE21867' \
  135. | gpg --dearmor \
  136. > /etc/apt/trusted.gpg.d/mozillateam-ubuntu-ppa.gpg \
  137. && echo \
  138. "deb https://ppa.launchpadcontent.net/mozillateam/ppa/ubuntu noble main" \
  139. > /etc/apt/sources.list.d/mozillateam-ubuntu-ppa.list \
  140. && curl -fsSL \
  141. 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xFC43B7352BCC0EC8AF2EEB8B25088A0359807596' \
  142. | gpg --dearmor \
  143. > /etc/apt/trusted.gpg.d/pipewire-debian-ubuntu.gpg \
  144. && echo \
  145. "deb https://ppa.launchpadcontent.net/pipewire-debian/pipewire-upstream/ubuntu noble main" \
  146. > /etc/apt/sources.list.d/pipewire-upstream.list \
  147. && echo \
  148. "deb https://ppa.launchpadcontent.net/pipewire-debian/wireplumber-upstream/ubuntu noble main" \
  149. > /etc/apt/sources.list.d/wireplumber-upstream.list
  150. # Base system, desktop, Xorg, NVIDIA runtime interfaces and user tools.
  151. # There are deliberately no Intel/AMD VA-API or Vulkan drivers and no i386
  152. # architecture.
  153. RUN apt-get update \
  154. && apt-get install --no-install-recommends -y \
  155. apt-utils \
  156. bash-completion \
  157. binutils \
  158. btop \
  159. bzip2 \
  160. clinfo \
  161. dbus-user-session \
  162. dbus-x11 \
  163. desktop-file-utils \
  164. dnsutils \
  165. file \
  166. firefox \
  167. fonts-dejavu \
  168. fonts-liberation \
  169. fonts-noto \
  170. fonts-noto-cjk \
  171. fonts-noto-color-emoji \
  172. fonts-noto-mono \
  173. fonts-ubuntu \
  174. fuse \
  175. git \
  176. gvfs \
  177. jq \
  178. kmod \
  179. less \
  180. libdrm2 \
  181. libegl1 \
  182. libelf-dev \
  183. libgcrypt20 \
  184. libgl1 \
  185. libgles1 \
  186. libgles2 \
  187. libglu1-mesa \
  188. libglvnd-dev \
  189. libglvnd0 \
  190. libglx0 \
  191. libgstreamer-plugins-bad1.0-0 \
  192. libopengl0 \
  193. libopus0 \
  194. libpci3 \
  195. libpulse0 \
  196. libsm6 \
  197. libva-drm2 \
  198. libva-x11-2 \
  199. libva2 \
  200. libvulkan1 \
  201. libx11-6 \
  202. libx11-xcb1 \
  203. libxau6 \
  204. libxcb-dri3-0 \
  205. libxcb1 \
  206. libxdamage1 \
  207. libxdmcp6 \
  208. libxext6 \
  209. libxfixes3 \
  210. libxkbcommon0 \
  211. libxtst6 \
  212. libxv1 \
  213. mousepad \
  214. nano \
  215. neofetch \
  216. net-tools \
  217. ocl-icd-libopencl1 \
  218. pavucontrol \
  219. pciutils \
  220. procps \
  221. psmisc \
  222. python3 \
  223. python3-pip \
  224. python3-venv \
  225. ristretto \
  226. sudo \
  227. supervisor \
  228. thunar \
  229. tumbler \
  230. udev \
  231. unzip \
  232. vainfo \
  233. vim \
  234. vulkan-tools \
  235. wget \
  236. wmctrl \
  237. x11-apps \
  238. x11-utils \
  239. x11-xkb-utils \
  240. x11-xserver-utils \
  241. x264 \
  242. x265 \
  243. xauth \
  244. xbitmaps \
  245. xclip \
  246. xcvt \
  247. xdg-user-dirs \
  248. xdg-utils \
  249. xfce4 \
  250. xfce4-goodies \
  251. xfce4-notifyd \
  252. xfce4-pulseaudio-plugin \
  253. xfce4-terminal \
  254. xfonts-base \
  255. xfonts-scalable \
  256. xinit \
  257. xkb-data \
  258. xsel \
  259. xserver-xorg-core \
  260. xserver-xorg-input-libinput \
  261. xserver-xorg-legacy \
  262. xsettingsd \
  263. xterm \
  264. xdotool \
  265. xz-utils \
  266. zip \
  267. zstd \
  268. pipewire \
  269. pipewire-alsa \
  270. pipewire-audio-client-libraries \
  271. pipewire-jack \
  272. pipewire-libcamera \
  273. pipewire-locales \
  274. pipewire-v4l2 \
  275. pipewire-vulkan \
  276. gstreamer1.0-libcamera \
  277. gstreamer1.0-pipewire \
  278. gir1.2-wp-0.5 \
  279. libpipewire-0.3-modules \
  280. libpipewire-module-x11-bell \
  281. libspa-0.2-bluetooth \
  282. libspa-0.2-jack \
  283. libspa-0.2-modules \
  284. wireplumber \
  285. wireplumber-locales \
  286. && apt-get clean \
  287. && rm -rf \
  288. /var/lib/apt/lists/* \
  289. /var/cache/apt/* \
  290. /var/cache/debconf/* \
  291. /var/log/* \
  292. /tmp/* \
  293. /var/tmp/*
  294. # Install only the compiled NVIDIA VA-API runtime from the builder stage.
  295. COPY --from=nvidia-vaapi-builder /out/usr/ /usr/
  296. # Make NVIDIA libraries injected by NVIDIA Container Toolkit discoverable.
  297. RUN printf '%s\n' \
  298. '/usr/local/nvidia/lib' \
  299. '/usr/local/nvidia/lib64' \
  300. > /etc/ld.so.conf.d/nvidia.conf \
  301. && install -d -m 0755 \
  302. /etc/OpenCL/vendors \
  303. /etc/vulkan/icd.d \
  304. /usr/share/glvnd/egl_vendor.d \
  305. && echo 'libnvidia-opencl.so.1' \
  306. > /etc/OpenCL/vendors/nvidia.icd \
  307. && cat > /etc/vulkan/icd.d/nvidia_icd.json <<'EOF'
  308. {
  309. "file_format_version": "1.0.0",
  310. "ICD": {
  311. "library_path": "libGLX_nvidia.so.0",
  312. "api_version": "1.3.0"
  313. }
  314. }
  315. EOF
  316. RUN cat > /usr/share/glvnd/egl_vendor.d/10_nvidia.json <<'EOF'
  317. {
  318. "file_format_version": "1.0.0",
  319. "ICD": {
  320. "library_path": "libEGL_nvidia.so.0"
  321. }
  322. }
  323. EOF
  324. ENV PATH="/opt/selkies/bin:/usr/local/nvidia/bin:${PATH}" \
  325. LD_LIBRARY_PATH="/usr/local/nvidia/lib:/usr/local/nvidia/lib64"
  326. # Install the Selkies wheel from the official stable build image.
  327. COPY --from=selkies-build /opt/pypi/dist/selkies-*.whl /tmp/
  328. RUN python3 -m venv /opt/selkies \
  329. && /opt/selkies/bin/python -m pip install \
  330. --no-cache-dir \
  331. --upgrade \
  332. pip \
  333. && /opt/selkies/bin/python -m pip install \
  334. --no-cache-dir \
  335. /tmp/selkies-*.whl \
  336. && rm -f /tmp/selkies-*.whl
  337. # Preserve browser gamepad support from the original image.
  338. COPY --from=selkies-js-interposer /opt/*.deb /tmp/selkies-js-interposer.deb
  339. RUN apt-get update \
  340. && apt-get install --no-install-recommends -y \
  341. /tmp/selkies-js-interposer.deb \
  342. && rm -f /tmp/selkies-js-interposer.deb \
  343. && rm -rf /var/lib/apt/lists/*
  344. # Create the regular desktop user. sudo-root is kept because Xorg and the
  345. # NVIDIA userspace installer need a few targeted root operations at runtime.
  346. RUN groupadd --gid "${USER_GID}" "${USER_NAME}" \
  347. && useradd \
  348. --uid "${USER_UID}" \
  349. --gid "${USER_GID}" \
  350. --create-home \
  351. --shell /bin/bash \
  352. "${USER_NAME}" \
  353. && for group in \
  354. adm audio cdrom dialout dip fax floppy games input lp plugdev render \
  355. ssl-cert sudo tape tty video voice; \
  356. do \
  357. getent group "${group}" >/dev/null \
  358. && usermod -aG "${group}" "${USER_NAME}" \
  359. || true; \
  360. done \
  361. && echo "${USER_NAME} ALL=(ALL:ALL) NOPASSWD: ALL" \
  362. > "/etc/sudoers.d/${USER_NAME}" \
  363. && chmod 0440 "/etc/sudoers.d/${USER_NAME}" \
  364. && echo "${USER_NAME}:${PASSWD}" | chpasswd \
  365. && cp -a /usr/bin/sudo /usr/bin/sudo-root \
  366. && chown root:root /usr/bin/sudo-root \
  367. && chmod 4755 /usr/bin/sudo-root \
  368. && install -d \
  369. -o "${USER_UID}" \
  370. -g "${USER_GID}" \
  371. -m 0700 \
  372. /tmp/runtime-ubuntu \
  373. && chown -R \
  374. "${USER_UID}:${USER_GID}" \
  375. "/home/${USER_NAME}" \
  376. /etc/X11 \
  377. /opt/selkies
  378. # XFCE defaults suitable for a permanently streamed desktop.
  379. RUN install -d -m 0755 \
  380. /etc/xdg/xfce4/xfconf/xfce-perchannel-xml \
  381. /etc/firefox/policies \
  382. && if [[ -f /etc/xdg/xfce4/panel/default.xml ]]; then \
  383. cp -f \
  384. /etc/xdg/xfce4/panel/default.xml \
  385. /etc/xdg/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml; \
  386. fi \
  387. && cat > /etc/xdg/xfce4/xfconf/xfce-perchannel-xml/xfce4-power-manager.xml <<'EOF'
  388. <?xml version="1.0" encoding="UTF-8"?>
  389. <channel name="xfce4-power-manager" version="1.0">
  390. <property name="xfce4-power-manager" type="empty">
  391. <property name="blank-on-ac" type="int" value="0"/>
  392. <property name="dpms-enabled" type="bool" value="false"/>
  393. <property name="lock-screen-suspend-hibernate" type="bool" value="false"/>
  394. </property>
  395. </channel>
  396. EOF
  397. RUN cat > /etc/firefox/policies/policies.json <<'EOF'
  398. {
  399. "policies": {
  400. "Preferences": {
  401. "gfx.x11-egl.force-enabled": {
  402. "Value": true,
  403. "Status": "default"
  404. },
  405. "media.ffmpeg.vaapi.enabled": {
  406. "Value": true,
  407. "Status": "default"
  408. },
  409. "media.hardware-video-decoding.force-enabled": {
  410. "Value": true,
  411. "Status": "default"
  412. },
  413. "media.rdd-ffmpeg.enabled": {
  414. "Value": true,
  415. "Status": "default"
  416. }
  417. }
  418. }
  419. }
  420. EOF
  421. RUN update-alternatives --set x-www-browser /usr/bin/firefox \
  422. || true
  423. # The three files below must be placed beside this Dockerfile.
  424. COPY --chown=${USER_UID}:${USER_GID} entrypoint.sh /etc/entrypoint.sh
  425. COPY --chown=${USER_UID}:${USER_GID} selkies-entrypoint.sh /etc/selkies-entrypoint.sh
  426. COPY --chown=${USER_UID}:${USER_GID} supervisord.conf /etc/supervisord.conf
  427. RUN chmod 0755 \
  428. /etc/entrypoint.sh \
  429. /etc/selkies-entrypoint.sh \
  430. /etc/supervisord.conf
  431. USER ${USER_UID}:${USER_GID}
  432. ENV USER="${USER_NAME}" \
  433. HOME="/home/${USER_NAME}" \
  434. SHELL="/bin/bash"
  435. WORKDIR /home/${USER_NAME}
  436. EXPOSE 8080
  437. ENTRYPOINT ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]