mirror of
https://github.com/sol1/rustguac.git
synced 2026-10-26 05:29:51 +00:00
994f138685
guacenc, from guacamole-server, converts .guac recordings to video and is what MP4 downloads (#241) run. Stop passing --disable-guacenc in build-deb.sh, the release workflow, install.sh, the Dockerfile and dev.sh, and ship /opt/rustguac/bin/guacenc in the .deb (debian/rules), the Docker runtime image and the release tarball (install-release.sh installs it when present). It needs only the ffmpeg libraries guacd is already built and shipped with, so no new dependencies. configure leaves guacenc out quietly when an ffmpeg library is missing, like the protocols, so check-guacd-plugins.sh now also fails the build when guacenc was not built.
253 lines
9.8 KiB
Docker
253 lines
9.8 KiB
Docker
# =============================================================================
|
|
# Multi-stage Dockerfile for rustguac
|
|
#
|
|
# Stages:
|
|
# 1. guacd-builder — compile guacd from guacamole-server source
|
|
# 2. rust-builder — compile rustguac binary
|
|
# 3. runtime — minimal image with both binaries + runtime deps
|
|
#
|
|
# Build:
|
|
# docker build -t rustguac .
|
|
#
|
|
# Run:
|
|
# docker run -d -p 8089:8089 rustguac
|
|
#
|
|
# Run with VDI (Docker desktop containers):
|
|
# docker run -d -p 8089:8089 \
|
|
# -v /var/run/docker.sock:/var/run/docker.sock \
|
|
# --group-add $(getent group docker | cut -d: -f3) \
|
|
# rustguac
|
|
#
|
|
# The image runs both guacd and rustguac under a simple entrypoint script.
|
|
# =============================================================================
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Stage 1: Build guacd from source
|
|
# ---------------------------------------------------------------------------
|
|
FROM debian:trixie-slim AS guacd-builder
|
|
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
autoconf automake libtool pkg-config make gcc g++ git ca-certificates \
|
|
libcairo2-dev libjpeg-dev libpng-dev libwebp-dev \
|
|
libssh2-1-dev libssl-dev libvncserver-dev \
|
|
libpango1.0-dev libpulse-dev \
|
|
libavcodec-dev libavformat-dev libavutil-dev libswscale-dev \
|
|
libcunit1-dev libtelnet-dev libwebsockets-dev \
|
|
uuid-dev freerdp3-dev libspice-client-glib-2.0-dev \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
WORKDIR /build
|
|
# Pin to known-good commit to avoid upstream -Werror breakage
|
|
RUN git clone https://github.com/apache/guacamole-server.git \
|
|
&& cd guacamole-server && git checkout 6719b20d
|
|
|
|
# Apply patches for FreeRDP 3.x / Debian 13 compatibility
|
|
COPY patches/ /build/patches/
|
|
COPY scripts/check-guacd-plugins.sh /build/
|
|
WORKDIR /build/guacamole-server
|
|
RUN for patch in /build/patches/*.patch; do \
|
|
[ -f "$patch" ] || continue; \
|
|
echo "Applying patch: $(basename "$patch")"; \
|
|
git apply "$patch"; \
|
|
done
|
|
|
|
RUN autoreconf -fi
|
|
|
|
WORKDIR /build/guacd-build
|
|
RUN /build/guacamole-server/configure \
|
|
--prefix=/opt/rustguac \
|
|
--with-ssh \
|
|
--with-vnc \
|
|
--with-rdp \
|
|
--with-spice \
|
|
--without-telnet \
|
|
--disable-kubernetes \
|
|
--disable-guaclog \
|
|
--disable-guacclip \
|
|
--disable-static \
|
|
&& make -j"$(nproc)" \
|
|
&& make install \
|
|
&& bash /build/check-guacd-plugins.sh /opt/rustguac/lib \
|
|
&& mkdir -p /opt/rustguac/lib/freerdp3 \
|
|
&& cp /opt/rustguac/lib/libguac*.so* /opt/rustguac/lib/freerdp3/ \
|
|
&& { cp /usr/lib/x86_64-linux-gnu/freerdp3/libguac*.so* /opt/rustguac/lib/freerdp3/ 2>/dev/null || true; }
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Stage 2: Build rustguac
|
|
# ---------------------------------------------------------------------------
|
|
FROM rust:1-bookworm AS rust-builder
|
|
|
|
WORKDIR /build
|
|
COPY Cargo.toml Cargo.lock ./
|
|
COPY build.rs ./
|
|
COPY src/ src/
|
|
COPY docs/ docs/
|
|
COPY static/ static/
|
|
|
|
RUN cargo build --release
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Stage 3: Runtime image
|
|
# ---------------------------------------------------------------------------
|
|
FROM debian:trixie-slim AS runtime
|
|
|
|
# Runtime libraries for guacd
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
libcairo2 libjpeg62-turbo libpng16-16t64 libwebp7 \
|
|
libssh2-1 libssl3t64 libvncclient1 \
|
|
libpango-1.0-0 libpulse0 \
|
|
libspice-client-glib-2.0-8 \
|
|
libavcodec61 libavformat61 libavutil59 libswscale8 \
|
|
libtelnet2 libwebsockets19t64 \
|
|
libfreerdp3-3 libfreerdp-client3-3 libwinpr3-3 \
|
|
# Xvnc + Chromium for web browser sessions
|
|
tigervnc-standalone-server \
|
|
chromium chromium-sandbox \
|
|
x11-utils \
|
|
# Minimal runtime utilities
|
|
ca-certificates \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# Install guacd
|
|
COPY --from=guacd-builder /opt/rustguac/sbin/ /opt/rustguac/sbin/
|
|
# guacenc converts recordings to video for MP4 downloads
|
|
COPY --from=guacd-builder /opt/rustguac/bin/guacenc /opt/rustguac/bin/guacenc
|
|
COPY --from=guacd-builder /opt/rustguac/lib/ /opt/rustguac/lib/
|
|
|
|
# Install rustguac binary
|
|
COPY --from=rust-builder /build/target/release/rustguac /opt/rustguac/bin/rustguac
|
|
|
|
# Install static web assets
|
|
COPY static/ /opt/rustguac/static/
|
|
|
|
# Library path for guacd
|
|
RUN echo "/opt/rustguac/lib" > /etc/ld.so.conf.d/rustguac.conf && ldconfig
|
|
|
|
# FreeRDP plugin setup: guacd loads "guac-common-svc" by name, which FreeRDP
|
|
# resolves to "guac-common-svc.so" in its plugin path. The build installs it as
|
|
# "libguac-common-svc-client.so", so we create a symlink with the expected name.
|
|
# We also ensure the system FreeRDP plugin dir exists and contains the plugins.
|
|
RUN mkdir -p /usr/lib/x86_64-linux-gnu/freerdp3 && \
|
|
if [ -d /opt/rustguac/lib/freerdp3 ]; then \
|
|
cp /opt/rustguac/lib/freerdp3/*.so* /usr/lib/x86_64-linux-gnu/freerdp3/ 2>/dev/null; \
|
|
ln -sf libguac-common-svc-client.so /opt/rustguac/lib/freerdp3/guac-common-svc.so; \
|
|
ln -sf libguac-common-svc-client.so /usr/lib/x86_64-linux-gnu/freerdp3/guac-common-svc.so; \
|
|
echo "FreeRDP plugins installed:"; \
|
|
ls /usr/lib/x86_64-linux-gnu/freerdp3/guac* /opt/rustguac/lib/freerdp3/guac-common-svc.so 2>/dev/null; \
|
|
fi
|
|
|
|
# Create writable runtime directories
|
|
RUN mkdir -p /opt/rustguac/data /opt/rustguac/recordings /opt/rustguac/tls \
|
|
/opt/rustguac/certs /opt/rustguac/drives /opt/rustguac/scripts \
|
|
/opt/rustguac/vdi-homes
|
|
|
|
# Chromium policy: web session hardening.
|
|
# DeveloperToolsAvailability=0: CDP needed for login scripts. Users can't reach DevTools
|
|
# through the UI anyway — chrome://* is in URLBlocklist.
|
|
RUN mkdir -p /etc/chromium/policies/managed && \
|
|
echo '{"AllowFileSelectionDialogs": false, "PasswordManagerEnabled": true, "ImportSavedPasswords": false, "DeveloperToolsAvailability": 0, "DownloadRestrictions": 3, "PrintingEnabled": false, "EditBookmarksEnabled": false, "BrowserSignin": 0, "SyncDisabled": true, "ExtensionInstallBlocklist": ["*"], "URLBlocklist": ["file://*", "chrome://*", "chrome-extension://*", "view-source:*", "javascript:*"], "URLAllowlist": ["chrome://policy"]}' \
|
|
> /etc/chromium/policies/managed/rustguac.json
|
|
|
|
# Create non-root user with a real home directory (Chromium crashpad needs it)
|
|
RUN groupadd -r rustguac && useradd -r -g rustguac -m -d /home/rustguac -s /bin/sh rustguac
|
|
|
|
# Generate self-signed cert for guacd TLS (internal loopback encryption)
|
|
RUN /opt/rustguac/bin/rustguac generate-cert --hostname localhost --out-dir /opt/rustguac/tls
|
|
|
|
# Default config template (copied to config.toml on first run if not mounted)
|
|
RUN cat > /opt/rustguac/config.toml.default <<'EOF'
|
|
listen_addr = "0.0.0.0:8089"
|
|
guacd_addr = "127.0.0.1:4822"
|
|
recording_path = "/opt/rustguac/recordings"
|
|
static_path = "/opt/rustguac/static"
|
|
db_path = "/opt/rustguac/data/rustguac.db"
|
|
session_pending_timeout_secs = 60
|
|
xvnc_path = "Xvnc"
|
|
chromium_path = "chromium"
|
|
display_range_start = 100
|
|
display_range_end = 199
|
|
|
|
[tls]
|
|
cert_path = "/opt/rustguac/tls/cert.pem"
|
|
key_path = "/opt/rustguac/tls/key.pem"
|
|
guacd_cert_path = "/opt/rustguac/tls/cert.pem"
|
|
|
|
# VDI Docker desktop containers (uncomment to enable)
|
|
# Requires: -v /var/run/docker.sock:/var/run/docker.sock
|
|
# [vdi]
|
|
# enabled = true
|
|
# idle_timeout_mins = 60
|
|
# home_base = "/opt/rustguac/vdi-homes"
|
|
EOF
|
|
|
|
# Set ownership so the non-root user can write to runtime dirs.
|
|
# The top-level dir is chowned (not recursive) so loaders can create config.toml;
|
|
# subdirs are chowned recursively for data, certs, etc.
|
|
RUN chown rustguac:rustguac /opt/rustguac && \
|
|
chown -R rustguac:rustguac /opt/rustguac/data /opt/rustguac/recordings \
|
|
/opt/rustguac/tls /opt/rustguac/certs /opt/rustguac/drives \
|
|
/opt/rustguac/scripts /opt/rustguac/vdi-homes /opt/rustguac/config.toml.default
|
|
|
|
# Entrypoint script: starts guacd in background, then rustguac in foreground
|
|
RUN cat > /opt/rustguac/entrypoint.sh <<'SCRIPT'
|
|
#!/bin/sh
|
|
set -e
|
|
|
|
# Copy default config on first run (if no config file is mounted/present)
|
|
CONFIG_PATH="/opt/rustguac/config.toml"
|
|
if [ ! -f "$CONFIG_PATH" ]; then
|
|
echo "No config.toml found — copying default configuration."
|
|
cp /opt/rustguac/config.toml.default "$CONFIG_PATH"
|
|
fi
|
|
|
|
# Create an admin API key on first run. rustguac decides what "first run"
|
|
# means: it opens the database named by db_path in the config and creates
|
|
# the admin only if there is none yet. Checking for a database file at a fixed
|
|
# path here broke any config that moved db_path: every restart then tried to
|
|
# create the admin again and failed on the existing one (#240).
|
|
ADMIN_OUT=$(/opt/rustguac/bin/rustguac --config "$CONFIG_PATH" add-admin --name docker-admin --if-none)
|
|
echo "$ADMIN_OUT"
|
|
case "$ADMIN_OUT" in
|
|
*"API Key:"*)
|
|
echo ""
|
|
echo "==> SAVE THE API KEY ABOVE — it is only shown once! <=="
|
|
echo ""
|
|
;;
|
|
esac
|
|
|
|
# Start guacd in background
|
|
echo "Starting guacd..."
|
|
LD_LIBRARY_PATH=/opt/rustguac/lib FREERDP_ADDIN_PATH=/opt/rustguac/lib/freerdp3 \
|
|
/opt/rustguac/sbin/guacd \
|
|
-b 127.0.0.1 -l 4822 -L "${GUACD_LOG_LEVEL:-info}" -f \
|
|
-C /opt/rustguac/tls/cert.pem -K /opt/rustguac/tls/key.pem &
|
|
GUACD_PID=$!
|
|
|
|
# Wait briefly to confirm guacd started
|
|
sleep 0.5
|
|
if ! kill -0 "$GUACD_PID" 2>/dev/null; then
|
|
echo "ERROR: guacd failed to start"
|
|
exit 1
|
|
fi
|
|
echo "guacd started (pid=$GUACD_PID)"
|
|
|
|
# Trap signals to shut down both processes
|
|
trap 'kill $GUACD_PID 2>/dev/null; wait; exit 0' TERM INT
|
|
|
|
# Run rustguac in foreground
|
|
echo "Starting rustguac..."
|
|
exec /opt/rustguac/bin/rustguac --config "$CONFIG_PATH" serve
|
|
SCRIPT
|
|
RUN chmod +x /opt/rustguac/entrypoint.sh
|
|
|
|
WORKDIR /opt/rustguac
|
|
EXPOSE 8089
|
|
VOLUME ["/opt/rustguac/data", "/opt/rustguac/recordings", "/opt/rustguac/drives", "/opt/rustguac/vdi-homes"]
|
|
|
|
ENV RUST_LOG=info
|
|
ENV GUACD_LOG_LEVEL=info
|
|
ENV HOME=/home/rustguac
|
|
|
|
USER rustguac
|
|
ENTRYPOINT ["/opt/rustguac/entrypoint.sh"]
|