Files
windmill/docker/DockerfileExtra
Ruben Fiszel 75b191b3ad add gateway reverse proxy for extra services (#8456)
* feat: add gateway reverse proxy for extra services

Add a lightweight Node.js gateway on port 3000 that routes requests
by URL prefix (/ws/*, /ws_mp/*, /ws_debug/*) to the correct backend
service, stripping the prefix before forwarding. This allows all
extra services to be accessed through a single port.

Also makes the multiplayer server more tolerant by generically
stripping /ws_mp/ prefix on HTTP requests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: enable gateway by default for extra services

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: add REMOTE_EXTRA env var for unified extra services proxy

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: make gateway port configurable via PORT env var

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: simplify Caddyfile extra services routing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 15:11:05 +00:00

158 lines
4.9 KiB
Plaintext

# DockerfileExtra - Combined Windmill Extra Services
#
# This image extends windmill-slim with three optional Windmill services:
# - LSP (Language Server Protocol) - Port 3001
# - Multiplayer (y-websocket) - Port 3002
# - Debugger (DAP WebSocket) - Port 3003
#
# Each service can be enabled/disabled via environment variables:
# - ENABLE_LSP=true (default: true)
# - ENABLE_MULTIPLAYER=true (default: true)
# - ENABLE_DEBUGGER=true (default: true)
#
# Build:
# docker build -f docker/DockerfileExtra -t windmill-extra .
#
# Run:
# docker run -p 3001:3001 -p 3002:3002 -p 3003:3003 windmill-extra
# ============================================================================
# Build final extra services image from windmill-ee-slim (includes nsjail)
# ============================================================================
FROM ghcr.io/windmill-labs/windmill-ee-slim:latest AS final
ARG APP=/usr/src/app
# Install Node.js 22 (needed for LSP and multiplayer)
RUN apt-get update && apt-get install -y --no-install-recommends \
gnupg \
&& mkdir -p /etc/apt/keyrings \
&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" > /etc/apt/sources.list.d/nodesource.list \
&& apt-get update \
&& apt-get install -y nodejs \
&& rm -rf /var/lib/apt/lists/*
# Install additional system dependencies
# - shellcheck: for bash LSP
RUN apt-get update && apt-get install -y --no-install-recommends \
shellcheck \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Install Go for gopls (Go LSP)
RUN set -eux; \
arch="$(dpkg --print-architecture)"; arch="${arch##*-}"; \
case "$arch" in \
'amd64') targz='go1.26.0.linux-amd64.tar.gz' ;; \
'arm64') targz='go1.26.0.linux-arm64.tar.gz' ;; \
'armhf') targz='go1.26.0.linux-armv6l.tar.gz' ;; \
*) echo >&2 "error: unsupported architecture '$arch'"; exit 1 ;; \
esac; \
wget "https://golang.org/dl/$targz" -nv && tar -C /usr/local -xzf "$targz" && rm "$targz"
ENV PATH="${PATH}:/usr/local/go/bin"
ENV GOBIN=/usr/local/go/bin
# Install gopls for Go LSP
RUN /usr/local/go/bin/go install -v golang.org/x/tools/gopls@latest
# Copy Deno for Deno LSP
COPY --from=denoland/deno:2.2.1 --chmod=755 /usr/bin/deno /usr/bin/deno
# ============================================================================
# LSP Setup
# ============================================================================
ENV PIPENV_VENV_IN_PROJECT=1
ENV XDG_CACHE_HOME=/pyls/.cache
# Install Python packages for LSP using uv
RUN uv pip install --system --break-system-packages pipenv tornado python-lsp-jsonrpc ruff Cython
# Install Node-based language servers
RUN npm install -g diagnostic-languageserver pyright
# Setup LSP working directory
WORKDIR /pyls
COPY lsp/Pipfile .
RUN pipenv install
COPY lsp/pyls_launcher.py .
# Setup Monaco temp directory for LSP
RUN mkdir -p /tmp/monaco && chmod -R 777 /tmp/monaco
RUN cd /tmp/monaco && npm install --save-dev windmill-client
RUN mkdir -p /pyls/.cache
# ============================================================================
# Debugger Setup
# ============================================================================
WORKDIR /debugger
# Copy debugger files
COPY debugger/dap_debug_service.ts .
COPY debugger/dap_websocket_server_bun.ts .
COPY debugger/dap_websocket_server.py .
COPY debugger/nsjail.debug.config.proto .
# Install Python debugger dependencies using uv
RUN uv pip install --system --break-system-packages websockets debugpy
# ============================================================================
# Multiplayer Setup (y-websocket with connection logging)
# ============================================================================
WORKDIR /multiplayer
# Copy multiplayer server files
COPY multiplayer/package.json .
COPY multiplayer/server.mjs .
COPY multiplayer/gateway.mjs .
# Install dependencies
RUN npm install
# ============================================================================
# Entrypoint Setup
# ============================================================================
WORKDIR /app
# Copy entrypoint script
COPY docker/entrypoint-extra.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
# Set permissions
RUN chmod -R a+rX /usr/local && \
chmod -R a+rX /pyls && \
chmod -R a+rX /debugger
# Expose all service ports
EXPOSE 3000 3001 3002 3003
# Environment variables for service control
ENV ENABLE_LSP=true
ENV ENABLE_MULTIPLAYER=true
ENV ENABLE_DEBUGGER=true
# nsjail sandboxing for debugger (requires --privileged, off by default)
ENV ENABLE_GATEWAY=true
ENV GATEWAY_PORT=3000
ENV ENABLE_NSJAIL=false
# LSP port
ENV LSP_PORT=3001
# Multiplayer port and host
ENV MULTIPLAYER_PORT=3002
ENV HOST=0.0.0.0
# Debugger port
ENV DEBUGGER_PORT=3003
# Windmill base URL for debugger token verification
ENV WINDMILL_BASE_URL=""
ENTRYPOINT ["/entrypoint.sh"]