Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ on:
- '*.md'
- '.github/**'
- '!.github/workflows/nightly.yml'
- '!docker/**'

permissions:
contents: write
Expand Down
67 changes: 53 additions & 14 deletions docker/dedicated-server/Dockerfile
Original file line number Diff line number Diff line change
@@ -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"]
101 changes: 3 additions & 98 deletions docker/dedicated-server/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
Expand All @@ -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"
Expand All @@ -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=(
Expand All @@ -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[@]}"
Loading