mirror of
https://github.com/itzg/docker-minecraft-server.git
synced 2026-06-22 18:14:18 +00:00
Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2fc873c01b | |||
| 737a9879f7 | |||
| 8b5f7ed771 | |||
| d20cd2dfe1 | |||
| b67d88f713 | |||
| 0dce4ed863 | |||
| 85170775fd | |||
| 11a78f5070 | |||
| 56179b56f5 | |||
| cfa58bb78c | |||
| 6094348d8f | |||
| ab018d75a0 | |||
| 1a8844cb62 | |||
| 2433473015 | |||
| 4495d9f8a7 | |||
| 56c4c95606 | |||
| 47efe3e4bb | |||
| 151143a141 | |||
| cecf4e8e95 | |||
| 1c30c8c476 | |||
| 802dc47c9c | |||
| a4719f2ba6 | |||
| cbd56fd012 | |||
| 544382d5d6 | |||
| e59cf8ac55 | |||
| 68830d5a9f | |||
| 14356b7662 | |||
| d375400541 | |||
| d5442ddb14 | |||
| f65c7f739c | |||
| 58781c3724 | |||
| 1e8aecd06e | |||
| 21920f3fe7 | |||
| 9352c45d6e | |||
| 3d4555557b | |||
| c95b638faa | |||
| fd823d6040 | |||
| 7656abeaa6 | |||
| a708715a9f | |||
| 5febc1ab5d | |||
| 6878ad6e01 | |||
| 889b607606 | |||
| f3b1d7ee93 | |||
| cdc2c7977e | |||
| 14d0be9430 | |||
| ffbd905ec4 | |||
| b35db38cd3 | |||
| 32696ae457 | |||
| 50155230bd | |||
| 14c8509bee | |||
| a44c717041 | |||
| 60ab277060 |
@@ -13,6 +13,9 @@ updates:
|
||||
- minor
|
||||
- package-ecosystem: pip
|
||||
directory: "/docs"
|
||||
labels:
|
||||
- dependencies
|
||||
- documentation
|
||||
schedule:
|
||||
interval: weekly
|
||||
groups:
|
||||
|
||||
+16
-12
@@ -75,24 +75,28 @@ jobs:
|
||||
baseImage: adoptopenjdk:16-jre-hotspot
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
mcVersion: 1.16.5
|
||||
# Pin version for pre-Java 17
|
||||
mcHelperVersion: 1.51.3-java8
|
||||
# JAVA 11
|
||||
- variant: java11
|
||||
baseImage: adoptopenjdk:11-jre-hotspot
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
mcVersion: 1.16.4
|
||||
# Pin version for pre-Java 17
|
||||
mcHelperVersion: 1.51.3-java8
|
||||
# JAVA 8: NOTE: Unable to go past 8u312 because of Forge dependencies
|
||||
- variant: java8
|
||||
baseImage: eclipse-temurin:8u312-b07-jre-focal
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
mcVersion: 1.12.2
|
||||
# Pin version for Java 8
|
||||
mcHelperVersion: 1.51.1
|
||||
# Pin version for Java 8, also be sure to set in verify-pr.yml
|
||||
mcHelperVersion: 1.51.3-java8
|
||||
- variant: java8-jdk
|
||||
baseImage: eclipse-temurin:8u312-b07-jdk-focal
|
||||
platforms: linux/amd64,linux/arm64
|
||||
mcVersion: 1.12.2
|
||||
# Pin version for Java 8
|
||||
mcHelperVersion: 1.51.1
|
||||
# Pin version for Java 8, also be sure to set in verify-pr.yml
|
||||
mcHelperVersion: 1.51.3-java8
|
||||
env:
|
||||
IMAGE_TO_TEST: "${{ github.repository_owner }}/minecraft-server:test-${{ matrix.variant }}-${{ github.run_id }}"
|
||||
HAS_IMAGE_REPO_ACCESS: ${{ secrets.DOCKER_USER != '' && secrets.DOCKER_PASSWORD != '' }}
|
||||
@@ -100,14 +104,14 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6.0.2
|
||||
uses: actions/checkout@v6.0.3
|
||||
with:
|
||||
# for build-files step
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v6.0.0
|
||||
uses: docker/metadata-action@v6.1.0
|
||||
with:
|
||||
# NOTE for forks: if your Docker Hub organization doesn't match your Github repo's,
|
||||
# then the use of ${{ github.repository_owner }} will need to be replaced.
|
||||
@@ -137,13 +141,13 @@ jobs:
|
||||
org.opencontainers.image.authors=Geoff Bourne <itzgeoff@gmail.com>
|
||||
|
||||
- name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4.0.0
|
||||
uses: docker/setup-buildx-action@v4.1.0
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v4.0.0
|
||||
uses: docker/setup-qemu-action@v4.1.0
|
||||
|
||||
- name: Build for test
|
||||
uses: docker/build-push-action@v7.1.0
|
||||
uses: docker/build-push-action@v7.2.0
|
||||
with:
|
||||
platforms: linux/amd64
|
||||
tags: ${{ env.IMAGE_TO_TEST }}
|
||||
@@ -168,14 +172,14 @@ jobs:
|
||||
tests/test.sh
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v4.1.0
|
||||
uses: docker/login-action@v4.2.0
|
||||
if: env.HAS_IMAGE_REPO_ACCESS
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USER }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@v4.1.0
|
||||
uses: docker/login-action@v4.2.0
|
||||
if: env.HAS_IMAGE_REPO_ACCESS
|
||||
with:
|
||||
registry: ghcr.io
|
||||
@@ -183,7 +187,7 @@ jobs:
|
||||
password: ${{ github.token }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v7.1.0
|
||||
uses: docker/build-push-action@v7.2.0
|
||||
if: github.actor == github.repository_owner
|
||||
with:
|
||||
platforms: ${{ matrix.platforms }}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
name: Label Sponsor Contributions
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- opened
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
|
||||
jobs:
|
||||
label-sponsor:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
issues: write
|
||||
|
||||
steps:
|
||||
- name: Check if sponsor
|
||||
uses: JasonEtco/is-sponsor-label-action@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
label: sponsor
|
||||
@@ -0,0 +1,35 @@
|
||||
name: Verify Docs
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- 'zensical.toml'
|
||||
- '.github/workflows/verify-docs.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
verify:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build docs image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docs/Dockerfile
|
||||
load: true
|
||||
tags: docs-verifier:latest
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Verify rendering
|
||||
run: |
|
||||
docker run --rm \
|
||||
-v ${{ github.workspace }}:/docs \
|
||||
docs-verifier:latest build --strict
|
||||
@@ -46,23 +46,23 @@ jobs:
|
||||
baseImage: eclipse-temurin:8u312-b07-jre-focal
|
||||
platforms: linux/amd64
|
||||
mcVersion: 1.12.2
|
||||
# Pin version for Java 8
|
||||
mcHelperVersion: 1.51.1
|
||||
# Pin version for Java 8, be sure to also set in build.yml
|
||||
mcHelperVersion: 1.51.3-java8
|
||||
env:
|
||||
IMAGE_TO_TEST: ${{ github.repository_owner }}/minecraft-server:test-${{ matrix.variant }}-${{ github.run_id }}
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6.0.2
|
||||
uses: actions/checkout@v6.0.3
|
||||
with:
|
||||
# for build-files step
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4.0.0
|
||||
uses: docker/setup-buildx-action@v4.1.0
|
||||
|
||||
- name: Confirm multi-arch build
|
||||
uses: docker/build-push-action@v7.1.0
|
||||
uses: docker/build-push-action@v7.2.0
|
||||
with:
|
||||
platforms: ${{ matrix.platforms }}
|
||||
# ensure latest base image is used
|
||||
@@ -73,7 +73,7 @@ jobs:
|
||||
cache-from: type=gha,scope=${{ matrix.variant }}
|
||||
|
||||
- name: Build for test
|
||||
uses: docker/build-push-action@v7.1.0
|
||||
uses: docker/build-push-action@v7.2.0
|
||||
with:
|
||||
# Only build single platform since loading multi-arch image into daemon fails with
|
||||
# "docker exporter does not currently support exporting manifest lists"
|
||||
|
||||
+6
-6
@@ -26,36 +26,36 @@ ARG APPS_REV=1
|
||||
ARG GITHUB_BASEURL=https://github.com
|
||||
|
||||
# renovate: datasource=github-releases packageName=itzg/easy-add
|
||||
ARG EASY_ADD_VERSION=0.8.11
|
||||
ARG EASY_ADD_VERSION=0.8.14
|
||||
ADD ${GITHUB_BASEURL}/itzg/easy-add/releases/download/${EASY_ADD_VERSION}/easy-add_${TARGETOS}_${TARGETARCH}${TARGETVARIANT} /usr/bin/easy-add
|
||||
RUN chmod +x /usr/bin/easy-add
|
||||
|
||||
# renovate: datasource=github-releases packageName=itzg/restify
|
||||
ARG RESTIFY_VERSION=1.7.13
|
||||
ARG RESTIFY_VERSION=1.7.16
|
||||
RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \
|
||||
--var version=${RESTIFY_VERSION} --var app=restify --file {{.app}} \
|
||||
--from ${GITHUB_BASEURL}/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_{{.os}}_{{.arch}}.tar.gz
|
||||
|
||||
# renovate: datasource=github-releases packageName=itzg/rcon-cli
|
||||
ARG RCON_CLI_VERSION=1.7.4
|
||||
ARG RCON_CLI_VERSION=1.7.6
|
||||
RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \
|
||||
--var version=${RCON_CLI_VERSION} --var app=rcon-cli --file {{.app}} \
|
||||
--from ${GITHUB_BASEURL}/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_{{.os}}_{{.arch}}.tar.gz
|
||||
|
||||
# renovate: datasource=github-releases packageName=itzg/mc-monitor
|
||||
ARG MC_MONITOR_VERSION=0.16.2
|
||||
ARG MC_MONITOR_VERSION=0.16.7
|
||||
RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \
|
||||
--var version=${MC_MONITOR_VERSION} --var app=mc-monitor --file {{.app}} \
|
||||
--from ${GITHUB_BASEURL}/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_{{.os}}_{{.arch}}.tar.gz
|
||||
|
||||
# renovate: datasource=github-releases packageName=itzg/mc-server-runner
|
||||
ARG MC_SERVER_RUNNER_VERSION=1.14.5
|
||||
ARG MC_SERVER_RUNNER_VERSION=1.15.0
|
||||
RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \
|
||||
--var version=${MC_SERVER_RUNNER_VERSION} --var app=mc-server-runner --file {{.app}} \
|
||||
--from ${GITHUB_BASEURL}/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_{{.os}}_{{.arch}}.tar.gz
|
||||
|
||||
# renovate: datasource=github-releases packageName=itzg/mc-image-helper versioning=loose
|
||||
ARG MC_HELPER_VERSION=1.57.2
|
||||
ARG MC_HELPER_VERSION=1.61.1
|
||||
ARG MC_HELPER_BASE_URL=${GITHUB_BASEURL}/itzg/mc-image-helper/releases/download/${MC_HELPER_VERSION}
|
||||
# used for cache busting local copy of mc-image-helper
|
||||
ARG MC_HELPER_REV=1
|
||||
|
||||
@@ -18,6 +18,7 @@ apk add --no-cache -U \
|
||||
curl \
|
||||
iputils \
|
||||
git \
|
||||
git-lfs \
|
||||
jq \
|
||||
mysql-client \
|
||||
tzdata \
|
||||
@@ -32,6 +33,7 @@ apk add --no-cache -U \
|
||||
libwebp \
|
||||
libcap \
|
||||
numactl \
|
||||
jattach \
|
||||
${EXTRA_ALPINE_PACKAGES}
|
||||
|
||||
# Download and install patched knockd
|
||||
@@ -45,4 +47,5 @@ cat <<EOF >> /etc/gitconfig
|
||||
[user]
|
||||
name = Minecraft Server on Docker
|
||||
email = server@example.com
|
||||
EOF
|
||||
EOF
|
||||
git lfs install
|
||||
@@ -46,6 +46,7 @@ dnf install -y \
|
||||
zstd \
|
||||
$([ "$os_major_version" -ge 10 ] && echo 'bzip2' || echo 'lbzip2') \
|
||||
libpcap \
|
||||
libcap \
|
||||
libwebp \
|
||||
findutils \
|
||||
which \
|
||||
@@ -81,3 +82,4 @@ cat <<EOF >> /etc/gitconfig
|
||||
name = Minecraft Server on Docker
|
||||
email = server@example.com
|
||||
EOF
|
||||
git lfs install
|
||||
|
||||
@@ -16,6 +16,7 @@ apt-get install -y \
|
||||
iputils-ping \
|
||||
curl \
|
||||
git \
|
||||
git-lfs \
|
||||
jq \
|
||||
dos2unix \
|
||||
mysql-client \
|
||||
@@ -28,13 +29,10 @@ apt-get install -y \
|
||||
nfs-common \
|
||||
libpcap0.8 \
|
||||
libnuma1 \
|
||||
libcap2-bin \
|
||||
jattach \
|
||||
${EXTRA_DEB_PACKAGES}
|
||||
|
||||
# Install Git LFS
|
||||
curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
|
||||
apt-get update
|
||||
apt-get install -y git-lfs
|
||||
|
||||
# Clean up APT when done
|
||||
apt-get clean
|
||||
|
||||
@@ -51,3 +49,4 @@ cat <<EOF >> /etc/gitconfig
|
||||
name = Minecraft Server on Docker
|
||||
email = server@example.com
|
||||
EOF
|
||||
git lfs install
|
||||
|
||||
@@ -22,6 +22,12 @@ docker run -d --pull=always \
|
||||
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
|
||||
```
|
||||
|
||||
## Clean server libraries
|
||||
|
||||
By default, supported server types remove stale server libraries during installation by setting `CLEAN_SERVER_LIBRARIES` to `true`. Set `CLEAN_SERVER_LIBRARIES` to `false` to disable this cleanup if it causes unexpected behavior.
|
||||
|
||||
Currently, library cleanup is supported by `TYPE=PAPER`. Other server jar types are not yet supported.
|
||||
|
||||
## Running as alternate user/group ID
|
||||
|
||||
By default, the container will switch to and run the Minecraft server as user ID 1000 and group ID 1000; however, that can be changed by setting the environment variables `UID` and `GID`.
|
||||
@@ -44,6 +50,8 @@ If this behavior interferes with the log content, then disable TTY or remove the
|
||||
|
||||
To allow time for players to finish what they're doing during a graceful server shutdown, set `STOP_SERVER_ANNOUNCE_DELAY` to a number of seconds to delay after an announcement is posted by the server.
|
||||
|
||||
To set a custom command to run at the start of this delay period, set `STOP_SERVER_DELAY_COMMAND` to the full command. This will run in place of the announcement.
|
||||
|
||||
!!! warning "Increase stop grace period"
|
||||
|
||||
The Docker stop grace period must be increased to a value longer than the announce delay. The value to use that is longer than announce delay will vary based upon the amount of time it takes for final world data saving. If the container exits with exit code 137, then that indicates a longer grace period is needed.
|
||||
@@ -236,4 +244,4 @@ To also include the timestamp with each log, set `LOG_TIMESTAMP` to "true". The
|
||||
|
||||
```
|
||||
[init] 2022-02-05 16:58:33+00:00 Starting the Minecraft server...
|
||||
```
|
||||
```
|
||||
@@ -78,6 +78,12 @@ To produce a multi-line MOTD, embed a newline character as `\n` in the string, s
|
||||
-e MOTD="Line one\nLine two"
|
||||
```
|
||||
|
||||
From bash shell
|
||||
|
||||
```
|
||||
-e MOTD=$'Line one\nLine two'
|
||||
```
|
||||
|
||||
or within a compose file
|
||||
|
||||
```yaml
|
||||
|
||||
@@ -35,4 +35,20 @@ The labels that are most interesting are:
|
||||
|
||||
- `org.opencontainers.image.created` : the date/time the image was built
|
||||
- `org.opencontainers.image.revision` : which maps to <https://github.com/itzg/docker-minecraft-server/commit/REVISION>
|
||||
- `org.opencontainers.image.version` : image tag and variant [as described in this page](../versions/java.md)
|
||||
- `org.opencontainers.image.version` : image tag and variant [as described in this page](../versions/java.md)
|
||||
|
||||
## jattach
|
||||
|
||||
This image bundles the [jattach](https://github.com/jattach/jattach) utility for attaching to running Java processes. It is described as
|
||||
|
||||
> The utility to send commands to a JVM process via Dynamic Attach mechanism.
|
||||
>
|
||||
> All-in-one jmap + jstack + jcmd + jinfo functionality in a single tiny program.
|
||||
|
||||
When exec'ed interactively into the container, jattach can be invoked against the Minecraft server's java process by using commands similar to the following
|
||||
|
||||
!!! example
|
||||
|
||||
```shell
|
||||
jattach $(pgrep java) threaddump
|
||||
```
|
||||
@@ -156,6 +156,54 @@ Disabling mods within docker compose files:
|
||||
mod2.jar
|
||||
```
|
||||
|
||||
### Loading container configuration from a pack
|
||||
|
||||
A pack can ship its own container configuration so that the server type, version,
|
||||
and other variables travel with the pack rather than being declared by the user.
|
||||
At startup, before `TYPE` is dispatched, the container can load environment
|
||||
variables from a file on disk, a URL, an entry inside an archive, or from the
|
||||
`.env` of each `GENERIC_PACK(S)` entry.
|
||||
|
||||
- `LOAD_ENV_FROM_GENERIC_PACK`: when `true`, each entry in `GENERIC_PACKS` (after
|
||||
`GENERIC_PACKS_PREFIX`/`SUFFIX` expansion) is probed for a top-level `.env`
|
||||
and each one found is sourced in the same order the packs are applied (later
|
||||
packs override earlier ones, matching the layering of the unpack itself). Packs
|
||||
without a `.env` are skipped without error. URLs are downloaded into
|
||||
`/data/packs/` and reused by the regular generic-pack unpack step, so they are
|
||||
not fetched twice.
|
||||
- `LOAD_ENV_FROM_FILE`: container path or URL of a shell-style env file (one
|
||||
`KEY=VALUE` per line). Comments and blank lines are allowed.
|
||||
- `LOAD_ENV_FROM_ARCHIVE`: container path or URL of a zip/tar archive containing
|
||||
an env file. The entry is sourced into the environment.
|
||||
- `LOAD_ENV_FROM_ARCHIVE_ENTRY`: relative path of the env file inside the archive.
|
||||
Defaults to `.env`.
|
||||
|
||||
These can be combined. Load order is: generic packs first, then
|
||||
`LOAD_ENV_FROM_FILE`, then `LOAD_ENV_FROM_ARCHIVE` — later loads override
|
||||
earlier ones, and all of them **override** values passed via `docker run -e` (or
|
||||
compose `environment:`), so the pack's declared values win.
|
||||
|
||||
```shell
|
||||
docker run -d \
|
||||
-e EULA=TRUE \
|
||||
-e GENERIC_PACK=https://cdn.example.org/my-pack.zip \
|
||||
-e LOAD_ENV_FROM_GENERIC_PACK=true \
|
||||
itzg/minecraft-server
|
||||
```
|
||||
|
||||
Where `my-pack.zip` contains a `.env` at its root such as:
|
||||
|
||||
```env
|
||||
TYPE=FABRIC
|
||||
VERSION=1.21.1
|
||||
FABRIC_LOADER_VERSION=0.16.0
|
||||
```
|
||||
|
||||
!!! warning
|
||||
The env file is sourced by `bash`, so any shell syntax it contains will be
|
||||
evaluated. Only point these variables at sources you trust. `EULA` cannot be
|
||||
set this way — it is checked before the env file is loaded.
|
||||
|
||||
## Mods/plugins list
|
||||
|
||||
You may also download or copy over individual mods/plugins using the `MODS` or `PLUGINS` environment variables. Both are a comma or newline delimited list of
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
click==8.3.3
|
||||
click==8.4.1
|
||||
colorama==0.4.6
|
||||
deepmerge==2.0
|
||||
ghp-import==2.1.0
|
||||
@@ -11,15 +11,15 @@ mkdocs==1.6.1
|
||||
mkdocs-autorefs==1.4.4
|
||||
mkdocs-get-deps==0.2.2
|
||||
mkdocstrings==1.0.4
|
||||
mkdocstrings-python==2.0.3
|
||||
mkdocstrings-python==2.0.4
|
||||
packaging==26.2
|
||||
pathspec==1.1.1
|
||||
platformdirs==4.9.6
|
||||
platformdirs==4.10.0
|
||||
Pygments==2.20.0
|
||||
pymdown-extensions==10.21.2
|
||||
pymdown-extensions==10.21.3
|
||||
python-dateutil==2.9.0.post0
|
||||
PyYAML==6.0.3
|
||||
pyyaml_env_tag==1.1
|
||||
six==1.17.0
|
||||
watchdog==6.0.0
|
||||
zensical==0.0.37
|
||||
zensical==0.0.45
|
||||
|
||||
@@ -6,7 +6,7 @@ The container can host an SSH console. It is enabled by setting `ENABLE_SSH` to
|
||||
The SSH server only supports password based authentication. The password is the same as the RCON password.
|
||||
|
||||
!!! question
|
||||
See [the RCON password](../configuration/server-properties.md/#rcon-password) section under configuration/server-properties for more information on how to set an RCON password.
|
||||
See [the RCON password](../configuration/server-properties.md#rcon-password) section under configuration/server-properties for more information on how to set an RCON password.
|
||||
|
||||
The SSH server runs on port `2222` inside the container.
|
||||
|
||||
@@ -15,7 +15,7 @@ The SSH server runs on port `2222` inside the container.
|
||||
!!! warning "Security Implications"
|
||||
By default, publishing ports in Docker binds them to all network interfaces (`0.0.0.0`), making the SSH console accessible to any device that can reach your host machine.
|
||||
|
||||
Since the SSH console grants **full administrative access** to your server, it is critical to use a strong [RCON password](../configuration/server-properties.md/#rcon-password).
|
||||
Since the SSH console grants **full administrative access** to your server, it is critical to use a strong [RCON password](../configuration/server-properties.md#rcon-password).
|
||||
|
||||
If you wish to restrict access to the local machine only, refer to the [Docker documentation](https://docs.docker.com/engine/network/port-publishing/#publishing-ports) on binding to specific IP addresses (e.g., `127.0.0.1:2222:2222`).
|
||||
|
||||
|
||||
@@ -26,9 +26,9 @@ When a connection is established, the last 50 (by default, configurable with `WE
|
||||
!!! warning "Security Implications"
|
||||
By default, publishing ports in Docker binds them to all network interfaces (`0.0.0.0`), making the WebSocket console accessible to any device that can reach your host machine.
|
||||
|
||||
Since the WebSocket console grants **full administrative access** to your server, it is critical to use a strong [WebSocket password](#password) or [RCON password](../configuration/server-properties.md/#rcon-password).
|
||||
Since the WebSocket console grants **full administrative access** to your server, it is critical to use a strong [WebSocket password](#password) or [RCON password](../configuration/server-properties.md#rcon-password).
|
||||
|
||||
If you wish to restrict access to the local machine only, refer to the [Docker documentation](https://docs.docker.com/engine/network/port-publishing/#publishing-ports) on binding to specific IP addresses (e.g., `127.0.0.1:80:80`).
|
||||
If you wish to restrict access to the local machine only, refer to the [Docker documentation](https://docs.docker.com/engine/network/port-publishing#publishing-ports) on binding to specific IP addresses (e.g., `127.0.0.1:80:80`).
|
||||
|
||||
If WebSocket access is only intended for inter-container connections, consider **NOT** forwarding the port to the host machine, and putting the containers in a shared [Docker network](https://docs.docker.com/engine/network/#user-defined-networks).
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ The desired modpack project is specified with the `MODRINTH_MODPACK` environment
|
||||
|
||||
- A custom URL of a hosted [mrpack file](https://support.modrinth.com/en/articles/8802351-modrinth-modpack-format-mrpack)
|
||||
|
||||
- The container path to a local [mrpack file](https://support.modrinth.com/en/articles/8802351-modrinth-modpack-format-mrpack)
|
||||
- The container path to a local [mrpack file](https://support.modrinth.com/en/articles/8802351-modrinth-modpack-format-mrpack). The file name **must have the `.mrpack` extension** in order to be correctly detected as a local file.
|
||||
|
||||
## Modpack version
|
||||
|
||||
|
||||
+7
-1
@@ -246,6 +246,12 @@ alternatively, you can mount: <code>/etc/localtime:/etc/localtime:ro
|
||||
<td><code></code></td>
|
||||
<td>⬜️</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>STOP_SERVER_DELAY_COMMAND</code></td>
|
||||
<td>To set a custom command to run at the start of this delay period, set <code>STOP_SERVER_DELAY_COMMAND</code> to the full command. This will run in place of the announcement.</td>
|
||||
<td><code></code></td>
|
||||
<td>⬜️</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>PROXY</code></td>
|
||||
<td>You may configure the use of an HTTP/HTTPS proxy by passing the proxy's URL</td>
|
||||
@@ -670,4 +676,4 @@ This image maps known server properties as described in [this section](configura
|
||||
<td></td>
|
||||
<td><code></code></td>
|
||||
<td>⬜️</td>
|
||||
</tr> -->
|
||||
</tr> -->
|
||||
@@ -0,0 +1,45 @@
|
||||
# Podman Quadlet Example
|
||||
|
||||
This example demonstrates how to deploy multiple autoscaling minecraft servers behind mc-router with [podman quadlets](https://docs.podman.io/en/stable/markdown/podman-systemd.unit.5.html).
|
||||
|
||||
The commands listed below assume rootless podman but can easily be modified for rootful.
|
||||
|
||||
## mc-router.host label
|
||||
|
||||
In `mc@.container`, replace `example.com` with your domain.
|
||||
|
||||
## Server instance configuration
|
||||
|
||||
Each server instance requries an environment file with a matching name in the mc folder; e.g. instance `example` uses `mc/example.env`.[^1]
|
||||
|
||||
## Container auto-removal fix
|
||||
|
||||
Once the quadlets files are installed and daemon-reloaded, the generated service file needs to be edited due to generated quadlets always adding `--rm`.[^2]
|
||||
To fix this, run `systemctl --user edit mc@.service` and replace the `ExecStart` entry with a copy that substitues `--restart=unless-stopped` where `--rm` is.
|
||||
The drop-in should look something like this:
|
||||
|
||||
```ini
|
||||
[Service]
|
||||
ExecStart=
|
||||
ExecStart=/usr/bin/podman run --name %p-%i --replace --restart=unless-stopped ...
|
||||
```
|
||||
|
||||
## Start containers/services
|
||||
|
||||
```sh
|
||||
systemctl --user enable --now podman.socket
|
||||
systemctl --user start mc@example.service mc-router.service
|
||||
# instances are enabled by symlinking from the template
|
||||
ln -s ${XDG_CONFIG_HOME}/containers/systemd/mc@.service ${XDG_CONFIG_HOME}/containers/systemd/mc@example.service
|
||||
```
|
||||
|
||||
## Rootless notes
|
||||
|
||||
If running rootless, be sure to enable lingering with `sudo loginctl enable-linger $USER`.
|
||||
|
||||
Also note that source IPs are currently lost due to how rootless podman handles custom networks.
|
||||
This should be fixed in a future podman release.[^3]
|
||||
|
||||
[^1]: The base config is a [template file](https://docs.podman.io/en/stable/markdown/podman-systemd.unit.5.html#template-files) with instance names after the @ sign .
|
||||
[^2]: <https://github.com/podman-container-tools/podman/discussions/28837>
|
||||
[^3]: <https://github.com/podman-container-tools/podman/pull/28478>
|
||||
@@ -0,0 +1,24 @@
|
||||
[Unit]
|
||||
Description=Minecraft proxy with autoscaling support
|
||||
|
||||
[Container]
|
||||
Image=docker.io/itzg/mc-router
|
||||
ContainerName=%N
|
||||
AutoUpdate=registry
|
||||
UserNS=host
|
||||
Volume=%t/podman/podman.sock:/var/run/docker.sock:ro
|
||||
Network=minecraft.network
|
||||
PublishPort=25565:25565
|
||||
SecurityLabelDisable=true
|
||||
Environment=\
|
||||
"IN_DOCKER=true" \
|
||||
"AUTO_SCALE_DOWN=true" \
|
||||
"AUTO_SCALE_UP=true" \
|
||||
"AUTO_SCALE_DOWN_AFTER=10m" \
|
||||
"AUTO_SCALE_ASLEEP_MOTD='Server is asleep. Join again to wake it up!'"
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -0,0 +1,9 @@
|
||||
# General options
|
||||
INIT_MEMORY=1G
|
||||
MAX_MEMORY=4G
|
||||
|
||||
# Server options
|
||||
EULA=TRUE
|
||||
VIEW_DISTANCE=16
|
||||
DIFFICULTY=normal
|
||||
MOTD=Example Server!\nRunning version %VERSION%
|
||||
@@ -0,0 +1,26 @@
|
||||
[Unit]
|
||||
Description=Minecraft server instance
|
||||
Before=mc-router.service
|
||||
|
||||
[Container]
|
||||
Image=docker.io/itzg/minecraft-server
|
||||
ContainerName=%p-%i
|
||||
AutoUpdate=registry
|
||||
UserNS=auto
|
||||
Volume=%p-%i:/data:Z,U
|
||||
Network=minecraft.network
|
||||
PodmanArgs=--tty --interactive
|
||||
HealthCmd="/usr/local/bin/mc-health"
|
||||
HealthInterval=10s
|
||||
HealthRetries=20
|
||||
HealthStartPeriod=1m
|
||||
HealthTimeout=10s
|
||||
Label=mc-router.host=%p-%i.example.com
|
||||
EnvironmentFile=./mc/%i.env
|
||||
|
||||
[Service]
|
||||
Restart=on-abnormal
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -0,0 +1,2 @@
|
||||
[Network]
|
||||
Driver=bridge
|
||||
@@ -10,7 +10,6 @@ services:
|
||||
VANILLATWEAKS_FILE: /config/vanillatweaks-datapacks.json
|
||||
REMOVE_OLD_VANILLATWEAKS: "TRUE"
|
||||
volumes:
|
||||
- data:/data
|
||||
- ./vanillatweaks-datapacks.json:/config/vanillatweaks-datapacks.json:ro
|
||||
vanillatweaks_sharecode:
|
||||
# port is set to 25566 to not conflict with vanillatweaks_file example
|
||||
@@ -35,7 +34,6 @@ services:
|
||||
VANILLATWEAKS_FILE: /config/vanillatweaks-datapacks.json,/config/vanillatweaks-resourcepacks.json,/config/vanillatweaks-craftingtweaks.json
|
||||
REMOVE_OLD_VANILLATWEAKS: "TRUE"
|
||||
volumes:
|
||||
- data:/data
|
||||
- ./vanillatweaks-datapacks.json:/config/vanillatweaks-datapacks.json:ro
|
||||
- ./vanillatweaks-resourcepacks.json:/config/vanillatweaks-resourcepacks.json:ro
|
||||
- ./vanillatweaks-craftingtweaks.json:/config/vanillatweaks-craftingtweaks.json:ro
|
||||
- ./vanillatweaks-craftingtweaks.json:/config/vanillatweaks-craftingtweaks.json:ro
|
||||
@@ -82,6 +82,7 @@
|
||||
"iceberg",
|
||||
"ignitioncoil",
|
||||
"illager-raid-music",
|
||||
"immersive-damage-indicators",
|
||||
"inmisaddon",
|
||||
"iris-flywheel-compat",
|
||||
"irisshaders",
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
"gpumemleakfix",
|
||||
"Highlighter",
|
||||
"ImmediatelyFast",
|
||||
"immersivedamageindicators",
|
||||
"indium",
|
||||
"inventory-profiles-next",
|
||||
"iris",
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
"max-players": {"env": "MAX_PLAYERS"},
|
||||
"max-tick-time": {"env": "MAX_TICK_TIME"},
|
||||
"max-world-size": {"env": "MAX_WORLD_SIZE"},
|
||||
"motd": {"env": "MOTD"},
|
||||
"motd": {"env": "MOTD", "translateLiteralNewlines": true},
|
||||
"network-compression-threshold": {"env": "NETWORK_COMPRESSION_THRESHOLD"},
|
||||
"online-mode": {"env": "ONLINE_MODE"},
|
||||
"op-permission-level": {"env": "OP_PERMISSION_LEVEL"},
|
||||
|
||||
@@ -123,7 +123,8 @@ function addToProxyArgs() {
|
||||
addToProxyArgs http.proxyHost "${PROXY_HOST:-}"
|
||||
addToProxyArgs http.proxyPort "${PROXY_PORT:-}"
|
||||
addToProxyArgs http.nonProxyHosts "${PROXY_NON_PROXY_HOSTS:-}"
|
||||
export MC_IMAGE_HELPER_OPTS+=" ${proxyArgs[*]}"
|
||||
LOCAL_IFS=$IFS; IFS=' '; MC_IMAGE_HELPER_OPTS+=" ${proxyArgs[*]}"; IFS=$LOCAL_IFS
|
||||
export MC_IMAGE_HELPER_OPTS
|
||||
|
||||
function fixJavaPath() {
|
||||
# Some Docker management UIs grab all the image declared variables and present them for configuration.
|
||||
@@ -152,6 +153,31 @@ fi
|
||||
|
||||
cd /data || exit 1
|
||||
|
||||
##########################################
|
||||
# Optionally load environment variables from a file or archive entry,
|
||||
# allowing packs/artifacts to declare TYPE, VERSION and other settings
|
||||
# inside-out. Loaded values override anything passed in through docker -e.
|
||||
# Generic packs are processed first so that LOAD_ENV_FROM_FILE and
|
||||
# LOAD_ENV_FROM_ARCHIVE can override any values they set.
|
||||
|
||||
if isTrue "${LOAD_ENV_FROM_GENERIC_PACK:-false}"; then
|
||||
if ! loadEnvFromGenericPack; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ${LOAD_ENV_FROM_FILE:-} ]]; then
|
||||
if ! loadEnvFromFile "${LOAD_ENV_FROM_FILE}"; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ${LOAD_ENV_FROM_ARCHIVE:-} ]]; then
|
||||
if ! loadEnvFromArchive "${LOAD_ENV_FROM_ARCHIVE}" "${LOAD_ENV_FROM_ARCHIVE_ENTRY:-.env}"; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
export DECLARED_TYPE=${TYPE^^}
|
||||
export DECLARED_VERSION="$VERSION"
|
||||
|
||||
|
||||
+52
-78
@@ -6,87 +6,61 @@
|
||||
# Define setup functions
|
||||
function getGTNHdownloadPath(){
|
||||
gtnh_download_path=""
|
||||
current_java_version=$(mc-image-helper java-release)
|
||||
|
||||
if ! packs_data="$(
|
||||
curl -fsSL "https://downloads.gtnewhorizons.com/versions.json" \
|
||||
| jq -r '.versions[]?.server? | .[]? | select(type=="string" and test("Server"))'
|
||||
)"; then
|
||||
logError "Failed to retrieve data from https://downloads.gtnewhorizons.com/versions.json"
|
||||
exit 1
|
||||
fi
|
||||
mapfile -t packs <<< "$packs_data"
|
||||
local release_object=""
|
||||
local current_java_version=$(mc-image-helper java-release)
|
||||
|
||||
log "Start locating server files..."
|
||||
for pack in "${packs[@]}"; do
|
||||
# Extract the Java version(s) from the pack filename
|
||||
if ! pack_java_version=$(basename "$pack" | grep -Eo 'Java_[0-9]+(-[0-9]+)?' | sed 's/Java_//'); then
|
||||
logWarning "Could not parse java version of $pack"
|
||||
# Select release JSON object
|
||||
if [ "$GTNH_PACK_VERSION" == "latest-dev" ]; then
|
||||
if ! release_object="$(
|
||||
curl -fsSL "https://downloads.gtnewhorizons.com/versions.json" \
|
||||
| jq -r '.versions|to_entries|sort_by(.value.releaseDate)|map(select(.value.title=="Beta release"))|.[-1]'
|
||||
)"; then logError "Failed to retrieve release from https://downloads.gtnewhorizons.com/versions.json"
|
||||
exit 1
|
||||
fi
|
||||
log "Selected $(jq '.key' <<< "$release_object") as latest dev version for download."
|
||||
|
||||
elif [ "$GTNH_PACK_VERSION" == "latest" ]; then
|
||||
if ! release_object="$(
|
||||
curl -fsSL "https://downloads.gtnewhorizons.com/versions.json" \
|
||||
| jq -r '.versions|to_entries|sort_by(.value.releaseDate)|map(select(.value.title=="Stable release"))|.[-1]'
|
||||
)"; then logError "Failed to retrieve release from https://downloads.gtnewhorizons.com/versions.json"
|
||||
exit 1
|
||||
fi
|
||||
log "Selected $(jq '.key' <<< "$release_object") as latest version for download."
|
||||
|
||||
else
|
||||
if ! release_object="$(
|
||||
curl -fsSL "https://downloads.gtnewhorizons.com/versions.json" \
|
||||
| jq -r --arg USRIN $GTNH_PACK_VERSION '.versions|to_entries|sort_by(.value.releaseDate)|map(select(.key==$USRIN))|.[]'
|
||||
)"; then logError "Failed to retrieve release from https://downloads.gtnewhorizons.com/versions.json"
|
||||
exit 1
|
||||
fi
|
||||
log "Selected $(jq -r '.key' <<< "$release_object") as matching version for download."
|
||||
|
||||
fi
|
||||
|
||||
# Select compatible server files for java version
|
||||
if (( current_java_version == 8 )); then
|
||||
gtnh_download_path=$(jq -r '.value.server.java8Url' <<< "$release_object")
|
||||
log "Use GTNH Server Java 8 release."
|
||||
|
||||
elif (( current_java_version >= 17 )); then
|
||||
if (( current_java_version > $(jq '.value.maxJavaVersion' <<< "$release_object") )); then
|
||||
logError "Container Java version $current_java_version is not supported by GTNH. Try an older release."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Skip the pack if the current Java version is not compatible
|
||||
if [[ "$pack_java_version" == *-* ]]; then
|
||||
# Handle range of Java versions (e.g., "17-21")
|
||||
java_min_version=$(echo "$pack_java_version" | cut -d'-' -f1)
|
||||
java_max_version=$(echo "$pack_java_version" | cut -d'-' -f2)
|
||||
if (( current_java_version < java_min_version || current_java_version > java_max_version )); then
|
||||
debug "Skipping $pack due to incompatible Java version: $current_java_version not in range $java_min_version-$java_max_version"
|
||||
continue
|
||||
fi
|
||||
else
|
||||
# Handle single Java version (e.g., "8")
|
||||
if (( current_java_version != pack_java_version )); then
|
||||
debug "Skipping $pack due to incompatible Java version: $current_java_version != $pack_java_version"
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
gtnh_download_path=$(jq -r '.value.server.java17_2XUrl' <<< "$release_object")
|
||||
log "Use GTNH Server Java 17+ release."
|
||||
|
||||
# Extract version numbers and release type (beta or RC) from the file names
|
||||
|
||||
if ! pack_version=$(basename "$pack" | grep -Eo '[0-9]+(\.[0-9]+)+'); then
|
||||
logWarning "Could not parse version of $pack"
|
||||
fi
|
||||
if ! pack_release_type=$(basename "$pack" | grep -Eo '(beta|RC)(-[0-9]+)?' || echo ""); then
|
||||
logWarning "Could not parse release type of $pack"
|
||||
fi
|
||||
if ! current_version=$(basename "$gtnh_download_path" | grep -Eo '[0-9]+(\.[0-9]+)+'); then
|
||||
debug "Could not parse version of selected download path. String might be empty."
|
||||
fi
|
||||
if ! current_release_type=$(basename "$gtnh_download_path" | grep -Eo '(beta|RC)(-[0-9]+)?' || echo ""); then
|
||||
debug "Could not parse release type of selected download path. String might be empty."
|
||||
fi
|
||||
# Check if the pack matches the desired type based on GTNH_PACK_VERSION:
|
||||
# - If GTNH_PACK_VERSION is "latest-dev", only consider beta packs (path contains "/betas/").
|
||||
# - If GTNH_PACK_VERSION is "latest", only consider non-beta packs (path does not contain "/betas/").
|
||||
if [[ ($pack == *"/betas/"* && $GTNH_PACK_VERSION == "latest-dev") || ($pack != *"/betas/"* && $GTNH_PACK_VERSION == "latest") ]]; then
|
||||
# Compare versions and update gtnh_download_path if pack is newer
|
||||
# Check if the current version is unset or if the pack version is newer than the current version.
|
||||
# This comparison uses version sorting to determine the latest version.
|
||||
if [[ -z "$current_version" || "$(printf '%s\n' "$pack_version" "$current_version" | sort -V | tail -n 1)" == "$pack_version" ]]; then
|
||||
|
||||
# If the pack version is the same as the current version, prioritize based on release type.
|
||||
# Full versions are preferred over RC (Release Candidate), and RC is preferred over beta.
|
||||
# Within the same release type, higher numbered versions are preferred.
|
||||
if [[ "$pack_version" == "$current_version" ]]; then
|
||||
if [[ -z "$pack_release_type" || ("$pack_release_type" == "RC" && "$current_release_type" == "beta") ||
|
||||
("$pack_release_type" == "$current_release_type" && "$(printf '%s\n' "$pack_release_type" "$current_release_type" | sort -V | tail -n 1)" == "$pack_release_type") ]]; then
|
||||
debug "$current_version-$current_release_type is older than $pack_version-$pack_release_type! Update latest version to: $pack_version-$pack_release_type"
|
||||
gtnh_download_path="$pack"
|
||||
fi
|
||||
else
|
||||
# If the pack version is newer than the current version, set it as the download path.
|
||||
debug "$current_version is older than $pack_version! Update latest version to: $pack_version"
|
||||
gtnh_download_path="$pack"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if [[ "$pack_version" == "$GTNH_PACK_VERSION" || "$pack_version-$pack_release_type" == "$GTNH_PACK_VERSION" ]]; then
|
||||
log "Found exact match $pack_version = $GTNH_PACK_VERSION! Select $pack_version for download."
|
||||
gtnh_download_path="$pack"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else
|
||||
logError "Container Java version $current_java_version is not supported by GTNH."
|
||||
exit 1
|
||||
|
||||
fi
|
||||
|
||||
debug "Download source URL: $gtnh_download_path"
|
||||
|
||||
}
|
||||
|
||||
function deleteGTNHbackup(){
|
||||
@@ -104,7 +78,7 @@ function updateGTNH(){
|
||||
folders_to_update=("libraries" "mods" "resources" "scripts")
|
||||
files_to_update=("lwjgl3ify-forgePatches.jar" "java9args.txt" "startserver-java9.bat" "startserver-java9.sh" "forge-1.7.10-10.13.4.1614-1.7.10-universal.jar" "startserver.bat" "startserver.sh" "server-icon.png")
|
||||
config_folder="config"
|
||||
backup_folder="/data/gtnh-upgrade-${current_version}${current_release_type:+-$current_release_type}-$current_datetime"
|
||||
backup_folder="/data/gtnh-upgrade-$current_datetime"
|
||||
journey_map_folder="JourneyMapServer"
|
||||
|
||||
# Delete specified folders if they exist
|
||||
|
||||
@@ -11,17 +11,26 @@ handleDebugMode
|
||||
: "${PAPER_DOWNLOAD_URL:=}"
|
||||
: "${PAPER_CUSTOM_JAR:=}"
|
||||
: "${PAPER_CONFIG_DEFAULTS_REPO:=${PAPER_CONFIG_REPO:=https://raw.githubusercontent.com/Shonz1/minecraft-default-configs/main}}"
|
||||
: "${CLEAN_SERVER_LIBRARIES:=true}"
|
||||
|
||||
resultsFile=/data/.paper.env
|
||||
if [[ $PAPER_CUSTOM_JAR ]]; then
|
||||
export SERVER="$PAPER_CUSTOM_JAR"
|
||||
elif [[ $PAPER_DOWNLOAD_URL ]]; then
|
||||
if ! mc-image-helper install-paper \
|
||||
--output-directory=/data \
|
||||
--results-file="$resultsFile" \
|
||||
--url="$PAPER_DOWNLOAD_URL"; then
|
||||
logError "Failed to download from custom PaperMC URL"
|
||||
exit 1
|
||||
|
||||
args=(
|
||||
--output-directory=/data
|
||||
--results-file="$resultsFile"
|
||||
--url="$PAPER_DOWNLOAD_URL"
|
||||
)
|
||||
|
||||
if [[ $CLEAN_SERVER_LIBRARIES ]]; then
|
||||
args+=(--clean-libraries)
|
||||
fi
|
||||
|
||||
if ! mc-image-helper install-paper "${args[@]}"; then
|
||||
logError "Failed to download from custom PaperMC URL"
|
||||
exit 1
|
||||
fi
|
||||
applyResultsFile ${resultsFile}
|
||||
else
|
||||
@@ -35,6 +44,11 @@ else
|
||||
if [[ $PAPER_BUILD ]]; then
|
||||
args+=(--build="$PAPER_BUILD")
|
||||
fi
|
||||
|
||||
if [[ $CLEAN_SERVER_LIBRARIES ]]; then
|
||||
args+=(--clean-libraries)
|
||||
fi
|
||||
|
||||
if ! mc-image-helper install-paper "${args[@]}"; then
|
||||
logError "Failed to download $PAPER_PROJECT"
|
||||
exit 1
|
||||
|
||||
@@ -481,6 +481,9 @@ fi
|
||||
if [[ ${STOP_SERVER_ANNOUNCE_DELAY} ]]; then
|
||||
mcServerRunnerArgs+=(--stop-server-announce-delay "${STOP_SERVER_ANNOUNCE_DELAY}s")
|
||||
fi
|
||||
if [[ ${STOP_SERVER_DELAY_COMMAND} ]]; then
|
||||
mcServerRunnerArgs+=(--stop-server-delay-command "${STOP_SERVER_DELAY_COMMAND}s")
|
||||
fi
|
||||
if isTrue "${ENABLE_SSH}"; then
|
||||
mcServerRunnerArgs+=(--remote-console)
|
||||
fi
|
||||
|
||||
+127
-3
@@ -26,6 +26,117 @@ function applyResultsFile() {
|
||||
set +a
|
||||
}
|
||||
|
||||
function loadEnvFromFile() {
|
||||
local source=${1?Missing required source argument}
|
||||
local downloaded=
|
||||
|
||||
if isURL "$source"; then
|
||||
mkdir -p /data/.tmp
|
||||
downloaded=$(mktemp -p /data/.tmp)
|
||||
log "Downloading env file from $source"
|
||||
if ! get -o "$downloaded" "$source"; then
|
||||
logError "Failed to download env file from $source"
|
||||
rm -f "$downloaded"
|
||||
return 1
|
||||
fi
|
||||
log "Loading env vars from $source"
|
||||
applyResultsFile "$downloaded"
|
||||
rm -f "$downloaded"
|
||||
elif [ -f "$source" ]; then
|
||||
log "Loading env vars from $source"
|
||||
applyResultsFile "$source"
|
||||
else
|
||||
logError "Env file not found: $source"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function loadEnvFromArchive() {
|
||||
local source=${1?Missing required source argument}
|
||||
local entry=${2:-.env}
|
||||
local archive=
|
||||
local downloaded=
|
||||
local tmpdir
|
||||
local rc=0
|
||||
|
||||
mkdir -p /data/.tmp
|
||||
|
||||
if isURL "$source"; then
|
||||
downloaded=$(mktemp -p /data/.tmp)
|
||||
log "Downloading archive from $source"
|
||||
if ! get -o "$downloaded" "$source"; then
|
||||
logError "Failed to download archive from $source"
|
||||
rm -f "$downloaded"
|
||||
return 1
|
||||
fi
|
||||
archive=$downloaded
|
||||
elif [ -f "$source" ]; then
|
||||
archive=$source
|
||||
else
|
||||
logError "Archive not found: $source"
|
||||
return 1
|
||||
fi
|
||||
|
||||
tmpdir=$(mktemp -d -p /data/.tmp)
|
||||
if extract "$archive" "$tmpdir" "$entry" && [ -f "$tmpdir/$entry" ]; then
|
||||
log "Loading env vars from '$entry' in $source"
|
||||
applyResultsFile "$tmpdir/$entry"
|
||||
else
|
||||
logError "Failed to load env entry '$entry' from $source"
|
||||
rc=1
|
||||
fi
|
||||
|
||||
rm -rf "$tmpdir"
|
||||
[[ -n "$downloaded" ]] && rm -f "$downloaded"
|
||||
return $rc
|
||||
}
|
||||
|
||||
function loadEnvFromGenericPack() {
|
||||
: "${GENERIC_PACKS:=${GENERIC_PACK:-}}"
|
||||
: "${GENERIC_PACKS_PREFIX:=}"
|
||||
: "${GENERIC_PACKS_SUFFIX:=}"
|
||||
|
||||
if [[ -z "${GENERIC_PACKS}" ]]; then
|
||||
logWarning "LOAD_ENV_FROM_GENERIC_PACK is set but GENERIC_PACK(S) is empty"
|
||||
return 0
|
||||
fi
|
||||
|
||||
mkdir -p /data/.tmp
|
||||
IFS=',' read -ra packs <<< "${GENERIC_PACKS}"
|
||||
local loaded=0
|
||||
local pack packEntry packFile tmpdir
|
||||
for packEntry in "${packs[@]}"; do
|
||||
pack="${GENERIC_PACKS_PREFIX}${packEntry}${GENERIC_PACKS_SUFFIX}"
|
||||
if isURL "$pack"; then
|
||||
mkdir -p /data/packs
|
||||
if ! packFile=$(get -o /data/packs --output-filename --skip-up-to-date "$pack"); then
|
||||
logError "Failed to download generic pack $pack"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
packFile=$pack
|
||||
fi
|
||||
|
||||
if [[ ! -f "$packFile" ]]; then
|
||||
logError "Generic pack not found: $packFile"
|
||||
return 1
|
||||
fi
|
||||
|
||||
tmpdir=$(mktemp -d -p /data/.tmp)
|
||||
# Packs without a .env are valid — silently skip; the unpack step still applies them.
|
||||
if extract "$packFile" "$tmpdir" .env 2>/dev/null && [ -f "$tmpdir/.env" ]; then
|
||||
log "Loading env vars from .env in $pack"
|
||||
applyResultsFile "$tmpdir/.env"
|
||||
loaded=$((loaded + 1))
|
||||
fi
|
||||
rm -rf "$tmpdir"
|
||||
done
|
||||
|
||||
if (( loaded == 0 )); then
|
||||
logWarning "LOAD_ENV_FROM_GENERIC_PACK is set but no pack in GENERIC_PACK(S) contained a .env"
|
||||
fi
|
||||
}
|
||||
|
||||
function join_by() {
|
||||
local d=$1
|
||||
shift
|
||||
@@ -445,17 +556,30 @@ function isType() {
|
||||
function extract() {
|
||||
src=${1?}
|
||||
destDir=${2?}
|
||||
shift 2
|
||||
# remaining args are paths within the archive to extract; if none, extract everything
|
||||
|
||||
type=$(file -b --mime-type "${src}")
|
||||
if [[ "$type" == application/octet-stream ]]; then
|
||||
logWarning "Detected non-specific file type $type for $src"
|
||||
case "$src" in
|
||||
*.zip)
|
||||
log "Assuming zip from extension"
|
||||
type=application/zip
|
||||
;;
|
||||
# otherwise fall through to
|
||||
esac
|
||||
fi
|
||||
|
||||
case "${type}" in
|
||||
application/zip)
|
||||
unzip -o -q -d "${destDir}" "${src}"
|
||||
unzip -o -q -d "${destDir}" "${src}" "$@"
|
||||
;;
|
||||
application/x-tar | application/gzip | application/x-gzip | application/x-bzip2)
|
||||
tar -C "${destDir}" -xf "${src}"
|
||||
tar -C "${destDir}" -xf "${src}" "$@"
|
||||
;;
|
||||
application/zstd | application/x-zstd)
|
||||
tar -C "${destDir}" --use-compress-program=unzstd -xf "${src}"
|
||||
tar -C "${destDir}" --use-compress-program=unzstd -xf "${src}" "$@"
|
||||
;;
|
||||
*)
|
||||
logError "Unsupported archive type: $type"
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
services:
|
||||
mc:
|
||||
image: ${IMAGE_TO_TEST:-itzg/minecraft-server}
|
||||
environment:
|
||||
EULA: "true"
|
||||
SETUP_ONLY: "true"
|
||||
LOAD_ENV_FROM_ARCHIVE: /test/load-env.zip
|
||||
MOTD: from-compose
|
||||
LOG_TIMESTAMP: "true"
|
||||
DEBUG: "true"
|
||||
# the following are only used to speed up test execution
|
||||
TYPE: CUSTOM
|
||||
CUSTOM_SERVER: /servers/fake.jar
|
||||
VERSION: 1.18.1
|
||||
volumes:
|
||||
- ./data:/data
|
||||
- ./load-env.zip:/test/load-env.zip
|
||||
- ./fake.jar:/servers/fake.jar
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
mc-image-helper assert propertyEquals --file=server.properties --property=motd --expect=from-archive
|
||||
@@ -0,0 +1,18 @@
|
||||
services:
|
||||
mc:
|
||||
image: ${IMAGE_TO_TEST:-itzg/minecraft-server}
|
||||
environment:
|
||||
EULA: "true"
|
||||
SETUP_ONLY: "true"
|
||||
LOAD_ENV_FROM_FILE: /test/load-env.env
|
||||
MOTD: from-compose
|
||||
LOG_TIMESTAMP: "true"
|
||||
DEBUG: "true"
|
||||
# the following are only used to speed up test execution
|
||||
TYPE: CUSTOM
|
||||
CUSTOM_SERVER: /servers/fake.jar
|
||||
VERSION: 1.18.1
|
||||
volumes:
|
||||
- ./data:/data
|
||||
- ./load-env.env:/test/load-env.env
|
||||
- ./fake.jar:/servers/fake.jar
|
||||
@@ -0,0 +1,2 @@
|
||||
# Loaded by LOAD_ENV_FROM_FILE during start-configuration
|
||||
MOTD=from-env-file
|
||||
@@ -0,0 +1 @@
|
||||
mc-image-helper assert propertyEquals --file=server.properties --property=motd --expect=from-env-file
|
||||
@@ -0,0 +1,19 @@
|
||||
services:
|
||||
mc:
|
||||
image: ${IMAGE_TO_TEST:-itzg/minecraft-server}
|
||||
environment:
|
||||
EULA: "true"
|
||||
SETUP_ONLY: "true"
|
||||
GENERIC_PACK: /packs/pack.zip
|
||||
LOAD_ENV_FROM_GENERIC_PACK: "true"
|
||||
MOTD: from-compose
|
||||
LOG_TIMESTAMP: "true"
|
||||
DEBUG: "true"
|
||||
# the following are only used to speed up test execution
|
||||
TYPE: CUSTOM
|
||||
CUSTOM_SERVER: /servers/fake.jar
|
||||
VERSION: 1.18.1
|
||||
volumes:
|
||||
- ./data:/data
|
||||
- ./pack.zip:/packs/pack.zip
|
||||
- ./fake.jar:/servers/fake.jar
|
||||
Binary file not shown.
@@ -0,0 +1,2 @@
|
||||
mc-image-helper assert propertyEquals --file=server.properties --property=motd --expect=from-generic-pack
|
||||
mc-image-helper assert fileExists config/dummy.yml
|
||||
Reference in New Issue
Block a user