# syntax=docker/dockerfile:1 # # Custom guacd image built against FreeRDP 3.8.0+ on Ubuntu 24.04. # # Why FreeRDP from source: Ubuntu 24.04 ships freerdp3-dev 3.5.1. # guacamole-server git main (1.7-dev) targets FreeRDP 3.8.0+: # - gdi.c's GUAC_ASSERT(current_context == NULL) is gated #if MINOR < 8 # so with 3.5.x it fires when GFX calls begin_paint before desktop_resize # - gdi_resize() in 3.8.0+ calls EndPaint internally, which guacamole relies on # - GFX pipeline surface synchronisation is fixed in 3.8.0+ # Building 3.x HEAD from source (always >= 3.8.0 by now) gives us the # correct FreeRDP that guacamole-server git main was developed against. # # Build notes: # - CPPFLAGS=-DHAVE_FREERDP_VERIFYCERTIFICATEEX=1 fixes a macro name mismatch # in guacamole-server: configure.ac generates HAVE_STRUCT_FREERDP_VERIFYCERTIFICATEEX # (AC_CHECK_MEMBERS adds STRUCT_ prefix) but rdp.c checks # HAVE_FREERDP_VERIFYCERTIFICATEEX (no STRUCT_). Without this the VerifyCertificateEx # callback is never registered, causing a silent drop ~430ms after keymap load. # - display-flush.c / display-plan.c patch: loop over layers doesn't advance # `current` before `continue` when pending_frame.buffer is NULL → infinite loop # or GUAC_ASSERT abort. Fixed by replacing the GUAC_ASSERT with a pointer advance. # - gdi.c patch: GUAC_ASSERT(current_context == NULL) in desktop_resize fires on # FreeRDP 3.5.x because the GFX pipeline calls begin_paint then gdi_resize before # end_paint. Replaced with a guard that calls end_paint if context is still open. # With FreeRDP 3.8.0+ this code is inside #if MINOR < 8 so the patch is harmless. # - user.c patch: guac_user_supports_webp() dereferences image_mimetypes without # NULL check → SIGSEGV when client didn't send image MIME types. FROM ubuntu:24.04 COPY docker/patch-display-flush.py /patch-display-flush.py ENV DEBIAN_FRONTEND=noninteractive # Build dependencies for guacamole-server AND FreeRDP source build RUN apt-get update && apt-get install -y --no-install-recommends \ autoconf \ automake \ build-essential \ ca-certificates \ cmake \ curl \ git \ libcairo2-dev \ libjpeg-turbo8-dev \ libossp-uuid-dev \ libpango1.0-dev \ libpng-dev \ libpulse-dev \ libssl-dev \ libssh2-1-dev \ libtelnet-dev \ libtool \ libvncserver-dev \ libwebp-dev \ libwebsockets-dev \ libkrb5-dev \ libavcodec-dev \ libavutil-dev \ libswscale-dev \ libusb-1.0-0-dev \ pkgconf \ zlib1g-dev \ && rm -rf /var/lib/apt/lists/* # Build FreeRDP 3.x from source (3.8.0+ required for guacamole-server git main). # We install to /usr with lib under lib/ (not lib/x86_64-linux-gnu/) so that # pkg-config --variable=libdir freerdp3 returns /usr/lib cleanly. # Optional features (audio, printing, X11 display, H264, Kerberos) are disabled # since guacd runs headless and we have disable-audio: true. RUN git clone --depth=1 --branch 3.22.0 https://github.com/FreeRDP/FreeRDP.git /tmp/freerdp \ && cmake -S /tmp/freerdp -B /tmp/freerdp-build \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr \ -DCMAKE_INSTALL_LIBDIR=lib \ -DWITH_X11=OFF \ -DWITH_WAYLAND=OFF \ -DWITH_PULSEAUDIO=OFF \ -DWITH_ALSA=OFF \ -DWITH_OSS=OFF \ -DWITH_CUPS=OFF \ -DWITH_FFMPEG=OFF \ -DWITH_OPENH264=OFF \ -DWITH_JPEG=ON \ -DWITH_CAIRO=ON \ -DWITH_CHANNELS=ON \ -DWITH_CLIENT=ON \ -DWITH_CLIENT_COMMON=ON \ -DWITH_SERVER=OFF \ -DWITH_SAMPLE=OFF \ -DBUILD_TESTING=OFF \ -DWITH_GSSAPI=OFF \ -DWITH_FUSE=OFF \ && cmake --build /tmp/freerdp-build -j"$(nproc)" \ && cmake --install /tmp/freerdp-build \ && ldconfig \ && rm -rf /tmp/freerdp /tmp/freerdp-build # Build guacamole-server from git main against our newly installed FreeRDP 3.x. RUN FREERDP_PLUGIN_DIR=$(pkg-config --variable=libdir freerdp3 2>/dev/null)/freerdp3 \ && echo "Building guacamole-server (git main) with FreeRDP plugin dir: ${FREERDP_PLUGIN_DIR}" \ && echo "FreeRDP version: $(pkg-config --modversion freerdp3)" \ && git clone --depth=1 https://github.com/apache/guacamole-server.git \ && cd guacamole-server \ && python3 /patch-display-flush.py \ && autoreconf -fi \ && CPPFLAGS="-Wno-error=deprecated-declarations -DHAVE_FREERDP_VERIFYCERTIFICATEEX=1" \ CFLAGS="-O2 -Wno-error=unused-variable" \ ./configure \ --prefix=/usr \ --sysconfdir=/etc \ --with-freerdp-plugin-dir="${FREERDP_PLUGIN_DIR}" \ && make -j"$(nproc)" \ && make install \ && ldconfig \ && cd / && rm -rf guacamole-server # guacd log level is passed via -L flag; exposed as env var for docker-compose ENV GUACD_LOG_LEVEL=info EXPOSE 4822 CMD sh -c "exec /usr/sbin/guacd -b 0.0.0.0 -f -L \"${GUACD_LOG_LEVEL}\""