Dockerfile 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  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:main
  8. ARG SELKIES_GIT_REF=main
  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. # Build the Selkies joystick interposer directly from its official source.
  18. FROM docker.io/library/ubuntu:${DISTRIB_RELEASE} AS selkies-js-interposer-builder
  19. ARG DEBIAN_FRONTEND=noninteractive
  20. ARG SELKIES_GIT_REF
  21. SHELL ["/bin/bash", "-o", "pipefail", "-c"]
  22. RUN apt-get update \
  23. && apt-get install --no-install-recommends -y \
  24. build-essential \
  25. ca-certificates \
  26. curl \
  27. && rm -rf /var/lib/apt/lists/*
  28. RUN set -eux; \
  29. curl -fsSL \
  30. "https://raw.githubusercontent.com/selkies-project/selkies/${SELKIES_GIT_REF}/addons/js-interposer/joystick_interposer.c" \
  31. -o /tmp/joystick_interposer.c; \
  32. install -d -m 0755 /out; \
  33. gcc -shared -fPIC -O2 \
  34. -Wl,-z,relro,-z,now \
  35. -o /out/selkies_joystick_interposer.so \
  36. /tmp/joystick_interposer.c \
  37. -ldl; \
  38. test -s /out/selkies_joystick_interposer.so
  39. # -----------------------------------------------------------------------------
  40. # Build the Selkies Python environment
  41. # -----------------------------------------------------------------------------
  42. FROM docker.io/library/ubuntu:${DISTRIB_RELEASE} AS selkies-runtime-builder
  43. ARG DEBIAN_FRONTEND=noninteractive
  44. SHELL ["/bin/bash", "-o", "pipefail", "-c"]
  45. COPY --from=selkies-build /opt/pypi/dist/selkies-*.whl /tmp/
  46. RUN apt-get update \
  47. && apt-get install --no-install-recommends -y \
  48. build-essential \
  49. libsm6 \
  50. libopus0 \
  51. libpulse0 \
  52. libxkbcommon-dev \
  53. pkg-config \
  54. python3 \
  55. python3-dev \
  56. python3-pip \
  57. python3-venv \
  58. && python3 -m venv /opt/selkies \
  59. && /opt/selkies/bin/python -m pip install \
  60. --no-cache-dir \
  61. --upgrade \
  62. pip \
  63. setuptools \
  64. wheel \
  65. && printf '%s\n' \
  66. 'pixelflux==1.6.4' \
  67. 'pcmflux==1.0.8' \
  68. > /tmp/selkies-constraints.txt \
  69. && /opt/selkies/bin/python -m pip install \
  70. --no-cache-dir \
  71. --force-reinstall \
  72. --constraint /tmp/selkies-constraints.txt \
  73. /tmp/selkies-*.whl
  74. # -----------------------------------------------------------------------------
  75. # Build the current nvidia-vaapi-driver without retaining build dependencies
  76. # -----------------------------------------------------------------------------
  77. FROM docker.io/library/ubuntu:${DISTRIB_RELEASE} AS nvidia-vaapi-builder
  78. ARG DEBIAN_FRONTEND=noninteractive
  79. ARG NVIDIA_VAAPI_DRIVER_VERSION
  80. SHELL ["/bin/bash", "-o", "pipefail", "-c"]
  81. RUN apt-get update \
  82. && apt-get install --no-install-recommends -y \
  83. ca-certificates \
  84. curl \
  85. gcc \
  86. jq \
  87. meson \
  88. ninja-build \
  89. pkg-config \
  90. libdrm-dev \
  91. libegl-dev \
  92. libffmpeg-nvenc-dev \
  93. libgstreamer-plugins-bad1.0-dev \
  94. libva-dev \
  95. && rm -rf /var/lib/apt/lists/*
  96. RUN set -eux; \
  97. version="${NVIDIA_VAAPI_DRIVER_VERSION}"; \
  98. if [[ "${version}" == "latest" ]]; then \
  99. version="$(curl -fsSL https://api.github.com/repos/elFarto/nvidia-vaapi-driver/releases/latest \
  100. | jq -r '.tag_name' \
  101. | sed 's/^v//')"; \
  102. fi; \
  103. curl -fsSL \
  104. "https://github.com/elFarto/nvidia-vaapi-driver/archive/refs/tags/v${version}.tar.gz" \
  105. -o /tmp/nvidia-vaapi-driver.tar.gz; \
  106. mkdir -p /tmp/nvidia-vaapi-driver; \
  107. tar -xzf /tmp/nvidia-vaapi-driver.tar.gz \
  108. --strip-components=1 \
  109. -C /tmp/nvidia-vaapi-driver; \
  110. cd /tmp/nvidia-vaapi-driver; \
  111. meson setup build \
  112. --prefix=/usr \
  113. --buildtype=release; \
  114. meson compile -C build; \
  115. DESTDIR=/out meson install -C build
  116. # -----------------------------------------------------------------------------
  117. # Build the Selkies web frontend from the official source repository
  118. # -----------------------------------------------------------------------------
  119. FROM docker.io/library/node:22-bookworm-slim AS selkies-web-builder
  120. ARG DEBIAN_FRONTEND=noninteractive
  121. ARG SELKIES_GIT_REF=main
  122. ARG SELKIES_MODE=websockets
  123. ARG SELKIES_UPLOAD_DIR=/home/ubuntu/Desktop
  124. SHELL ["/bin/bash", "-o", "pipefail", "-c"]
  125. RUN apt-get update \
  126. && apt-get install --no-install-recommends -y \
  127. ca-certificates \
  128. cmake \
  129. curl \
  130. git \
  131. && rm -rf /var/lib/apt/lists/*
  132. WORKDIR /tmp/selkies
  133. RUN curl -fsSL \
  134. "https://github.com/selkies-project/selkies/archive/${SELKIES_GIT_REF}.tar.gz" \
  135. -o /tmp/selkies.tar.gz \
  136. && tar -xzf /tmp/selkies.tar.gz \
  137. --strip-components=1 \
  138. -C /tmp/selkies \
  139. && rm -f /tmp/selkies.tar.gz
  140. RUN set -eux; \
  141. cd /tmp/selkies/addons/selkies-web-core; \
  142. npm install; \
  143. npm run build; \
  144. \
  145. cd /tmp/selkies/addons/selkies-dashboard; \
  146. cp ../selkies-web-core/dist/selkies-core.js src/; \
  147. npm install; \
  148. SELKIES_INJECT=1 \
  149. SELKIES_MODE="${SELKIES_MODE}" \
  150. SELKIES_UPLOAD_DIR="${SELKIES_UPLOAD_DIR}" \
  151. npm run build; \
  152. \
  153. mkdir -p dist/src; \
  154. cp ../selkies-web-core/dist/selkies-core.js dist/src/; \
  155. cp ../universal-touch-gamepad/universalTouchGamepad.js dist/src/; \
  156. cp -r ../selkies-web-core/dist/jsdb dist/; \
  157. \
  158. mkdir -p /out; \
  159. cp -a dist/. /out/; \
  160. test -f /out/index.html
  161. FROM docker.io/library/ubuntu:${DISTRIB_RELEASE} AS pixelflux-legacy-builder
  162. ARG DEBIAN_FRONTEND=noninteractive
  163. ARG PIXELFLUX_VERSION=1.6.4
  164. SHELL ["/bin/bash", "-o", "pipefail", "-c"]
  165. RUN apt-get update \
  166. && apt-get install --no-install-recommends -y \
  167. ca-certificates \
  168. curl \
  169. g++ \
  170. pkg-config \
  171. libavcodec-dev \
  172. libavutil-dev \
  173. libdrm-dev \
  174. libjpeg-dev \
  175. libva-dev \
  176. libx11-dev \
  177. libx264-dev \
  178. libxext-dev \
  179. libxfixes-dev \
  180. libyuv-dev \
  181. && rm -rf /var/lib/apt/lists/*
  182. WORKDIR /tmp/pixelflux
  183. RUN curl -fsSL \
  184. "https://codeload.github.com/linuxserver/pixelflux/tar.gz/refs/tags/${PIXELFLUX_VERSION}" \
  185. -o /tmp/pixelflux.tar.gz \
  186. && tar -xzf /tmp/pixelflux.tar.gz \
  187. --strip-components=1 \
  188. -C /tmp/pixelflux \
  189. && mkdir -p /out \
  190. && test -f /usr/include/va/va.h \
  191. && test -f /usr/include/va/va_drm.h \
  192. && test -f /usr/include/libdrm/drm.h \
  193. && pkg-config --exists libavcodec libavutil libva libdrm x11 xext xfixes \
  194. && g++ \
  195. -std=c++17 \
  196. -Wno-unused-function \
  197. -fPIC \
  198. -O3 \
  199. -flto \
  200. -shared \
  201. -Ipixelflux/include \
  202. -o /out/screen_capture_module.so \
  203. pixelflux/screen_capture_module.cpp \
  204. pixelflux/include/xxhash.c \
  205. -lX11 \
  206. -lXext \
  207. -lXfixes \
  208. -ljpeg \
  209. -lx264 \
  210. -lyuv \
  211. -ldl \
  212. -lavcodec \
  213. -lavutil \
  214. && test -s /out/screen_capture_module.so \
  215. && ! ldd /out/screen_capture_module.so | grep -q "not found"
  216. && g++ \
  217. -std=c++17 \
  218. -Wno-unused-function \
  219. -fPIC \
  220. -O3 \
  221. -flto \
  222. -shared \
  223. -Ipixelflux/include \
  224. -o /out/screen_capture_module.so \
  225. pixelflux/screen_capture_module.cpp \
  226. pixelflux/include/xxhash.c \
  227. -lX11 \
  228. -lXext \
  229. -lXfixes \
  230. -ljpeg \
  231. -lx264 \
  232. -lyuv \
  233. -ldl \
  234. -lavcodec \
  235. -lavutil \
  236. && test -s /out/screen_capture_module.so
  237. # -----------------------------------------------------------------------------
  238. # Final image
  239. # -----------------------------------------------------------------------------
  240. FROM docker.io/library/ubuntu:${DISTRIB_RELEASE}
  241. ARG DEBIAN_FRONTEND=noninteractive
  242. ARG DISTRIB_RELEASE
  243. ARG TZ=UTC
  244. ARG USER_NAME=ubuntu
  245. ARG USER_UID=1000
  246. ARG USER_GID=1000
  247. LABEL org.opencontainers.image.title="Selkies NVIDIA XFCE Desktop" \
  248. org.opencontainers.image.description="XFCE remote desktop with Selkies, PipeWire and NVIDIA acceleration" \
  249. org.opencontainers.image.source="https://github.com/selkies-project/selkies"
  250. SHELL ["/bin/bash", "-o", "pipefail", "-c"]
  251. ENV TZ="${TZ}" \
  252. LANG="en_US.UTF-8" \
  253. LANGUAGE="en_US:en" \
  254. LC_ALL="en_US.UTF-8" \
  255. PASSWD="mypasswd" \
  256. DISPLAY=":20" \
  257. DISPLAY_SIZEW="1920" \
  258. DISPLAY_SIZEH="1080" \
  259. DISPLAY_REFRESH="60" \
  260. DISPLAY_DPI="96" \
  261. DISPLAY_CDEPTH="24" \
  262. VIDEO_PORT="DFP" \
  263. DESKTOP_SESSION="xfce" \
  264. XDG_SESSION_DESKTOP="xfce" \
  265. XDG_CURRENT_DESKTOP="XFCE" \
  266. XDG_SESSION_TYPE="x11" \
  267. SELKIES_MODE="websockets" \
  268. SELKIES_PORT="8081" \
  269. SELKIES_ENCODER="h264enc" \
  270. SELKIES_ENABLE_RESIZE="false" \
  271. SELKIES_ENABLE_BASIC_AUTH="true" \
  272. NVIDIA_VISIBLE_DEVICES="all" \
  273. NVIDIA_DRIVER_CAPABILITIES="all" \
  274. __GL_SYNC_TO_VBLANK="0" \
  275. __GLX_VENDOR_LIBRARY_NAME="nvidia" \
  276. LIBVA_DRIVER_NAME="nvidia" \
  277. NVD_BACKEND="direct" \
  278. MOZ_DISABLE_RDD_SANDBOX="1" \
  279. MOZ_X11_EGL="1" \
  280. PIPEWIRE_LATENCY="128/48000" \
  281. XDG_RUNTIME_DIR="/tmp/runtime-ubuntu" \
  282. PIPEWIRE_RUNTIME_DIR="/tmp/runtime-ubuntu" \
  283. PULSE_RUNTIME_PATH="/tmp/runtime-ubuntu/pulse" \
  284. PULSE_SERVER="unix:/tmp/runtime-ubuntu/pulse/native" \
  285. DBUS_SYSTEM_BUS_ADDRESS="unix:path=/tmp/runtime-ubuntu/dbus-system-bus" \
  286. APPIMAGE_EXTRACT_AND_RUN="1" \
  287. SUDO_EDITOR="mousepad"
  288. # Bootstrap packages needed to configure APT repositories.
  289. RUN apt-get update \
  290. && apt-get install --no-install-recommends -y \
  291. ca-certificates \
  292. curl \
  293. gnupg \
  294. locales \
  295. ssl-cert \
  296. tzdata \
  297. && locale-gen en_US.UTF-8 fr_FR.UTF-8 \
  298. && ln -snf "/usr/share/zoneinfo/${TZ}" /etc/localtime \
  299. && echo "${TZ}" > /etc/timezone \
  300. && rm -rf /var/lib/apt/lists/*
  301. # Keep the same Mozilla and PipeWire repositories as the original image.
  302. RUN install -d -m 0755 \
  303. /etc/apt/preferences.d \
  304. /etc/apt/sources.list.d \
  305. /etc/apt/trusted.gpg.d \
  306. && printf '%s\n' \
  307. 'Package: firefox*' \
  308. 'Pin: version 1:1snap*' \
  309. 'Pin-Priority: -1' \
  310. > /etc/apt/preferences.d/firefox-nosnap \
  311. && curl -fsSL \
  312. 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x738BEB9321D1AAEC13EA9391AEBDF4819BE21867' \
  313. | gpg --dearmor \
  314. > /etc/apt/trusted.gpg.d/mozillateam-ubuntu-ppa.gpg \
  315. && echo \
  316. "deb https://ppa.launchpadcontent.net/mozillateam/ppa/ubuntu noble main" \
  317. > /etc/apt/sources.list.d/mozillateam-ubuntu-ppa.list \
  318. && curl -fsSL \
  319. 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xFC43B7352BCC0EC8AF2EEB8B25088A0359807596' \
  320. | gpg --dearmor \
  321. > /etc/apt/trusted.gpg.d/pipewire-debian-ubuntu.gpg \
  322. && echo \
  323. "deb https://ppa.launchpadcontent.net/pipewire-debian/pipewire-upstream/ubuntu noble main" \
  324. > /etc/apt/sources.list.d/pipewire-upstream.list \
  325. && echo \
  326. "deb https://ppa.launchpadcontent.net/pipewire-debian/wireplumber-upstream/ubuntu noble main" \
  327. > /etc/apt/sources.list.d/wireplumber-upstream.list
  328. # Base system, desktop, Xorg, NVIDIA runtime interfaces and user tools.
  329. # There are deliberately no Intel/AMD VA-API or Vulkan drivers and no i386
  330. # architecture.
  331. RUN apt-get update \
  332. && apt-get install --no-install-recommends -y \
  333. apt-utils \
  334. bash-completion \
  335. binutils \
  336. btop \
  337. bzip2 \
  338. clinfo \
  339. dbus-user-session \
  340. dbus-x11 \
  341. desktop-file-utils \
  342. dnsutils \
  343. file \
  344. firefox \
  345. fonts-dejavu \
  346. fonts-liberation \
  347. fonts-noto \
  348. fonts-noto-cjk \
  349. fonts-noto-color-emoji \
  350. fonts-noto-mono \
  351. fonts-ubuntu \
  352. fuse \
  353. git \
  354. gvfs \
  355. jq \
  356. kmod \
  357. less \
  358. libdrm2 \
  359. libegl1 \
  360. libelf-dev \
  361. libgcrypt20 \
  362. libgl1 \
  363. libgles1 \
  364. libgles2 \
  365. libglu1-mesa \
  366. libglvnd-dev \
  367. libglvnd0 \
  368. libglx0 \
  369. libgstreamer-plugins-bad1.0-0 \
  370. libopengl0 \
  371. libopus0 \
  372. libpci3 \
  373. libpulse0 \
  374. libsm6 \
  375. libva-drm2 \
  376. libva-x11-2 \
  377. libva2 \
  378. libvulkan1 \
  379. libx11-6 \
  380. libx11-xcb1 \
  381. libxau6 \
  382. libxcb-dri3-0 \
  383. libxcb1 \
  384. libxdamage1 \
  385. libxdmcp6 \
  386. libxext6 \
  387. libxfixes3 \
  388. libxkbcommon0 \
  389. libxtst6 \
  390. libxv1 \
  391. mousepad \
  392. nano \
  393. neofetch \
  394. net-tools \
  395. ocl-icd-libopencl1 \
  396. pavucontrol \
  397. pciutils \
  398. procps \
  399. psmisc \
  400. python3 \
  401. python3-pip \
  402. python3-venv \
  403. ristretto \
  404. sudo \
  405. supervisor \
  406. thunar \
  407. tumbler \
  408. udev \
  409. unzip \
  410. vainfo \
  411. vim \
  412. vulkan-tools \
  413. wget \
  414. wmctrl \
  415. x11-apps \
  416. x11-utils \
  417. x11-xkb-utils \
  418. x11-xserver-utils \
  419. x264 \
  420. x265 \
  421. xauth \
  422. xbitmaps \
  423. xclip \
  424. xcvt \
  425. xdg-user-dirs \
  426. xdg-utils \
  427. xfce4 \
  428. xfce4-goodies \
  429. xfce4-notifyd \
  430. xfce4-pulseaudio-plugin \
  431. xfce4-terminal \
  432. xfonts-base \
  433. xfonts-scalable \
  434. xinit \
  435. xkb-data \
  436. xsel \
  437. xserver-xorg-core \
  438. xserver-xorg-input-libinput \
  439. xserver-xorg-legacy \
  440. xsettingsd \
  441. xterm \
  442. xdotool \
  443. xz-utils \
  444. zip \
  445. zstd \
  446. pipewire \
  447. pipewire-alsa \
  448. pipewire-audio-client-libraries \
  449. pipewire-jack \
  450. pipewire-libcamera \
  451. pipewire-locales \
  452. pipewire-v4l2 \
  453. pipewire-vulkan \
  454. gstreamer1.0-libcamera \
  455. gstreamer1.0-pipewire \
  456. gir1.2-wp-0.5 \
  457. libpipewire-0.3-modules \
  458. libpipewire-module-x11-bell \
  459. libspa-0.2-bluetooth \
  460. libspa-0.2-jack \
  461. libspa-0.2-modules \
  462. wireplumber \
  463. wireplumber-locales \
  464. apache2-utils \
  465. nginx \
  466. netcat-openbsd \
  467. && apt-get clean \
  468. && rm -rf \
  469. /var/lib/apt/lists/* \
  470. /var/cache/apt/* \
  471. /var/cache/debconf/* \
  472. /var/log/* \
  473. /tmp/* \
  474. /var/tmp/*
  475. # Install only the compiled NVIDIA VA-API runtime from the builder stage.
  476. COPY --from=nvidia-vaapi-builder /out/usr/ /usr/
  477. # Make NVIDIA libraries injected by NVIDIA Container Toolkit discoverable.
  478. RUN printf '%s\n' \
  479. '/usr/local/nvidia/lib' \
  480. '/usr/local/nvidia/lib64' \
  481. > /etc/ld.so.conf.d/nvidia.conf \
  482. && install -d -m 0755 \
  483. /etc/OpenCL/vendors \
  484. /etc/vulkan/icd.d \
  485. /usr/share/glvnd/egl_vendor.d \
  486. && echo 'libnvidia-opencl.so.1' \
  487. > /etc/OpenCL/vendors/nvidia.icd \
  488. && cat > /etc/vulkan/icd.d/nvidia_icd.json <<'EOF'
  489. {
  490. "file_format_version": "1.0.0",
  491. "ICD": {
  492. "library_path": "libGLX_nvidia.so.0",
  493. "api_version": "1.3.0"
  494. }
  495. }
  496. EOF
  497. RUN cat > /usr/share/glvnd/egl_vendor.d/10_nvidia.json <<'EOF'
  498. {
  499. "file_format_version": "1.0.0",
  500. "ICD": {
  501. "library_path": "libEGL_nvidia.so.0"
  502. }
  503. }
  504. EOF
  505. ENV PATH="/opt/selkies/bin:/usr/local/nvidia/bin:${PATH}" \
  506. LD_LIBRARY_PATH="/usr/local/nvidia/lib:/usr/local/nvidia/lib64"
  507. # Install the Selkies wheel from the official stable build image.
  508. COPY --from=selkies-runtime-builder /opt/selkies /opt/selkies
  509. COPY --from=pixelflux-legacy-builder \
  510. /out/screen_capture_module.so \
  511. /tmp/screen_capture_module.so
  512. RUN set -eux; \
  513. PIXELFLUX_DIR="$(/opt/selkies/bin/python -c \
  514. 'from pathlib import Path; import pixelflux; print(Path(pixelflux.__file__).resolve().parent)')"; \
  515. install -m 0755 \
  516. /tmp/screen_capture_module.so \
  517. "${PIXELFLUX_DIR}/screen_capture_module.so"; \
  518. ldd "${PIXELFLUX_DIR}/screen_capture_module.so"; \
  519. test -z "$(ldd "${PIXELFLUX_DIR}/screen_capture_module.so" | grep 'not found' || true)"; \
  520. rm -f /tmp/screen_capture_module.so
  521. COPY --chown=${USER_UID}:${USER_GID} \
  522. --from=selkies-web-builder \
  523. /out/ \
  524. /opt/selkies-web/
  525. COPY --from=selkies-js-interposer-builder \
  526. /out/selkies_joystick_interposer.so \
  527. /usr/local/lib/selkies_joystick_interposer.so
  528. RUN chmod 0755 /usr/local/lib/selkies_joystick_interposer.so
  529. # Create the regular desktop user. sudo-root is kept because Xorg and the
  530. # NVIDIA userspace installer need a few targeted root operations at runtime.
  531. RUN set -eux; \
  532. if ! getent group "${USER_NAME}" >/dev/null; then \
  533. groupadd --gid "${USER_GID}" "${USER_NAME}"; \
  534. fi; \
  535. if ! id -u "${USER_NAME}" >/dev/null 2>&1; then \
  536. useradd \
  537. --uid "${USER_UID}" \
  538. --gid "${USER_NAME}" \
  539. --create-home \
  540. --shell /bin/bash \
  541. "${USER_NAME}"; \
  542. else \
  543. usermod --shell /bin/bash "${USER_NAME}"; \
  544. fi; \
  545. for group in \
  546. adm audio cdrom dialout dip fax floppy games input lp plugdev render \
  547. ssl-cert sudo tape tty video voice; \
  548. do \
  549. getent group "${group}" >/dev/null \
  550. && usermod -aG "${group}" "${USER_NAME}" \
  551. || true; \
  552. done; \
  553. echo "${USER_NAME} ALL=(ALL:ALL) NOPASSWD: ALL" \
  554. > "/etc/sudoers.d/${USER_NAME}"; \
  555. chmod 0440 "/etc/sudoers.d/${USER_NAME}"; \
  556. echo "${USER_NAME}:${PASSWD}" | chpasswd; \
  557. cp -a /usr/bin/sudo /usr/bin/sudo-root; \
  558. chown root:root /usr/bin/sudo-root; \
  559. chmod 4755 /usr/bin/sudo-root; \
  560. install -d \
  561. -o "${USER_UID}" \
  562. -g "${USER_GID}" \
  563. -m 0700 \
  564. /tmp/runtime-ubuntu; \
  565. chown -R \
  566. "${USER_UID}:${USER_GID}" \
  567. "/home/${USER_NAME}" \
  568. /etc/X11 \
  569. /opt/selkies
  570. # XFCE defaults suitable for a permanently streamed desktop.
  571. RUN install -d -m 0755 \
  572. /etc/xdg/xfce4/xfconf/xfce-perchannel-xml \
  573. /etc/firefox/policies \
  574. && if [[ -f /etc/xdg/xfce4/panel/default.xml ]]; then \
  575. cp -f \
  576. /etc/xdg/xfce4/panel/default.xml \
  577. /etc/xdg/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml; \
  578. fi \
  579. && cat > /etc/xdg/xfce4/xfconf/xfce-perchannel-xml/xfce4-power-manager.xml <<'EOF'
  580. <?xml version="1.0" encoding="UTF-8"?>
  581. <channel name="xfce4-power-manager" version="1.0">
  582. <property name="xfce4-power-manager" type="empty">
  583. <property name="blank-on-ac" type="int" value="0"/>
  584. <property name="dpms-enabled" type="bool" value="false"/>
  585. <property name="lock-screen-suspend-hibernate" type="bool" value="false"/>
  586. </property>
  587. </channel>
  588. EOF
  589. RUN cat > /etc/firefox/policies/policies.json <<'EOF'
  590. {
  591. "policies": {
  592. "Preferences": {
  593. "gfx.x11-egl.force-enabled": {
  594. "Value": true,
  595. "Status": "default"
  596. },
  597. "media.ffmpeg.vaapi.enabled": {
  598. "Value": true,
  599. "Status": "default"
  600. },
  601. "media.hardware-video-decoding.force-enabled": {
  602. "Value": true,
  603. "Status": "default"
  604. },
  605. "media.rdd-ffmpeg.enabled": {
  606. "Value": true,
  607. "Status": "default"
  608. }
  609. }
  610. }
  611. }
  612. EOF
  613. RUN update-alternatives --set x-www-browser /usr/bin/firefox \
  614. || true
  615. # The three files below must be placed beside this Dockerfile.
  616. COPY --chown=${USER_UID}:${USER_GID} entrypoint.sh /etc/entrypoint.sh
  617. COPY --chown=${USER_UID}:${USER_GID} selkies-entrypoint.sh /etc/selkies-entrypoint.sh
  618. COPY --chown=${USER_UID}:${USER_GID} supervisord.conf /etc/supervisord.conf
  619. COPY --chown=${USER_UID}:${USER_GID} nginx.conf /etc/nginx/nginx.conf
  620. COPY --chown=${USER_UID}:${USER_GID} nginx-entrypoint.sh /etc/nginx-entrypoint.sh
  621. RUN sed -i 's/\r$//' \
  622. /etc/entrypoint.sh \
  623. /etc/selkies-entrypoint.sh \
  624. /etc/nginx-entrypoint.sh \
  625. && chmod 0755 \
  626. /etc/entrypoint.sh \
  627. /etc/selkies-entrypoint.sh \
  628. /etc/nginx-entrypoint.sh \
  629. /etc/supervisord.conf
  630. USER ${USER_UID}:${USER_GID}
  631. ENV USER="${USER_NAME}" \
  632. HOME="/home/${USER_NAME}" \
  633. SHELL="/bin/bash"
  634. WORKDIR /home/${USER_NAME}
  635. EXPOSE 8080
  636. ENTRYPOINT ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]