diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 789db3e84f..0e1a602c36 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -10,6 +10,7 @@ on: - '*.md' - '.github/**' - '!.github/workflows/nightly.yml' + - '!docker/**' permissions: contents: write diff --git a/docker/dedicated-server/Dockerfile b/docker/dedicated-server/Dockerfile index 14760afdc3..babd324fc1 100644 --- a/docker/dedicated-server/Dockerfile +++ b/docker/dedicated-server/Dockerfile @@ -1,33 +1,72 @@ -FROM debian:bookworm-slim +FROM debian:trixie-slim ARG DEBIAN_FRONTEND=noninteractive # basically, it only works with a Release build.(libs are not included in Debug build) -ARG MC_RUNTIME_DIR=x64/Minecraft.Server/Release +ARG MC_RUNTIME_DIR=srv/mc + +ENV PROTONPATH=GE-Proton +ENV PROTON_ENABLE_WAYLAND=1 +ENV WINEARCH=win64 +ENV WINEPREFIX=/var/opt/wineprefix64 RUN dpkg --add-architecture i386 \ && apt-get update \ && apt-get install -y --no-install-recommends \ + sudo \ ca-certificates \ - wine \ - wine64 \ - wine32:i386 \ - xvfb \ + xwayland-run \ + cage \ + curl \ tini \ + unzip \ && rm -rf /var/lib/apt/lists/* -ENV WINEARCH=win64 -ENV WINEPREFIX=/var/opt/wineprefix64 +# Wine from the upstream repo +RUN mkdir -pm755 /etc/apt/keyrings && \ + curl -fsSL https://dl.winehq.org/wine-builds/winehq.key \ + -o /etc/apt/keyrings/winehq-archive.key && \ + curl -fsSL https://dl.winehq.org/wine-builds/debian/dists/trixie/winehq-trixie.sources \ + -o /etc/apt/sources.list.d/winehq-trixie.sources && \ + apt-get update && \ + apt-get install -y --install-recommends winehq-devel -WORKDIR /srv/mc +# UMU +RUN set -eux; \ + ver="$( \ + curl -sIL https://github.com/Open-Wine-Components/umu-launcher/releases/latest \ + | grep -i '^location:' \ + | sed -E 's|.*tag/||' \ + | tr -d '\r' \ + )"; \ + curl -Lo /tmp/umu-launcher.deb \ + "https://github.com/Open-Wine-Components/umu-launcher/releases/download/${ver}/python3-umu-launcher_${ver}-1_amd64_debian-13.deb"; \ + apt-get install -y /tmp/umu-launcher.deb; \ + rm -f /tmp/umu-launcher.deb; + +# Create user +RUN useradd -m -s /bin/bash mclce -COPY ${MC_RUNTIME_DIR}/Minecraft.Server.exe /srv/mc/Minecraft.Server.exe -COPY ${MC_RUNTIME_DIR}/iggy_w64.dll /srv/mc/iggy_w64.dll -COPY ${MC_RUNTIME_DIR}/Common /srv/mc/Common -COPY ${MC_RUNTIME_DIR}/Windows64 /srv/mc/Windows64 -COPY docker/dedicated-server/entrypoint.sh /usr/local/bin/entrypoint.sh +# Give sudo without password +RUN echo "mclce ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/mclce \ + && chmod 0440 /etc/sudoers.d/mclce + +USER mclce + +# ownership +RUN mkdir -p /srv/mc && sudo chmod 0755 /srv/mc + +# latest server build +RUN curl -Lo /tmp/LCEServerWindows64.zip \ + "https://github.com/smartcmd/MinecraftConsoles/releases/download/nightly-dedicated-server/LCEServerWindows64.zip" \ + && unzip /tmp/LCEServerWindows64.zip -d /srv/mc \ + && rm /tmp/LCEServerWindows64.zip + +COPY entrypoint.sh /usr/local/bin/entrypoint.sh RUN chmod 0755 /usr/local/bin/entrypoint.sh \ && mkdir -p /var/opt/wineprefix64 /srv/mc \ && test -f /srv/mc/Minecraft.Server.exe +WORKDIR /srv/mc + ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/entrypoint.sh"] diff --git a/docker/dedicated-server/entrypoint.sh b/docker/dedicated-server/entrypoint.sh index 26b40da981..b63eb175d6 100644 --- a/docker/dedicated-server/entrypoint.sh +++ b/docker/dedicated-server/entrypoint.sh @@ -8,7 +8,6 @@ SERVER_PORT="25565" SERVER_BIND_IP="0.0.0.0" PERSIST_DIR="/srv/persist" -WINE_CMD="" ensure_persist_file() { local persist_path="$1" @@ -30,65 +29,6 @@ ensure_persist_file() { ln -sfn "${persist_path}" "${runtime_path}" } -wait_for_xvfb_ready() { - local display="$1" - local xvfb_pid="$2" - local wait_seconds="${XVFB_WAIT_SECONDS:-10}" - local wait_ticks=$((wait_seconds * 10)) - local display_number="${display#:}" - display_number="${display_number%%.*}" - - if [ -z "${display_number}" ] || ! [[ "${display_number}" =~ ^[0-9]+$ ]]; then - echo "[error] Invalid DISPLAY format for Xvfb wait: ${display}" >&2 - return 1 - fi - - local socket_path="/tmp/.X11-unix/X${display_number}" - local elapsed=0 - - while [ "${elapsed}" -lt "${wait_ticks}" ]; do - if ! kill -0 "${xvfb_pid}" 2>/dev/null; then - echo "[error] Xvfb exited before the display became ready." >&2 - if [ -f /tmp/xvfb.log ]; then - echo "[error] ---- /tmp/xvfb.log ----" >&2 - tail -n 200 /tmp/xvfb.log >&2 || true - echo "[error] ----------------------" >&2 - fi - return 1 - fi - - if [ -S "${socket_path}" ]; then - # Keep a short extra delay so Wine does not race display handshake. - sleep 0.2 - if kill -0 "${xvfb_pid}" 2>/dev/null && [ -S "${socket_path}" ]; then - return 0 - fi - fi - - # One more liveness check after the ready probe branch. - if ! kill -0 "${xvfb_pid}" 2>/dev/null; then - echo "[error] Xvfb exited during display readiness probe." >&2 - if [ -f /tmp/xvfb.log ]; then - echo "[error] ---- /tmp/xvfb.log ----" >&2 - tail -n 200 /tmp/xvfb.log >&2 || true - echo "[error] ----------------------" >&2 - fi - return 1 - fi - - sleep 0.1 - elapsed=$((elapsed + 1)) - done - - echo "[error] Timed out waiting for Xvfb display ${display}." >&2 - if [ -f /tmp/xvfb.log ]; then - echo "[error] ---- /tmp/xvfb.log ----" >&2 - tail -n 200 /tmp/xvfb.log >&2 || true - echo "[error] ----------------------" >&2 - fi - return 1 -} - if [ ! -d "$SERVER_DIR" ]; then echo "[error] Server directory not found: $SERVER_DIR" >&2 exit 1 @@ -103,6 +43,7 @@ if [ ! -f "$SERVER_EXE" ]; then fi mkdir -p "${PERSIST_DIR}" +chmod 0755 "${PERSIST_DIR}" # created because it is not implemented on the server side mkdir -p "${PERSIST_DIR}/GameHDD" @@ -117,45 +58,9 @@ if [ -e "Windows64/GameHDD" ] && [ ! -L "Windows64/GameHDD" ]; then fi ln -sfn "${PERSIST_DIR}/GameHDD" "Windows64/GameHDD" -# for compatibility with other images -if command -v wine64 >/dev/null 2>&1; then - WINE_CMD="wine64" -elif [ -x "/usr/lib/wine/wine64" ]; then - WINE_CMD="/usr/lib/wine/wine64" -elif command -v wine >/dev/null 2>&1; then - WINE_CMD="wine" -else - echo "[error] No Wine executable found (wine64/wine)." >&2 - exit 1 -fi - if [ ! -d "${WINEPREFIX}" ] || [ -z "$(ls -A "${WINEPREFIX}" 2>/dev/null)" ]; then mkdir -p "${WINEPREFIX}" -fi - -# in the current implementation, a virtual screen is required because the client-side logic is being called for compatibility -if [ -z "${DISPLAY:-}" ]; then - export DISPLAY="${XVFB_DISPLAY:-:99}" - XVFB_SCREEN="${XVFB_SCREEN:-64x64x16}" - DISPLAY_NUMBER="${DISPLAY#:}" - DISPLAY_NUMBER="${DISPLAY_NUMBER%%.*}" - if [ -z "${DISPLAY_NUMBER}" ] || ! [[ "${DISPLAY_NUMBER}" =~ ^[0-9]+$ ]]; then - echo "[error] Invalid XVFB_DISPLAY format: ${DISPLAY}" >&2 - exit 1 - fi - XVFB_SOCKET="/tmp/.X11-unix/X${DISPLAY_NUMBER}" - XVFB_LOCK="/tmp/.X${DISPLAY_NUMBER}-lock" - # The check is performed assuming the same container will be restarted. - if [ -S "${XVFB_SOCKET}" ] || [ -e "${XVFB_LOCK}" ]; then - echo "[warn] Removing stale Xvfb state for ${DISPLAY} before startup." >&2 - rm -f "${XVFB_SOCKET}" "${XVFB_LOCK}" - fi - Xvfb "${DISPLAY}" -nolisten tcp -screen 0 "${XVFB_SCREEN}" >/tmp/xvfb.log 2>&1 & - XVFB_PID=$! - wait_for_xvfb_ready "${DISPLAY}" "${XVFB_PID}" - echo "[info] Xvfb ready on ${DISPLAY} (pid=${XVFB_PID}, screen=${XVFB_SCREEN})" -else - echo "[info] Using existing DISPLAY=${DISPLAY}; skipping Xvfb startup" + sudo chmod 0755 "${WINEPREFIX}" fi args=( @@ -164,4 +69,4 @@ args=( ) echo "[info] Starting ${SERVER_EXE} on ${SERVER_BIND_IP}:${SERVER_PORT}" -exec "${WINE_CMD}" "${SERVER_EXE}" "${args[@]}" +exec wlheadless-run -c cage -- umu-run "${SERVER_EXE}" "${args[@]}"