Compare commits

...

15 Commits

Author SHA1 Message Date
renovate[bot] 07fd8aacd6 Update dependency itzg/rcon-cli to v1.7.6 2026-06-12 22:51:27 +00:00
Leon Kampwerth 2433473015 Improve get gtnh download path (#4101) 2026-06-12 07:14:52 -05:00
renovate[bot] 4495d9f8a7 Update dependency itzg/mc-image-helper to v1.60.2 (#4102) 2026-06-12 06:57:25 -05:00
Echo Nar 56c4c95606 examples: podman quadlet example (#4099) 2026-06-10 07:17:02 -05:00
dependabot[bot] 47efe3e4bb build(deps): bump the patches group in /docs with 2 updates (#4100) 2026-06-10 07:14:40 -05:00
dependabot[bot] 151143a141 build(deps): bump platformdirs from 4.9.6 to 4.10.0 in /docs in the patches group (#4094) 2026-06-04 11:29:57 -05:00
Grim cecf4e8e95 fix(exclude): exclude ImmersiveDamageIndicators from server mods (#4080) 2026-06-04 09:29:29 -05:00
dependabot[bot] 1c30c8c476 build(deps): bump the updates group with 2 updates (#4095) 2026-06-03 22:05:50 -05:00
renovate[bot] 802dc47c9c Update dependency itzg/mc-image-helper to v1.60.1 (#4088)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-02 08:47:45 -05:00
Geoff Bourne a4719f2ba6 Support literal newlines in motd from docker env files (#4087) 2026-05-31 09:44:51 -05:00
Echo Nar cbd56fd012 Note ANSI-C Quoting bash in MOTD (#4085) 2026-05-30 10:40:16 -05:00
dependabot[bot] 544382d5d6 build(deps): bump the updates group with 4 updates (#4083) 2026-05-27 07:18:24 -05:00
dependabot[bot] e59cf8ac55 build(deps): bump the patches group across 1 directory with 2 updates (#4073)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-27 07:04:47 -05:00
renovate[bot] 68830d5a9f Update dependency itzg/mc-monitor to v0.16.6 (#4082) 2026-05-26 17:51:10 -05:00
Geoff Bourne 14356b7662 Corrected the setting of MC_IMAGE_HELPER_OPTS from PROXY_* vars (#4081) 2026-05-26 11:39:58 -05:00
15 changed files with 188 additions and 99 deletions
+8 -8
View File
@@ -104,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.
@@ -141,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 }}
@@ -172,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
@@ -187,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 }}
+4 -4
View File
@@ -53,16 +53,16 @@ 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: 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"
+3 -3
View File
@@ -37,13 +37,13 @@ RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \
--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.5
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.5
ARG MC_MONITOR_VERSION=0.16.6
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
@@ -55,7 +55,7 @@ RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \
--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.59.1
ARG MC_HELPER_VERSION=1.60.2
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
+6
View File
@@ -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
+4 -4
View File
@@ -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,10 +11,10 @@ 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.3
python-dateutil==2.9.0.post0
@@ -22,4 +22,4 @@ PyYAML==6.0.3
pyyaml_env_tag==1.1
six==1.17.0
watchdog==6.0.0
zensical==0.0.41
zensical==0.0.45
+45
View File
@@ -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
+9
View File
@@ -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%
+26
View File
@@ -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
+1
View File
@@ -82,6 +82,7 @@
"iceberg",
"ignitioncoil",
"illager-raid-music",
"immersive-damage-indicators",
"inmisaddon",
"iris-flywheel-compat",
"irisshaders",
+1
View File
@@ -56,6 +56,7 @@
"gpumemleakfix",
"Highlighter",
"ImmediatelyFast",
"immersivedamageindicators",
"indium",
"inventory-profiles-next",
"iris",
+1 -1
View File
@@ -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"},
+2 -1
View File
@@ -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.
+52 -78
View File
@@ -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