Compare commits

...

78 Commits

Author SHA1 Message Date
Geoff Bourne
aeae29046c Auto-merging via docker-versions-create 2022-01-23 22:24:39 -06:00
itzg
cbbc817279 docs: Auto update markdown TOC 2022-01-24 04:19:38 +00:00
Geoff Bourne
18d8aba20f feat: support WORLD files in compressed tar format (#1297) 2022-01-23 22:19:25 -06:00
itzg
09834c289a docs: Auto update markdown TOC 2022-01-24 00:34:13 +00:00
Jawa_Juice
880dca1ae5 Update Airplane download URL, clarify version support (#1296) 2022-01-23 18:34:00 -06:00
Geoff Bourne
726c77537c Auto-merging via docker-versions-create 2022-01-23 11:01:32 -06:00
itzg
b1e33d4049 docs: Auto update markdown TOC 2022-01-23 16:57:49 +00:00
Geoff Bourne
284c260886 Added java17-openj9 to merge system 2022-01-23 10:57:31 -06:00
Nailima
05bbb45046 fix: changed packwiz url to reflect new repo address (#1293) 2022-01-22 10:36:52 -06:00
Geoff Bourne
d11fe229df ci: Reference branch and html URL from completed workflow in discord workflow (#1292) 2022-01-20 20:52:48 -06:00
Geoff Bourne
854ac86bed Auto-merging via docker-versions-create 2022-01-20 23:10:46 +00:00
itzg
b7801565c2 docs: Auto update markdown TOC 2022-01-20 23:09:54 +00:00
chblodg
bd4760e504 Adding MODS_FORGEAPI to auto-download by project ids (#1275)
Co-authored-by: christopher blodgett <christopher.blodgett@gmail.com>
Co-authored-by: Geoff Bourne <itzgeoff@gmail.com>
2022-01-20 17:09:34 -06:00
Geoff Bourne
edc25b216f misc: exclude high priority issues from stale check 2022-01-17 20:23:56 -06:00
Geoff Bourne
79345d69c2 Auto-merging via docker-versions-create 2022-01-17 20:17:28 -06:00
dependabot[bot]
5499867ae8 build(deps): bump stefanzweifel/git-auto-commit-action (#1288) 2022-01-17 07:14:21 -06:00
Geoff Bourne
e4c575c130 fix(purpur): apply log4j mitigations specific to Purpur (#1280) 2022-01-16 20:49:15 -06:00
itzg
f29f098b26 docs: Auto update markdown TOC 2022-01-11 00:37:32 +00:00
Jawa_Juice
1d751ab2bc Docs: Flare flags (#1270) 2022-01-10 18:37:10 -06:00
Geoff Bourne
7516b53e84 Auto-merging via docker-versions-create 2022-01-10 06:58:54 -06:00
Drew Brown
4f87662664 fix: Set default MOTD if unset (#1265)
Co-authored-by: Geoff Bourne <itzgeoff@gmail.com>
2022-01-10 06:56:28 -06:00
Geoff Bourne
eafdf26d94 Auto-merging via docker-versions-create 2022-01-08 15:23:11 -06:00
Geoff Bourne
7e2937aa8d fix(forge): improved tracking and use of Forge run.sh (#1264)
Fixes #1260
2022-01-08 13:19:30 -06:00
itzg
529781adda docs: Auto update markdown TOC 2022-01-08 00:32:28 +00:00
Geoff Bourne
977d082638 fix(limbo): convert MOTD to JSON chat format (#1259) 2022-01-07 18:32:10 -06:00
Geoff Bourne
984c969da2 Auto-merging via docker-versions-create 2022-01-06 22:17:05 -06:00
itzg
c506cf11ac docs: Auto update markdown TOC 2022-01-06 12:50:04 +00:00
Bram
967d5159ea Add Pufferfish support (#1255) 2022-01-06 06:49:46 -06:00
Geoff Bourne
79f978359c fix: ensured GENERIC_PACKS are re-applied with REMOVE_OLD_MODS (#1257)
#1253
2022-01-05 21:38:51 -06:00
itzg
4c7bb313be docs: Auto update markdown TOC 2022-01-04 03:59:33 +00:00
chblodg
83d3555eab Adding Vanilla Tweaks Options (#1246) 2022-01-03 21:59:19 -06:00
Geoff Bourne
e93cc569c6 fix[purpur]: use mc-image-helper for robust Purpur build lookup (#1242) 2022-01-02 10:17:32 -06:00
itzg
5c0cf03548 docs: Auto update markdown TOC 2022-01-01 21:46:38 +00:00
Geoff Bourne
00cae995a7 Removed USE_LARGE_PAGES since its use is removed from Java 17
#1239
2022-01-01 15:46:43 -06:00
Jordy Hulck
4ba0a9c98c Support downloading CurseForge modpack when USE_MODPACK_START_SCRIPT is false (#1229) 2022-01-01 15:23:21 -06:00
itzg
6520655d6c docs: Auto update markdown TOC 2022-01-01 18:28:00 +00:00
Geoff Bourne
6bd722b11b docs: added note about log4jshell mitigation 2022-01-01 12:28:01 -06:00
itzg
4576882f07 docs: Auto update markdown TOC 2022-01-01 17:53:42 +00:00
Geoff Bourne
224553f695 Added java17-openj9 variant
#1209
2022-01-01 11:53:45 -06:00
itzg
cc100fd8bb docs: Auto update markdown TOC 2022-01-01 17:51:22 +00:00
Bartosz Stefańczyk
a7a0e54cb9 docs: Added note about mc-status under autopause section (#1224) 2022-01-01 11:51:07 -06:00
Jordy Hulck
ce32eb8d4f fix [CurseForge]: Fix script not deleting old version files when upgrading (#1230) 2022-01-01 11:05:07 -06:00
Geoff Bourne
39519427bb build: provide option to push image for a PR (#1221) 2021-12-23 18:38:18 -06:00
Geoff Bourne
aff65b74ff Auto-merging via docker-versions-create 2021-12-23 16:10:08 -06:00
itzg
2f1fed822c docs: Auto update markdown TOC 2021-12-22 13:01:44 +00:00
Caden Kriese
bf5824b6e5 Added support for downloading and installing datapacks (#1214) 2021-12-22 07:01:23 -06:00
itzg
52bf2ae094 docs: Auto update markdown TOC 2021-12-21 00:27:44 +00:00
Michael Kirsch
fa4a0e92ce Autostop feature (#1212) 2021-12-20 18:27:27 -06:00
Geoff Bourne
c15e231d7e fix: write to console pipe as minecraft user (#1216) 2021-12-20 07:09:29 -06:00
Daniel Hoffend
cc885276f5 fix: verify that the downloaded resource is a valid plugin (#1210) 2021-12-19 19:24:02 -06:00
Geoff Bourne
9dee47cb6d docs: exclude dependabot from changelog 2021-12-13 21:35:14 -06:00
Geoff Bourne
2ed5de68f9 Auto-merging via docker-versions-create 2021-12-13 21:30:01 -06:00
itzg
39611fa9cb docs: Auto update markdown TOC 2021-12-14 02:14:33 +00:00
Jawa_Juice
bb56de694a Remove Airplane 1.16 as unsupported (#1199) 2021-12-13 20:14:16 -06:00
woeisme
c4d4d2bcc1 Created new template for docker-compose-paper.yml (#1198) 2021-12-13 14:25:21 -06:00
Levy Ehrstein
4e44f33db9 fix: fabric downgrading not working (#1197, #1192)
See #1192 for an in-depth explanation of the problem.

Reported-by: Erik "Coding-Kiwi"
2021-12-13 13:50:20 -06:00
dependabot[bot]
58c085527f build(deps): bump actions/stale from 4.0.0 to 4.1.0 (#1196) 2021-12-13 07:45:16 -06:00
itzg
79fa4b95c3 docs: Auto update markdown TOC 2021-12-13 02:08:27 +00:00
Geoff Bourne
d5f1660c77 docs: Removed docker-compose-paper.yml since it was out of date (#1195) 2021-12-12 20:08:13 -06:00
Geoff Bourne
a4b6ee6d3b Auto-merging via docker-versions-create 2021-12-12 19:53:03 -06:00
Geoff Bourne
6729ba462e Merge branch 'master' of github.com:itzg/docker-minecraft-server 2021-12-12 15:35:14 -06:00
Geoff Bourne
3a3b5fc002 fix: qualify Fabric server jar by installer version (#1193) 2021-12-12 15:34:24 -06:00
Geoff Bourne
4b28d5e472 fix: qualify Fabric server jar by installer version
Fixes #1191
2021-12-12 15:28:30 -06:00
Geoff Bourne
3a31ce757d Merging latest from master 2021-12-12 09:19:48 -06:00
Levy Ehrstein
eccc989887 secruity: Fix CVE-2021-44228 mitigation (#1190) 2021-12-12 08:19:16 -06:00
Brett Randall
c4aa105042 Added --chmod to all COPY instructions in Dockerfile (#1184) 2021-12-12 08:10:18 -06:00
Geoff Bourne
ffcb76f73f build: auto-create github release when docker-versions-create with tag (#1188) 2021-12-11 16:51:01 -06:00
Geoff Bourne
be2ef20fc1 Auto-merging via docker-versions-create 2021-12-11 16:25:35 -06:00
Geoff Bourne
3f2022da40 Merge branch 'master' of github.com:itzg/docker-minecraft-server 2021-12-11 16:23:25 -06:00
Geoff Bourne
0f7464403c build: added github release creation step to docker-versions-create.sh 2021-12-11 16:09:15 -06:00
itzg
bee39343a6 docs: Auto update markdown TOC 2021-12-11 22:09:11 +00:00
StealthCT
e9326db933 Improved whitelist and ops support (#1182) 2021-12-11 16:08:53 -06:00
itzg
dd1cc82fcd docs: Auto update markdown TOC 2021-12-11 19:01:44 +00:00
Brett Randall
93825895b9 Startup fail-fast with error message if both ENABLE_AUTOPAUSE=true and EXEC_DIRECTLY=true are set. (#1186) 2021-12-11 13:01:30 -06:00
Bram
492aebc718 Remove old Airplane versions (#1185) 2021-12-11 12:56:11 -06:00
Levy Ehrstein
e66b2eda60 fix: log4j patch being applied to <1.7 versions (#1183)
As described in https://www.minecraft.net/en-us/article/important-message--security-vulnerability-java-edition,
versions below 1.7 are not affected by the log4j exploit. They should therefore not use any mitigations.

See #1179 discussion after merge.

Reported-and-tested-by: Daniel Porter "Stealthii" <dan.porter@rehabstudio.com>
2021-12-11 11:33:44 -06:00
Geoff Bourne
6020400d3b Auto-merging via docker-versions-create 2021-12-10 21:05:35 -06:00
Geoff Bourne
3bb21d8581 Used log4j2.formatMsgNoLookups as fallback for non-vanilla
#1180
2021-12-10 20:50:40 -06:00
72 changed files with 1532 additions and 322 deletions

4
.github/release.yml vendored Normal file
View File

@@ -0,0 +1,4 @@
changelog:
exclude:
authors:
- dependabot

View File

@@ -8,8 +8,7 @@ on:
- java11* - java11*
- java16* - java16*
- java17* - java17*
- test/* - test/**
- fix/*
tags: tags:
- "[0-9]+.[0-9]+.[0-9]+" - "[0-9]+.[0-9]+.[0-9]+"
- "[0-9]+.[0-9]+.[0-9]+-java8-multiarch" - "[0-9]+.[0-9]+.[0-9]+-java8-multiarch"
@@ -58,7 +57,7 @@ jobs:
- name: Build for test - name: Build for test
uses: docker/build-push-action@v2.7.0 uses: docker/build-push-action@v2.7.0
if: github.ref_name == 'master' if: github.ref_name == 'master' || startsWith(github.ref_name, 'test/')
with: with:
context: . context: .
platforms: linux/amd64 platforms: linux/amd64
@@ -68,11 +67,11 @@ jobs:
load: true load: true
push: false push: false
cache-from: type=gha cache-from: type=gha
cache-to: type=gha,mode=max # no cache-to to avoid cross-cache update from next build step
- name: Run tests - name: Run tests
# It is assumed that image variants are merged from master and tested there # It is assumed that image variants are merged from master and tested there
if: github.ref_name == 'master' if: github.ref_name == 'master' || startsWith(github.ref_name, 'test/')
run: | run: |
tests/test.sh tests/test.sh
@@ -82,7 +81,7 @@ jobs:
with: with:
context: . context: .
platforms: linux/amd64,linux/arm/v7,linux/arm64 platforms: linux/amd64,linux/arm/v7,linux/arm64
push: ${{ github.event_name != 'pull_request' }} push: true
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
# ensure latest base image is used # ensure latest base image is used
pull: true pull: true

43
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: ContinuousIntegration
on:
push:
branches:
- 'dev*'
- '!master'
- '!java*'
- '!multi*'
paths-ignore:
- "*.md"
- "docs/**"
- "examples/**"
env:
IMAGE_TO_TEST: ${{ secrets.IMAGE_ORG }}/minecraft-server:test-${{ github.repository_owner }}-${{ github.run_id }}
MODS_FORGEAPI_KEY: ${{ secrets.MODS_FORGEAPI_KEY }}
jobs:
test:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2.4.0
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Build
uses: docker/build-push-action@v2.7.0
with:
context: .
platforms: linux/amd64
tags: ${{ env.IMAGE_TO_TEST }}
load: true
cache-from: type=gha
- name: Run Setup Only Tests
run: sh tests/setuponlytests/test.sh
# - name: Run Full Minecraft Service Tests
# run: |
# tests/fulltests/test.sh

26
.github/workflows/discord.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: discord
on:
workflow_run:
workflows: ["ContinuousIntegration", "Build and Publish", "Build and publish multiarch" ]
types:
- completed
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
jobs:
discord:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: on-success
if: ${{ github.event.workflow_run.conclusion == 'success' }}
uses: Ilshidur/action-discord@master
with:
args: "Github repo: ${{ github.repository }}\n- Branch: ${{ github.event.workflow_run.head_branch }}\n- [Link: to Actions](<${{ github.event.workflow_run.html_url }}>)\n- Status: 🎉 ${{ github.event.workflow_run.conclusion }} 🍏"
- name: on-failure
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
uses: Ilshidur/action-discord@master
with:
args: "Github repo: ${{ github.repository }}\n- Branch: ${{ github.event.workflow_run.head_branch }}\n- [Link: to Actions](<${{ github.event.workflow_run.html_url }}>)\n- Status: 🤔 ${{ github.event.workflow_run.conclusion }} 💣💥"

View File

@@ -16,6 +16,6 @@ jobs:
curl https://raw.githubusercontent.com/ekalinin/github-markdown-toc/master/gh-md-toc -o gh-md-toc curl https://raw.githubusercontent.com/ekalinin/github-markdown-toc/master/gh-md-toc -o gh-md-toc
chmod a+x gh-md-toc chmod a+x gh-md-toc
./gh-md-toc --insert --no-backup README.md ./gh-md-toc --insert --no-backup README.md
- uses: stefanzweifel/git-auto-commit-action@v4.12.0 - uses: stefanzweifel/git-auto-commit-action@v4.13.1
with: with:
commit_message: "docs: Auto update markdown TOC" commit_message: "docs: Auto update markdown TOC"

17
.github/workflows/issue-label.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
on:
issues:
types: [labeled]
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
jobs:
labelNotify:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: notify
if: github.event.label.name == 'enhancement' || github.event.label.name == 'bug'
uses: Ilshidur/action-discord@master
with:
args: "[${{ github.event.issue.title }}](<${{ github.event.issue.html_url }}>) added `${{ github.event.label.name }}` label"

View File

@@ -1,15 +1,21 @@
name: Validate PR name: PullRequest
on: on:
pull_request: pull_request:
branches: [ master ] branches: [ master ]
types: [assigned, opened, synchronize, labeled]
paths-ignore:
- "*.md"
- "docs/**"
- "examples/**"
env: env:
IMAGE_TO_TEST: itzg/minecraft-server:test-${{ github.repository_owner }}-${{ github.run_id }} IMAGE_TO_TEST: itzg/minecraft-server:test-${{ github.repository_owner }}-${{ github.run_id }}
MODS_FORGEAPI_KEY: ${{ secrets.MODS_FORGEAPI_KEY }}
jobs: jobs:
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v2.4.0 - uses: actions/checkout@v2.4.0
@@ -25,8 +31,34 @@ jobs:
tags: ${{ env.IMAGE_TO_TEST }} tags: ${{ env.IMAGE_TO_TEST }}
load: true load: true
cache-from: type=gha cache-from: type=gha
cache-to: type=gha,mode=max
- name: Run tests - name: Run tests
run: | run: |
tests/test.sh tests/test.sh
- name: Gather Docker metadata
if: contains(github.event.pull_request.labels.*.name, 'ci/push-image')
id: meta
uses: docker/metadata-action@v3
with:
images: |
itzg/minecraft-server
- name: Login to DockerHub
if: contains(github.event.pull_request.labels.*.name, 'ci/push-image')
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Push
if: contains(github.event.pull_request.labels.*.name, 'ci/push-image')
uses: docker/build-push-action@v2.7.0
with:
context: .
platforms: linux/amd64,linux/arm/v7,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
pull: true
push: true
cache-from: type=gha
labels: ${{ steps.meta.outputs.labels }}

View File

@@ -12,7 +12,7 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- name: Process Stale Issues - name: Process Stale Issues
uses: actions/stale@v4.0.0 uses: actions/stale@v4.1.0
with: with:
stale-issue-label: status/stale stale-issue-label: status/stale
stale-pr-label: status/stale stale-pr-label: status/stale
@@ -21,5 +21,5 @@ jobs:
Please add a comment describing the reason to keep this issue open. Please add a comment describing the reason to keep this issue open.
days-before-stale: 30 days-before-stale: 30
days-before-close: 5 days-before-close: 5
exempt-issue-labels: 'enhancement,keep,status/needs triage' exempt-issue-labels: 'enhancement,keep,status/needs triage,priority/high'

3
.gitignore vendored
View File

@@ -1,4 +1,5 @@
.vscode
/data/ /data/
/.idea/ /.idea/
*.iml *.iml
/gh-md-toc /gh-md-toc

View File

@@ -5,28 +5,29 @@ LABEL org.opencontainers.image.authors="Geoff Bourne <itzgeoff@gmail.com>"
RUN apt-get update \ RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \ && DEBIAN_FRONTEND=noninteractive \
apt-get install -y \ apt-get install -y \
imagemagick \ imagemagick \
gosu \ file \
sudo \ gosu \
net-tools \ sudo \
iputils-ping \ net-tools \
curl wget \ iputils-ping \
git \ curl \
jq \ git \
dos2unix \ jq \
mysql-client \ dos2unix \
tzdata \ mysql-client \
rsync \ tzdata \
nano \ rsync \
unzip \ nano \
knockd \ unzip \
ttf-dejavu \ knockd \
&& apt-get clean ttf-dejavu \
&& apt-get clean
RUN addgroup --gid 1000 minecraft \ RUN addgroup --gid 1000 minecraft \
&& adduser --system --shell /bin/false --uid 1000 --ingroup minecraft --home /data minecraft && adduser --system --shell /bin/false --uid 1000 --ingroup minecraft --home /data minecraft
COPY files/sudoers* /etc/sudoers.d COPY --chmod=644 files/sudoers* /etc/sudoers.d
EXPOSE 25565 25575 EXPOSE 25565 25575
@@ -45,26 +46,26 @@ RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \
--from https://github.com/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_{{.os}}_{{.arch}}.tar.gz --from https://github.com/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_{{.os}}_{{.arch}}.tar.gz
RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \ RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \
--var version=1.5.1 --var app=rcon-cli --file {{.app}} \ --var version=1.5.1 --var app=rcon-cli --file {{.app}} \
--from https://github.com/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_{{.os}}_{{.arch}}.tar.gz --from https://github.com/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_{{.os}}_{{.arch}}.tar.gz
RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \ RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \
--var version=0.10.3 --var app=mc-monitor --file {{.app}} \ --var version=0.10.3 --var app=mc-monitor --file {{.app}} \
--from https://github.com/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_{{.os}}_{{.arch}}.tar.gz --from https://github.com/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_{{.os}}_{{.arch}}.tar.gz
RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \ RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \
--var version=1.8.0 --var app=mc-server-runner --file {{.app}} \ --var version=1.8.0 --var app=mc-server-runner --file {{.app}} \
--from https://github.com/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_{{.os}}_{{.arch}}.tar.gz --from https://github.com/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_{{.os}}_{{.arch}}.tar.gz
RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \ RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \
--var version=0.1.1 --var app=maven-metadata-release --file {{.app}} \ --var version=0.1.1 --var app=maven-metadata-release --file {{.app}} \
--from https://github.com/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_{{.os}}_{{.arch}}.tar.gz --from https://github.com/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_{{.os}}_{{.arch}}.tar.gz
ARG MC_HELPER_VERSION=1.9.10 ARG MC_HELPER_VERSION=1.16.0
ARG MC_HELPER_BASE_URL=https://github.com/itzg/mc-image-helper/releases/download/v${MC_HELPER_VERSION} ARG MC_HELPER_BASE_URL=https://github.com/itzg/mc-image-helper/releases/download/v${MC_HELPER_VERSION}
RUN curl -fsSL ${MC_HELPER_BASE_URL}/mc-image-helper-${MC_HELPER_VERSION}.tgz \ RUN curl -fsSL ${MC_HELPER_BASE_URL}/mc-image-helper-${MC_HELPER_VERSION}.tgz \
| tar -C /usr/share -zxf - \ | tar -C /usr/share -zxf - \
&& ln -s /usr/share/mc-image-helper-${MC_HELPER_VERSION}/bin/mc-image-helper /usr/bin && ln -s /usr/share/mc-image-helper-${MC_HELPER_VERSION}/bin/mc-image-helper /usr/bin
VOLUME ["/data"] VOLUME ["/data"]
WORKDIR /data WORKDIR /data
@@ -76,17 +77,18 @@ ENV UID=1000 GID=1000 \
TYPE=VANILLA VERSION=LATEST \ TYPE=VANILLA VERSION=LATEST \
ENABLE_RCON=true RCON_PORT=25575 RCON_PASSWORD=minecraft \ ENABLE_RCON=true RCON_PORT=25575 RCON_PASSWORD=minecraft \
ENABLE_AUTOPAUSE=false AUTOPAUSE_TIMEOUT_EST=3600 AUTOPAUSE_TIMEOUT_KN=120 AUTOPAUSE_TIMEOUT_INIT=600 \ ENABLE_AUTOPAUSE=false AUTOPAUSE_TIMEOUT_EST=3600 AUTOPAUSE_TIMEOUT_KN=120 AUTOPAUSE_TIMEOUT_INIT=600 \
AUTOPAUSE_PERIOD=10 AUTOPAUSE_KNOCK_INTERFACE=eth0 AUTOPAUSE_PERIOD=10 AUTOPAUSE_KNOCK_INTERFACE=eth0 \
ENABLE_AUTOSTOP=false AUTOSTOP_TIMEOUT_EST=3600 AUTOSTOP_TIMEOUT_INIT=1800 AUTOSTOP_PERIOD=10
COPY scripts/start* / COPY --chmod=755 scripts/start* /
COPY bin/ /usr/local/bin/ COPY --chmod=755 bin/ /usr/local/bin/
COPY bin/mc-health /health.sh COPY --chmod=755 bin/mc-health /health.sh
COPY files/server.properties /tmp/server.properties COPY --chmod=644 files/server.properties /tmp/server.properties
COPY files/log4j2.xml /tmp/log4j2.xml COPY --chmod=644 files/log4j2.xml /tmp/log4j2.xml
COPY files/autopause /autopause COPY --chmod=755 files/autopause /autopause
COPY --chmod=755 files/autostop /autostop
RUN dos2unix /start* && chmod +x /start* \ RUN dos2unix /start* /autopause/* /autostop/*
&& dos2unix /autopause/* && chmod +x /autopause/*.sh
ENTRYPOINT [ "/start" ] ENTRYPOINT [ "/start" ]
HEALTHCHECK --start-period=1m CMD mc-health HEALTHCHECK --start-period=1m CMD mc-health

224
README.md
View File

@@ -24,6 +24,7 @@ By default, the container will download the latest version of the "vanilla" [Min
**TABLE OF CONTENTS** **TABLE OF CONTENTS**
<!--ts--> <!--ts-->
* [Mitigated Log4jShell Vulnerability](#mitigated-log4jshell-vulnerability)
* [Looking for a Bedrock Dedicated Server](#looking-for-a-bedrock-dedicated-server) * [Looking for a Bedrock Dedicated Server](#looking-for-a-bedrock-dedicated-server)
* [Interacting with the server](#interacting-with-the-server) * [Interacting with the server](#interacting-with-the-server)
* [Data Directory](#data-directory) * [Data Directory](#data-directory)
@@ -45,6 +46,7 @@ By default, the container will download the latest version of the "vanilla" [Min
* [Running a Bukkit/Spigot server](#running-a-bukkitspigot-server) * [Running a Bukkit/Spigot server](#running-a-bukkitspigot-server)
* [Running a Paper server](#running-a-paper-server) * [Running a Paper server](#running-a-paper-server)
* [Running an Airplane server](#running-an-airplane-server) * [Running an Airplane server](#running-an-airplane-server)
* [Running a Pufferfish server](#running-a-pufferfish-server)
* [Running a Purpur server](#running-a-purpur-server) * [Running a Purpur server](#running-a-purpur-server)
* [Running a Magma server](#running-a-magma-server) * [Running a Magma server](#running-a-magma-server)
* [Running a Mohist server](#running-a-mohist-server) * [Running a Mohist server](#running-a-mohist-server)
@@ -66,6 +68,7 @@ By default, the container will download the latest version of the "vanilla" [Min
* [Optional plugins, mods, and config attach points](#optional-plugins-mods-and-config-attach-points) * [Optional plugins, mods, and config attach points](#optional-plugins-mods-and-config-attach-points)
* [Auto-downloading SpigotMC/Bukkit/PaperMC plugins](#auto-downloading-spigotmcbukkitpapermc-plugins) * [Auto-downloading SpigotMC/Bukkit/PaperMC plugins](#auto-downloading-spigotmcbukkitpapermc-plugins)
* [Downloadable mod/plugin pack for Forge, Fabric, and Bukkit-like Servers](#downloadable-modplugin-pack-for-forge-fabric-and-bukkit-like-servers) * [Downloadable mod/plugin pack for Forge, Fabric, and Bukkit-like Servers](#downloadable-modplugin-pack-for-forge-fabric-and-bukkit-like-servers)
* [<strong>ForgeAPI</strong> usage to use non-version specific projects](#forgeapi-usage-to-use-non-version-specific-projects)
* [Generic pack file](#generic-pack-file) * [Generic pack file](#generic-pack-file)
* [Mod/Plugin URL Listing File](#modplugin-url-listing-file) * [Mod/Plugin URL Listing File](#modplugin-url-listing-file)
* [Remove old mods/plugins](#remove-old-modsplugins) * [Remove old mods/plugins](#remove-old-modsplugins)
@@ -73,6 +76,8 @@ By default, the container will download the latest version of the "vanilla" [Min
* [Downloadable world](#downloadable-world) * [Downloadable world](#downloadable-world)
* [Cloning world from a container path](#cloning-world-from-a-container-path) * [Cloning world from a container path](#cloning-world-from-a-container-path)
* [Overwrite world on start](#overwrite-world-on-start) * [Overwrite world on start](#overwrite-world-on-start)
* [Datapacks](#datapacks)
* [VanillaTweaks](#vanillatweaks)
* [Server configuration](#server-configuration) * [Server configuration](#server-configuration)
* [Message of the Day](#message-of-the-day) * [Message of the Day](#message-of-the-day)
* [Difficulty](#difficulty) * [Difficulty](#difficulty)
@@ -128,16 +133,22 @@ By default, the container will download the latest version of the "vanilla" [Min
* [Explicitly disable GUI](#explicitly-disable-gui) * [Explicitly disable GUI](#explicitly-disable-gui)
* [Stop Duration](#stop-duration) * [Stop Duration](#stop-duration)
* [Setup only](#setup-only) * [Setup only](#setup-only)
* [Enable Flare Flags](#enable-flare-flags)
* [Autopause](#autopause) * [Autopause](#autopause)
* [Description](#description) * [Description](#description)
* [Enabling Autopause](#enabling-autopause) * [Enabling Autopause](#enabling-autopause)
* [Autostop](#autostop)
* [Running on RaspberryPi](#running-on-raspberrypi) * [Running on RaspberryPi](#running-on-raspberrypi)
* [Contributing](#contributing) * [Contributing](#contributing)
<!-- Added by: runner, at: Tue Dec 7 03:43:47 UTC 2021 --> <!-- Added by: runner, at: Mon Jan 24 04:19:37 UTC 2022 -->
<!--te--> <!--te-->
## Mitigated Log4jShell Vulnerability
**Please ensure you have pulled the latest image** since [all official mitigations](https://www.minecraft.net/en-us/article/important-message--security-vulnerability-java-edition) are automatically applied by the container startup process.
## Looking for a Bedrock Dedicated Server ## Looking for a Bedrock Dedicated Server
For Minecraft clients running on consoles, mobile, or native Windows, you'll need to For Minecraft clients running on consoles, mobile, or native Windows, you'll need to
@@ -281,8 +292,8 @@ When using the image `itzg:/minecraft-server` without a tag, the `latest` image
| java8-openj9 | 8 | Debian | OpenJ9 | amd64 | | java8-openj9 | 8 | Debian | OpenJ9 | amd64 |
| java11 | 11 | Debian | Hotspot | amd64,arm64,armv7 | | java11 | 11 | Debian | Hotspot | amd64,arm64,armv7 |
| java11-openj9 | 11 | Debian | OpenJ9 | amd64 | | java11-openj9 | 11 | Debian | OpenJ9 | amd64 |
| java16-openj9 | 16 | Debian | OpenJ9 | amd64 |
| java17 | 17 | Ubuntu | Hotspot | amd64,arm64,armv7 | | java17 | 17 | Ubuntu | Hotspot | amd64,arm64,armv7 |
| java17-openj9 | 17 | Debian | OpenJ9 | amd64 |
For example, to use Java version 8 on any supported architecture: For example, to use Java version 8 on any supported architecture:
@@ -300,7 +311,7 @@ The following image tags have been deprecated and are no longer receiving update
- adopt15 - adopt15
- openj9-nightly - openj9-nightly
- multiarch-latest - multiarch-latest
- java16 - java16/java16-openj9
## Healthcheck ## Healthcheck
@@ -452,19 +463,13 @@ Plugins can either be managed within the `plugins` subdirectory of the [data dir
Enable Paper server mode by adding a `-e TYPE=PAPER` to your command-line. Enable Paper server mode by adding a `-e TYPE=PAPER` to your command-line.
By default the container will run the latest build of [Paper server](https://papermc.io/downloads) By default, the container will run the latest build of [Paper server](https://papermc.io/downloads) but you can also choose to run a specific build with `-e PAPERBUILD=205`.
but you can also choose to run a specific build with `-e PAPERBUILD=205`.
docker run -d -v /path/on/host:/data \ docker run -d -v /path/on/host:/data \
-e TYPE=PAPER \ -e TYPE=PAPER \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server -p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
If you are hosting your own copy of Paper you can override the download URL with: If you are hosting your own copy of Paper you can override the download URL with `PAPER_DOWNLOAD_URL=<url>`.
- -e PAPER_DOWNLOAD_URL=<url>
An example compose file is provided at
[examples/docker-compose-paper.yml](examples/docker-compose-paper.yml).
If you have attached a host directory to the `/data` volume, then you can install plugins via the `plugins` subdirectory. You can also [attach a `/plugins` volume](#optional-plugins-mods-and-config-attach-points). If you add plugins while the container is running, you'll need to restart it to pick those up. If you have attached a host directory to the `/data` volume, then you can install plugins via the `plugins` subdirectory. You can also [attach a `/plugins` volume](#optional-plugins-mods-and-config-attach-points). If you add plugins while the container is running, you'll need to restart it to pick those up.
@@ -476,12 +481,24 @@ An [Airplane](https://airplane.gg) server, which is "a stable, optimized, well s
-e TYPE=AIRPLANE -e TYPE=AIRPLANE
> NOTE: The `VERSION` variable is used to select an Airplane branch to download from. The available options are "LATEST" "1.17" "1.16" "PURPUR" and "PURPUR-1.16" > NOTE: The `VERSION` variable is used to select an Airplane type to download. The available options are "LATEST" and "PURPUR", both 1.17.1. Airplane does not support 1.18 -- use Paper/Pufferfish/Purpur.
Extra variables: Extra variables:
- `AIRPLANE_BUILD=lastSuccessfulBuild` : set a specific Airplane build to use
- `FORCE_REDOWNLOAD=false` : set to true to force the located server jar to be re-downloaded - `FORCE_REDOWNLOAD=false` : set to true to force the located server jar to be re-downloaded
- `USE_FLARE_FLAGS=false` : set to true to add appropriate flags for the [Flare](https://blog.airplane.gg/flare) profiler - `USE_FLARE_FLAGS=false` : set to true to add appropriate flags for the built-in [Flare](https://blog.airplane.gg/flare) profiler
### Running a Pufferfish server
A [Pufferfish](https://github.com/pufferfish-gg/Pufferfish) server, which is "a highly optimized Paper fork designed for large servers requiring both maximum performance, stability, and "enterprise" features."
-e TYPE=PUFFERFISH
> NOTE: The `VERSION` variable is used to select a Pufferfish branch to download from. The available options are "LATEST" and "1.18"
Extra variables:
- `PUFFERFISH_BUILD=lastSuccessfulBuild` : set a specific Pufferfish build to use
- `FORCE_REDOWNLOAD=false` : set to true to force the located server jar to be re-downloaded
- `USE_FLARE_FLAGS=false` : set to true to add appropriate flags for the built-in [Flare](https://blog.airplane.gg/flare) profiler
### Running a Purpur server ### Running a Purpur server
@@ -494,7 +511,7 @@ A [Purpur](https://purpur.pl3x.net/) server, which is "drop-in replacement for P
Extra variables: Extra variables:
- `PURPUR_BUILD=LATEST` : set a specific Purpur build to use - `PURPUR_BUILD=LATEST` : set a specific Purpur build to use
- `FORCE_REDOWNLOAD=false` : set to true to force the located server jar to be re-downloaded - `FORCE_REDOWNLOAD=false` : set to true to force the located server jar to be re-downloaded
- `USE_FLARE_FLAGS=false` : set to true to add appropriate flags for the [Flare](https://blog.airplane.gg/flare) profiler - `USE_FLARE_FLAGS=false` : set to true to add appropriate flags for the built-in [Flare](https://blog.airplane.gg/flare) profiler
### Running a Magma server ### Running a Magma server
@@ -571,6 +588,8 @@ Configuration options with defaults:
- `LIMBO_SCHEMA_FILENAME`=default.schem - `LIMBO_SCHEMA_FILENAME`=default.schem
- `LEVEL`="Default;${LIMBO_SCHEMA_FILENAME}" - `LEVEL`="Default;${LIMBO_SCHEMA_FILENAME}"
> NOTE: instead of using format codes in the MOTD, Limbo requires [JSON chat content](https://minecraft.fandom.com/wiki/Raw_JSON_text_format#Java_Edition). If a plain string is provided, which is the default, then it gets converted into the required JSON structure.
### Running a Crucible server ### Running a Crucible server
A [Crucible](https://github.com/CrucibleMC/Crucible) server can be run by setting `TYPE` to `CRUCIBLE`. A [Crucible](https://github.com/CrucibleMC/Crucible) server can be run by setting `TYPE` to `CRUCIBLE`.
@@ -725,6 +744,47 @@ You may also download or copy over individual mods using the `MODS` environment
docker run -d -e MODS=https://www.example.com/mods/mod1.jar,/plugins/common,/plugins/special/mod2.jar ... docker run -d -e MODS=https://www.example.com/mods/mod1.jar,/plugins/common,/plugins/special/mod2.jar ...
### **ForgeAPI** usage to use non-version specific projects
**NOTE:** This potentially could lead to unexpected behavior if the Mod recieves an update with unexpected behavior.
This is more complicated because you will be pulling/using the latest mod for the release of your game. To get started make sure you have a [CursedForge API Key](https://docs.curseforge.com/#getting-started). Then use the environmental parameters in your docker build.
Parameters to use the ForgeAPI:
* `MODS_FORGEAPI_KEY` - Required
* `MODS_FORGEAPI_FILE` - Required or use MODS_FORGEAPI_PROJECTIDS (Overrides MODS_FORGEAPI_PROJECTIDS)
* `MODS_FORGEAPI_PROJECTIDS` - Required or use MODS_FORGEAPI_FILE
* `MODS_FORGEAPI_RELEASES` - Default is release, Options: [Release|Beta|Alpha]
* `REMOVE_OLD_FORGEAPI_MODS` - Default is False
* `REMOVE_OLD_DATAPACKS_DEPTH` - Default is 1
* `REMOVE_OLD_DATAPACKS_INCLUDE` - Default is *.jar
Example of expected forge api project ids, releases, and key:
```yaml
MODS_FORGEAPI_PROJECTIDS: 306612,256717
MODS_FORGEAPI_RELEASES: Release
MODS_FORGEAPI_KEY: $WRX...
```
Example of expected ForgeAPI file format: **Note**: name is currently unused, but can be used to document each entry.
```json
[
{
"name": "fabric api",
"projectId": "306612",
"releaseType": "release"
},
{
"name": "fabric voice mod",
"projectId": "416089",
"releaseType": "beta"
}
]
```
### Generic pack file ### Generic pack file
To install all of the server content (jars, mods, plugins, configs, etc) from a zip file, such as a CurseForge modpack that is missing a server start script, then set `GENERIC_PACK` to the container path of the zip file. That, combined with `TYPE`, allows for custom content along with container managed server download and install. To install all of the server content (jars, mods, plugins, configs, etc) from a zip file, such as a CurseForge modpack that is missing a server start script, then set `GENERIC_PACK` to the container path of the zip file. That, combined with `TYPE`, allows for custom content along with container managed server download and install.
@@ -769,23 +829,19 @@ before unpacking new content from the MODPACK or MODS.
### Downloadable world ### Downloadable world
Instead of mounting the `/data` volume, you can instead specify the URL of a ZIP file containing an archived world. It will be searched for a file `level.dat` and the containing subdirectory moved to the directory named by `$LEVEL`. This means that most of the archived Minecraft worlds downloadable from the Internet will already be in the correct format. Instead of mounting the `/data` volume, you can instead specify the URL of a ZIP or compressed TAR file containing an archived world. It will be searched for a file `level.dat` and the containing subdirectory moved to the directory named by `$LEVEL`. This means that most of the archived Minecraft worlds downloadable from the Internet will already be in the correct format.
docker run -d -e WORLD=http://www.example.com/worlds/MySave.zip ... docker run -d -e WORLD=http://www.example.com/worlds/MySave.zip ...
**NOTE:** This URL must be accessible from inside the container. Therefore, **NOTE:** This URL must be accessible from inside the container. Therefore, you should use an IP address or a globally resolvable FQDN, or else the name of a linked container.
you should use an IP address or a globally resolvable FQDN, or else the
name of a linked container.
**NOTE:** If the archive contains more than one `level.dat`, then the one to select can be picked with `WORLD_INDEX`, which defaults to 1. **NOTE:** If the archive contains more than one `level.dat`, then the one to select can be picked with `WORLD_INDEX`, which defaults to 1.
### Cloning world from a container path ### Cloning world from a container path
The `WORLD` option can also be used to reference a directory or zip file that will be used as a source to clone or unzip the world directory. The `WORLD` option can also be used to reference a directory, zip file, or compressed tar file that will be used as a source to clone or extract the world directory.
For example, the following would initially clone the world's content For example, the following would initially clone the world's content from `/worlds/basic`. Also notice in the example that you should use a read-only volume attachment to ensure the clone source remains pristine.
from `/worlds/basic`. Also notice in the example that you can use a
read-only volume attachment to ensure the clone source remains pristine.
``` ```
docker run ... -v $HOME/worlds:/worlds:ro -e WORLD=/worlds/basic docker run ... -v $HOME/worlds:/worlds:ro -e WORLD=/worlds/basic
@@ -798,6 +854,57 @@ The following diagram shows how this option can be used in a compose deployment
### Overwrite world on start ### Overwrite world on start
The world will only be downloaded or copied if it doesn't exist already. Set `FORCE_WORLD_COPY=TRUE` to force overwrite the world on every server start. The world will only be downloaded or copied if it doesn't exist already. Set `FORCE_WORLD_COPY=TRUE` to force overwrite the world on every server start.
### Datapacks
Datapacks can be installed in a similar manner to mods/plugins. There are many environment variables which function in the same way they do for [mods](#working-with-mods-and-plugins):
* `DATAPACKS`
* `DATAPACKS_FILE`
* `REMOVE_OLD_DATAPACKS`
* `REMOVE_OLD_DATAPACKS_DEPTH`
* `REMOVE_OLD_DATAPACKS_INCLUDE`
* `REMOVE_OLD_DATAPACKS_EXCLUDE`
Datapacks will be placed in `/data/$LEVEL/datapacks`
### VanillaTweaks
VanillaTweaks datapacks can be installed with a share code from the website UI **OR** a json file to specify packs to download and install.
Accepted Parameters:
- `VANILLATWEAKS_FILE`
- `VANILLATWEAKS_SHARECODE`
- `REMOVE_OLD_VANILLATWEAKS`
- `REMOVE_OLD_VANILLATWEAKS_DEPTH`
- `REMOVE_OLD_VANILLATWEAKS_INCLUDE`
- `REMOVE_OLD_VANILLATWEAKS_EXCLUDE`
Example of expected Vanillatweaks sharecode:
```yaml
VANILLATWEAKS_SHARECODE: MGr52E
```
Example of expected Vanillatweaks file format:
```json
{
"version": "1.18",
"packs": {
"survival": [
"graves",
"multiplayer sleep",
"afk display",
"armor statues",
"unlock all recipes",
"fast leaf decay",
"coordinates hud"
],
"items": ["armored elytra"]
}
}
```
Datapacks will be placed in `/data/$LEVEL/datapacks`
## Server configuration ## Server configuration
By default, the server configuration will be created and set based on the following environment variables, but only the first time the server is started. If the `server.properties` file already exists, the values in them will not be changed. By default, the server configuration will be created and set based on the following environment variables, but only the first time the server is started. If the `server.properties` file already exists, the values in them will not be changed.
@@ -846,30 +953,35 @@ values.
> **NOTE** it is very important to set this with servers exposed to the internet where you want only limited players to join. > **NOTE** it is very important to set this with servers exposed to the internet where you want only limited players to join.
To whitelist players for your Minecraft server, pass the Minecraft usernames separated by commas via the `WHITELIST` environment variable, such as To whitelist players for your Minecraft server, you can:
- Provide the url or path to a whitelist file via `WHITELIST_FILE` environment variable
`docker run -d -e WHITELIST_FILE=/extra/whitelist.json ...`
- Provide a list of usernames and/or UUIDs separated by commas via the `WHITELIST` environment variable
`docker run -d -e WHITELIST=user1,uuid2 ...`
docker run -d -e WHITELIST=user1,user2 ... To enforce the whitelist and auto-kick players not included in whitelist configuration, set `ENFORCE_WHITELIST=TRUE`. **By default** any user can join your Minecraft server if it's publicly accessible, regardless of your whitelist configuration.
or If whitelist configuration already exists, `WHITELIST_FILE` will not be retrieved and any usernames in `WHITELIST` are **added** to the whitelist configuration. You can enforce regeneration of the whitelist on each server startup by setting `OVERRIDE_WHITELIST` to "true". This will delete the whitelist file before processing whitelist configuration.
docker run -d -e WHITELIST=uuid1,uuid2 ... > NOTE: You can provide both `WHITELIST_FILE` and `WHITELIST`, which are processed in that order.
If the `WHITELIST` environment variable is not used, any user can join your Minecraft server if it's publicly accessible. > NOTE: UUIDs passed via `WHITELIST` need to be the dashed variant, otherwise it not be recognised and instead added as a username.
> NOTE: When using uuids in the whitelist, please make sure it is the dashed variant otherwise it will not parse correctly. > If running Minecraft 1.7.5 or earlier, these variables will apply to `white-list.txt`, with 1.7.6 implementing support for `whitelist.json`. Make sure your `WHITELIST_FILE` is in the appropriate format.
> NOTE: When `WHITELIST` is used the server properties `white-list` and `whitelist` will automatically get set to `true`. If either `WHITELIST_FILE` or `WHITELIST` is provided, the server property `white-list` is automatically set to `true`, enabline whitelist functionality. Alternatively you can set `ENABLE_WHITELIST=TRUE` to only set the server property `white-list` without modifying the whitelist file. In this case the whitelist can be managed using the `whitelist add` and `whitelist remove` commands. Remember you can set enforcement via the `ENFORCE_WHITELIST` variable.
> By default, the players in `WHITELIST` are **added** to the final `whitelist.json` file by the Minecraft server. If you set `OVERRIDE_WHITELIST` to "true" then the `whitelist.json` file will be recreated on each server startup.
Alternatively, you can set `ENABLE_WHITELIST=true` to only set the server properties `white-list` and `whitelist` without modifying the whitelist file. In this case the whitelist is solely managed using the `whitelist add` and `whitelist remove` commands.
### Op/Administrator Players ### Op/Administrator Players
To add more "op" (aka adminstrator) users to your Minecraft server, pass the Minecraft usernames separated by commas via the `OPS` environment variable, such as Similar to the whitelist, to add users as operators (aka adminstrators) to your Minecraft server, you can:
- Provide te url or path to an ops file via `OPS_FILE` environment variable
`docker run -d -e OPS_FILE=https://config.example.com/extra/ops.json ...`
- Provide a list of usernames and/or UUIDs separated by commas via the `OPS` environment variable
`docker run -d -e OPS=user1,uuid2 ...`
docker run -d -e OPS=user1,user2 ... If ops configuration already exists, `OPS_FILE` will not be retrieved and any usernames in `OPS` are **added** to the ops configuration. You can enforce regeneration of the ops configuration on each server startup by setting `OVERRIDE_OPS` to "true". This will delete the ops file before processing ops configuration.
> By default, the players in `OPS` are **added** to the final `ops.json` file by the Minecraft server. If you set `OVERRIDE_OPS` to "true" then the `ops.json` file will be recreated on each server startup. > Similar to whitelists, you can provide both `OPS_FILE` and `OPS`, and Minecraft 1.7.5 or earlier will use `ops.txt` rather than `ops.json`.
### Server icon ### Server icon
@@ -1327,6 +1439,8 @@ If you would like to `docker attach` to the Minecraft server console with color
> This will bypass graceful server shutdown handling when using `docker stop`, so be sure the server console's `stop` command. > This will bypass graceful server shutdown handling when using `docker stop`, so be sure the server console's `stop` command.
> >
> Make to enable stdin and tty with `-it` when using `docker run` or `stdin_open: true` and `tty: true` when using docker compose. > Make to enable stdin and tty with `-it` when using `docker run` or `stdin_open: true` and `tty: true` when using docker compose.
>
> This feature is incompatible with Autopause and cannot be set when `ENABLE_AUTOPAUSE=true`.
### Server Shutdown Options ### Server Shutdown Options
@@ -1387,10 +1501,6 @@ To enable remote JMX, such as for profiling with VisualVM or JMC, add the enviro
When `MEMORY` is greater than or equal to 12G, then the Aikar flags will be adjusted according to the article. When `MEMORY` is greater than or equal to 12G, then the Aikar flags will be adjusted according to the article.
Large page support can also be enabled by adding
-e USE_LARGE_PAGES=true
### HTTP Proxy ### HTTP Proxy
You may configure the use of an HTTP/HTTPS proxy by passing the proxy's URL via the `PROXY` You may configure the use of an HTTP/HTTPS proxy by passing the proxy's URL via the `PROXY`
@@ -1415,6 +1525,14 @@ When the container is signalled to stop, the Minecraft process wrapper will atte
### Setup only ### Setup only
If you are using a host-attached data directory, then you can have the image setup the Minecraft server files and stop prior to launching the server process by setting `SETUP_ONLY` to `true`. If you are using a host-attached data directory, then you can have the image setup the Minecraft server files and stop prior to launching the server process by setting `SETUP_ONLY` to `true`.
### Enable Flare Flags
To enable the JVM flags required to fully support the [Flare profiling suite](https://blog.airplane.gg/flare), set the following variable:
-e USE_FLARE_FLAGS=true
Flare is built-in to Airplane/Pufferfish/Purpur, and is available in [plugin form](https://github.com/TECHNOVE/FlarePlugin) for other server types.
## Autopause ## Autopause
@@ -1444,6 +1562,10 @@ Enable the Autopause functionality by setting:
-e ENABLE_AUTOPAUSE=TRUE -e ENABLE_AUTOPAUSE=TRUE
``` ```
Autopause is not compatible with `EXEC_DIRECTLY=true` and the two cannot be set together.
> When configuring kubernetes readiness/liveness health checks with auto-pause enabled, be sure to reference the `mc-health` wrapper script rather than `mc-status` directly.
The following environment variables define the behaviour of auto-pausing: The following environment variables define the behaviour of auto-pausing:
* `AUTOPAUSE_TIMEOUT_EST`, default `3600` (seconds) * `AUTOPAUSE_TIMEOUT_EST`, default `3600` (seconds)
describes the time between the last client disconnect and the pausing of the process (read as timeout established) describes the time between the last client disconnect and the pausing of the process (read as timeout established)
@@ -1456,6 +1578,28 @@ The following environment variables define the behaviour of auto-pausing:
* `AUTOPAUSE_KNOCK_INTERFACE`, default `eth0` * `AUTOPAUSE_KNOCK_INTERFACE`, default `eth0`
<br>Describes the interface passed to the `knockd` daemon. If the default interface does not work, run the `ifconfig` command inside the container and derive the interface receiving the incoming connection from its output. The passed interface must exist inside the container. Using the loopback interface (`lo`) does likely not yield the desired results. <br>Describes the interface passed to the `knockd` daemon. If the default interface does not work, run the `ifconfig` command inside the container and derive the interface receiving the incoming connection from its output. The passed interface must exist inside the container. Using the loopback interface (`lo`) does likely not yield the desired results.
## Autostop
An option to stop the server after a specified time has been added for niche applications (e.g. billing saving on AWS Fargate). The function is incompatible with the Autopause functionality, as they basically cancel out each other.
Note that the docker container variables have to be set accordingly (restart policy set to "no") and that the container has to be manually restarted.
A starting, example compose file has been provided in [examples/docker-compose-autostop.yml](examples/docker-compose-autostop.yml).
Enable the Autostop functionality by setting:
```
-e ENABLE_AUTOSTOP=TRUE
```
The following environment variables define the behaviour of auto-stopping:
* `AUTOSTOP_TIMEOUT_EST`, default `3600` (seconds)
describes the time between the last client disconnect and the stopping of the server (read as timeout established)
* `AUTOSTOP_TIMEOUT_INIT`, default `1800` (seconds)
describes the time between server start and the stopping of the server, when no client connects inbetween (read as timeout initialized)
* `AUTOSTOP_PERIOD`, default `10` (seconds)
describes period of the daemonized state machine, that handles the stopping of the server
## Running on RaspberryPi ## Running on RaspberryPi
To run this image on a RaspberryPi 3 B+, 4, or newer, use any of the image tags [list in the Java version section](#running-minecraft-server-on-different-java-version) that specify `armv7` for the architecture, which includes `itzg/minecraft-server:latest`. To run this image on a RaspberryPi 3 B+, 4, or newer, use any of the image tags [list in the Java version section](#running-minecraft-server-on-different-java-version) that specify `armv7` for the architecture, which includes `itzg/minecraft-server:latest`.

View File

@@ -12,4 +12,4 @@ if [ ! -p "${CONSOLE_IN_NAMED_PIPE}" ]; then
exit 1 exit 1
fi fi
echo "$@" > "${CONSOLE_IN_NAMED_PIPE:-/tmp/minecraft-console-in}" gosu minecraft bash -c "echo $* > '${CONSOLE_IN_NAMED_PIPE:-/tmp/minecraft-console-in}'"

View File

@@ -7,8 +7,8 @@ branches_list=(
'java8-openj9' 'java8-openj9'
'java11' 'java11'
'java11-openj9' 'java11-openj9'
'java16-openj9'
'java17' 'java17'
'java17-openj9'
) )
function TrapExit { function TrapExit {
@@ -130,3 +130,28 @@ EOL
fi fi
done done
if [[ $tag ]]; then
if [ -f "$HOME/.github.env" ]; then
source "$HOME/.github.env"
if [[ $GITHUB_TOKEN ]]
then
auth=(-u ":$GITHUB_TOKEN")
base=https://api.github.com
: "${owner:=itzg}"
: "${repo:=docker-minecraft-server}"
read -r -d '' releaseBody << EOF
{
"tag_name": "$tag",
"name": "$tag",
"generate_release_notes": true
}
EOF
if ! curl "${auth[@]}" -H "Accept: application/vnd.github.v3+json" \
"${base}/repos/${owner}/${repo}/releases" -d "$releaseBody"; then
echo "ERROR failed to create github release $tag"
exit 1
fi
fi
fi
fi

View File

@@ -0,0 +1,20 @@
version: '3.8'
services:
minecraft:
image: itzg/minecraft-server
ports:
- "25565:25565"
volumes:
- "mc:/data"
environment:
EULA: "TRUE"
ENABLE_AUTOSTOP: "TRUE"
# More aggressive settings for demo purposes
AUTOSTOP_TIMEOUT_INIT: "30"
AUTOSTOP_TIMEOUT_EST: "20"
# Important not to auto-restart the server!!!
restart: "no"
volumes:
mc: {}

View File

@@ -13,6 +13,7 @@ services:
VERSION: ${VERSION:-1.17.1} VERSION: ${VERSION:-1.17.1}
FORGEVERSION: ${FORGEVERSION:-37.0.90} FORGEVERSION: ${FORGEVERSION:-37.0.90}
GENERIC_PACK: /modpacks/${MODPACK:-Server-Files-0.0.21.zip} GENERIC_PACK: /modpacks/${MODPACK:-Server-Files-0.0.21.zip}
REMOVE_OLD_MODS: "${REMOVE_OLD_MODS:-false}"
ports: ports:
- "25565:25565" - "25565:25565"

View File

@@ -1,18 +1,19 @@
version: '3.8' version: '3.8'
services: services:
mc: mc:
image: itzg/minecraft-server image: itzg/minecraft-server
container_name: paper
environment: environment:
EULA: "true" EULA: "true"
ENABLE_RCON: "true"
TYPE: PAPER TYPE: PAPER
VERSION: 1.9.4 VIEW_DISTANCE: 10
# needed for Paper versions before 1.14 MEMORY: 2G
CONSOLE: "false" CONSOLE: "false"
ports: ports:
- 25565:25565 - 25565:25565
volumes: volumes:
- mc-paper:/data - mc-paper:/data
restart: unless-stopped
volumes: volumes:
mc-paper: mc-paper:

View File

@@ -0,0 +1,27 @@
version: "3.3"
services:
vanillatweaks_file:
restart: "no"
image: itzg/minecraft-server
ports:
- "25565:25565/tcp"
environment:
EULA: "TRUE"
VERSION: ${MINECRAFT_VERSION:-LATEST}
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
ports:
- "25566:25565/tcp"
restart: "no"
image: itzg/minecraft-server
environment:
EULA: "TRUE"
VERSION: ${MINECRAFT_VERSION:-LATEST}
VANILLATWEAKS_SHARECODE: MGr52E
REMOVE_OLD_VANILLATWEAKS: "TRUE"

View File

@@ -0,0 +1,15 @@
{
"version": "1.18",
"packs": {
"survival": [
"graves",
"multiplayer sleep",
"afk display",
"armor statues",
"unlock all recipes",
"fast leaf decay",
"coordinates hud"
],
"items": ["armored elytra"]
}
}

View File

@@ -0,0 +1,69 @@
#!/bin/bash
# needed for the clients connected function residing in autopause
. /autopause/autopause-fcns.sh
. ${SCRIPTS:-/}start-utils
# wait for java process to be started
while :
do
if java_process_exists ; then
break
fi
sleep 0.1
done
STATE=INIT
while :
do
case X$STATE in
XINIT)
# Server startup
if mc_server_listening ; then
TIME_THRESH=$(($(current_uptime)+$AUTOSTOP_TIMEOUT_INIT))
logAutostop "MC Server listening for connections - stopping in $AUTOSTOP_TIMEOUT_INIT seconds"
STATE=II
fi
;;
XII)
# Initial idle
if java_clients_connected ; then
logAutostop "Client connected - waiting for disconnect"
STATE=E
else
if [[ $(current_uptime) -ge $TIME_THRESH ]] ; then
logAutostop "No client connected since startup - stopping server"
/autostop/stop.sh
exit 0
fi
fi
;;
XE)
# Established
if ! java_clients_connected ; then
TIME_THRESH=$(($(current_uptime)+$AUTOSTOP_TIMEOUT_EST))
logAutostop "All clients disconnected - stopping in $AUTOSTOP_TIMEOUT_EST seconds"
STATE=I
fi
;;
XI)
# Idle
if java_clients_connected ; then
logAutostop "Client reconnected - waiting for disconnect"
STATE=E
else
if [[ $(current_uptime) -ge $TIME_THRESH ]] ; then
logAutostop "No client reconnected - stopping"
/autostop/stop.sh
exit 0
fi
fi
;;
*)
logAutostop "Error: invalid state: $STATE"
;;
esac
sleep $AUTOSTOP_PERIOD
done

6
files/autostop/stop.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/bash
. /start-utils
logAutostopAction "Stopping Java process"
kill -SIGTERM 1

View File

@@ -40,7 +40,7 @@ if ! isTrue "${SKIP_SUDO:-false}" && [ $(id -u) = 0 ]; then
echo 'hosts: files dns' > /etc/nsswitch.conf echo 'hosts: files dns' > /etc/nsswitch.conf
fi fi
exec gosu ${runAsUser}:${runAsGroup} ${SCRIPTS:-/}start-configuration $@ exec gosu ${runAsUser}:${runAsGroup} ${SCRIPTS:-/}start-configuration "$@"
else else
exec ${SCRIPTS:-/}start-configuration $@ exec ${SCRIPTS:-/}start-configuration "$@"
fi fi

34
scripts/start-autostop Executable file
View File

@@ -0,0 +1,34 @@
#!/bin/bash
# shellcheck source=start-utils
. "${SCRIPTS:-/}start-utils"
: "${SERVER_PORT:=25565}"
export SERVER_PORT
log "Autostop functionality enabled"
isDebugging && set -x
if ! [[ $AUTOSTOP_PERIOD =~ ^[0-9]+$ ]]; then
AUTOSTOP_PERIOD=10
export AUTOSTOP_PERIOD
log "Warning: AUTOSTOP_PERIOD is not numeric, set to 10 (seconds)"
fi
if [ "$AUTOSTOP_PERIOD" -eq "0" ] ; then
AUTOSTOP_PERIOD=10
export AUTOSTOP_PERIOD
log "Warning: AUTOSTOP_PERIOD must not be 0, set to 10 (seconds)"
fi
if ! [[ $AUTOSTOP_TIMEOUT_EST =~ ^[0-9]+$ ]] ; then
AUTOSTOP_TIMEOUT_EST=3600
export AUTOSTOP_TIMEOUT_EST
log "Warning: AUTOSTOP_TIMEOUT_EST is not numeric, set to 3600 (seconds)"
fi
if ! [[ $AUTOSTOP_TIMEOUT_INIT =~ ^[0-9]+$ ]] ; then
AUTOSTOP_TIMEOUT_INIT=1800
export AUTOSTOP_TIMEOUT_INIT
log "Warning: AUTOSTOP_TIMEOUT_INIT is not numeric, set to 1800 (seconds)"
fi
/autostop/autostop-daemon.sh &

View File

@@ -32,6 +32,15 @@ if [ ! -e /data/eula.txt ]; then
writeEula writeEula
fi fi
if isTrue "${ENABLE_AUTOPAUSE}" && isTrue "${EXEC_DIRECTLY:-false}"; then
log "EXEC_DIRECTLY=true is incompatible with ENABLE_AUTOPAUSE=true"
exit 1
fi
if isTrue "${ENABLE_AUTOPAUSE}" && isTrue "${ENABLE_AUTOSTOP}"; then
log "ENABLE_AUTOPAUSE=true is incompatible with ENABLE_AUTOSTOP=true"
exit 1
fi
if [[ $PROXY ]]; then if [[ $PROXY ]]; then
export http_proxy="$PROXY" export http_proxy="$PROXY"
@@ -92,6 +101,10 @@ if isTrue "${ENABLE_AUTOPAUSE}"; then
${SCRIPTS:-/}start-autopause ${SCRIPTS:-/}start-autopause
fi fi
if isTrue "${ENABLE_AUTOSTOP}"; then
${SCRIPTS:-/}start-autostop
fi
if versionLessThan 1.7; then if versionLessThan 1.7; then
echo " echo "
MC_HEALTH_EXTRA_ARGS=( MC_HEALTH_EXTRA_ARGS=(
@@ -170,6 +183,10 @@ case "${TYPE^^}" in
exec ${SCRIPTS:-/}start-deployAirplane "$@" exec ${SCRIPTS:-/}start-deployAirplane "$@"
;; ;;
PUFFERFISH)
exec ${SCRIPTS:-/}start-deployPufferfish "$@"
;;
CANYON) CANYON)
exec ${SCRIPTS:-/}start-deployCanyon "$@" exec ${SCRIPTS:-/}start-deployCanyon "$@"
;; ;;
@@ -192,7 +209,7 @@ case "${TYPE^^}" in
log "Invalid type: '$TYPE'" log "Invalid type: '$TYPE'"
log "Must be: VANILLA, FORGE, BUKKIT, SPIGOT, PAPER, FTBA (multiarch-only)," log "Must be: VANILLA, FORGE, BUKKIT, SPIGOT, PAPER, FTBA (multiarch-only),"
log " CURSEFORGE, SPONGEVANILLA, PURPUR, CUSTOM," log " CURSEFORGE, SPONGEVANILLA, PURPUR, CUSTOM,"
log " MAGMA, MOHIST, CATSERVER, AIRPLANE, CANYON, LIMBO, CRUCIBLE" log " MAGMA, MOHIST, CATSERVER, AIRPLANE, PUFFERFISH, CANYON, LIMBO, CRUCIBLE"
exit 1 exit 1
;; ;;

View File

@@ -1,52 +1,47 @@
#!/bin/bash #!/bin/bash
set -euo pipefail
IFS=$'\n\t'
. ${SCRIPTS:-/}start-utils . ${SCRIPTS:-/}start-utils
set -euo pipefail
isDebugging && set -x isDebugging && set -x
if [ "${VERSION}" != "LATEST" ] && [ "${VERSION}" != "1.16" ] && [ "${VERSION}" != "1.17" ] && [ "${VERSION}" != "PURPUR" ] && [ "${VERSION}" != "PURPUR-1.16" ] ; then IFS=$'\n\t'
log "ERROR: Airplane server type only supports VERSION=LATEST, VERSION=1.17, VERSION=1.16, VERSION=PURPUR or VERSION=PURPUR-1.16. Note that these are branches, not #.#.# versions."
if [ "${VERSION}" != "LATEST" ] && [ "${VERSION}" != "PURPUR" ] ; then
log "ERROR: Airplane server type only supports VERSION=LATEST, VERSION=PURPUR."
exit 1 exit 1
fi fi
: ${AIRPLANE_BUILD:=lastSuccessfulBuild}
: ${AIRPLANE_TYPE:=airplane} : ${AIRPLANE_TYPE:=airplane}
if [ "${VERSION}" = "LATEST" ] || [ "${VERSION}" = "1.17" ]; then if [ "${VERSION}" = "LATEST" ] ; then
AIRPLANE_BRANCH="1.17" AIRPLANE_TYPE="airplane"
fi
if [ "${VERSION}" = "1.16" ]; then
AIRPLANE_BRANCH="1.16"
fi fi
if [ "${VERSION}" = "PURPUR" ]; then if [ "${VERSION}" = "PURPUR" ]; then
AIRPLANE_BRANCH="Purpur-1.17"
AIRPLANE_TYPE="airplanepurpur" AIRPLANE_TYPE="airplanepurpur"
fi fi
if [ "${VERSION}" = "PURPUR-1.16" ]; then log "Using ${AIRPLANE_TYPE} 1.17.1 (1.18 unsupported - use Paper/Pufferfish/Purpur for newer versions)"
AIRPLANE_BRANCH="Purpur-1.16"
AIRPLANE_TYPE="airplanepurpur"
fi
log "Using Airplane-${AIRPLANE_BRANCH} branch" export SERVER=${AIRPLANE_TYPE}-1.17.1.jar
export SERVER=airplane-${AIRPLANE_BRANCH}-${AIRPLANE_BUILD}.jar log "Removing old Airplane versions ..."
shopt -s nullglob
for f in airplane*.jar; do
[[ $f != $SERVER ]] && rm $f
done
if [ ! -f "$SERVER" ] || isTrue "${FORCE_REDOWNLOAD:-false}"; then if [ ! -f "$SERVER" ] || isTrue "${FORCE_REDOWNLOAD:-false}"; then
downloadUrl="https://ci.tivy.ca/job/Airplane-${AIRPLANE_BRANCH}/${AIRPLANE_BUILD}/artifact/launcher-${AIRPLANE_TYPE}.jar" downloadUrl="https://airplane.gg/dl/launcher-${AIRPLANE_TYPE}1.17.1.jar"
log "Downloading Airplane from $downloadUrl ..." log "Downloading Airplane from $downloadUrl ..."
curl -fsSL -o "$SERVER" "$downloadUrl" if ! get -o "$SERVER" "$downloadUrl"; then
if [ ! -f "$SERVER" ]; then
log "ERROR: failed to download from $downloadUrl (status=$?)" log "ERROR: failed to download from $downloadUrl (status=$?)"
exit 3 exit 3
fi fi
fi fi
# Normalize on Spigot for later operations # Normalize on Spigot for later operations
export TYPE=SPIGOT export FAMILY=SPIGOT
export SKIP_LOG4J_CONFIG=true export SKIP_LOG4J_CONFIG=true
exec ${SCRIPTS:-/}start-spiget "$@" exec "${SCRIPTS:-/}start-spiget" "$@"

View File

@@ -126,7 +126,7 @@ else
fi fi
# Normalize on Spigot for operations below # Normalize on Spigot for operations below
export TYPE=SPIGOT export FAMILY=SPIGOT
export SKIP_LOG4J_CONFIG=true export SKIP_LOG4J_CONFIG=true
exec ${SCRIPTS:-/}start-spiget "$@" exec ${SCRIPTS:-/}start-spiget "$@"

View File

@@ -35,11 +35,37 @@ FTB_SERVER_MOD=${FTB_SERVER_MOD:-$CF_SERVER_MOD}
log "Looking for Feed-The-Beast / CurseForge server modpack." log "Looking for Feed-The-Beast / CurseForge server modpack."
requireVar FTB_SERVER_MOD requireVar FTB_SERVER_MOD
if ! isTrue "${USE_MODPACK_START_SCRIPT:-true}"; then downloadModpack() {
if ! [ -f "${FTB_SERVER_MOD}" ]; then srv_modpack=${FTB_SERVER_MOD}
log "ERROR unable to find requested modpack file ${FTB_SERVER_MOD}" if isURL "${srv_modpack}"; then
exit 2 log "Downloading modpack from ${srv_modpack}..."
if ! srv_modpack=$(get -o /data --output-filename --skip-existing "${srv_modpack}"); then
log "ERROR: failed to download modpack"
exit 1
fi
fi fi
if [[ "${srv_modpack:0:5}" == "data/" ]]; then
# Prepend with "/"
srv_modpack="/${srv_modpack}"
fi
if [[ ! "${srv_modpack:0:1}" == "/" ]]; then
# If not an absolute path, assume file is in "/data"
srv_modpack=/data/${srv_modpack}
fi
if [[ ! -f "${srv_modpack}" ]]; then
log "FTB server modpack ${srv_modpack} not found."
exit 2
fi
if [[ ! "${srv_modpack: -4}" == ".zip" ]]; then
log "FTB server modpack ${srv_modpack} is not a zip archive."
log "Please set FTB_SERVER_MOD to a file with a .zip extension."
exit 2
fi
FTB_SERVER_MOD=${srv_modpack}
}
if ! isTrue "${USE_MODPACK_START_SCRIPT:-true}"; then
downloadModpack
needsInstall=true needsInstall=true
installMarker=/data/.curseforge-installed installMarker=/data/.curseforge-installed
@@ -47,7 +73,7 @@ if ! isTrue "${USE_MODPACK_START_SCRIPT:-true}"; then
if [ "$(cat $installMarker)" != "${FTB_SERVER_MOD}" ]; then if [ "$(cat $installMarker)" != "${FTB_SERVER_MOD}" ]; then
log "Upgrading modpack" log "Upgrading modpack"
serverJar=$(find "${FTB_BASE_DIR}" -not -name "forge*installer.jar" -name "forge*.jar") serverJar=$(find "${FTB_BASE_DIR}" -type f \( -path "*/libraries/*" -o -path "*/mods/*" \) -prune -o -name "forge*.jar" -not -name "forge*installer.jar" -print)
if [[ "${serverJar}" ]]; then if [[ "${serverJar}" ]]; then
rm -rf "$(dirname "${serverJar}")"/{mods,*.jar,libraries,resources,scripts,config} rm -rf "$(dirname "${serverJar}")"/{mods,*.jar,libraries,resources,scripts,config}
fi fi
@@ -132,32 +158,9 @@ fi
# also check for the start script rather than just the folder # also check for the start script rather than just the folder
# this allows saving just the world separate from the rest of the data directory # this allows saving just the world separate from the rest of the data directory
if [[ $startScriptCount = 0 ]]; then if [[ $startScriptCount = 0 ]]; then
downloadModpack
srv_modpack=${FTB_SERVER_MOD} srv_modpack=${FTB_SERVER_MOD}
if isURL "${srv_modpack}"; then
log "Downloading modpack from ${srv_modpack}..."
if ! srv_modpack=$(get -o /data --output-filename --skip-existing "${srv_modpack}"); then
log "ERROR: failed to download modpack"
exit 1
fi
fi
if [[ "${srv_modpack:0:5}" == "data/" ]]; then
# Prepend with "/"
srv_modpack="/${srv_modpack}"
fi
if [[ ! "${srv_modpack:0:1}" == "/" ]]; then
# If not an absolute path, assume file is in "/data"
srv_modpack=/data/${srv_modpack}
fi
if [[ ! -f "${srv_modpack}" ]]; then
log "FTB server modpack ${srv_modpack} not found."
exit 2
fi
if [[ ! "${srv_modpack: -4}" == ".zip" ]]; then
log "FTB server modpack ${srv_modpack} is not a zip archive."
log "Please set FTB_SERVER_MOD to a file with a .zip extension."
exit 2
fi
log "Unpacking FTB server modpack ${srv_modpack} ..." log "Unpacking FTB server modpack ${srv_modpack} ..."
mkdir -p "${FTB_BASE_DIR}" mkdir -p "${FTB_BASE_DIR}"
unzip -o "${srv_modpack}" -d "${FTB_BASE_DIR}" | awk '{printf "."} END {print ""}' unzip -o "${srv_modpack}" -d "${FTB_BASE_DIR}" | awk '{printf "."} END {print ""}'
@@ -233,4 +236,5 @@ elif [ -e "${FTB_DIR}/Install.sh" ]; then
popd popd
fi fi
export FAMILY=FORGE
exec "${SCRIPTS:-/}start-setupWorld" "$@" exec "${SCRIPTS:-/}start-setupWorld" "$@"

View File

@@ -43,7 +43,7 @@ if [ ! -f "$SERVER" ]; then
fi fi
# Normalize on Spigot for later operations # Normalize on Spigot for later operations
export TYPE=SPIGOT export FAMILY=SPIGOT
export SKIP_LOG4J_CONFIG=true export SKIP_LOG4J_CONFIG=true
exec ${SCRIPTS:-/}start-spiget "$@" exec ${SCRIPTS:-/}start-spiget "$@"

View File

@@ -28,5 +28,6 @@ fi
export SKIP_LOG4J_CONFIG=true export SKIP_LOG4J_CONFIG=true
export FAMILY=HYBRID
# Continue to Final Setup # Continue to Final Setup
exec ${SCRIPTS:-/}start-setupWorld "$@" exec ${SCRIPTS:-/}start-setupWorld "$@"

View File

@@ -56,5 +56,6 @@ fi
export SERVER export SERVER
export SKIP_LOG4J_CONFIG=true export SKIP_LOG4J_CONFIG=true
export FAMILY=HYBRID
exec "${SCRIPTS:-$(dirname "$0")}/start-setupWorld" "$@" exec "${SCRIPTS:-$(dirname "$0")}/start-setupWorld" "$@"

View File

@@ -31,5 +31,5 @@ else
fi fi
export SKIP_LOG4J_CONFIG=true export SKIP_LOG4J_CONFIG=true
export FAMILY=HYBRID
exec ${SCRIPTS:-/}start-setupWorld $@ exec ${SCRIPTS:-/}start-setupWorld $@

View File

@@ -79,4 +79,5 @@ if ! [ -v SERVER ]; then
exit 2 exit 2
fi fi
export FAMILY=FORGE
exec ${SCRIPTS:-/}start-setupWorld $@ exec ${SCRIPTS:-/}start-setupWorld $@

View File

@@ -2,27 +2,31 @@
set -eu set -eu
# shellcheck source=start-utils # shellcheck source=start-utils
. ${SCRIPTS:-/}start-utils . "${SCRIPTS:-/}start-utils"
requireVar VANILLA_VERSION requireVar VANILLA_VERSION
export TYPE=FABRIC export TYPE=FABRIC
export SERVER=fabric-server-${VANILLA_VERSION}.jar : "${FABRIC_INSTALLER_VERSION:=${FABRICVERSION:-LATEST}}"
: "${FABRIC_INSTALLER:=}"
: "${FABRIC_INSTALLER_URL:=}"
: "${FABRIC_LOADER_VERSION:=LATEST}"
isDebugging && set -x isDebugging && set -x
if [[ ! -e ${SERVER} ]]; then log "Checking Fabric version information."
if [[ $FABRIC_INSTALLER ]]; then
FABRIC_INSTALLER_VERSION=$(echo -n "$FABRIC_INSTALLER" | mc-image-helper hash)
elif [[ $FABRIC_INSTALLER_URL ]]; then
FABRIC_INSTALLER_VERSION=$(echo -n "$FABRIC_INSTALLER_URL" | mc-image-helper hash)
elif [[ ${FABRIC_INSTALLER_VERSION^^} = LATEST ]]; then
FABRIC_INSTALLER_VERSION=$(maven-metadata-release https://maven.fabricmc.net/net/fabricmc/fabric-installer/maven-metadata.xml)
fi
: ${FABRIC_INSTALLER:=} export SERVER=fabric-server-${VANILLA_VERSION}-${FABRIC_INSTALLER_VERSION}.jar
: ${FABRIC_INSTALLER_URL:=}
: ${FABRIC_LOADER_VERSION:=LATEST} if [ ! \( -e ${SERVER} -a -e "server-${VANILLA_VERSION}.jar" \) ]; then
: ${FABRIC_INSTALLER_VERSION:=${FABRICVERSION:-LATEST}}
if [[ -z $FABRIC_INSTALLER && -z $FABRIC_INSTALLER_URL ]]; then if [[ -z $FABRIC_INSTALLER && -z $FABRIC_INSTALLER_URL ]]; then
log "Checking Fabric version information."
if [[ ${FABRIC_INSTALLER_VERSION^^} = LATEST ]]; then
FABRIC_INSTALLER_VERSION=$(maven-metadata-release https://maven.fabricmc.net/net/fabricmc/fabric-installer/maven-metadata.xml)
fi
FABRIC_INSTALLER="fabric-installer-${FABRIC_INSTALLER_VERSION}.jar" FABRIC_INSTALLER="fabric-installer-${FABRIC_INSTALLER_VERSION}.jar"
FABRIC_INSTALLER_URL="https://maven.fabricmc.net/net/fabricmc/fabric-installer/${FABRIC_INSTALLER_VERSION}/fabric-installer-${FABRIC_INSTALLER_VERSION}.jar" FABRIC_INSTALLER_URL="https://maven.fabricmc.net/net/fabricmc/fabric-installer/${FABRIC_INSTALLER_VERSION}/fabric-installer-${FABRIC_INSTALLER_VERSION}.jar"
elif [[ -z $FABRIC_INSTALLER ]]; then elif [[ -z $FABRIC_INSTALLER ]]; then
@@ -66,7 +70,12 @@ if [[ ! -e ${SERVER} ]]; then
exit 10 exit 10
fi fi
mv server.jar "server-${VANILLA_VERSION}.jar"
mv fabric-server-launch.jar "${SERVER}" mv fabric-server-launch.jar "${SERVER}"
fi fi
exec ${SCRIPTS:-/}start-setupWorld "$@" # Specify which server jar to run
echo "serverJar=server-${VANILLA_VERSION}.jar" > fabric-server-launcher.properties
export FAMILY=FABRIC
exec "${SCRIPTS:-/}start-setupWorld" "$@"

View File

@@ -147,4 +147,5 @@ else
fi fi
fi fi
export FAMILY=FORGE
exec "${SCRIPTS:-/}start-setupWorld" "$@" exec "${SCRIPTS:-/}start-setupWorld" "$@"

View File

@@ -60,4 +60,5 @@ export LEVEL
export SKIP_LOG4J_CONFIG=true export SKIP_LOG4J_CONFIG=true
export FAMILY=LIMBO
exec ${SCRIPTS:-/}start-setupWorld $@ exec ${SCRIPTS:-/}start-setupWorld $@

View File

@@ -89,4 +89,5 @@ else
fi fi
fi fi
exec ${SCRIPTS:-/}start-setupWorld $@ export FAMILY=HYBRID
exec ${SCRIPTS:-/}start-setupWorld "$@"

View File

@@ -40,4 +40,5 @@ fi
export SKIP_LOG4J_CONFIG=true export SKIP_LOG4J_CONFIG=true
export FAMILY=HYBRID
exec "${SCRIPTS:-$(dirname "$0")}/start-setupWorld" "$@" exec "${SCRIPTS:-$(dirname "$0")}/start-setupWorld" "$@"

View File

@@ -73,7 +73,7 @@ else
fi fi
# Normalize on Spigot for downstream operations # Normalize on Spigot for downstream operations
export TYPE=SPIGOT export FAMILY=SPIGOT
export SKIP_LOG4J_CONFIG=true export SKIP_LOG4J_CONFIG=true
exec ${SCRIPTS:-/}start-spiget "$@" exec ${SCRIPTS:-/}start-spiget "$@"

45
scripts/start-deployPufferfish Executable file
View File

@@ -0,0 +1,45 @@
#!/bin/bash
. ${SCRIPTS:-/}start-utils
set -euo pipefail
isDebugging && set -x
IFS=$'\n\t'
if [ "${VERSION}" != "LATEST" ] && [ "${VERSION}" != "1.18" ] ; then
log "ERROR: Pufferfish server type only supports VERSION=LATEST, VERSION=1.18. Note that these are branches, not #.#.# versions."
exit 1
fi
: ${PUFFERFISH_BUILD:=lastSuccessfulBuild}
if [ "${VERSION}" = "LATEST" ] || [ "${VERSION}" = "1.18" ]; then
PUFFERFISH_BRANCH="1.18"
PUFFERFISH_VERSION="1.18.1-R0.1"
fi
log "Using Pufferfish-${PUFFERFISH_BRANCH} branch"
export SERVER=pufferfish-${PUFFERFISH_BRANCH}-${PUFFERFISH_BUILD}.jar
log "Removing old Pufferfish versions ..."
shopt -s nullglob
for f in pufferfish-*.jar; do
[[ $f != $SERVER ]] && rm $f
done
if [ ! -f "$SERVER" ] || isTrue "${FORCE_REDOWNLOAD:-false}"; then
artifact="build/libs/pufferfish-paperclip-${PUFFERFISH_VERSION}-SNAPSHOT-reobf.jar"
downloadUrl="https://ci.pufferfish.host/job/Pufferfish-${PUFFERFISH_BRANCH}/${PUFFERFISH_BUILD}/artifact/${artifact}"
log "Downloading Pufferfish from $downloadUrl ..."
if ! get -o "$SERVER" "$downloadUrl"; then
log "ERROR: failed to download from $downloadUrl (status=$?)"
exit 3
fi
fi
# Normalize on Spigot for later operations
export FAMILY=SPIGOT
export SKIP_LOG4J_CONFIG=true
exec ${SCRIPTS:-/}start-spiget "$@"

View File

@@ -2,7 +2,8 @@
set -euo pipefail set -euo pipefail
IFS=$'\n\t' IFS=$'\n\t'
. ${SCRIPTS:-/}start-utils # shellcheck source=start-utils
. "${SCRIPTS:-/}start-utils"
isDebugging && set -x isDebugging && set -x
: ${VANILLA_VERSION:?} : ${VANILLA_VERSION:?}
@@ -10,12 +11,10 @@ isDebugging && set -x
: ${FORCE_REDOWNLOAD:=false} : ${FORCE_REDOWNLOAD:=false}
if [[ ${PURPUR_BUILD} == LATEST ]]; then if [[ ${PURPUR_BUILD} == LATEST ]]; then
PURPUR_BUILD=$(curl -fsSL "https://api.purpurmc.org/v2/purpur/${VANILLA_VERSION}" | if ! PURPUR_BUILD=$(get --json-path=".builds.latest" "https://api.purpurmc.org/v2/purpur/${VANILLA_VERSION}"); then
jq -r '.builds.latest' || echo "")
if [[ -z ${PURPUR_BUILD} ]]; then
log "ERROR: Failed to locate a Purpur build for ${VANILLA_VERSION}." log "ERROR: Failed to locate a Purpur build for ${VANILLA_VERSION}."
log " Please check if a download is available at https://purpur.pl3x.net/downloads/" log " Please check if a download is available at https://purpur.pl3x.net/downloads/"
exit 3 exit 1
fi fi
fi fi
@@ -24,14 +23,14 @@ export SERVER="purpur-${VANILLA_VERSION}-${PURPUR_BUILD}.jar"
if [ ! -f "$SERVER" ] || isTrue "$FORCE_REDOWNLOAD"; then if [ ! -f "$SERVER" ] || isTrue "$FORCE_REDOWNLOAD"; then
downloadUrl="https://api.purpurmc.org/v2/purpur/${VANILLA_VERSION}/${PURPUR_BUILD}/download" downloadUrl="https://api.purpurmc.org/v2/purpur/${VANILLA_VERSION}/${PURPUR_BUILD}/download"
log "Downloading Purpur from $downloadUrl ..." log "Downloading Purpur from $downloadUrl ..."
if ! curl -fsSL -o "$SERVER" "$downloadUrl"; then if ! get -o "$SERVER" "$downloadUrl"; then
log "ERROR: failed to download from $downloadUrl (status=$?)" log "ERROR: failed to download from $downloadUrl (status=$?)"
exit 3 exit 3
fi fi
fi fi
# Normalize on Spigot for later operations # Normalize on Spigot for later operations
export TYPE=SPIGOT export FAMILY=SPIGOT
export SKIP_LOG4J_CONFIG=true export SKIP_LOG4J_CONFIG=true
exec ${SCRIPTS:-/}start-spiget "$@" exec "${SCRIPTS:-/}start-spiget" "$@"

View File

@@ -37,4 +37,5 @@ if [ ! -e $SERVER ] || [ -n "$FORCE_REDOWNLOAD" ]; then
curl -sSL -o $SERVER https://repo.spongepowered.org/maven/org/spongepowered/$TYPE/$SPONGEVERSION/$SERVER curl -sSL -o $SERVER https://repo.spongepowered.org/maven/org/spongepowered/$TYPE/$SPONGEVERSION/$SERVER
fi fi
exec ${SCRIPTS:-/}start-setupWorld $@ export FAMILY=SPONGE
exec ${SCRIPTS:-/}start-setupWorld "$@"

View File

@@ -52,5 +52,5 @@ elif [[ -L /data/minecraft_server.jar ]]; then
fi fi
isDebugging && ls -l isDebugging && ls -l
export FAMILY=VANILLA
exec "${SCRIPTS:-/}start-setupWorld" "$@" exec "${SCRIPTS:-/}start-setupWorld" "$@"

View File

@@ -3,28 +3,93 @@
. ${SCRIPTS:-/}start-utils . ${SCRIPTS:-/}start-utils
isDebugging && set -x isDebugging && set -x
if [ -n "$OPS" ]; then if versionLessThan 1.7.6; then
log "Updating ops" opsFile=ops.txt
rm -f /data/ops.txt.converted whitelistFile=white-list.txt
echo $OPS | awk -v RS=, '{print}' > /data/ops.txt else
fi opsFile=ops.json
if isTrue "${OVERRIDE_OPS}"; then whitelistFile=whitelist.json
log "Recreating ops.json file at server startup"
rm -f /data/ops.json
fi fi
if [ -n "$WHITELIST" ]; then function process_user_file() {
log "Updating whitelist" local output=$1
rm -f /data/white-list.txt.converted local source=$2
if [[ $WHITELIST == *"-"* ]]; then
echo $WHITELIST | awk -v RS=, '{print}' | xargs -l -i curl -s https://playerdb.co/api/player/minecraft/{} | jq -r '.["data"]["player"] | {"uuid": .id, "name": .username}' | jq -s . > "whitelist.json" if isURL "$source"; then
log "Downloading $output from $source"
if ! get -o /data/$output "$source"; then
log "ERROR: failed to download from $source"
exit 2
fi
else else
echo $WHITELIST | awk -v RS=, '{print}' > /data/white-list.txt log "Copying $output from $source"
if ! cp "$source" /data/$output; then
log "ERROR: failed to copy from $source"
exit 1
fi
fi fi
}
function process_user_csv() {
local output=$1
local list=$2
local playerDataList
if [[ "$output" == *"ops"* ]]; then
# Extra data for ops.json
userData='{"uuid": .id, "name": .username, "level": 4}'
else
userData='{"uuid": .id, "name": .username}'
fi
log "Updating ${output%.*}"
for i in ${list//,/ }
do
if [ -e "$output" ] && grep -q "$i" "$output"; then
log "$i already present in $output, skipping"
continue
fi
if ! playerData=$(get "https://playerdb.co/api/player/minecraft/$i" | jq -re ".data.player"); then
log "WARNING: Could not lookup user $i for ${output} addition"
else
playerDataList=$playerDataList$(echo $playerData | jq -r "$userData")
fi
done
local newUsers=$(echo $playerDataList | jq -s .)
if [[ $output =~ .*\.txt ]]; then
# username list for txt config (Minecraft <= 1.7.5)
echo $newUsers | jq -r '.[].name' >> /data/${output}
sort -u /data/${output} -o /data/${output}
elif [ -e /data/${output} ]; then
# Merge with existing json file
local currentUsers=$(cat /data/${output})
jq --argjson current "$currentUsers" --argjson new "$newUsers" -n '$new + $current | unique_by(.uuid)' > /data/${output}
else
# New json file
echo $newUsers > /data/${output}
fi
}
if isTrue "${OVERRIDE_OPS}"; then
log "Recreating ${opsFile} file at server startup"
rm -f /data/${opsFile}
fi fi
if [ -n "${OPS_FILE}" ] && [ ! -e "/data/${opsFile}" ]; then
process_user_file ${opsFile} "$OPS_FILE"
fi
if [ -n "${OPS}" ]; then
process_user_csv ${opsFile} "$OPS"
fi
if isTrue "${OVERRIDE_WHITELIST}"; then if isTrue "${OVERRIDE_WHITELIST}"; then
log "Recreating whitelist.json file at server startup" log "Recreating ${whitelistFile} file at server startup"
rm -f /data/whitelist.json rm -f /data/${whitelistFile}
fi
if [ -n "${WHITELIST_FILE}" ] && [ ! -e "/data/${whitelistFile}" ]; then
process_user_file ${whitelistFile} "$WHITELIST_FILE"
fi
if [ -n "${WHITELIST}" ]; then
process_user_csv ${whitelistFile} "$WHITELIST"
fi fi
if [ -n "$ICON" ]; then if [ -n "$ICON" ]; then
@@ -42,7 +107,41 @@ if [ -n "$ICON" ]; then
fi fi
fi fi
canUseRollingLogs=true
patchLog4jConfig() {
file=${1?}
url=${2?}
if ! get -o "$file" "$url"; then
log "ERROR: failed to download corrected log4j config"
exit 1
fi
JVM_OPTS="-Dlog4j.configurationFile=${file} ${JVM_OPTS}"
canUseRollingLogs=false
}
# Patch Log4j remote code execution vulnerability
# See https://www.minecraft.net/en-us/article/important-message--security-vulnerability-java-edition
if versionLessThan 1.7; then
: # No patch required here.
elif isFamily VANILLA && versionLessThan 1.12; then
patchLog4jConfig log4j2_17-111.xml https://launcher.mojang.com/v1/objects/dd2b723346a8dcd48e7f4d245f6bf09e98db9696/log4j2_17-111.xml
elif isFamily VANILLA && versionLessThan 1.17; then
patchLog4jConfig log4j2_112-116.xml https://launcher.mojang.com/v1/objects/02937d122c86ce73319ef9975b58896fc1b491d1/log4j2_112-116.xml
# See https://purpurmc.org/docs/Log4j/
elif isType PURPUR && versionLessThan 1.17; then
patchLog4jConfig purpur_log4j2_1141-1165.xml https://purpurmc.org/docs/xml/purpur_log4j2_1141-1165.xml
elif isType PURPUR && versionLessThan 1.18.1; then
patchLog4jConfig purpur_log4j2_117.xml https://purpurmc.org/docs/xml/purpur_log4j2_117.xml
elif versionLessThan 1.18.1; then
JVM_OPTS="-Dlog4j2.formatMsgNoLookups=true ${JVM_OPTS}"
fi
if isTrue ${ENABLE_ROLLING_LOGS:-false}; then if isTrue ${ENABLE_ROLLING_LOGS:-false}; then
if ! ${canUseRollingLogs}; then
log "ERROR: Using rolling logs is currently not possible in the selected version due to CVE-2021-44228"
exit 1
fi
# Set up log configuration # Set up log configuration
LOGFILE="/data/log4j2.xml" LOGFILE="/data/log4j2.xml"
if [ ! -e "$LOGFILE" ]; then if [ ! -e "$LOGFILE" ]; then
@@ -85,26 +184,6 @@ if [ -n "$JVM_DD_OPTS" ]; then
done done
fi fi
patchLog4jConfig() {
file=${1?}
url=${2?}
if ! get -o "$file" "$url"; then
log "ERROR: failed to download corrected log4j config"
exit 1
fi
JVM_OPTS="-Dlog4j.configurationFile=${file} ${JVM_OPTS}"
}
# Patch Log4j remote code execution vulnerability
# NOTE: Paper, bukkit, and spigot are normalized to SPIGOT
if [[ ${TYPE^^} != SPIGOT ]] && versionLessThan 1.12; then
patchLog4jConfig log4j2_17-111.xml https://launcher.mojang.com/v1/objects/dd2b723346a8dcd48e7f4d245f6bf09e98db9696/log4j2_17-111.xml
elif [[ ${TYPE^^} != SPIGOT ]] && versionLessThan 1.17; then
patchLog4jConfig log4j2_112-116.xml https://launcher.mojang.com/v1/objects/02937d122c86ce73319ef9975b58896fc1b491d1/log4j2_112-116.xml
elif versionLessThan 1.18.1; then
JVM_OPTS="-Dlog4j2.formatMsgNoLookups=true ${JVM_OPTS}"
fi
if isTrue ${ENABLE_JMX}; then if isTrue ${ENABLE_JMX}; then
: ${JMX_PORT:=7091} : ${JMX_PORT:=7091}
JVM_OPTS="${JVM_OPTS} JVM_OPTS="${JVM_OPTS}
@@ -162,12 +241,6 @@ if isTrue "${USE_AIKAR_FLAGS}"; then
" "
fi fi
if isTrue "${USE_LARGE_PAGES}"; then
JVM_XX_OPTS="${JVM_XX_OPTS}
-XX:+UseLargePagesInMetaspace
"
fi
if isTrue "${USE_FLARE_FLAGS}"; then if isTrue "${USE_FLARE_FLAGS}"; then
JVM_XX_OPTS="${JVM_XX_OPTS} JVM_XX_OPTS="${JVM_XX_OPTS}
-XX:+UnlockDiagnosticVMOptions -XX:+UnlockDiagnosticVMOptions
@@ -255,10 +328,10 @@ EOF
else else
exec mc-server-runner "${mcServerRunnerArgs[@]}" "${finalArgs[@]}" exec mc-server-runner "${mcServerRunnerArgs[@]}" "${finalArgs[@]}"
fi fi
elif [[ -x run.sh ]]; then elif [[ $SERVER =~ run.sh ]]; then
log "Using Forge supplied run.sh script..." log "Using Forge supplied run.sh script..."
echo $JVM_XX_OPTS $JVM_OPTS $expandedDOpts > user_jvm_args.txt echo $JVM_XX_OPTS $JVM_OPTS $expandedDOpts > user_jvm_args.txt
exec mc-server-runner "${mcServerRunnerArgs[@]}" --shell bash run.sh exec mc-server-runner "${mcServerRunnerArgs[@]}" --shell bash "${SERVER}"
else else
# If we have a bootstrap.txt file... feed that in to the server stdin # If we have a bootstrap.txt file... feed that in to the server stdin
if [ -f /data/bootstrap.txt ]; then if [ -f /data/bootstrap.txt ]; then

77
scripts/start-setupDatapack Executable file
View File

@@ -0,0 +1,77 @@
#!/bin/bash
set -e -o pipefail
: "${REMOVE_OLD_DATAPACKS:=false}"
: "${DATAPACKS_FILE:=}"
: "${REMOVE_OLD_DATAPACKS_DEPTH:=1} "
: "${REMOVE_OLD_DATAPACKS_INCLUDE:=*.zip}"
# shellcheck source=start-utils
. "${SCRIPTS:-/}start-utils"
isDebugging && set -x
out_dir=/data/${LEVEL:-world}/datapacks
# Remove old datapacks
if isTrue "${REMOVE_OLD_DATAPACKS}" && [ -z "${DATAPACKS_FILE}" ]; then
if [ -d "$out_dir" ]; then
find "$out_dir" -mindepth 1 -maxdepth ${REMOVE_OLD_DATAPACKS_DEPTH:-16} -wholename "${REMOVE_OLD_DATAPACKS_INCLUDE:-*}" -not -wholename "${REMOVE_OLD_DATAPACKS_EXCLUDE:-}" -delete
fi
fi
if [[ "$DATAPACKS" ]]; then
mkdir -p "$out_dir"
for i in ${DATAPACKS//,/ }
do
if isURL "$i"; then
log "Downloading datapack $i ..."
if ! get -o "${out_dir}" "$i"; then
log "ERROR: failed to download from $i into $out_dir"
exit 2
fi
elif [[ -f "$i" && "$i" =~ .*\.zip ]]; then
log "Copying datapack located at $i ..."
out_file=$(basename "$i")
if ! cp "$i" "${out_dir}/$out_file"; then
log "ERROR: failed to copy from $i into $out_dir"
exit 2
fi
elif [[ -d "$i" ]]; then
log "Copying datapacks from $i ..."
cp "$i"/*.zip "${out_dir}"
else
log "ERROR Invalid URL or path given in DATAPACKS: $i"
exit 2
fi
done
elif [[ "$DATAPACKS_FILE" ]]; then
if [ ! -f "$DATAPACKS_FILE" ]; then
log "ERROR: given DATAPACKS_FILE file does not exist"
exit 2
fi
mkdir -p "$out_dir"
args=(
-o "${out_dir}"
--log-progress-each
--skip-existing
--uris-file "${DATAPACKS_FILE}"
)
if isTrue "${REMOVE_OLD_DATAPACKS}"; then
args+=(
--prune-others "${REMOVE_OLD_DATAPACKS_INCLUDE}"
--prune-depth "${REMOVE_OLD_DATAPACKS_DEPTH}"
)
fi
if ! get "${args[@]}" ; then
log "ERROR: failed to retrieve one or more datapacks"
exit 1
fi
fi
exec "${SCRIPTS:-/}start-setupForgeApiMods" "$@"

View File

@@ -0,0 +1,177 @@
#!/bin/bash
set -e -o pipefail
: "${MODS_FORGEAPI_KEY:=}"
: "${REMOVE_OLD_FORGEAPI_MODS:=false}"
: "${MODS_FORGEAPI_PROJECTIDS:=}"
: "${MODS_FORGEAPI_FILE:=}"
: "${MODS_FORGEAPI_RELEASES:=RELEASE}"
: "${REMOVE_OLD_MODS_DEPTH:=1} "
: "${REMOVE_OLD_MODS_INCLUDE:=*.jar}"
# FORGEAPI_BASE_URL used in manifest downloads below
FORGEAPI_BASE_URL=${FORGEAPI_BASE_URL:-https://api.curseforge.com/v1}
RELEASE_NUMBER_FILTER=1
MINECRAFT_GAME_ID=432
out_dir=/data/mods
# shellcheck source=start-utils
. "${SCRIPTS:-/}start-utils"
isDebugging && set -x
# Remove old mods/plugins
if isTrue "${REMOVE_OLD_FORGEAPI_MODS}" && [ -z "${MODS_FORGEAPI_FILE}" ]; then
removeOldMods /data/mods
fi
ensureModKey(){
if [ -z "$MODS_FORGEAPI_KEY" ]; then
log "ERROR: MODS_FORGEAPI_KEY REQUIRED to Connect to FORGE API, you supplied: ${MODS_FORGEAPI_KEY}"
exit 2
fi
}
# Set the global release type per the text.
# NOTE: downcasing release type for comparing types.
updateReleaseNumber(){
releaseType=$1
if [ "release" = "${releaseType,,}" ]; then
RELEASE_NUMBER_FILTER=1
elif [ "beta" = "${releaseType,,}" ]; then
RELEASE_NUMBER_FILTER=2
elif [ "alpha" = "${releaseType,,}" ]; then
RELEASE_NUMBER_FILTER=3
fi
}
retrieveVersionTypeNumber(){
VERSION_NAME="Minecraft ${VANILLA_VERSION%.*}"
minecraft_types=$(curl -X GET -s \
"${FORGEAPI_BASE_URL}/games/${MINECRAFT_GAME_ID}/version-types" \
-H 'Accept: application/json' -H 'x-api-key: '${MODS_FORGEAPI_KEY}'')
if [ ! "$minecraft_types" ]; then
log "ERROR: unable to retrieve version types for ${VERSION_NAME} from ForgeAPI"
exit 2
fi
TYPE_ID=$(jq -n "$minecraft_types" | jq --arg VERSION_NAME "$VERSION_NAME" -jc '
.data[] | select(.name==$VERSION_NAME) | .id')
if [ ! "$TYPE_ID" ]; then
log "ERROR: unable to retrieve version types for ${VERSION_NAME} from ForgeAPI"
exit 2
fi
}
modFileByProjectID(){
project_id=$(echo $1 | tr -d '"')
project_id_release_type=$2
unset PROJECT_FILE
# if Type id isn't defined use minecraft version to go get it.
if [ ! "$TYPE_ID" ]; then
retrieveVersionTypeNumber
fi
# JQ is struggling with larger page sizes so having to pagination for mods with a lot of releases
pageSize=42
index=0
total_count=1
while [ $index -lt $total_count ]; do
project_files=$(curl -X GET -s \
"${FORGEAPI_BASE_URL}/mods/${project_id}/files?gameVersionTypeId=${TYPE_ID}&index=${index}&pageSize=${pageSize}" \
-H 'Accept: application/json' -H 'x-api-key: '${MODS_FORGEAPI_KEY}'')
if [ ! "$project_files" ]; then
log "ERROR: unable to retrieve any project id files for ${project_id} from ForgeAPI"
exit 2
fi
# Use project files to grab out the total count of mods.
total_count=$(jq -n "$project_files" | jq -c '.pagination.totalCount' )
# Checking for a individual release type input, if not use global
if [ $project_id_release_type ]; then
updateReleaseNumber $project_id_release_type
else
updateReleaseNumber $MODS_FORGEAPI_RELEASES
fi
# grabs the highest ID of the releaseTypes selected.
# Default is 1 for Release, Beta is 2, and Alpha is 3. Using less than we can validate highest release.
current_project_file=$(jq -n "$project_files" | jq --arg RELEASE_FILTER "$RELEASE_NUMBER_FILTER" -jc '
.data | sort_by(.id) | reverse | map(select(.releaseType<=($RELEASE_FILTER|tonumber))) | .[0]')
# Logic to grab the latest release over the entire pagination
if [ ! "$PROJECT_FILE" ]; then
PROJECT_FILE=$current_project_file
elif [ "$current_project_file" ]; then
current_project_file_id=$(jq -n "$current_project_file" | jq -jc '.id' )
PROJECT_FILE_ID=$(jq -n "$PROJECT_FILE" | jq -jc '.id' )
if (( current_project_file_id > PROJECT_FILE_ID )); then
PROJECT_FILE=$current_project_file
fi
fi
# check to see if we have gone to far or lost our index and exit with an error
if [ -z "$index" ] || [ -z "$total_count" ] || [ $index -ge $total_count ]; then
log "ERROR: Unable to retrieve any files for ${project_id} from ForgeAPI also Validate files have release type associated with no. ${RELEASE_NUMBER_FILTER}"
exit 2
fi
# Increment start index to new set.
index=$(($index + $pageSize))
done
}
downloadModPackfromModFile() {
if [ ! "$PROJECT_FILE" ]; then
log "ERROR: Project File not found from the ForgeAPI"
exit 2
fi
# grabs needed values from our json return
file_name=$(jq -n "$PROJECT_FILE" | jq -jc '.fileName' )
download_url=$(jq -n "$PROJECT_FILE" | jq -jc '.downloadUrl' )
# trys to make the output directory incase it doesnt exist.
mkdir -p "$out_dir"
echo "Downloading ${download_url}"
if ! get -o "${out_dir}/${file_name}" $download_url ; then
log "ERROR: failed to download from ${download_url}"
exit 2
fi
}
# Use forge api json file to filter and download the correct mods
if [ "$MODS_FORGEAPI_FILE" ] && [ -z "$MODS_FORGEAPI_PROJECTIDS" ]; then
ensureModKey
if [ ! -f "$MODS_FORGEAPI_FILE" ]; then
log "ERROR: given MODS_FORGEAPI_FILE file does not exist"
exit 2
fi
MODS_FORGEAPI_PROJECTIDS=$(jq --raw-output '[.[] | .projectId] | join(",")' $MODS_FORGEAPI_FILE)
if [ ! "$MODS_FORGEAPI_PROJECTIDS" ]; then
log "ERROR: unable to retrieve packs from $MODS_FORGEAPI_FILE"
exit 2
fi
# Needs loop here to look up release types befor calling download.
for project_id in ${MODS_FORGEAPI_PROJECTIDS//,/ }; do
current_release_type=$(jq --arg PROJECT_ID "$project_id" -jc '
.[] | select(.projectId==$PROJECT_ID) | .releaseType' "$MODS_FORGEAPI_FILE")
modFileByProjectID $project_id $current_release_type
downloadModPackfromModFile
done
fi
# Use only project ids and global release data.
if [ "$MODS_FORGEAPI_PROJECTIDS" ] && [ -z "$MODS_FORGEAPI_FILE" ]; then
ensureModKey
for project_id in ${MODS_FORGEAPI_PROJECTIDS//,/ }; do
modFileByProjectID $project_id
downloadModPackfromModFile
done
fi
exec "${SCRIPTS:-/}start-setupModpack" "$@"

View File

@@ -1,6 +1,7 @@
#!/bin/bash #!/bin/bash
. ${SCRIPTS:-/}start-utils # shellcheck source=start-utils
. "${SCRIPTS:-/}start-utils"
# If supplied with a URL for a config (simple zip of configurations), download it and unpack # If supplied with a URL for a config (simple zip of configurations), download it and unpack
if [[ "$MODCONFIG" ]]; then if [[ "$MODCONFIG" ]]; then
@@ -9,7 +10,7 @@ case "X$MODCONFIG" in
log "Downloading mod/plugin configs via HTTP" log "Downloading mod/plugin configs via HTTP"
log " from $MODCONFIG ..." log " from $MODCONFIG ..."
curl -sSL -o /tmp/modconfig.zip "$MODCONFIG" curl -sSL -o /tmp/modconfig.zip "$MODCONFIG"
if [ "$TYPE" = "SPIGOT" ]; then if [ "$FAMILY" = "SPIGOT" ]; then
mkdir -p /data/plugins mkdir -p /data/plugins
unzip -o -d /data/plugins /tmp/modconfig.zip unzip -o -d /data/plugins /tmp/modconfig.zip
else else
@@ -24,4 +25,4 @@ case "X$MODCONFIG" in
esac esac
fi fi
exec ${SCRIPTS:-/}start-setupMounts $@ exec "${SCRIPTS:-/}start-setupMounts" "$@"

View File

@@ -6,6 +6,7 @@ set -e -o pipefail
: "${MODS_FILE:=}" : "${MODS_FILE:=}"
: "${REMOVE_OLD_MODS_DEPTH:=1} " : "${REMOVE_OLD_MODS_DEPTH:=1} "
: "${REMOVE_OLD_MODS_INCLUDE:=*.jar}" : "${REMOVE_OLD_MODS_INCLUDE:=*.jar}"
sum_file=/data/.generic_pack.sum
# shellcheck source=start-utils # shellcheck source=start-utils
. "${SCRIPTS:-/}start-utils" . "${SCRIPTS:-/}start-utils"
@@ -18,12 +19,13 @@ CURSE_URL_BASE=${CURSE_URL_BASE:-https://minecraft.curseforge.com/projects}
if isTrue "${REMOVE_OLD_MODS}" && [ -z "${MODS_FILE}" ]; then if isTrue "${REMOVE_OLD_MODS}" && [ -z "${MODS_FILE}" ]; then
removeOldMods /data/mods removeOldMods /data/mods
removeOldMods /data/plugins removeOldMods /data/plugins
rm -f "$sum_file"
fi fi
# If packwiz url passed, bootstrap packwiz and update mods before other modpack processing # If packwiz url passed, bootstrap packwiz and update mods before other modpack processing
if [[ "${PACKWIZ_URL}" ]]; then if [[ "${PACKWIZ_URL}" ]]; then
# Ensure we have the latest packwiz bootstrap installer # Ensure we have the latest packwiz bootstrap installer
latestPackwiz=$(curl -fsSL https://api.github.com/repos/comp500/packwiz-installer-bootstrap/releases/latest) latestPackwiz=$(curl -fsSL https://api.github.com/repos/packwiz/packwiz-installer-bootstrap/releases/latest)
if [[ -z "${latestPackwiz}" ]]; then if [[ -z "${latestPackwiz}" ]]; then
log "WARNING: Could not retrieve Packwiz bootstrap installer release information" log "WARNING: Could not retrieve Packwiz bootstrap installer release information"
else else
@@ -65,7 +67,7 @@ if [[ "$MODPACK" ]]; then
exit 1 exit 1
fi fi
if [ "$TYPE" = "SPIGOT" ]; then if [ "$FAMILY" = "SPIGOT" ]; then
mkdir -p /data/plugins mkdir -p /data/plugins
if ! unzip -o -d /data/plugins /tmp/modpack.zip; then if ! unzip -o -d /data/plugins /tmp/modpack.zip; then
log "ERROR: failed to unzip the modpack from ${MODPACK}" log "ERROR: failed to unzip the modpack from ${MODPACK}"
@@ -79,7 +81,7 @@ if [[ "$MODPACK" ]]; then
rm -f /tmp/modpack.zip rm -f /tmp/modpack.zip
elif [[ "$MODS" ]]; then elif [[ "$MODS" ]]; then
if [ "$TYPE" = "SPIGOT" ]; then if [ "$FAMILY" = "SPIGOT" ]; then
out_dir=/data/plugins out_dir=/data/plugins
else else
out_dir=/data/mods out_dir=/data/mods
@@ -116,7 +118,7 @@ elif [[ "$MODS_FILE" ]]; then
exit 2 exit 2
fi fi
if [ "$TYPE" = "SPIGOT" ]; then if [ "$FAMILY" = "SPIGOT" ]; then
out_dir=/data/plugins out_dir=/data/plugins
else else
out_dir=/data/mods out_dir=/data/mods
@@ -204,7 +206,6 @@ if [[ "${GENERIC_PACKS}" ]]; then
fi fi
done done
sum_file=/data/.generic_pack.sum
isDebugging && [ -f "$sum_file}" ] && cat "$sum_file" isDebugging && [ -f "$sum_file}" ] && cat "$sum_file"
if ! sha256sum -c "${sum_file}" --status 2> /dev/null; then if ! sha256sum -c "${sum_file}" --status 2> /dev/null; then
base_dir=/tmp/generic_pack_base base_dir=/tmp/generic_pack_base

View File

@@ -1,14 +1,15 @@
#!/bin/bash #!/bin/bash
. ${SCRIPTS:-/}start-utils # shellcheck source=start-utils
. "${SCRIPTS:-/}start-utils"
: ${SYNC_SKIP_NEWER_IN_DESTINATION:=${PLUGINS_SYNC_UPDATE:-true}} : "${SYNC_SKIP_NEWER_IN_DESTINATION:=${PLUGINS_SYNC_UPDATE:-true}}"
: ${REPLACE_ENV_DURING_SYNC:=true} : "${REPLACE_ENV_DURING_SYNC:=true}"
: ${REPLACE_ENV_SUFFIXES:=yml,yaml,txt,cfg,conf,properties,hjson,json,tml,toml} : "${REPLACE_ENV_SUFFIXES:=yml,yaml,txt,cfg,conf,properties,hjson,json,tml,toml}"
: ${REPLACE_ENV_VARIABLE_PREFIX:=${ENV_VARIABLE_PREFIX:-CFG_}} : "${REPLACE_ENV_VARIABLE_PREFIX:=${ENV_VARIABLE_PREFIX:-CFG_}}"
: ${REPLACE_ENV_VARIABLES_EXCLUDES:=} : "${REPLACE_ENV_VARIABLES_EXCLUDES:=}"
: ${REPLACE_ENV_VARIABLES_EXCLUDE_PATHS:=} : "${REPLACE_ENV_VARIABLES_EXCLUDE_PATHS:=}"
: ${DEBUG:=false} : "${DEBUG:=false}"
set -e set -e
isDebugging && set -x isDebugging && set -x
@@ -24,8 +25,8 @@ else
fi fi
if [ -d /plugins ]; then if [ -d /plugins ]; then
case ${TYPE} in case ${FAMILY} in
SPIGOT|BUKKIT|PAPER|MAGMA) SPIGOT|HYBRID)
mkdir -p /data/plugins mkdir -p /data/plugins
log "Copying plugins over..." log "Copying plugins over..."
mc-image-helper \ mc-image-helper \
@@ -40,7 +41,7 @@ if [ -d /plugins ]; then
fi fi
# If any modules have been provided, copy them over # If any modules have been provided, copy them over
: ${COPY_MODS_DEST:="/data/mods"} : "${COPY_MODS_DEST:="/data/mods"}"
if [ -d /mods ]; then if [ -d /mods ]; then
log "Copying any mods over..." log "Copying any mods over..."
@@ -53,7 +54,7 @@ if [ -d /mods ]; then
/mods "${COPY_MODS_DEST}" /mods "${COPY_MODS_DEST}"
fi fi
: ${COPY_CONFIG_DEST:="/data/config"} : "${COPY_CONFIG_DEST:="/data/config"}"
if [ -d /config ]; then if [ -d /config ]; then
log "Copying any configs from /config to ${COPY_CONFIG_DEST}" log "Copying any configs from /config to ${COPY_CONFIG_DEST}"
@@ -66,4 +67,4 @@ if [ -d /config ]; then
/config "${COPY_CONFIG_DEST}" /config "${COPY_CONFIG_DEST}"
fi fi
exec ${SCRIPTS:-/}start-setupServerProperties $@ exec "${SCRIPTS:-/}start-setupServerProperties" "$@"

View File

@@ -33,19 +33,22 @@ function setServerProp {
} }
function customizeServerProps { function customizeServerProps {
if [ -n "$WHITELIST" ] || isTrue "${ENABLE_WHITELIST:-false}"; then # Whitelist processing
log "Creating whitelist" if [ -n "$WHITELIST" ] || [ -n "$WHITELIST_FILE" ] || isTrue "${ENABLE_WHITELIST:-false}"; then
setServerPropValue "whitelist" "true" log "Enabling whitelist functionality"
setServerPropValue "white-list" "true" setServerPropValue "white-list" "true"
else else
log "Disabling whitelist" log "Disabling whitelist functionality"
setServerPropValue "whitelist" "false"
setServerPropValue "white-list" "false" setServerPropValue "white-list" "false"
fi fi
setServerProp "enforce-whitelist" ENFORCE_WHITELIST
if [[ $(grep "enforce-whitelist" $SERVER_PROPERTIES) != *true ]]; then
log "WARNING: whitelist enabled but not enforced. Set ENFORCE_WHITELIST=TRUE or update 'enforce-whitelist' in server.properties to enforce the whitelist."
fi
# If not provided, generate a reasonable default message-of-the-day, # If not provided, generate a reasonable default message-of-the-day,
# which shows up in the server listing in the client # which shows up in the server listing in the client
if [ -z "$MOTD" ]; then if ! [ -v MOTD ]; then
# snapshot is the odd case where we have to look at version to identify that label # snapshot is the odd case where we have to look at version to identify that label
if [[ ${ORIGINAL_TYPE} == "VANILLA" && ${VERSION} == "SNAPSHOT" ]]; then if [[ ${ORIGINAL_TYPE} == "VANILLA" && ${VERSION} == "SNAPSHOT" ]]; then
label=SNAPSHOT label=SNAPSHOT
@@ -59,6 +62,13 @@ function customizeServerProps {
MOTD="A ${label} Minecraft Server powered by Docker" MOTD="A ${label} Minecraft Server powered by Docker"
fi fi
# normalize MOTD
if [[ ${TYPE^^} = LIMBO ]]; then
if [[ $MOTD ]] && ! [[ $MOTD =~ ^{ ]]; then
MOTD="{\"text\":\"${MOTD}\"}"
fi
fi
setServerProp "server-name" SERVER_NAME setServerProp "server-name" SERVER_NAME
setServerProp "server-ip" SERVER_IP setServerProp "server-ip" SERVER_IP
setServerProp "server-port" SERVER_PORT setServerProp "server-port" SERVER_PORT
@@ -104,7 +114,6 @@ function customizeServerProps {
setServerProp "op-permission-level" OP_PERMISSION_LEVEL setServerProp "op-permission-level" OP_PERMISSION_LEVEL
setServerProp "prevent-proxy-connections" PREVENT_PROXY_CONNECTIONS setServerProp "prevent-proxy-connections" PREVENT_PROXY_CONNECTIONS
setServerProp "use-native-transport" USE_NATIVE_TRANSPORT setServerProp "use-native-transport" USE_NATIVE_TRANSPORT
setServerProp "enforce-whitelist" ENFORCE_WHITELIST
setServerProp "simulation-distance" SIMULATION_DISTANCE setServerProp "simulation-distance" SIMULATION_DISTANCE
setServerPropValue "motd" "$(echo "$MOTD" | mc-image-helper asciify)" setServerPropValue "motd" "$(echo "$MOTD" | mc-image-helper asciify)"
[[ $LEVEL_TYPE ]] && setServerPropValue "level-type" "${LEVEL_TYPE^^}" [[ $LEVEL_TYPE ]] && setServerPropValue "level-type" "${LEVEL_TYPE^^}"

View File

@@ -0,0 +1,84 @@
#!/bin/bash
set -e -o pipefail
: "${REMOVE_OLD_VANILLATWEAKS:=false}"
: "${VANILLATWEAKS_FILE:=}"
: "${VANILLATWEAKS_SHARECODE:=}"
: "${REMOVE_OLD_VANILLATWEAKS_DEPTH:=1} "
: "${REMOVE_OLD_VANILLATWEAKS_INCLUDE:=*.zip}"
# shellcheck source=start-utils
. "${SCRIPTS:-/}start-utils"
isDebugging && set -x
out_dir=/data/${LEVEL:-world}/datapacks
# Remove old VANILLATWEAKS
if isTrue "${REMOVE_OLD_VANILLATWEAKS}" && [ -z "${VANILLATWEAKS_FILE}" ]; then
if [ -d "$out_dir" ]; then
find "$out_dir" -mindepth 1 -maxdepth ${REMOVE_OLD_VANILLATWEAKS_DEPTH:-16} -wholename "${REMOVE_OLD_VANILLATWEAKS_INCLUDE:-*}" -not -wholename "${REMOVE_OLD_VANILLATWEAKS_EXCLUDE:-}" -delete
fi
fi
# Example: VANILLATWEAKS_SHARECODE=MGr52E
# Code generated from the UI website, typically a alphanumeric 6 digit code.
if [[ "$VANILLATWEAKS_SHARECODE" ]]; then
VANILLATWEAKS_FILE=/tmp/vanillatweaksfile.json
SHARECODE_LOOKUP_URL="https://vanillatweaks.net/assets/server/sharecode.php?code=${VANILLATWEAKS_SHARECODE}"
curl -f $SHARECODE_LOOKUP_URL -o $VANILLATWEAKS_FILE
if [ ! -f "$VANILLATWEAKS_FILE" ]; then
log "ERROR: Unable to use share code provided to retreive vanillatweaks file"
exit 2
fi
fi
# Use vanillatweaks file to specify VT and datapacks
if [[ "$VANILLATWEAKS_FILE" ]]; then
if [ ! -f "$VANILLATWEAKS_FILE" ]; then
log "ERROR: given VANILLATWEAKS_FILE file does not exist"
exit 2
fi
PACKS=$(jq -jc '.packs' $VANILLATWEAKS_FILE)
if [ ! "$PACKS" ]; then
log "ERROR: unable to retrieve packs from $VANILLATWEAKS_FILE"
exit 2
fi
VT_VERSION=$(jq -jc '.version' $VANILLATWEAKS_FILE)
if [ ! "$VT_VERSION" ]; then
log "ERROR: unable to retrieve version from $VANILLATWEAKS_FILE"
exit 2
fi
fi
# Download and unzip packs
if [[ "$PACKS" ]] && [[ "$VT_VERSION" ]]; then
VT_ZIPDATA_URL=https://vanillatweaks.net/assets/server/zipdatapacks.php
DOWNLOAD_URL=$(curl -X POST -F "packs=${PACKS}" -F "version=${VT_VERSION}" $VT_ZIPDATA_URL | jq -r '.link')
if [ ! "$DOWNLOAD_URL" ]; then
log "ERROR: unable to retrieve DOWNLOAD_URL from vanillatweaks.net!"
exit 2
fi
TEMPZIP=/tmp/vanillatweaks.zip
if ! get -o $TEMPZIP "https://vanillatweaks.net${DOWNLOAD_URL}"; then
log "ERROR: failed to download from ${DOWNLOAD_URL}"
exit 2
fi
mkdir -p "$out_dir"
if ! unzip -o -d "$out_dir" $TEMPZIP; then
log "ERROR: failed to unzip the ${PACKS} from ${$TEMPZIP}"
fi
# clean up files time!
rm -f $TEMPZIP
# cleans up temp vanilla tweaks file download to get stored packs
if [[ "$VANILLATWEAKS_SHARECODE" ]]; then
rm -f $VANILLATWEAKS_FILE
fi
fi
exec "${SCRIPTS:-/}start-setupDatapack" "$@"

View File

@@ -5,7 +5,7 @@
set -e set -e
isDebugging && set -x isDebugging && set -x
if [ $TYPE = "CURSEFORGE" ]; then if [ "$TYPE" = "CURSEFORGE" ]; then
worldDest=$FTB_DIR/${LEVEL:-world} worldDest=$FTB_DIR/${LEVEL:-world}
else else
worldDest=/data/${LEVEL:-world} worldDest=/data/${LEVEL:-world}
@@ -19,26 +19,35 @@ if [[ "$WORLD" ]] && ( isTrue "${FORCE_WORLD_COPY}" || [ ! -d "$worldDest" ] );
"${worldDest}_the_end" "${worldDest}_the_end"
fi fi
if isURL $WORLD; then if isURL "$WORLD"; then
curl -fsSL "$WORLD" -o /tmp/world.zip log "Downloading world from $WORLD"
zipSrc=/tmp/world.zip if ! get -o /tmp/world.bin "$WORLD"; then
elif [[ "$WORLD" =~ .*\.zip ]]; then log "ERROR: failed to download world from $WORLD"
zipSrc="$WORLD" exit 1
fi
WORLD=/tmp/world.bin
fi fi
if [[ "$zipSrc" ]]; then if [ -f "$WORLD" ]; then
log "Unzipping world" log "Extracting world"
# Stage contents so that the correct subdirectory can be picked off # Stage contents so that the correct subdirectory can be picked off
mkdir -p /tmp/world-data mkdir -p /tmp/world-data
(cd /tmp/world-data && unzip -o -q "$zipSrc") if ! extract "$WORLD" /tmp/world-data; then
exit 1
fi
if [ "$TYPE" = "SPIGOT" ]; then if [ "$FAMILY" = "SPIGOT" ]; then
baseDirs=$(find /tmp/world-data -name "level.dat" -not -path "*_nether*" -not -path "*_the_end*" -exec dirname "{}" \;) baseDirs=$(find /tmp/world-data -name "level.dat" -not -path "*_nether*" -not -path "*_the_end*" -exec dirname "{}" \;)
else else
baseDirs=$(find /tmp/world-data -name "level.dat" -exec dirname "{}" \;) baseDirs=$(find /tmp/world-data -name "level.dat" -exec dirname "{}" \;)
fi fi
if ! [[ $baseDirs ]]; then
log "ERROR world content is not valid since level.dat could not be found"
exit 2
fi
count=$(echo "$baseDirs" | wc -l) count=$(echo "$baseDirs" | wc -l)
if [[ $count -gt 1 ]]; then if [[ $count -gt 1 ]]; then
baseDir="$(echo "$baseDirs" | sed -n ${WORLD_INDEX:-1}p)" baseDir="$(echo "$baseDirs" | sed -n ${WORLD_INDEX:-1}p)"
@@ -51,17 +60,20 @@ if [[ "$WORLD" ]] && ( isTrue "${FORCE_WORLD_COPY}" || [ ! -d "$worldDest" ] );
exit 1 exit 1
fi fi
rsync --remove-source-files --recursive --delete "$baseDir/" "$worldDest" rsync --remove-source-files --recursive --delete "$baseDir/" "$worldDest"
if [ "$TYPE" = "SPIGOT" ]; then if [ "$FAMILY" = "SPIGOT" ]; then
log "Copying end and nether ..." log "Copying end and nether ..."
[ -d "${baseDir}_nether" ] && rsync --remove-source-files --recursive --delete "${baseDir}_nether/" "${worldDest}_nether" [ -d "${baseDir}_nether" ] && rsync --remove-source-files --recursive --delete "${baseDir}_nether/" "${worldDest}_nether"
[ -d "${baseDir}_the_end" ] && rsync --remove-source-files --recursive --delete "${baseDir}_the_end/" "${worldDest}_the_end" [ -d "${baseDir}_the_end" ] && rsync --remove-source-files --recursive --delete "${baseDir}_the_end/" "${worldDest}_the_end"
fi fi
else elif [ -d "$WORLD" ]; then
log "Cloning world directory from $WORLD ..." log "Cloning world directory from $WORLD ..."
rsync --recursive --delete "${WORLD%/}"/ "$worldDest" rsync --recursive --delete "${WORLD%/}"/ "$worldDest"
else
log "ERROR: world file/directory $WORLD is missing"
exit 1
fi fi
if [ "$TYPE" = "SPIGOT" ]; then if [ "$FAMILY" = "SPIGOT" ]; then
# Reorganise if a Spigot server # Reorganise if a Spigot server
log "Moving End and Nether maps to Spigot location" log "Moving End and Nether maps to Spigot location"
[ -d "$worldDest/DIM1" ] && mv -f "$worldDest/DIM1" "${worldDest}_the_end" [ -d "$worldDest/DIM1" ] && mv -f "$worldDest/DIM1" "${worldDest}_the_end"
@@ -69,4 +81,4 @@ if [[ "$WORLD" ]] && ( isTrue "${FORCE_WORLD_COPY}" || [ ! -d "$worldDest" ] );
fi fi
fi fi
exec "${SCRIPTS:-/}start-setupModpack" "$@" exec "${SCRIPTS:-/}start-setupVanillaTweaks" "$@"

View File

@@ -22,6 +22,20 @@ containsJars() {
return 1 return 1
} }
containsPlugin() {
file=${1?}
pat='plugin.yml$'
while read -r line; do
if [[ $line =~ $pat ]]; then
return 0
fi
done <<<$(unzip -l "$file")
return 1
}
getResourceFromSpiget() { getResourceFromSpiget() {
resource=${1?} resource=${1?}
@@ -81,9 +95,12 @@ downloadResourceFromSpiget() {
log "Extracting contents of resource ${resource} into plugins" log "Extracting contents of resource ${resource} into plugins"
unzip -o -q -d /data/plugins "${tmpfile}" unzip -o -q -d /data/plugins "${tmpfile}"
rm "${tmpfile}" rm "${tmpfile}"
else elif containsPlugin "${tmpfile}"; then
log "Moving resource ${resource} into plugins" log "Moving resource ${resource} into plugins"
mv "${tmpfile}" "/data/plugins/${resource}.jar" mv "${tmpfile}" "/data/plugins/${resource}.jar"
else
log "ERROR downloaded resource '${resource}' seems to be not a valid plugin"
exit 2
fi fi
} }

View File

@@ -93,6 +93,14 @@ function logAutopauseAction() {
echo "[$(date -Iseconds)] [Autopause] $*" echo "[$(date -Iseconds)] [Autopause] $*"
} }
function logAutostop() {
echo "[Autostop loop] $*"
}
function logAutostopAction() {
echo "[$(date -Iseconds)] [Autostop] $*"
}
function normalizeMemSize() { function normalizeMemSize() {
local scale=1 local scale=1
case ${1,,} in case ${1,,} in
@@ -112,34 +120,7 @@ function normalizeMemSize() {
} }
function versionLessThan() { function versionLessThan() {
local activeParts mc-image-helper compare-versions "${VANILLA_VERSION}" lt "${1?}"
version=${VANILLA_VERSION%%-*} # for snapshot/rc versions
version=${version##b} # for versions like b1.7.3
IFS=. read -ra activeParts <<<"${version}"
local givenParts
IFS=. read -ra givenParts <<<"$1"
if ((${#activeParts[@]} < 2)); then
return 1
fi
if ((${#activeParts[@]} == 2)); then
if ((activeParts[0] < givenParts[0])) ||
((activeParts[0] == givenParts[0] && activeParts[1] < givenParts[1])); then
return 0
else
return 1
fi
else
if ((activeParts[0] < givenParts[0])) ||
((activeParts[0] == givenParts[0] && activeParts[1] < givenParts[1])) ||
((activeParts[0] == givenParts[0] && activeParts[1] == givenParts[1] && activeParts[2] < givenParts[2])); then
return 0
else
return 1
fi
fi
} }
requireVar() { requireVar() {
@@ -163,7 +144,7 @@ requireEnum() {
fi fi
done done
log "ERROR: $var must be set to one of $@" log "ERROR: $var must be set to one of $*"
# exit 1 # exit 1
} }
@@ -189,4 +170,37 @@ function get() {
flags+=("--debug") flags+=("--debug")
fi fi
mc-image-helper "${flags[@]}" get "$@" mc-image-helper "${flags[@]}" get "$@"
}
function isFamily() {
for f in "${@}"; do
if [[ $FAMILY == "$f" ]]; then
return 0
fi
done
return 1
}
function isType() {
for t in "${@}"; do
if [[ $TYPE == "$t" ]]; then
return 0
fi
done
return 1
}
function extract() {
src=${1?}
destDir=${2?}
type=$(file -b --mime-type "${src}")
if [[ $type == application/zip ]]; then
unzip -q -d "${destDir}" "${src}"
elif [[ $type == application/x-tar ]]; then
tar -C "${destDir}" -xf "${src}"
else
log "ERROR: unsupported archive type: $type"
return 1
fi
} }

1
tests/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
data/

43
tests/fulltests/test.sh Normal file
View File

@@ -0,0 +1,43 @@
#!/bin/bash
# go to script root directory
cd "$(dirname "$0")" || exit 1
# compose down function for reuse
down() {
docker-compose down -v --remove-orphans
}
checkandExitOnFailure(){
failed=$1
# docker-compose logs outputs messages from the specified container
if $failed; then
docker-compose logs mc
down
cd ..
exit 2
fi
}
# tests to completely spin up Minecraft and use the monitor to validate the service is running.
fullMinecraftUpTest(){
folder=$1
cd "$folder"
failed=false
# run the monitor to validate the Minecraft image is healthy
docker-compose run monitor || failed=true
echo "${folder} Result: failed=$failed"
checkandExitOnFailure $failed
down
cd ..
}
# go through each folder in fulltests and run fullbuilds
FOLDERS=$(ls)
for folder in $FOLDERS; do
# If folder is a directory
if [ -d "$folder" ]; then
echo "Starting Tests on ${folder}"
fullMinecraftUpTest $folder
fi
done

View File

@@ -1,4 +1,4 @@
version: "3.8" version: "3"
services: services:
monitor: monitor:

View File

@@ -0,0 +1,17 @@
version: "3"
services:
mc:
restart: "no"
image: ${IMAGE_TO_TEST:-itzg/minecraft-server}
environment:
EULA: "TRUE"
SETUP_ONLY: "TRUE"
VERSION: ${MINECRAFT_VERSION:-LATEST}
MODS_FORGEAPI_FILE: /config/example.json
# Key is defined in .github/workflows/pr.yml and ci.yml
# This should be coming from github secrets.
MODS_FORGEAPI_KEY: ${MODS_FORGEAPI_KEY}
REMOVE_OLD_FORGEAPI_MODS: "TRUE"
volumes:
- ./example.json:/config/example.json:ro

View File

@@ -0,0 +1,11 @@
[{
"name": "fabric api",
"projectId": "306612",
"releaseType": "release"
},
{
"name": "Fabric Voice Mod",
"projectId": "416089",
"releaseType": "beta"
}
]

View File

@@ -0,0 +1,15 @@
version: "3"
services:
mc:
restart: "no"
image: ${IMAGE_TO_TEST:-itzg/minecraft-server}
environment:
EULA: "TRUE"
SETUP_ONLY: "TRUE"
VERSION: ${MINECRAFT_VERSION:-LATEST}
MODS_FORGEAPI_PROJECTIDS: 306612,416089
# Allows for Beta releases of 416089 the Fabric Voice Mod
MODS_FORGEAPI_RELEASES: BETA
MODS_FORGEAPI_KEY: ${MODS_FORGEAPI_KEY}
REMOVE_OLD_FORGEAPI_MODS: "TRUE"

View File

@@ -2,14 +2,11 @@ version: "3"
services: services:
mc: mc:
image: itzg/minecraft-server image: ${IMAGE_TO_TEST:-itzg/minecraft-server}
environment: environment:
EULA: "true" EULA: "true"
SETUP_ONLY: "TRUE"
GENERIC_PACKS: https://github.com/itzg/mc-image-helper/releases/download/v1.9.5/mc-image-helper-1.9.5.zip,/packs/testing.zip GENERIC_PACKS: https://github.com/itzg/mc-image-helper/releases/download/v1.9.5/mc-image-helper-1.9.5.zip,/packs/testing.zip
DEBUG: "true"
volumes: volumes:
- ./packs:/packs - ./packs:/packs
- data:/data - ./data:/data
volumes:
data: {}

View File

@@ -0,0 +1 @@
mc-image-helper assert fileExists one.txt mods/two.txt

View File

@@ -0,0 +1,50 @@
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
# go to script root directory
cd "$(dirname "$0")" || exit 1
# tests that only run the setup files for things like downloads and configuration.
setupOnlyMinecraftTest(){
folder=$1
cd "$folder"
result=0
if ! logs=$(docker compose run --quiet-pull mc 2>&1); then
echo "${folder} setup FAILED"
echo ":::::::::::: LOGS ::::::::::::::::
$logs
::::::::::::::::::::::::::::::::::
"
result=1
elif [ -f verify.sh ]; then
if ! docker run --rm --entrypoint bash -v "${PWD}/data":/data -v "${PWD}/verify.sh":/verify "${IMAGE_TO_TEST:-itzg/minecraft-server}" /verify; then
echo "${folder} verify FAILED"
result=1
else
echo "${folder} verify PASS"
fi
else
echo "${folder} PASS"
fi
docker compose down -v --remove-orphans
cd ..
return $result
}
# go through each folder in setuponly and test setups
if (( $# > 0 )); then
for folder in "$@"; do
echo "Starting Tests in ${folder}"
setupOnlyMinecraftTest "$folder"
done
else
readarray -t folders < <(find . -maxdepth 2 -mindepth 2 -name docker-compose.yml -printf '%h\n')
for folder in "${folders[@]}"; do
echo "Starting Tests in ${folder}"
setupOnlyMinecraftTest "$folder"
done
fi

View File

@@ -0,0 +1,14 @@
version: "3"
services:
mc:
restart: "no"
image: ${IMAGE_TO_TEST:-itzg/minecraft-server}
environment:
EULA: "TRUE"
SETUP_ONLY: "TRUE"
VERSION: ${MINECRAFT_VERSION:-LATEST}
VANILLATWEAKS_FILE: /config/vanillatweaks-datapacks.json
REMOVE_OLD_VANILLATWEAKS: "TRUE"
volumes:
- ./vanillatweaks-datapacks.json:/config/vanillatweaks-datapacks.json:ro

View File

@@ -0,0 +1,17 @@
{
"type": "datapacks",
"version": "1.18",
"packs": {
"survival": [
"graves",
"multiplayer sleep",
"afk display",
"armor statues",
"unlock all recipes",
"fast leaf decay",
"coordinates hud"
],
"items": ["armored elytra"]
},
"result": "ok"
}

View File

@@ -0,0 +1,12 @@
version: "3"
services:
mc:
restart: "no"
image: ${IMAGE_TO_TEST:-itzg/minecraft-server}
environment:
EULA: "TRUE"
SETUP_ONLY: "TRUE"
VERSION: ${MINECRAFT_VERSION:-LATEST}
VANILLATWEAKS_SHARECODE: MGr52E
REMOVE_OLD_VANILLATWEAKS: "TRUE"

View File

@@ -0,0 +1,14 @@
version: "3"
services:
mc:
restart: "no"
image: ${IMAGE_TO_TEST:-itzg/minecraft-server}
environment:
EULA: "TRUE"
SETUP_ONLY: "TRUE"
VERSION: ${MINECRAFT_VERSION:-LATEST}
WORLD: /worlds/world-for-testing.tgz
volumes:
- ./worlds:/worlds:ro
- ./data:/data

View File

@@ -0,0 +1 @@
mc-image-helper assert fileExists world/level.dat

View File

@@ -0,0 +1,14 @@
version: "3"
services:
mc:
restart: "no"
image: ${IMAGE_TO_TEST:-itzg/minecraft-server}
environment:
EULA: "TRUE"
SETUP_ONLY: "TRUE"
VERSION: ${MINECRAFT_VERSION:-LATEST}
WORLD: /worlds/world-for-testing.zip
volumes:
- ./worlds:/worlds:ro
- ./data:/data

View File

@@ -0,0 +1 @@
mc-image-helper assert fileExists world/level.dat

View File

@@ -1,22 +1,15 @@
#!/bin/bash #!/bin/bash
set -euo pipefail
IFS=$'\n\t'
# go to script root directory
cd "$(dirname "$0")" || exit 1 cd "$(dirname "$0")" || exit 1
failed=false # go through top level folders and trigger the tests in the subfolders
readarray -t folders < <(find . -maxdepth 2 -mindepth 2 -name test.sh -printf '%h\n')
down() { for folder in "${folders[@]}"; do
docker-compose down -v cd "$folder"
} echo "Starting ${folder} Tests"
bash ./test.sh
docker-compose run monitor || failed=true cd ..
echo " done
Result: failed=$failed"
if $failed; then
docker-compose logs mc
down
exit 1
else
down
fi