diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfdb8b7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.sh text eol=lf diff --git a/.github/workflows/developer.yml b/.github/workflows/developer.yml index d79531d..7499942 100644 --- a/.github/workflows/developer.yml +++ b/.github/workflows/developer.yml @@ -28,7 +28,7 @@ jobs: - name: Docker - Build / Push uses: docker/build-push-action@v6 with: - platforms: linux/amd64 + platforms: linux/amd64,linux/arm64 push: true tags: '${{ steps.meta.outputs.tags }}' push-wine-staging: @@ -55,6 +55,6 @@ jobs: uses: docker/build-push-action@v6 with: file: Dockerfile.staging - platforms: linux/amd64 + platforms: linux/amd64,linux/arm64 push: true tags: '${{ steps.meta.outputs.tags }}' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9f44170..af2d05e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,7 +32,7 @@ jobs: id: docker_build uses: docker/build-push-action@v6 with: - platforms: 'linux/amd64' + platforms: 'linux/amd64,linux/arm64' push: true tags: '${{ steps.meta.outputs.tags }}' release-wine-staging: @@ -64,6 +64,6 @@ jobs: uses: docker/build-push-action@v6 with: file: Dockerfile.staging - platforms: 'linux/amd64' + platforms: 'linux/amd64,linux/arm64' push: true - tags: '${{ steps.meta.outputs.tags }}' \ No newline at end of file + tags: '${{ steps.meta.outputs.tags }}' diff --git a/Dockerfile b/Dockerfile index f344ffa..350272e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,32 @@ +# BUILD HELPER TOOLS NATIVELY FOR THE TARGET ARCHITECTURE +FROM --platform=$TARGETPLATFORM rust:bookworm AS rust-tools-builder + +ARG REPAK_VERSION=v0.2.3 +ARG RETOC_VERSION=v0.1.5 + +RUN set -eux; \ + git clone --branch "${REPAK_VERSION}" --depth 1 https://github.com/trumank/repak.git /tmp/repak && \ + cargo build --manifest-path /tmp/repak/Cargo.toml --locked --release --bin repak && \ + install -m 0755 /tmp/repak/target/release/repak /usr/local/bin/repak + +RUN set -eux; \ + git clone --branch "${RETOC_VERSION}" --depth 1 https://github.com/trumank/retoc.git /tmp/retoc && \ + cargo build --manifest-path /tmp/retoc/Cargo.toml --locked --release --bin retoc && \ + install -m 0755 /tmp/retoc/target/release/retoc /usr/local/bin/retoc + # BUILD THE SERVER IMAGE -FROM --platform=linux/amd64 debian:bookworm-slim +FROM --platform=$TARGETPLATFORM debian:bookworm-slim + +ARG TARGETARCH +ARG DEPOT_DOWNLOADER_VERSION=3.4.0 +ARG HANGOVER_VERSION=hangover-10.18 +ARG POWERSHELL_VERSION=7.5.4 +ARG WINDROSE_PLUS_VERSION_DEFAULT=latest ENV DEBIAN_FRONTEND=noninteractive +ENV WINDROSE_PLUS_VERSION_DEFAULT=${WINDROSE_PLUS_VERSION_DEFAULT} -RUN dpkg --add-architecture i386 && \ - apt-get update && apt-get install -y --no-install-recommends \ +RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ ca-certificates \ gnupg \ @@ -16,43 +38,77 @@ RUN dpkg --add-architecture i386 && \ xvfb \ xauth \ jq \ - && curl -fsSL https://dl.winehq.org/wine-builds/winehq.key | \ - gpg --dearmor -o /usr/share/keyrings/winehq-archive.key \ - && echo "deb [arch=amd64,i386 signed-by=/usr/share/keyrings/winehq-archive.key] https://dl.winehq.org/wine-builds/debian/ bookworm main" \ - > /etc/apt/sources.list.d/winehq.list \ - && apt-get update \ - && apt-get install -y --install-recommends winehq-stable \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* -# Install PowerShell 7 (pwsh) — used by WindrosePlus scripts natively on Linux -RUN curl -fsSL https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb \ - -o /tmp/packages-microsoft-prod.deb && \ - dpkg -i /tmp/packages-microsoft-prod.deb && \ - rm /tmp/packages-microsoft-prod.deb && \ - apt-get update && \ - apt-get install -y --no-install-recommends powershell && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* - -# Install Linux-native repak and retoc (replace WindrosePlus bundled .exe tools) -ARG REPAK_VERSION=v0.2.3 -ARG RETOC_VERSION=v0.1.5 RUN set -eux; \ - curl -fsSL "https://github.com/trumank/repak/releases/download/${REPAK_VERSION}/repak_cli-x86_64-unknown-linux-gnu.tar.xz" \ - -o /tmp/repak.tar.xz && \ - tar -xJf /tmp/repak.tar.xz -C /tmp && \ - install -m 0755 "$(find /tmp -maxdepth 3 -type f -name repak | head -1)" /usr/local/bin/repak && \ - rm -rf /tmp/repak.tar.xz /tmp/repak_cli-* ; \ - curl -fsSL "https://github.com/trumank/retoc/releases/download/${RETOC_VERSION}/retoc_cli-x86_64-unknown-linux-gnu.tar.xz" \ - -o /tmp/retoc.tar.xz && \ - tar -xJf /tmp/retoc.tar.xz -C /tmp && \ - install -m 0755 "$(find /tmp -maxdepth 3 -type f -name retoc | head -1)" /usr/local/bin/retoc && \ - rm -rf /tmp/retoc.tar.xz /tmp/retoc_cli-* - -# Default Windrose+ version — can be overridden at runtime via WINDROSE_PLUS_VERSION -ARG WINDROSE_PLUS_VERSION_DEFAULT=latest -ENV WINDROSE_PLUS_VERSION_DEFAULT=${WINDROSE_PLUS_VERSION_DEFAULT} + case "${TARGETARCH}" in \ + amd64) \ + dpkg --add-architecture i386; \ + curl -fsSL https://dl.winehq.org/wine-builds/winehq.key | \ + gpg --dearmor -o /usr/share/keyrings/winehq-archive.key; \ + echo "deb [arch=amd64,i386 signed-by=/usr/share/keyrings/winehq-archive.key] https://dl.winehq.org/wine-builds/debian/ bookworm main" \ + > /etc/apt/sources.list.d/winehq.list; \ + apt-get update; \ + apt-get install -y --install-recommends winehq-stable; \ + ;; \ + arm64) \ + asset_url="$(curl -fsSL "https://api.github.com/repos/AndreRH/hangover/releases/tags/${HANGOVER_VERSION}" | jq -r '.assets[] | select((.name | test("debian12|bookworm"; "i")) and (.name | test("arm64"; "i")) and (.name | test("\\.(tar|deb)$"; "i"))) | .browser_download_url' | head -n 1)"; \ + if [ -z "${asset_url}" ] || [ "${asset_url}" = "null" ]; then \ + echo "Could not find a Debian 12 / bookworm arm64 Hangover package for ${HANGOVER_VERSION}" >&2; \ + exit 1; \ + fi; \ + mkdir -p /tmp/hangover; \ + if echo "${asset_url}" | grep -qi '\.deb$'; then \ + curl -fsSL "${asset_url}" -o /tmp/hangover/hangover.deb; \ + else \ + curl -fsSL "${asset_url}" -o /tmp/hangover/hangover.tar; \ + tar -xf /tmp/hangover/hangover.tar -C /tmp/hangover; \ + fi; \ + apt-get update; \ + find /tmp/hangover -type f -name '*.deb' -print0 | xargs -0 apt-get install -y --no-install-recommends; \ + ;; \ + *) \ + echo "Unsupported TARGETARCH: ${TARGETARCH}" >&2; \ + exit 1; \ + ;; \ + esac; \ + apt-get clean; \ + rm -rf /var/lib/apt/lists/* /tmp/hangover + +# Install PowerShell 7 (pwsh) used by WindrosePlus scripts natively on Linux. +# Debian arm64 packages are not published in the Microsoft apt repo, so use +# the official release tarball on arm64. +RUN set -eux; \ + case "${TARGETARCH}" in \ + amd64) \ + curl -fsSL https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb \ + -o /tmp/packages-microsoft-prod.deb; \ + dpkg -i /tmp/packages-microsoft-prod.deb; \ + rm /tmp/packages-microsoft-prod.deb; \ + apt-get update; \ + apt-get install -y --no-install-recommends powershell; \ + apt-get clean; \ + rm -rf /var/lib/apt/lists/*; \ + ;; \ + arm64) \ + mkdir -p /opt/microsoft/powershell/7; \ + curl -fsSL \ + "https://github.com/PowerShell/PowerShell/releases/download/v${POWERSHELL_VERSION}/powershell-${POWERSHELL_VERSION}-linux-arm64.tar.gz" \ + -o /tmp/powershell.tar.gz; \ + tar -xzf /tmp/powershell.tar.gz -C /opt/microsoft/powershell/7; \ + chmod +x /opt/microsoft/powershell/7/pwsh; \ + ln -sf /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh; \ + rm /tmp/powershell.tar.gz; \ + ;; \ + *) \ + echo "Unsupported TARGETARCH: ${TARGETARCH}" >&2; \ + exit 1; \ + ;; \ + esac + +COPY --from=rust-tools-builder /usr/local/bin/repak /usr/local/bin/repak +COPY --from=rust-tools-builder /usr/local/bin/retoc /usr/local/bin/retoc # Install .NET 8 runtime (required for DepotDownloader) RUN curl -sL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh && \ @@ -62,9 +118,14 @@ RUN curl -sL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh && \ rm /tmp/dotnet-install.sh # Download DepotDownloader -ARG DEPOT_DOWNLOADER_VERSION=3.4.0 -RUN curl -sL \ - "https://github.com/SteamRE/DepotDownloader/releases/download/DepotDownloader_${DEPOT_DOWNLOADER_VERSION}/DepotDownloader-linux-x64.zip" -o \ +RUN set -eux; \ + case "${TARGETARCH}" in \ + amd64) depot_arch="x64" ;; \ + arm64) depot_arch="arm64" ;; \ + *) echo "Unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;; \ + esac; \ + curl -fsSL \ + "https://github.com/SteamRE/DepotDownloader/releases/download/DepotDownloader_${DEPOT_DOWNLOADER_VERSION}/DepotDownloader-linux-${depot_arch}.zip" -o \ /tmp/dd.zip && \ mkdir -p /depotdownloader && \ unzip /tmp/dd.zip -d /depotdownloader && \ @@ -90,6 +151,7 @@ COPY ./scripts /home/steam/server/ COPY branding /branding RUN mkdir -p /home/steam/server-files && \ + sed -i 's/\r$//' /home/steam/server/*.sh && \ chmod +x /home/steam/server/*.sh # Persist user data: game files, Windrose+ config, and Lua mods all live under diff --git a/Dockerfile.staging b/Dockerfile.staging index dfaf818..2a2075d 100644 --- a/Dockerfile.staging +++ b/Dockerfile.staging @@ -1,10 +1,32 @@ +# BUILD HELPER TOOLS NATIVELY FOR THE TARGET ARCHITECTURE +FROM --platform=$TARGETPLATFORM rust:bookworm AS rust-tools-builder + +ARG REPAK_VERSION=v0.2.3 +ARG RETOC_VERSION=v0.1.5 + +RUN set -eux; \ + git clone --branch "${REPAK_VERSION}" --depth 1 https://github.com/trumank/repak.git /tmp/repak && \ + cargo build --manifest-path /tmp/repak/Cargo.toml --locked --release --bin repak && \ + install -m 0755 /tmp/repak/target/release/repak /usr/local/bin/repak + +RUN set -eux; \ + git clone --branch "${RETOC_VERSION}" --depth 1 https://github.com/trumank/retoc.git /tmp/retoc && \ + cargo build --manifest-path /tmp/retoc/Cargo.toml --locked --release --bin retoc && \ + install -m 0755 /tmp/retoc/target/release/retoc /usr/local/bin/retoc + # BUILD THE SERVER IMAGE -FROM --platform=linux/amd64 debian:bookworm-slim +FROM --platform=$TARGETPLATFORM debian:bookworm-slim + +ARG TARGETARCH +ARG DEPOT_DOWNLOADER_VERSION=3.4.0 +ARG HANGOVER_VERSION=hangover-10.18 +ARG POWERSHELL_VERSION=7.5.4 +ARG WINDROSE_PLUS_VERSION_DEFAULT=latest ENV DEBIAN_FRONTEND=noninteractive +ENV WINDROSE_PLUS_VERSION_DEFAULT=${WINDROSE_PLUS_VERSION_DEFAULT} -RUN dpkg --add-architecture i386 && \ - apt-get update && apt-get install -y --no-install-recommends \ +RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ ca-certificates \ gnupg \ @@ -17,43 +39,77 @@ RUN dpkg --add-architecture i386 && \ xauth \ jq \ cabextract \ - && curl -fsSL https://dl.winehq.org/wine-builds/winehq.key | \ - gpg --dearmor -o /usr/share/keyrings/winehq-archive.key \ - && echo "deb [arch=amd64,i386 signed-by=/usr/share/keyrings/winehq-archive.key] https://dl.winehq.org/wine-builds/debian/ bookworm main" \ - > /etc/apt/sources.list.d/winehq.list \ - && apt-get update \ - && apt-get install -y --install-recommends winehq-staging \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* -# Install PowerShell 7 (pwsh) — used by WindrosePlus scripts natively on Linux -RUN curl -fsSL https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb \ - -o /tmp/packages-microsoft-prod.deb && \ - dpkg -i /tmp/packages-microsoft-prod.deb && \ - rm /tmp/packages-microsoft-prod.deb && \ - apt-get update && \ - apt-get install -y --no-install-recommends powershell && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* - -# Install Linux-native repak and retoc (replace WindrosePlus bundled .exe tools) -ARG REPAK_VERSION=v0.2.3 -ARG RETOC_VERSION=v0.1.5 RUN set -eux; \ - curl -fsSL "https://github.com/trumank/repak/releases/download/${REPAK_VERSION}/repak_cli-x86_64-unknown-linux-gnu.tar.xz" \ - -o /tmp/repak.tar.xz && \ - tar -xJf /tmp/repak.tar.xz -C /tmp && \ - install -m 0755 "$(find /tmp -maxdepth 3 -type f -name repak | head -1)" /usr/local/bin/repak && \ - rm -rf /tmp/repak.tar.xz /tmp/repak_cli-* ; \ - curl -fsSL "https://github.com/trumank/retoc/releases/download/${RETOC_VERSION}/retoc_cli-x86_64-unknown-linux-gnu.tar.xz" \ - -o /tmp/retoc.tar.xz && \ - tar -xJf /tmp/retoc.tar.xz -C /tmp && \ - install -m 0755 "$(find /tmp -maxdepth 3 -type f -name retoc | head -1)" /usr/local/bin/retoc && \ - rm -rf /tmp/retoc.tar.xz /tmp/retoc_cli-* - -# Default Windrose+ version — can be overridden at runtime via WINDROSE_PLUS_VERSION -ARG WINDROSE_PLUS_VERSION_DEFAULT=latest -ENV WINDROSE_PLUS_VERSION_DEFAULT=${WINDROSE_PLUS_VERSION_DEFAULT} + case "${TARGETARCH}" in \ + amd64) \ + dpkg --add-architecture i386; \ + curl -fsSL https://dl.winehq.org/wine-builds/winehq.key | \ + gpg --dearmor -o /usr/share/keyrings/winehq-archive.key; \ + echo "deb [arch=amd64,i386 signed-by=/usr/share/keyrings/winehq-archive.key] https://dl.winehq.org/wine-builds/debian/ bookworm main" \ + > /etc/apt/sources.list.d/winehq.list; \ + apt-get update; \ + apt-get install -y --install-recommends winehq-staging; \ + ;; \ + arm64) \ + asset_url="$(curl -fsSL "https://api.github.com/repos/AndreRH/hangover/releases/tags/${HANGOVER_VERSION}" | jq -r '.assets[] | select((.name | test("debian12|bookworm"; "i")) and (.name | test("arm64"; "i")) and (.name | test("\\.(tar|deb)$"; "i"))) | .browser_download_url' | head -n 1)"; \ + if [ -z "${asset_url}" ] || [ "${asset_url}" = "null" ]; then \ + echo "Could not find a Debian 12 / bookworm arm64 Hangover package for ${HANGOVER_VERSION}" >&2; \ + exit 1; \ + fi; \ + mkdir -p /tmp/hangover; \ + if echo "${asset_url}" | grep -qi '\.deb$'; then \ + curl -fsSL "${asset_url}" -o /tmp/hangover/hangover.deb; \ + else \ + curl -fsSL "${asset_url}" -o /tmp/hangover/hangover.tar; \ + tar -xf /tmp/hangover/hangover.tar -C /tmp/hangover; \ + fi; \ + apt-get update; \ + find /tmp/hangover -type f -name '*.deb' -print0 | xargs -0 apt-get install -y --no-install-recommends; \ + ;; \ + *) \ + echo "Unsupported TARGETARCH: ${TARGETARCH}" >&2; \ + exit 1; \ + ;; \ + esac; \ + apt-get clean; \ + rm -rf /var/lib/apt/lists/* /tmp/hangover + +# Install PowerShell 7 (pwsh) used by WindrosePlus scripts natively on Linux. +# Debian arm64 packages are not published in the Microsoft apt repo, so use +# the official release tarball on arm64. +RUN set -eux; \ + case "${TARGETARCH}" in \ + amd64) \ + curl -fsSL https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb \ + -o /tmp/packages-microsoft-prod.deb; \ + dpkg -i /tmp/packages-microsoft-prod.deb; \ + rm /tmp/packages-microsoft-prod.deb; \ + apt-get update; \ + apt-get install -y --no-install-recommends powershell; \ + apt-get clean; \ + rm -rf /var/lib/apt/lists/*; \ + ;; \ + arm64) \ + mkdir -p /opt/microsoft/powershell/7; \ + curl -fsSL \ + "https://github.com/PowerShell/PowerShell/releases/download/v${POWERSHELL_VERSION}/powershell-${POWERSHELL_VERSION}-linux-arm64.tar.gz" \ + -o /tmp/powershell.tar.gz; \ + tar -xzf /tmp/powershell.tar.gz -C /opt/microsoft/powershell/7; \ + chmod +x /opt/microsoft/powershell/7/pwsh; \ + ln -sf /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh; \ + rm /tmp/powershell.tar.gz; \ + ;; \ + *) \ + echo "Unsupported TARGETARCH: ${TARGETARCH}" >&2; \ + exit 1; \ + ;; \ + esac + +COPY --from=rust-tools-builder /usr/local/bin/repak /usr/local/bin/repak +COPY --from=rust-tools-builder /usr/local/bin/retoc /usr/local/bin/retoc # Install winetricks RUN curl -fsSL https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks \ @@ -68,9 +124,14 @@ RUN curl -sL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh && \ rm /tmp/dotnet-install.sh # Download DepotDownloader -ARG DEPOT_DOWNLOADER_VERSION=3.4.0 -RUN curl -sL \ - "https://github.com/SteamRE/DepotDownloader/releases/download/DepotDownloader_${DEPOT_DOWNLOADER_VERSION}/DepotDownloader-linux-x64.zip" -o \ +RUN set -eux; \ + case "${TARGETARCH}" in \ + amd64) depot_arch="x64" ;; \ + arm64) depot_arch="arm64" ;; \ + *) echo "Unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;; \ + esac; \ + curl -fsSL \ + "https://github.com/SteamRE/DepotDownloader/releases/download/DepotDownloader_${DEPOT_DOWNLOADER_VERSION}/DepotDownloader-linux-${depot_arch}.zip" -o \ /tmp/dd.zip && \ mkdir -p /depotdownloader && \ unzip /tmp/dd.zip -d /depotdownloader && \ @@ -96,6 +157,7 @@ COPY ./scripts /home/steam/server/ COPY branding /branding RUN mkdir -p /home/steam/server-files && \ + sed -i 's/\r$//' /home/steam/server/*.sh && \ chmod +x /home/steam/server/*.sh # Persist user data: game files, Windrose+ config, and Lua mods all live under diff --git a/README.md b/README.md index efdfd48..971a319 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,16 @@ Game server hosting · Fast RAM · High-speed internet · Eat lag for breakfast A Docker container for running a Windrose dedicated server. The server binary is Windows-only and runs via Wine. +## ARM64 support + +This repository supports both `linux/amd64` and `linux/arm64` images. + +- On `amd64`, the container uses the existing WineHQ-based path. +- On `arm64`, the container uses [Hangover](https://github.com/AndreRH/hangover) to run the same Windows dedicated-server binary on ARM Linux. +- Windrose+ helper tools are built for the target architecture during the Docker build, and PowerShell is installed on `arm64` from the official PowerShell release tarball because Microsoft does not publish a Debian 12 `arm64` apt package. + +This is still a compatibility path, not a native ARM server build. Expect lower performance on `arm64` than on an equivalent `amd64` host. + ## Server Requirements | | 2 Players | 4 Players | 10 Players | @@ -44,6 +54,20 @@ services: docker compose up -d ``` +### Build locally + +To build for the current machine architecture: + +```shell +docker build -t windrose-server-docker . +``` + +To build an ARM64 image explicitly with Buildx: + +```shell +docker buildx build --load --platform linux/arm64 -t windrose-server-docker:arm64 . +``` + ### Docker Run ```shell @@ -296,6 +320,12 @@ If you are hosting this server inside a Proxmox VM or LXC container, set the CPU Proxmox's default CPU types (e.g. `kvm64`) omit instruction sets that Wine and the server binary may depend on. This can cause the server to fail to start, crash at runtime, or fail silently with no useful output. +## Implementation notes + +- `arm64` support relies on Hangover's ARM64 Wine compatibility layer for the Windows server executable. +- The upstream dedicated server is still downloaded from Steam as the original Windows build. +- Image publishing workflows now build both `linux/amd64` and `linux/arm64`. + ## About This is a Dockerized Windrose dedicated server maintained by [indifferent broccoli](https://indifferentbroccoli.com). We offer [managed Windrose server hosting](https://indifferentbroccoli.com/windrose-server-hosting) if you'd rather not self-host. diff --git a/docker-compose.yml b/docker-compose.yml index 64728a3..9a27e1b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,6 @@ services: windrose: image: indifferentbroccoli/windrose-server-docker - platform: linux/amd64 restart: unless-stopped container_name: windrose stop_grace_period: 30s diff --git a/scripts/start.sh b/scripts/start.sh index 4572a13..09d68b6 100644 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -7,6 +7,7 @@ SERVER_FILES="/home/steam/server-files" cd "$SERVER_FILES" || exit LogAction "Starting Windrose Dedicated Server" +LogInfo "Container architecture: $(uname -m)" SERVER_DESC="$SERVER_FILES/R5/ServerDescription.json"