Compare commits

..

37 Commits

Author SHA1 Message Date
Geoff Bourne
9bacaa11d8 Auto-merging via docker-versions-create 2020-08-09 13:07:53 -05:00
Geoff Bourne
c7c4c7497a docs: Added test multiarch build instruction 2020-07-26 13:51:16 -05:00
Geoff Bourne
e442baab31 Added writing of eula file after FTBA modpack is installed (#550) 2020-07-26 13:50:57 -05:00
Geoff Bourne
8101c8b51c Merge branch 'master' into multiarch
Renamed to start-deployFTBA

# Conflicts:
#	start-configuration
#	start-deployCF
2020-07-26 13:47:17 -05:00
Geoff Bourne
eba1ef6ab9 Auto-merging via docker-versions-create
# Conflicts:
#	start-deployFTB
#	start-minecraftFinalSetup
2020-07-26 08:35:13 -05:00
Geoff Bourne
6462e1580c Removed improperly merged apk call 2020-07-18 19:29:49 -05:00
Geoff Bourne
8b5552bb62 Auto-merging via docker-versions-create 2020-07-18 18:41:10 -05:00
Geoff Bourne
3ca514f2b2 Auto-merging via docker-versions-create 2020-07-11 13:14:10 -05:00
Geoff Bourne
c07f899870 Auto-merging via docker-versions-create
# Conflicts:
#	start-deployFTB
2020-07-10 17:13:05 -05:00
Geoff Bourne
e527fd9551 Auto-merging via docker-versions-create 2020-07-04 14:58:40 -05:00
Geoff Bourne
047a477f7b Auto-merging via docker-versions-create 2020-06-20 15:45:29 -05:00
Geoff Bourne
78cb05adda ci: added multiarch tags to triggers 2020-06-19 15:03:29 -05:00
Geoff Bourne
8493252645 Auto-merging via docker-versions-create
# Conflicts:
#	Dockerfile
#	README.md
#	start
#	start-configuration
#	start-deployFTB
2020-06-19 15:01:28 -05:00
Geoff Bourne
aa42633ab2 Added support for FTB application modpacks via modpacks.ch
For #524
2020-05-31 18:18:54 -05:00
Geoff Bourne
9ec336283f Updated to support multiarch/BuiltKit builds 2020-05-21 20:48:54 -05:00
Geoff Bourne
bbdb2c9b36 Auto-merging via docker-versions-create 2020-05-20 08:15:50 -05:00
Geoff Bourne
48e09f42fc Changed base ubuntu to 18.04 2020-05-14 20:09:12 -05:00
Geoff Bourne
ec7d182d38 Avoid touch since rpi mounts default to noatime 2020-05-14 15:21:51 -05:00
Geoff Bourne
9c7c95cf4f Pinned Java version at 11 2020-05-03 11:51:56 -05:00
Geoff Bourne
e32ffd1819 Auto-merging via docker-versions-create 2020-05-02 09:34:58 -05:00
Geoff Bourne
095c6ad099 Auto-merging via docker-versions-create 2020-04-25 12:11:39 -05:00
Geoff Bourne
14342c9632 Auto-merging via docker-versions-create
# Conflicts:
#	Dockerfile
2020-04-17 21:32:03 -05:00
Geoff Bourne
f6df4d6694 Auto-merging via docker-versions-create
# Conflicts:
#	.circleci/config.yml
2020-04-11 08:56:29 -05:00
Geoff Bourne
0406e89c2a Auto-merging via docker-versions-create 2020-04-10 11:09:12 -05:00
Geoff Bourne
5ef21e1ddf Auto-merging via docker-versions-create 2020-04-03 13:31:53 -05:00
Geoff Bourne
414d5bd8ac Auto-merging via docker-versions-create 2020-04-03 13:29:03 -05:00
Geoff Bourne
15ccf03b28 Auto-merging via docker-versions-create 2020-04-02 17:47:52 -05:00
Geoff Bourne
828a48998f Auto-merging via docker-versions-create 2020-03-30 08:32:11 -05:00
Geoff Bourne
4b590e03ff Auto-merging via docker-versions-create 2020-03-26 20:54:25 -05:00
Geoff Bourne
0db8780ad9 Changed base image to arm32v7/adoptopenjdk 2020-03-25 21:05:16 -05:00
Geoff Bourne
5b744176df Merge remote-tracking branch 'origin/master' into multiarch 2020-03-25 20:08:47 -05:00
Geoff Bourne
20b15e0330 Merge remote-tracking branch 'origin/master' into multiarch
# Conflicts:
#	Dockerfile
2020-02-06 16:59:59 -06:00
Geoff Bourne
818539e3de Switched base image to adoptopenjdk (debian) 2020-02-05 21:33:08 -06:00
Geoff Bourne
f48741f65c Try BuildKit via regular setup_remote_docker 2020-02-05 08:21:52 -06:00
Geoff Bourne
e9e5af849f Use docker executor 2020-02-04 20:14:32 -06:00
Geoff Bourne
22d68f5c7c Enable use-remote-docker 2020-02-04 20:13:02 -06:00
Geoff Bourne
690598da60 Try BuildKit/multiarch support on CircleCI 2020-02-04 20:10:45 -06:00
47 changed files with 775 additions and 1317 deletions

View File

@@ -1,4 +1,2 @@
[start-*] [start-*]
indent_size = 2 indent_size = 2
indent_style = space
end_of_line = lf

View File

@@ -3,81 +3,23 @@ on:
push: push:
branches: branches:
- multiarch - multiarch
- java8-multiarch
- multiarch-latest
- java15
- java15-openj9
- test/multiarch/*
tags: tags:
- "[0-9]+.[0-9]+.[0-9]+-multiarch" - "[0-9]+.[0-9]+.[0-9]+-multiarch"
- "[0-9]+.[0-9]+.[0-9]+-multiarch-latest"
- "[0-9]+.[0-9]+.[0-9]+-java15"
jobs: jobs:
docker-buildx: docker-buildx:
runs-on: ubuntu-20.04 runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2.2.0 uses: actions/checkout@v2.2.0
- name: Get branch name
- name: Prepare uses: nelonoel/branch-name@v1
id: prep - name: Docker Buildx
run: | uses: ilteoood/docker_buildx@1.0.4
DOCKER_IMAGE=itzg/minecraft-server
VERSION=edge
if [[ $GITHUB_REF == refs/tags/* ]]; then
VERSION=${GITHUB_REF#refs/tags/}
fi
if [[ $GITHUB_REF == refs/heads/* ]]; then
VERSION=${GITHUB_REF#refs/heads/}
if [[ $VERSION == master ]]; then
VERSION=latest
fi
fi
TAGS="${DOCKER_IMAGE}:${VERSION//\//-}"
echo ::set-output name=tags::${TAGS}
echo ::set-output name=cache_from::${TAGS}
echo ::set-output name=version::${VERSION//\//-}
echo ::set-output name=cache_version::${VERSION//\//-}
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Cache Docker layers
uses: actions/cache@v2
with: with:
path: /tmp/.buildx-cache publish: true
key: ${{ runner.os }}-buildx-${{ steps.prep.outputs.cache_version }}-${{ github.sha }} imageName: itzg/minecraft-server
restore-keys: | tag: ${{ env.BRANCH_NAME }}
${{ runner.os }}-buildx-${{ steps.prep.outputs.cache_version }}- dockerHubUser: ${{ secrets.DOCKER_USER }}
dockerHubPassword: ${{ secrets.DOCKER_PASSWORD }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
id: docker_build
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm/v7,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.prep.outputs.tags }}
# ensure latest base image is used
pull: true
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache
labels: |
org.opencontainers.image.documentation=https://github.com/itzg/docker-minecraft-server
org.opencontainers.image.source=https://github.com/itzg/docker-minecraft-server
org.opencontainers.image.version=${{ steps.prep.outputs.version }}
org.opencontainers.image.revision=${{ github.sha }}
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}

View File

@@ -4,22 +4,20 @@ on:
push: push:
branches: branches:
- master - master
- java8
- openj9 - openj9
- openj9-11 - openj9-nightly
- adopt11 - adopt11
- test/* - adopt13
tags: tags:
- "[0-9]+.[0-9]+.[0-9]+" - "[0-9]+.[0-9]+.[0-9]+"
- "[0-9]+.[0-9]+.[0-9]+-java8"
- "[0-9]+.[0-9]+.[0-9]+-openj9" - "[0-9]+.[0-9]+.[0-9]+-openj9"
- "[0-9]+.[0-9]+.[0-9]+-openj9-11"
- "[0-9]+.[0-9]+.[0-9]+-openj9-nightly" - "[0-9]+.[0-9]+.[0-9]+-openj9-nightly"
- "[0-9]+.[0-9]+.[0-9]+-adopt11" - "[0-9]+.[0-9]+.[0-9]+-adopt11"
- "[0-9]+.[0-9]+.[0-9]+-adopt13"
jobs: jobs:
test: test:
runs-on: ubuntu-20.04 runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -30,68 +28,20 @@ jobs:
build: build:
needs: needs:
- test - test
runs-on: ubuntu-20.04 runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Prepare - name: Build and push Docker images
id: prep uses: docker/build-push-action@v1.1.0
run: |
DOCKER_IMAGE=itzg/minecraft-server
VERSION=edge
if [[ $GITHUB_REF == refs/tags/* ]]; then
VERSION=${GITHUB_REF#refs/tags/}
fi
if [[ $GITHUB_REF == refs/heads/* ]]; then
VERSION=${GITHUB_REF#refs/heads/}
if [[ $VERSION == master ]]; then
VERSION=latest
fi
fi
TAGS="${DOCKER_IMAGE}:${VERSION//\//-}"
echo ::set-output name=tags::${TAGS}
echo ::set-output name=cache_from::${TAGS}
echo ::set-output name=version::${VERSION//\//-}
echo ::set-output name=cache_version::${VERSION//\//-}
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ steps.prep.outputs.cache_version }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-${{ steps.prep.outputs.cache_version }}-
${{ runner.os }}-buildx-
- name: Login to DockerHub
uses: docker/login-action@v1
with: with:
repository: itzg/minecraft-server
username: ${{ secrets.DOCKER_USER }} username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASSWORD }} password: ${{ secrets.DOCKER_PASSWORD }}
tag_with_ref: true
- name: Build and push tag_with_sha: false
id: docker_build cache_froms: itzg/minecraft-server:latest
uses: docker/build-push-action@v2 add_git_labels: true
with: labels: org.opencontainers.image.url=https://github.com/itzg/docker-minecraft-server,org.opencontainers.image.documentation=https://github.com/itzg/docker-minecraft-server
context: .
file: ./Dockerfile
# ensure latest base image is used
pull: true
# publish
push: true push: true
# tags determined by prep step
tags: ${{ steps.prep.outputs.tags }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache
labels: |
org.opencontainers.image.documentation=https://github.com/itzg/docker-minecraft-server
org.opencontainers.image.version=${{ steps.prep.outputs.version }}
org.opencontainers.image.source=https://github.com/itzg/docker-minecraft-server
org.opencontainers.image.revision=${{ github.sha }}
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}

11
BUILDING.md Normal file
View File

@@ -0,0 +1,11 @@
Ensure buildx/BuildKit support is enabled and run:
```shell script
docker buildx build --platform=linux/arm64 --platform=linux/arm/v7 --platform=linux/amd64 --tag itzg/minecraft-server:multiarch --push .
```
To build for local testing, use:
```shell script
docker buildx build --platform=linux/amd64 --tag mc-multiarch --load .
```

View File

@@ -1,32 +1,27 @@
FROM openjdk:8u212-jre-alpine FROM ubuntu:18.04
LABEL org.opencontainers.image.authors="Geoff Bourne <itzgeoff@gmail.com>" LABEL org.opencontainers.image.authors="Geoff Bourne <itzgeoff@gmail.com>"
# upgrade all packages since alpine jre8 base image tops out at 8u212 RUN apt-get update \
RUN apk -U --no-cache upgrade && DEBIAN_FRONTEND=noninteractive \
apt-get install -y \
openjdk-8-jre-headless \
imagemagick \
gosu \
curl wget \
jq \
dos2unix \
mysql-client \
tzdata \
rsync \
nano \
unzip \
knockd \
ttf-dejavu \
&& apt-get clean
RUN apk add --no-cache -U \ RUN addgroup --gid 1000 minecraft \
openssl \ && adduser --system --shell /bin/false --uid 1000 --ingroup minecraft --home /data minecraft
imagemagick \
lsof \
su-exec \
shadow \
bash \
curl iputils wget \
git \
jq \
mysql-client \
tzdata \
rsync \
nano \
sudo \
knock \
ttf-dejavu
RUN addgroup -g 1000 minecraft \
&& adduser -Ss /bin/false -u 1000 -G minecraft -h /home/minecraft minecraft \
&& mkdir -m 777 /data \
&& chown minecraft:minecraft /data /home/minecraft
COPY files/sudoers* /etc/sudoers.d COPY files/sudoers* /etc/sudoers.d
@@ -34,9 +29,9 @@ EXPOSE 25565 25575
# hook into docker BuildKit --platform support # hook into docker BuildKit --platform support
# see https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope # see https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope
ARG TARGETOS=linux ARG TARGETOS
ARG TARGETARCH=amd64 ARG TARGETARCH
ARG TARGETVARIANT="" ARG TARGETVARIANT
ARG EASY_ADD_VER=0.7.1 ARG EASY_ADD_VER=0.7.1
ADD https://github.com/itzg/easy-add/releases/download/${EASY_ADD_VER}/easy-add_${TARGETOS}_${TARGETARCH}${TARGETVARIANT} /usr/bin/easy-add ADD https://github.com/itzg/easy-add/releases/download/${EASY_ADD_VER}/easy-add_${TARGETOS}_${TARGETARCH}${TARGETVARIANT} /usr/bin/easy-add
@@ -51,11 +46,11 @@ 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=0.7.1 --var app=mc-monitor --file {{.app}} \ --var version=0.1.7 --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.5.0 --var app=mc-server-runner --file {{.app}} \ --var version=1.4.3 --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} \
@@ -70,12 +65,11 @@ COPY log4j2.xml /tmp/log4j2.xml
WORKDIR /data WORKDIR /data
ENV UID=1000 GID=1000 \ ENV UID=1000 GID=1000 \
JVM_XX_OPTS="-XX:+UseG1GC" MEMORY="1G" \ MEMORY="1G" \
TYPE=VANILLA VERSION=LATEST \ TYPE=VANILLA VERSION=LATEST FORGEVERSION=RECOMMENDED SPONGEBRANCH=STABLE SPONGEVERSION= FABRICVERSION=LATEST LEVEL=world \
ENABLE_RCON=true RCON_PORT=25575 RCON_PASSWORD=minecraft \ PVP=true DIFFICULTY=easy ENABLE_RCON=true RCON_PORT=25575 RCON_PASSWORD=minecraft \
SERVER_PORT=25565 ONLINE_MODE=TRUE SERVER_NAME="Dedicated Server" \ LEVEL_TYPE=DEFAULT SERVER_PORT=25565 ONLINE_MODE=TRUE SERVER_NAME="Dedicated Server" \
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_PERIOD=10 AUTOPAUSE_KNOCK_INTERFACE=eth0
COPY start* / COPY start* /
COPY health.sh / COPY health.sh /

766
README.md
View File

@@ -1,7 +1,7 @@
[![Docker Pulls](https://img.shields.io/docker/pulls/itzg/minecraft-server.svg)](https://hub.docker.com/r/itzg/minecraft-server/) [![Docker Pulls](https://img.shields.io/docker/pulls/itzg/minecraft-server.svg)](https://hub.docker.com/r/itzg/minecraft-server/)
[![Docker Stars](https://img.shields.io/docker/stars/itzg/minecraft-server.svg?maxAge=2592000)](https://hub.docker.com/r/itzg/minecraft-server/) [![Docker Stars](https://img.shields.io/docker/stars/itzg/minecraft-server.svg?maxAge=2592000)](https://hub.docker.com/r/itzg/minecraft-server/)
[![GitHub Issues](https://img.shields.io/github/issues-raw/itzg/docker-minecraft-server.svg)](https://github.com/itzg/docker-minecraft-server/issues) [![GitHub Issues](https://img.shields.io/github/issues-raw/itzg/docker-minecraft-server.svg)](https://github.com/itzg/docker-minecraft-server/issues)
[![Discord](https://img.shields.io/discord/660567679458869252?label=Discord&logo=discord)](https://discord.gg/DXfKpjB) [![Discord](https://img.shields.io/discord/660567679458869252)](https://discord.gg/DXfKpjB)
[![Build and Publish](https://github.com/itzg/docker-minecraft-server/workflows/Build%20and%20Publish/badge.svg)](https://github.com/itzg/docker-minecraft-server/actions) [![Build and Publish](https://github.com/itzg/docker-minecraft-server/workflows/Build%20and%20Publish/badge.svg)](https://github.com/itzg/docker-minecraft-server/actions)
[![](https://img.shields.io/badge/Donate-Buy%20me%20a%20coffee-orange.svg)](https://www.buymeacoffee.com/itzg) [![](https://img.shields.io/badge/Donate-Buy%20me%20a%20coffee-orange.svg)](https://www.buymeacoffee.com/itzg)
@@ -11,21 +11,21 @@ latest snapshot. See the _Versions_ section below for more information.
To simply use the latest stable version, run To simply use the latest stable version, run
docker run -d -it -p 25565:25565 -e EULA=TRUE itzg/minecraft-server docker run -d -p 25565:25565 --name mc -e EULA=TRUE itzg/minecraft-server
where the standard server port, 25565, will be exposed on your host machine. where the standard server port, 25565, will be exposed on your host machine.
If you want to serve up multiple Minecraft servers or just use an alternate port, If you want to serve up multiple Minecraft servers or just use an alternate port,
change the host-side port mapping such as change the host-side port mapping such as
... -p 25566:25565 ... docker run -p 25566:25565 ...
will serve your Minecraft server on your host's port 25566 since the `-p` syntax is will serve your Minecraft server on your host's port 25566 since the `-p` syntax is
`host-port`:`container-port`. `host-port`:`container-port`.
Speaking of multiple servers, it's handy to give your containers explicit names using `--name`, such as naming this one "mc" Speaking of multiple servers, it's handy to give your containers explicit names using `--name`, such as
... --name mc itzg/minecraft-server docker run -d -p 25565:25565 --name mc itzg/minecraft-server
With that you can easily view the logs, stop, or re-start the container: With that you can easily view the logs, stop, or re-start the container:
@@ -35,8 +35,7 @@ With that you can easily view the logs, stop, or re-start the container:
docker stop mc docker stop mc
docker start mc docker start mc
*Be sure to always include `-e EULA=TRUE` in your commands, as Mojang/Microsoft requires EULA acceptance.*
> Be sure to always include `-e EULA=TRUE` in your commands, as Mojang/Microsoft requires EULA acceptance.
## Looking for a Bedrock Dedicated Server ## Looking for a Bedrock Dedicated Server
@@ -82,59 +81,43 @@ and attach from another machine:
Unless you're on a home/private LAN, you should [enable TLS access](https://docs.docker.com/articles/https/). Unless you're on a home/private LAN, you should [enable TLS access](https://docs.docker.com/articles/https/).
## Data Directory ## EULA Support
Everything the container manages is located under the **container's** `/data` path, as shown here: Mojang now requires accepting the [Minecraft EULA](https://account.mojang.com/documents/minecraft_eula). To accept add
![](docs/level-vs-world.drawio.png) -e EULA=TRUE
> NOTE: The container path `/data` is pre-declared as a volume, so if you do nothing then it will be allocated as an anonymous volume. As such, it is subject to removal when the container is removed. such as
### Attaching data directory to host filesystem docker run -d -it -e EULA=TRUE -p 25565:25565 --name mc itzg/minecraft-server
In most cases the easier way to persist and work with the minecraft data files is to use the `-v` argument to map a directory on your host machine to the container's `/data` directory, such as the following where `/home/user/minecraft-data` would be a directory of your choosing on your host machine: ## Timezone Configuration
docker run -d -v /home/user/minecraft-data:/data ... You can configure the timezone to match yours by setting the `TZ` environment variable:
When attached in this way you can stop the server, edit the configuration under your attached directory and start the server again to pick up the new configuration. -e TZ=Europe/London
With Docker Compose, setting up a host attached directory is even easier since relative paths can be configured. For example, with the following `docker-compose.yml` Docker will automatically create/attach the relative directory `minecraft-data` to the container. such as:
```yaml docker run -d -it -e TZ=Europe/London -p 25565:25565 --name mc itzg/minecraft-server
version: "3"
services: Or mounting `/etc/timezone` as readonly (not supported on Windows):
mc:
image: itzg/minecraft-server
ports:
- 25565:25565
environment:
EULA: "TRUE"
volumes:
# attach a directory relative to the directory containing this compose file
- ./minecraft-data:/data
```
### Converting anonymous `/data` volume to named volume -v /etc/timezone:/etc/timezone:ro
If you had used the commands in the first section, without the `-v` volume attachment, then an anonymous data volume was created by Docker. You can later bring over that content to a named or host attached volume using the following procedure. such as:
> In this example, it is assumed the original container was given a `--name` of "mc", so change the container identifier accordingly. docker run -d -it -v /etc/timezone:/etc/timezone:ro -p 25565:25565 --name mc itzg/minecraft-server
First, stop the existing container: ## Attaching data directory to host filesystem
```shell
docker stop mc
```
Use a temporary container to copy over the anonymous volume's content into a named volume, "mc" in this case: In order to readily access the Minecraft data, use the `-v` argument
```shell to map a directory on your host machine to the container's `/data` directory, such as:
docker run --rm --volumes-from mc -v mc:/new alpine cp -avT /data /new
```
Now you can recreate the container with any environment variable changes, etc by attaching the named volume created from the previous step: docker run -d -v /path/on/host:/data ...
```shell
docker run -d -it --name mc-new -v mc:/data -p 25565:25565 -e EULA=TRUE -e MEMORY=2G itzg/minecraft-server When attached in this way you can stop the server, edit the configuration under your attached `/path/on/host`
``` and start the server again with `docker start CONTAINERID` to pick up the new configuration.
## Versions ## Versions
@@ -161,32 +144,20 @@ the server jar remain in the `/data` directory. It is safe to remove those._
To use a different version of Java, please use a docker tag to run your Minecraft server. To use a different version of Java, please use a docker tag to run your Minecraft server.
| Tag name | Java version | Linux | JVM Type | Architecture | | Tag name | Description | Linux |
| -------------- | -------------|--------|----------|-------------------| | -------------- | ------------------------------------------- | ------------ |
| latest | 11 | Alpine | Hotspot | amd64 | | latest | **Default**. Uses Java version 8 update 212 | Alpine Linux |
| java8 | 8 | Alpine | Hotspot | amd64 | | adopt13 | Uses Java version 13 latest update | Alpine Linux |
| java8-multiarch | 8 | Debian | Hotspot | amd64,arm64,armv7 | | adopt11 | Uses Java version 11 latest update | Alpine Linux |
| java15 | 15 | Debian | Hotspot | amd64,arm64,armv7 | | openj9 | Uses Eclipse OpenJ9 JVM | Alpine Linux |
| java15-openj9 | 15 | Debian | OpenJ9 | amd64,arm64 | | openj9-nightly | Uses Eclipse OpenJ9 JVM testing builds | Alpine Linux |
| adopt11 | 11 | Alpine | Hotspot | amd64 | | multiarch | Uses Java version 8 latest update | Debian Linux |
| openj9 | 8 | Alpine | OpenJ9 | amd64 |
| openj9-11 | 11 | Alpine | OpenJ9 | amd64 |
| multiarch | 11 | Debian | Hotspot | amd64,arm64,armv7 |
| multiarch-latest | 15+ | Debian | Hotspot | amd64,arm64,armv7 |
For example, to use Java version 15 on any supported architecture: For example, to use a Java version 13:
docker run --name mc itzg/minecraft-server:java15 docker run --name mc itzg/minecraft-server:adopt13
> Keep in mind that some versions of Minecraft server can't work on the newest versions of Java. Also, FORGE doesn't support openj9 JVM implementation. Keep in mind that some versions of Minecraft server can't work on the newest versions of Java. Also, FORGE doesn't support openj9 JVM implementation.
### Deprecated Image Tags
The following image tags have been deprecated and are no longer receiving updates:
- adopt13
- adopt14
- adopt15
- openj9-nightly
## Healthcheck ## Healthcheck
@@ -208,6 +179,42 @@ healthy
Some orchestration systems, such as Portainer, don't allow for disabling the default `HEALTHCHECK` declared by this image. In those cases you can approximate the disabling of healthchecks by setting the environment variable `DISABLE_HEALTHCHECK` to `true`. Some orchestration systems, such as Portainer, don't allow for disabling the default `HEALTHCHECK` declared by this image. In those cases you can approximate the disabling of healthchecks by setting the environment variable `DISABLE_HEALTHCHECK` to `true`.
## Autopause (experimental)
### Description
> EXPERIMENTAL: this feature only works with default bridge networking using official Docker distributions. Host networking and container management software, such as Portainer, and NAS solutions do not seem to provide compatible networking.
There are various bug reports on [Mojang](https://bugs.mojang.com) about high CPU usage of servers with newer versions, even with few or no clients connected (e.g. [this one](https://bugs.mojang.com/browse/MC-149018), in fact the functionality is based on [this comment in the thread](https://bugs.mojang.com/browse/MC-149018?focusedCommentId=593606&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-593606)).
An autopause functionality has been added to this image to monitor whether clients are connected to the server. If for a specified time no client is connected, the Java process is stopped. When knocking on the server port (e.g. by the ingame Multiplayer server overview), the process is resumed. The experience for the client does not change.
Of course, even loaded chunks are not ticked when the process is stopped.
From the server's point of view, the pausing causes a single tick to take as long as the process is stopped, so the server watchdog might intervene after the process is continued, possibly forcing a container restart. To prevent this, ensure that the `max-tick-time` in the `server.properties` file is set correctly.
On startup the `server.properties` file is checked and, if applicable, a warning is printed to the terminal. When the server is created (no data available in the persistent directory), the properties file is created with the Watchdog disabled.
A starting, example compose file has been provided in [examples/docker-compose-autopause.yml](examples/docker-compose-autopause.yml).
### Enabling Autopause
Enable the Autopause functionality by setting:
```
-e ENABLE_AUTOPAUSE=TRUE
```
There are 4 more environment variables that define the behaviour:
* `AUTOPAUSE_TIMEOUT_EST`, default `3600` (seconds)
describes the time between the last client disconnect and the pausing of the process (read as timeout established)
* `AUTOPAUSE_TIMEOUT_INIT`, default `600` (seconds)
describes the time between server start and the pausing of the process, when no client connects inbetween (read as timeout initialized)
* `AUTOPAUSE_TIMEOUT_KN`, default `120` (seconds)
describes the time between knocking of the port (e.g. by the main menu ping) and the pausing of the process, when no client connects inbetween (read as timeout knocked)
* `AUTOPAUSE_PERIOD`, default `10` (seconds)
describes period of the daemonized state machine, that handles the pausing of the process (resuming is done independently)
## Deployment Templates and Examples ## Deployment Templates and Examples
### Helm Charts ### Helm Charts
@@ -219,19 +226,14 @@ Some orchestration systems, such as Portainer, don't allow for disabling the def
The [examples directory](https://github.com/itzg/docker-minecraft-server/tree/master/examples) also provides examples of deploying the [itzg/minecraft-server](https://hub.docker.com/r/itzg/minecraft-server/) Docker image. The [examples directory](https://github.com/itzg/docker-minecraft-server/tree/master/examples) also provides examples of deploying the [itzg/minecraft-server](https://hub.docker.com/r/itzg/minecraft-server/) Docker image.
### Amazon Web Services (AWS) Deployment
If you're looking for a simple way to deploy this to the Amazon Web Services Cloud, check out the [Minecraft Server Deployment (CloudFormation) repository](https://github.com/vatertime/minecraft-spot-pricing). This repository contains a CloudFormation template that will get you up and running in AWS in a matter of minutes. Optionally it uses Spot Pricing so the server is very cheap, and you can easily turn it off when not in use.
## Running a Forge Server ## Running a Forge Server
Enable [Forge server](http://www.minecraftforge.net/wiki/) mode by adding a `-e TYPE=FORGE` to your command-line. Enable Forge server mode by adding a `-e TYPE=FORGE` to your command-line.
By default the container will run the `RECOMMENDED` version of [Forge server](http://www.minecraftforge.net/wiki/)
The overall version is specified by `VERSION`, [as described in the section above](#versions) and will run the recommended Forge version by default. You can also choose to run a specific Forge version with `FORGEVERSION`, such as `-e FORGEVERSION=14.23.5.2854`. but you can also choose to run a specific version with `-e FORGEVERSION=10.13.4.1448`.
$ docker run -d -v /path/on/host:/data \ $ docker run -d -v /path/on/host:/data \
-e TYPE=FORGE \ -e TYPE=FORGE -e FORGEVERSION=10.13.4.1448 \
-e VERSION=1.12.2 -e FORGEVERSION=14.23.5.2854 \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server -p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
To use a pre-downloaded Forge installer, place it in the attached `/data` directory and To use a pre-downloaded Forge installer, place it in the attached `/data` directory and
@@ -248,241 +250,7 @@ the URL with `FORGE_INSTALLER_URL`, such as:
In both of the cases above, there is no need for the `VERSION` or `FORGEVERSION` variables. In both of the cases above, there is no need for the `VERSION` or `FORGEVERSION` variables.
### Managing mods In order to add mods, you have two options.
In order to manage mods, you have two options:
1. [Attach a host directory to the /data path](#attaching-data-directory-to-host-filesystem) and manage the contents of the `mods` subdirectory
2. Using a mods-mount
If the container paths `/mods` and/or `/config` exist, such as by attaching a docker volume or host path, then any files in either of these directories will be copied over to the respective `/data` subdirectory before starting Minecraft.
If you want old mods to be removed as the `/mods` content is updated, then add `-e REMOVE_OLD_MODS=TRUE`. You can fine tune the removal process by specifying the `REMOVE_OLD_MODS_INCLUDE` and `REMOVE_OLD_MODS_EXCLUDE` variables. By default, everything will be removed. You can also specify the `REMOVE_OLD_MODS_DEPTH` (default is 16) variable to only delete files up to a certain level.
For example: `-e REMOVE_OLD_MODS=TRUE -e REMOVE_OLD_MODS_INCLUDE="*.jar" -e REMOVE_OLD_MODS_DEPTH=1` will remove all old jar files that are directly inside the `plugins/` or `mods/` directory.
You can specify the destination of the files that are copied from `/config` by setting the `COPY_CONFIG_DEST` variable, where the default is `/data/config`. For example, `-v ./config:/config -e COPY_CONFIG_DEST=/data` will allow you to copy over files like `bukkit.yml` and so on directly into the server directory.
> NOTE: If a file was updated in the destination path and is newer than the source file from `/config`, then it will not be overwritten.
## Running a Bukkit/Spigot server
Enable Bukkit/Spigot server mode by adding a `-e TYPE=BUKKIT` or `-e TYPE=SPIGOT` to your command-line.
docker run -d -v /path/on/host:/data \
-e TYPE=SPIGOT \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
If you are hosting your own copy of Bukkit/Spigot you can override the download URLs with:
- -e BUKKIT_DOWNLOAD_URL=<url>
- -e SPIGOT_DOWNLOAD_URL=<url>
You can build spigot from source by adding `-e BUILD_FROM_SOURCE=true`
Plugins can either be managed within the `plugins` subdirectory of the [data directory](#data-directory) or you can also [attach a `/plugins` volume](#deploying-plugins-from-attached-volume). If you add plugins while the container is running, you'll need to restart it to pick those up.
[You can also auto-download plugins using `SPIGET_RESOURCES`.](#auto-downloading-spigotmcbukkitpapermc-plugins)
> NOTE some of the `VERSION` values are not as intuitive as you would think, so make sure to click into the version entry to find the **exact** version needed for the download. For example, "1.8" is not sufficient since their download naming expects `1.8-R0.1-SNAPSHOT-latest` exactly.
## Running a Paper server
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)
but you can also choose to run a specific build with `-e PAPERBUILD=205`.
docker run -d -v /path/on/host:/data \
-e TYPE=PAPER \
-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:
- -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](#deploying-plugins-from-attached-volume). If you add plugins while the container is running, you'll need to restart it to pick those up.
[You can also auto-download plugins using `SPIGET_RESOURCES`.](#auto-downloading-spigotmcbukkitpapermc-plugins)
## Running a Tuinity server
A [Tuinity](https://github.com/Spottedleaf/Tuinity) server, which is a fork of Paper aimed at improving server performance at high playercounts.
-e TYPE=TUINITY
> **NOTE** only `VERSION=LATEST` is supported
## Running a Purpur server
A [Purpur](https://purpur.pl3x.net/) server, which is "a fork of Paper and Tuinity with the goal of providing new and interesting configuration options".
-e TYPE=PURPUR
> NOTE: the `VERSION` variable is used to lookup a build of Purpur to download
Extra variables:
- `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
## Running a Yatopia server
A [Yatopia](https://github.com/YatopiaMC/Yatopia) server, which is a "blazing fast Tuinity fork with best in class performance".
-e TYPE=YATOPIA
> NOTE: the `VERSION` variable is used to locate the Yatopia version to download
Extra variables:
- `RELEASE=stable` : set to `stable` or `latest`
- `FORCE_REDOWNLOAD=false` : set to true to force the located server jar to be re-downloaded
## Running a Magma server
A [Magma](https://magmafoundation.org/) server, which is a combination of Forge and PaperMC, can be used with
-e TYPE=MAGMA
> **NOTE** there are limited base versions supported, so you will also need to set `VERSION`, such as "1.12.2"
## Running a Mohist server
A [Mohist](https://github.com/Mohist-Community/Mohist) server can be used with
-e TYPE=MOHIST
> **NOTE** there are limited base versions supported, so you will also need to set `VERSION`, such as "1.12.2"
By default the latest build will be used; however, a specific build number can be selected by setting `MOHIST_BUILD`, such as
-e VERSION=1.16.5 -e MOHIST_BUILD=374
## Running a Catserver type server
A [Catserver](http://catserver.moe/) type server can be used with
-e TYPE=CATSERVER
> **NOTE** Catserver only provides a single release stream, so `VERSION` is ignored
## Running a server with a Feed the Beast modpack
> **NOTE** requires one of the Debian based images listed in [the Java versions section](#running-minecraft-server-on-different-java-version).
[Feed the Beast application](https://www.feed-the-beast.com/) modpacks are supported by using `-e TYPE=FTBA` (**note** the "A" at the end of the type). This server type will automatically take care of downloading and installing the modpack and appropriate version of Forge, so the `VERSION` does not need to be specified.
### Environment Variables:
- `FTB_MODPACK_ID`: **required**, the numerical ID of the modpack to install. The ID can be located by [finding the modpack](https://www.feed-the-beast.com/modpack) and using the "ID" displayed next to the name
- `FTB_MODPACK_VERSION_ID`: optional, the numerical Id of the version to install. If not specified, the latest version will be installed. The "Version ID" can be obtained by drilling into the Versions tab and clicking a specific version.
### Upgrading
If a specific `FTB_MODPACK_VERSION_ID` was not specified, simply restart the container to pick up the newest modpack version. If using a specific version ID, recreate the container with the new version ID.
### Example
The following example runs the latest version of [FTB Presents Direwolf20 1.12](https://ftb.neptunepowered.org/pack/ftb-presents-direwolf20-1-12/):
```
docker run -d --name mc-ftb -e EULA=TRUE \
-e TYPE=FTBA -e FTB_MODPACK_ID=31 \
-p 25565:25565 \
itzg/minecraft-server:multiarch
```
> Normally you will also add `-v` volume for `/data` since the mods and config are installed there along with world data.
## Running a server with a CurseForge modpack
Enable this server mode by adding `-e TYPE=CURSEFORGE` to your command-line,
but note the following additional steps needed...
You need to specify a modpack to run, using the `CF_SERVER_MOD` environment
variable. A CurseForge server modpack is available together with its respective
client modpack at <https://www.curseforge.com/minecraft/modpacks> .
Now you can add a `-e CF_SERVER_MOD=name_of_modpack.zip` to your command-line.
docker run -d -v /path/on/host:/data -e TYPE=CURSEFORGE \
-e CF_SERVER_MOD=SkyFactory_4_Server_4.1.0.zip \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
If you want to keep the pre-download modpacks separate from your data directory,
then you can attach another volume at a path of your choosing and reference that.
The following example uses `/modpacks` as the container path as the pre-download area:
docker run -d -v /path/on/host:/data -v /path/to/modpacks:/modpacks \
-e TYPE=CURSEFORGE \
-e CF_SERVER_MOD=/modpacks/SkyFactory_4_Server_4.1.0.zip \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
#### Modpack data directory
By default, CurseForge modpacks are expanded into the sub-directory `/data/FeedTheBeast` and executed from there. (The default location was chosen for legacy reasons, when Curse and FTB were maintained together.)
The directory can be changed by setting `CF_BASE_DIR`, such as `-e CF_BASE_DIR=/data`.
#### Buggy start scripts
Some modpacks have buggy or overly complex start scripts. You can avoid using the bundled start script and use this image's standard server-starting logic by adding `-e USE_MODPACK_START_SCRIPT=false`.
### Fixing "unable to launch forgemodloader"
If your server's modpack fails to load with an error [like this](https://support.feed-the-beast.com/t/cant-start-crashlanding-server-unable-to-launch-forgemodloader/6028/2):
unable to launch forgemodloader
then you apply a workaround by adding this to the run invocation:
-e FTB_LEGACYJAVAFIXER=true
## Running a SpongeVanilla server
Enable SpongeVanilla server mode by adding a `-e TYPE=SPONGEVANILLA` to your command-line.
By default the container will run the latest `STABLE` version.
If you want to run a specific version, you can add `-e SPONGEVERSION=1.11.2-6.1.0-BETA-19` to your command-line.
docker run -d -v /path/on/host:/data -e TYPE=SPONGEVANILLA \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
You can also choose to use the `EXPERIMENTAL` branch.
Just change it with `SPONGEBRANCH`, such as:
$ docker run -d -v /path/on/host:/data ... \
-e TYPE=SPONGEVANILLA -e SPONGEBRANCH=EXPERIMENTAL ...
## Running a Fabric Server
Enable [Fabric server](http://fabricmc.net/use/) mode by adding a `-e TYPE=FABRIC` to your command-line. By default, the container will run the latest version, but you can also choose to run a specific version with `VERSION`.
```
docker run -d -v /path/on/host:/data \
-e TYPE=FABRIC \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
```
A specific installer version can be requested using `FABRIC_INSTALLER_VERSION`.
To use a pre-downloaded Fabric installer, place it in a directory attached into the container, such as the `/data` volume and specify the name of the installer file with `FABRIC_INSTALLER`, such as:
```
docker run -d -v /path/on/host:/data ... \
-e FABRIC_INSTALLER=fabric-installer-0.5.0.32.jar ...
```
To download a Fabric installer from a custom location, such as your own file repository, specify the URL with `FABRIC_INSTALLER_URL`, such as:
```
docker run -d -v /path/on/host:/data ... \
-e FABRIC_INSTALLER_URL=http://HOST/fabric-installer-0.5.0.32.jar ...
```
In order to add mods, you have two options:
### Using the /data volume ### Using the /data volume
@@ -502,10 +270,20 @@ the `/path/on/host` folder contents look like:
├── ops.json ├── ops.json
├── server.properties ├── server.properties
├── whitelist.json ├── whitelist.json
├── worlds
│   └── ... PLACE MAPS IN THEIR OWN FOLDERS HERE ...
└── ... └── ...
``` ```
If you add mods while the container is running, you'll need to restart it to pick those Providing a presistent `/data` mount is a good idea, both to persist the game world and to allow for the manual configuration which is sometimes needed.
For instance, imagine a scenario when the initial launch has completed, but you now want to change the worldmap for your server.
Assuming you have a shared directory to your container, you can then (after first launch) drag and drop your premade maps or worlds into the `\worlds\` directory. **Note:** each world should be placed in its own folder under the `\worlds\` directory.
Once your maps are in the proper path, you can then specify which map the server uses by changing the `level-name` value in `server.properties` to match the name of your map.
If you add mods or make changes to `server.properties` while the container is running, you'll need to restart it to pick those
up: up:
docker stop mc docker stop mc
@@ -524,28 +302,9 @@ This works well if you want to have a common set of modules in a separate
location, but still have multiple worlds with different server requirements location, but still have multiple worlds with different server requirements
in either persistent volumes or a downloadable archive. in either persistent volumes or a downloadable archive.
## Deploying plugins from attached volume
If the `/plugins` directory exists in the container, such as from an attached volume, any files in this directory will be copied over to `/data/plugins` before starting Minecraft. Set `PLUGINS_SYNC_UPDATE=false` if you want files from `/plugins` to take precedence over newer files in `/data/plugins`.
This works well if you want to have a common set of plugins in a separate location, but still have multiple worlds with different server requirements in either persistent volumes or a downloadable archive. ### Replacing variables inside configs
## Auto-downloading SpigotMC/Bukkit/PaperMC plugins
The `SPIGET_RESOURCES` variable can be set with a comma-separated list of SpigotMC resource IDs to automatically download [SpigotMC resources/plugins](https://www.spigotmc.org/resources/) using [the spiget API](https://spiget.org/). Resources that are zip files will be expanded into the plugins directory and resources that are simply jar files will be moved there.
> NOTE: the variable is purposely spelled SPIG**E**T with an "E"
The **resource ID** can be located from the numerical part of the URL after the shortname and a dot. For example, the ID is **9089** from
https://www.spigotmc.org/resources/essentialsx.9089/
====
For example, the following will auto-download the [EssentialsX](https://www.spigotmc.org/resources/essentialsx.9089/) and [Vault](https://www.spigotmc.org/resources/vault.34315/) plugins:
-e SPIGET_RESOURCES=9089,34315
## Replacing variables inside configs
Sometimes you have mods or plugins that require configuration information that is only available at runtime. Sometimes you have mods or plugins that require configuration information that is only available at runtime.
For example if you need to configure a plugin to connect to a database, For example if you need to configure a plugin to connect to a database,
@@ -644,6 +403,229 @@ secrets:
The content of `db_password`: The content of `db_password`:
ug23u3bg39o-ogADSs ug23u3bg39o-ogADSs
## Running a Bukkit/Spigot server
Enable Bukkit/Spigot server mode by adding a `-e TYPE=BUKKIT` or `-e TYPE=SPIGOT` to your command-line.
docker run -d -v /path/on/host:/data \
-e TYPE=SPIGOT \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
If you are hosting your own copy of Bukkit/Spigot you can override the download URLs with:
- -e BUKKIT_DOWNLOAD_URL=<url>
- -e SPIGOT_DOWNLOAD_URL=<url>
You can build spigot from source by adding `-e BUILD_FROM_SOURCE=true`
If you have attached a host directory to the `/data` volume, then you can install plugins within the `plugins` subdirectory. You can also [attach a `/plugins` volume](#deploying-plugins-from-attached-volume). If you add plugins while the container is running, you'll need to restart it to pick those up.
## Running a PaperSpigot server
Enable PaperSpigot 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)
but you can also choose to run a specific build with `-e PAPERBUILD=205`.
docker run -d -v /path/on/host:/data \
-e TYPE=PAPER \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
If you are hosting your own copy of PaperSpigot you can override the download URL with:
- -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](#deploying-plugins-from-attached-volume). If you add plugins while the container is running, you'll need to restart it to pick those up.
## Running a Tuinity server
A [Tuinity](https://github.com/Spottedleaf/Tuinity) server, which is a fork of Paper aimed at improving server performance at high playercounts.
-e TYPE=TUINITY
> **NOTE** only `VERSION=LATEST` is supported
## Running a Magma server
A [Magma](https://magmafoundation.org/) server, which is a combination of Forge and PaperMC, can be used with
-e TYPE=MAGMA
> **NOTE** there are limited base versions supported, so you will also need to set `VERSION`, such as "1.12.2"
## Running a Mohist server
A [Mohist](https://github.com/Mohist-Community/Mohist) server can be used with
-e TYPE=MOHIST
> **NOTE** there are limited base versions supported, so you will also need to set `VERSION`, such as "1.12.2"
## Running a Catserver type server
A [Catserver](http://catserver.moe/) type server can be used with
-e TYPE=CATSERVER
> **NOTE** Catserver only provides a single release stream, so `VERSION` is ignored
## Running a server with a Feed the Beast modpack
> **NOTE** requires `itzg/minecraft-server:multiarch` image
[Feed the Beast application](https://www.feed-the-beast.com/) modpacks are supported by using `-e TYPE=FTBA` (**note** the "A" at the end of the type). This server type will automatically take care of downloading and installing the modpack and appropriate version of Forge, so the `VERSION` does not need to be specified.
### Environment Variables:
- `FTB_MODPACK_ID`: **required**, the numerical ID of the modpack to install. The ID can be located by finding the modpack at [Neptune FTB](https://ftb.neptunepowered.org/) and using the "Pack ID"
- `FTB_MODPACK_VERSION_ID`: optional, the numerical Id of the version to install. If not specified, the latest version will be installed. The "Version ID" can be obtained by drilling into the Versions tab and clicking a specific version.
### Upgrading
If a specific `FTB_MODPACK_VERSION_ID` was not specified, simply restart the container to pick up the newest modpack version. If using a specific version ID, recreate the container with the new version ID.
### Example
The following example runs the latest version of [FTB Presents Direwolf20 1.12](https://ftb.neptunepowered.org/pack/ftb-presents-direwolf20-1-12/):
```
docker run -d --name mc-ftb -e EULA=TRUE \
-e TYPE=FTBA -e FTB_MODPACK_ID=31 \
-p 25565:25565 \
itzg/minecraft-server:multiarch
```
> Normally you will also add `-v` volume for `/data` since the mods and config are installed there along with world data.
## Running a server with a CurseForge modpack
Enable this server mode by adding `-e TYPE=CURSEFORGE` to your command-line,
but note the following additional steps needed...
You need to specify a modpack to run, using the `CF_SERVER_MOD` environment
variable. A CurseForge server modpack is available together with its respective
client modpack at <https://www.curseforge.com/minecraft/modpacks> .
Now you can add a `-e CF_SERVER_MOD=name_of_modpack.zip` to your command-line.
docker run -d -v /path/on/host:/data -e TYPE=CURSEFORGE \
-e CF_SERVER_MOD=SkyFactory_4_Server_4.1.0.zip \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
If you want to keep the pre-download modpacks separate from your data directory,
then you can attach another volume at a path of your choosing and reference that.
The following example uses `/modpacks` as the container path as the pre-download area:
docker run -d -v /path/on/host:/data -v /path/to/modpacks:/modpacks \
-e TYPE=CURSEFORGE \
-e CF_SERVER_MOD=/modpacks/SkyFactory_4_Server_4.1.0.zip \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
#### Buggy start scripts
Some modpacks have buggy or overly complex start scripts. You can avoid using the bundled start script and use this image's standard server-starting logic by adding `-e USE_MODPACK_START_SCRIPT=false`.
### Fixing "unable to launch forgemodloader"
If your server's modpack fails to load with an error [like this](https://support.feed-the-beast.com/t/cant-start-crashlanding-server-unable-to-launch-forgemodloader/6028/2):
unable to launch forgemodloader
then you apply a workaround by adding this to the run invocation:
-e FTB_LEGACYJAVAFIXER=true
## Running a SpongeVanilla server
Enable SpongeVanilla server mode by adding a `-e TYPE=SPONGEVANILLA` to your command-line.
By default the container will run the latest `STABLE` version.
If you want to run a specific version, you can add `-e SPONGEVERSION=1.11.2-6.1.0-BETA-19` to your command-line.
docker run -d -v /path/on/host:/data -e TYPE=SPONGEVANILLA \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
You can also choose to use the `EXPERIMENTAL` branch.
Just change it with `SPONGEBRANCH`, such as:
$ docker run -d -v /path/on/host:/data ... \
-e TYPE=SPONGEVANILLA -e SPONGEBRANCH=EXPERIMENTAL ...
## Running a Fabric Server
Enable Fabric server mode by adding a `-e TYPE=FABRIC` to your command-line.
By default the container will run the latest version of [Fabric server](http://fabricmc.net/use/)
but you can also choose to run a specific version with `-e FABRICVERSION=0.5.0.32`.
$ docker run -d -v /path/on/host:/data \
-e TYPE=FABRIC -e FABRICVERSION=0.5.0.32 \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
To use a pre-downloaded Fabric installer, place it in the attached `/data` directory and
specify the name of the installer file with `FABRIC_INSTALLER`, such as:
$ docker run -d -v /path/on/host:/data ... \
-e FABRIC_INSTALLER=fabric-installer-0.5.0.32.jar ...
To download a Fabric installer from a custom location, such as your own file repository, specify
the URL with `FABRIC_INSTALLER_URL`, such as:
$ docker run -d -v /path/on/host:/data ... \
-e FORGE_INSTALLER_URL=http://HOST/fabric-installer-0.5.0.32.jar ...
In both of the cases above, there is no need for the `VERSION` or `FABRICVERSION` variables.
In order to add mods, you have two options.
### Using the /data volume
This is the easiest way if you are using a persistent `/data` mount.
To do this, you will need to attach the container's `/data` directory
(see "Attaching data directory to host filesystem”).
Then, you can add mods to the `/path/on/host/mods` folder you chose. From the example above,
the `/path/on/host` folder contents look like:
```
/path/on/host
├── mods
│   └── ... INSTALL MODS HERE ...
├── config
│   └── ... CONFIGURE MODS HERE ...
├── ops.json
├── server.properties
├── whitelist.json
└── ...
```
If you add mods while the container is running, you'll need to restart it to pick those
up:
docker stop mc
docker start mc
### Using separate mounts
This is the easiest way if you are using an ephemeral `/data` filesystem,
or downloading a world with the `WORLD` option.
There are two additional volumes that can be mounted; `/mods` and `/config`.
Any files in either of these filesystems will be copied over to the main
`/data` filesystem before starting Minecraft.
This works well if you want to have a common set of modules in a separate
location, but still have multiple worlds with different server requirements
in either persistent volumes or a downloadable archive.
## Deploying plugins from attached volume
There is one additional volume that can be mounted; `/plugins`. Any files in this filesystem will be copied over to the main `/data/plugins` filesystem before starting Minecraft. Set `PLUGINS_SYNC_UPDATE=false` if you want files from `/plugins` to take precedence over newer files in `/data/plugins`.
This works well if you want to have a common set of plugins in a separate location, but still have multiple worlds with different server requirements in either persistent volumes or a downloadable archive.
## Running with a custom server JAR ## Running with a custom server JAR
@@ -677,14 +659,16 @@ every time you want to create new Minecraft server, you can now use
``` ```
minecraft-server: minecraft-server:
image: itzg/minecraft-server
ports: ports:
- "25565:25565" - "25565:25565"
environment: environment:
EULA: "TRUE" EULA: "TRUE"
image: itzg/minecraft-server
container_name: mc
tty: true tty: true
stdin_open: true stdin_open: true
restart: always restart: always
@@ -746,18 +730,12 @@ To whitelist players for your Minecraft server, pass the Minecraft usernames sep
If the `WHITELIST` environment variable is not used, any user can join your Minecraft server if it's publicly accessible. If the `WHITELIST` environment variable is not used, any user can join your Minecraft server if it's publicly accessible.
> NOTE: When `WHITELIST` is used the server property `white-list` will automatically get set to `true`.
> 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.
### 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 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
docker run -d -e OPS=user1,user2 ... docker run -d -e OPS=user1,user2 ...
> 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.
### Server icon ### Server icon
A server icon can be configured using the `ICON` variable. The image will be automatically A server icon can be configured using the `ICON` variable. The image will be automatically
@@ -765,10 +743,6 @@ downloaded, scaled, and converted from any other image format:
docker run -d -e ICON=http://..../some/image.png ... docker run -d -e ICON=http://..../some/image.png ...
The server icon which has been set doesn't get overridden by default. It can be changed and overridden by setting `OVERRIDE_ICON` to `TRUE`.
docker run -d -e ICON=http://..../some/other/image.png -e OVERRIDE_ICON=TRUE...
### Rcon ### Rcon
To use rcon use the `ENABLE_RCON` and `RCON_PASSORD` variables. To use rcon use the `ENABLE_RCON` and `RCON_PASSORD` variables.
@@ -892,11 +866,7 @@ It determines the server-side viewing distance.
If you want to create the Minecraft level with a specific seed, use `SEED`, such as If you want to create the Minecraft level with a specific seed, use `SEED`, such as
-e SEED=1785852800490497919 docker run -d -e SEED=1785852800490497919 ...
If using a negative value for the seed, make sure to quote the value such as:
-e SEED="-1785852800490497919"
### Game Mode ### Game Mode
@@ -918,13 +888,16 @@ For example:
The message of the day, shown below each server entry in the UI, can be changed with the `MOTD` environment variable, such as The message of the day, shown below each server entry in the UI, can be changed with the `MOTD` environment variable, such as
-e MOTD="My Server" docker run -d -e 'MOTD=My Server' ...
If you leave it off, a default is computed from the server type and version, such as If you leave it off, a default is computed from the server type and version, such as
A Paper Minecraft Server powered by Docker A Paper Minecraft Server powered by Docker
That way you can easily differentiate between several servers you may have started. when `TYPE` is `PAPER`. That way you can easily differentiate between several servers you may have started.
_The example shows how to specify a server message of the day that contains spaces by putting quotes
around the whole thing._
### PVP Mode ### PVP Mode
@@ -936,7 +909,7 @@ environment variable set to `false`, such as
### Level Type and Generator Settings ### Level Type and Generator Settings
By default, a standard world is generated with hills, valleys, water, etc. A different level type can By default, a standard world is generated with hills, valleys, water, etc. A different level type can
be configured by setting `LEVEL_TYPE` to an expected type, for example be configured by setting `LEVEL_TYPE` to an expected type, such as
- DEFAULT - DEFAULT
- FLAT - FLAT
@@ -944,8 +917,6 @@ be configured by setting `LEVEL_TYPE` to an expected type, for example
- AMPLIFIED - AMPLIFIED
- CUSTOMIZED - CUSTOMIZED
- BUFFET - BUFFET
- BIOMESOP (Biomes O' Plenty for 1.12 and older)
- BIOMESOPLENTY (Biomes O' Plenty for 1.15 and above)
Descriptions are available at the [gamepedia](http://minecraft.gamepedia.com/Server.properties). Descriptions are available at the [gamepedia](http://minecraft.gamepedia.com/Server.properties).
@@ -1076,18 +1047,19 @@ is passed to `docker run`.
### Memory Limit ### Memory Limit
By default, the image declares an initial and maximum Java memory-heap limit of 1 GB. There are several ways to adjust the memory settings: By default, the image declares a Java initial and maximum memory limit of 1 GB. There are several
ways to adjust the memory settings:
- `MEMORY`: "1G" by default, can be used to adjust both initial (`Xms`) and max (`Xmx`) memory heap settings of the JVM - `MEMORY`, "1G" by default, can be used to adjust both initial (`Xms`) and max (`Xmx`)
- `INIT_MEMORY`: independently sets the initial heap size memory settings of the JVM
- `MAX_MEMORY`: independently sets the max heap size - `INIT_MEMORY`, independently sets the initial heap size
- `MAX_MEMORY`, independently sets the max heap size
The values of all three are passed directly to the JVM and support format/units as `<size>[g|G|m|M|k|K]`. For example: The values of all three are passed directly to the JVM and support format/units as
`<size>[g|G|m|M|k|K]`. For example:
-e MEMORY=2G -e MEMORY=2G
> NOTE: the settings above only set the Java **heap** limits. Memory resource requests and limits on the overall container should also account for non-heap memory usage. An extra 25% is [a general best practice](https://dzone.com/articles/best-practices-java-memory-arguments-for-container).
### JVM Options ### JVM Options
General JVM options can be passed to the Minecraft Server invocation by passing a `JVM_OPTS` General JVM options can be passed to the Minecraft Server invocation by passing a `JVM_OPTS`
@@ -1097,31 +1069,11 @@ via a `JVM_XX_OPTS` environment variable.
For some cases, if e.g. after removing mods, it could be necessary to startup minecraft with an additional `-D` parameter like `-Dfml.queryResult=confirm`. To address this you can use the environment variable `JVM_DD_OPTS`, which builds the params from a given list of values separated by space, but without the `-D` prefix. To make things running under systems (e.g. Plesk), which doesn't allow `=` inside values, a `:` (colon) could be used instead. The upper example would look like this: For some cases, if e.g. after removing mods, it could be necessary to startup minecraft with an additional `-D` parameter like `-Dfml.queryResult=confirm`. To address this you can use the environment variable `JVM_DD_OPTS`, which builds the params from a given list of values separated by space, but without the `-D` prefix. To make things running under systems (e.g. Plesk), which doesn't allow `=` inside values, a `:` (colon) could be used instead. The upper example would look like this:
`JVM_DD_OPTS=fml.queryResult:confirm`, and will be converted to `-Dfml.queryResult=confirm`. `JVM_DD_OPTS=fml.queryResult:confirm`, and will be converted to `-Dfml.queryResult=confirm`.
## Timezone Configuration
You can configure the timezone to match yours by setting the `TZ` environment variable:
-e TZ=Europe/London
such as:
docker run -d -it -e TZ=Europe/London -p 25565:25565 --name mc itzg/minecraft-server
Or mounting `/etc/timezone` as readonly (not supported on Windows):
-v /etc/timezone:/etc/timezone:ro
such as:
docker run -d -it -v /etc/timezone:/etc/timezone:ro -p 25565:25565 --name mc itzg/minecraft-server
### Enable Remote JMX for Profiling ### Enable Remote JMX for Profiling
To enable remote JMX, such as for profiling with VisualVM or JMC, add the environment variable `ENABLE_JMX=true`, set `JMX_HOST` to the IP/host running the Docker container, and add a port forwarding of TCP port 7091, such as: To enable remote JMX, such as for profiling with VisualVM or JMC, add the environment variable `ENABLE_JMX=true` and add a port forwarding of TCP port 7091, such as:
``` -e ENABLE_JMX=true -p 7091:7091
-e ENABLE_JMX=true -e JMX_HOST=$HOSTNAME -p 7091:7091
```
### Enable Aikar's Flags ### Enable Aikar's Flags
@@ -1152,56 +1104,10 @@ Some older versions (pre-1.14) of Spigot required `--noconsole` to be passed whe
Some older servers get confused and think that the GUI interface is enabled. You can explicitly Some older servers get confused and think that the GUI interface is enabled. You can explicitly
disable that by passing `-e GUI=FALSE`. disable that by passing `-e GUI=FALSE`.
### Stop Duration
When the container is signalled to stop, the Minecraft process wrapper will attempt to send a "stop" command via RCON or console and waits for the process to gracefully finish. By defaul it waits 60 seconds, but that duration can be configured by setting the environment variable `STOP_DURATION` to the number of seconds.
## Autopause
### Description
There are various bug reports on [Mojang](https://bugs.mojang.com) about high CPU usage of servers with newer versions, even with few or no clients connected (e.g. [this one](https://bugs.mojang.com/browse/MC-149018), in fact the functionality is based on [this comment in the thread](https://bugs.mojang.com/browse/MC-149018?focusedCommentId=593606&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-593606)).
An autopause functionality has been added to this image to monitor whether clients are connected to the server. If for a specified time no client is connected, the Java process is stopped. When knocking on the server port (e.g. by the ingame Multiplayer server overview), the process is resumed. The experience for the client does not change.
Of course, even loaded chunks are not ticked when the process is stopped.
**You must greatly increase or disable max-tick-time watchdog functionality.** From the server's point of view, the pausing causes a single tick to take as long as the process is stopped, so the server watchdog might intervene after the process is continued, possibly forcing a container restart. To prevent this, ensure that the `max-tick-time` in the `server.properties` file is set to a very large value or -1 to disable it entirely, which is highly recommended. That can be set with `MAX_TICK_TIME` as described in [the section below](#max-tick-time).
> **NOTE:** Non-vanilla versions might have their own configuration file, you might have to disable their watchdogs separately (e.g. PAPER Servers).
On startup the `server.properties` file is checked and, if applicable, a warning is printed to the terminal. When the server is created (no data available in the persistent directory), the properties file is created with the Watchdog disabled.
The utility used to wake the server (`knock(d)`) works at network interface level. So the correct interface has to be set using the `AUTOPAUSE_KNOCK_INTERFACE` variable when using non-default networking environments (e.g. host-networking, Portainer oder NAS solutions). See the description of the variable below.
A starting, example compose file has been provided in [examples/docker-compose-autopause.yml](examples/docker-compose-autopause.yml).
### Enabling Autopause
Enable the Autopause functionality by setting:
```
-e ENABLE_AUTOPAUSE=TRUE
```
The following environment variables define the behaviour of auto-pausing:
* `AUTOPAUSE_TIMEOUT_EST`, default `3600` (seconds)
describes the time between the last client disconnect and the pausing of the process (read as timeout established)
* `AUTOPAUSE_TIMEOUT_INIT`, default `600` (seconds)
describes the time between server start and the pausing of the process, when no client connects inbetween (read as timeout initialized)
* `AUTOPAUSE_TIMEOUT_KN`, default `120` (seconds)
describes the time between knocking of the port (e.g. by the main menu ping) and the pausing of the process, when no client connects inbetween (read as timeout knocked)
* `AUTOPAUSE_PERIOD`, default `10` (seconds)
describes period of the daemonized state machine, that handles the pausing of the process (resuming is done independently)
* `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.
## 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, such as To run this image on a RaspberryPi 3 B+, 4, or newer, use the image tag
itzg/minecraft-server:multiarch itzg/minecraft-server:multiarch
> NOTE: you may need to lower the memory allocation, such as `-e MEMORY=750m` > NOTE: you may need to lower the memory allocation, such as `-e MEMORY=750m`
> If experiencing issues such as "sleep: cannot read realtime clock: Operation not permitted", ensure `libseccomp` is up to date on your host. In some cases adding `:Z` flag to the `/data` mount may be needed, [but use cautiously](https://docs.docker.com/storage/bind-mounts/#configure-the-selinux-label).

View File

@@ -1,17 +1,7 @@
#!/bin/bash #!/bin/bash
#set -x #set -x
# Use this variable to indicate a list of branches that docker hub is watching # Use this variable to indicate a list of branches that docker hub is watching
branches_list=( branches_list=('openj9' 'openj9-nightly' 'adopt11' 'adopt13' 'multiarch')
'java8'
'java8-multiarch'
'openj9'
'openj9-11'
'adopt11'
'java15'
'java15-openj9'
'multiarch'
'multiarch-latest'
)
function TrapExit { function TrapExit {
echo "Checking out back in master" echo "Checking out back in master"

0
docs/.gitkeep Normal file
View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -2,7 +2,7 @@ version: '3.2'
services: services:
mc: mc:
image: itzg/minecraft-server:java8 image: itzg/minecraft-server
volumes: volumes:
- ./modpacks:/modpacks:ro - ./modpacks:/modpacks:ro
environment: environment:

View File

@@ -0,0 +1,20 @@
version: "3.7"
services:
mc:
image: itzg/minecraft-server
ports:
- 25565:25565
volumes:
# Attach .../Curse/Minecraft/Instances for use at /instances
- ./Instances:/instances:ro
# Attach /data as usual
- ./ServerData:/data
environment:
EULA: "TRUE"
# Modpacks generally need more memory, so let's give at 2 GB
MEMORY: 2G
# Use new CURSE_INSTANCE type
TYPE: CURSE_INSTANCE
# Reference directory of or full path to minecraftinstance.json
CURSE_INSTANCE_JSON: /instances/FTB Presents SkyFactory 3

View File

@@ -2,7 +2,7 @@ version: "3.7"
services: services:
mc: mc:
image: itzg/minecraft-server:java8 image: itzg/minecraft-server
ports: ports:
# expose the Minecraft server port outside of container # expose the Minecraft server port outside of container
- 25565:25565 - 25565:25565

View File

@@ -2,8 +2,8 @@ version: "3.7"
services: services:
mc: mc:
# FTBA support is only available in non-Alpine images # FTBA support is only available in multiarch image tag
image: itzg/minecraft-server:java8-multiarch image: itzg/minecraft-server:multiarch
ports: ports:
# expose the Minecraft server port outside of container # expose the Minecraft server port outside of container
- 25565:25565 - 25565:25565

View File

@@ -1,12 +0,0 @@
version: "3"
services:
mc:
image: itzg/minecraft-server
ports:
- 25565:25565
environment:
EULA: "TRUE"
volumes:
# attach the relative directory 'data' to the container's /data path
- ./data:/data

View File

@@ -5,7 +5,7 @@ version: '3'
services: services:
minecraft: minecraft:
image: itzg/minecraft-server:java8 image: itzg/minecraft-server
ports: ports:
- "25565:25565" - "25565:25565"
volumes: volumes:

View File

@@ -1,3 +1,3 @@
Place server [modpacks downloaded from CurseForge](https://www.curseforge.com/minecraft/modpacks) in this directory. Please server [modpacks downloaded from CurseForge](https://www.curseforge.com/minecraft/modpacks) in this directory.
The example [`docker-compose-curseforge.yml`](../docker-compose-curseforge.yml) references a modpack downloaded from <https://www.curseforge.com/minecraft/modpacks/skyfactory-4/files/2787018>. The example [`docker-compose-curseforge.yml`](../docker-compose-curseforge.yml) references a modpack downloaded from <https://www.curseforge.com/minecraft/modpacks/skyfactory-4/files/2787018>.

View File

@@ -2,48 +2,23 @@
. /autopause/autopause-fcns.sh . /autopause/autopause-fcns.sh
. ${SCRIPTS:-/}start-utils . /start-utils
sudo /usr/sbin/knockd -c /tmp/knockd-config.cfg -d
autopause_error_loop() { if [ $? -ne 0 ] ; then
logAutopause "Available interfaces within the docker container:"
INTERFACES=$(echo /sys/class/net/*)
INTERFACES=${INTERFACES//\/sys\/class\/net\//}
logAutopause " $INTERFACES"
logAutopause "Please set the environment variable AUTOPAUSE_KNOCK_INTERFACE to the interface that handles incoming connections."
logAutopause "If unsure which interface to choose, run the ifconfig command in the container."
logAutopause "Autopause failed to initialize. This log entry will be printed every 30 minutes."
while : while :
do do
sleep 1800 if [[ -n $(ps -o comm | grep java) ]] ; then
logAutopause "Autopause failed to initialize." break
fi
sleep 0.1
done done
}
# wait for java process to be started
while :
do
if java_process_exists ; then
break
fi
sleep 0.1
done
# check for interface existence
if [[ -z "$AUTOPAUSE_KNOCK_INTERFACE" ]] ; then
logAutopause "AUTOPAUSE_KNOCK_INTERFACE variable must not be empty!"
autopause_error_loop
fi
if ! [[ -d "/sys/class/net/$AUTOPAUSE_KNOCK_INTERFACE" ]] ; then
logAutopause "Selected interface \"$AUTOPAUSE_KNOCK_INTERFACE\" does not exist!"
autopause_error_loop
fi
sudo /usr/sbin/knockd -c /tmp/knockd-config.cfg -d -i "$AUTOPAUSE_KNOCK_INTERFACE"
if [ $? -ne 0 ] ; then
logAutopause "Failed to start knockd daemon." logAutopause "Failed to start knockd daemon."
logAutopause "Probable cause: Unable to attach to interface \"$AUTOPAUSE_KNOCK_INTERFACE\"." logAutopause "Possible cause: docker's host network mode."
autopause_error_loop logAutopause "Recreate without host mode or disable autopause functionality."
logAutopause "Stopping server."
killall -SIGTERM java
exit 1
fi fi
STATE=INIT STATE=INIT

View File

@@ -8,16 +8,12 @@ java_running() {
[[ $( ps -a -o stat,comm | grep 'java' | awk '{ print $1 }') =~ ^S.*$ ]] [[ $( ps -a -o stat,comm | grep 'java' | awk '{ print $1 }') =~ ^S.*$ ]]
} }
java_process_exists() {
[[ -n "$(ps -a -o comm | grep 'java')" ]]
}
rcon_client_exists() { rcon_client_exists() {
[[ -n "$(ps -a -o comm | grep 'rcon-cli')" ]] [[ -n "$(ps -a -o comm | grep 'rcon-cli')" ]]
} }
mc_server_listening() { mc_server_listening() {
[[ -n $(netstat -tln | grep -e "0.0.0.0:$SERVER_PORT" -e ":::$SERVER_PORT" | grep LISTEN) ]] [[ -n $(netstat -tln | grep "0.0.0.0:$SERVER_PORT" | grep LISTEN) ]]
} }
java_clients_connected() { java_clients_connected() {
@@ -33,7 +29,7 @@ java_clients_connected() {
# remember, that the host network mode does not work with autopause because of the knockd utility # remember, that the host network mode does not work with autopause because of the knockd utility
for (( i=0; i<${#connections[@]}; i++ )) for (( i=0; i<${#connections[@]}; i++ ))
do do
if [[ ! $(echo "${connections[$i]}" | awk '{print $5}') =~ ^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$ ]] ; then if [[ ! $(echo "${connections[$i]}" | awk '{print $5}') =~ ^\s*127\.0\.0\.1:.*$ ]] ; then
# not localhost # not localhost
return 0 return 0
fi fi

View File

@@ -17,5 +17,5 @@ if [[ $( ps -a -o stat,comm | grep 'java' | awk '{ print $1 }') =~ ^S.*$ ]] ; th
# finally pause the process # finally pause the process
logAutopauseAction "Pausing Java process" logAutopauseAction "Pausing Java process"
pkill -STOP java killall -q -STOP java
fi fi

View File

@@ -4,5 +4,5 @@
if [[ $( ps -a -o stat,comm | grep 'java' | awk '{ print $1 }') =~ ^T.*$ ]] ; then if [[ $( ps -a -o stat,comm | grep 'java' | awk '{ print $1 }') =~ ^T.*$ ]] ; then
logAutopauseAction "Knocked, resuming Java process" logAutopauseAction "Knocked, resuming Java process"
pkill -CONT java killall -q -CONT java
fi fi

View File

@@ -1,2 +1,2 @@
%minecraft ALL=(ALL) NOPASSWD:/usr/bin/pkill %minecraft ALL=(ALL) NOPASSWD:/usr/bin/killall
%minecraft ALL=(ALL) NOPASSWD:/usr/sbin/knockd %minecraft ALL=(ALL) NOPASSWD:/usr/sbin/knockd

2
start
View File

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

View File

@@ -46,15 +46,10 @@ if ! [[ $AUTOPAUSE_TIMEOUT_INIT =~ ^[0-9]+$ ]] ; then
export AUTOPAUSE_TIMEOUT_INIT export AUTOPAUSE_TIMEOUT_INIT
log "Warning: AUTOPAUSE_TIMEOUT_INIT is not numeric, set to 600 (seconds)" log "Warning: AUTOPAUSE_TIMEOUT_INIT is not numeric, set to 600 (seconds)"
fi fi
if [[ "$AUTOPAUSE_KNOCK_INTERFACE" == "lo" ]] ; then
log "Warning: AUTOPAUSE_KNOCK_INTERFACE is set to the local loopback interface."
log " This is not advisable, as incoming connections are likely not picked up there."
log " Continuing with this setting."
fi
if [[ -n "$MAX_TICK_TIME" && "$MAX_TICK_TIME" != "-1" ]] ; then if [[ -n $MAX_TICK_TIME ]] ; then
log "Warning: MAX_TICK_TIME is non-default, for autopause to work properly, this check should be disabled (-1 for versions >= 1.8.1)" log "Warning: MAX_TICK_TIME is non-default, for autopause to work properly, this check should be disabled (-1 for versions >= 1.8.1)"
elif [[ -z "$MAX_TICK_TIME" ]] ; then else
if versionLessThan 1.8.1; then if versionLessThan 1.8.1; then
# 10 years # 10 years
MAX_TICK_TIME=315360000000 MAX_TICK_TIME=315360000000

View File

@@ -1,18 +1,14 @@
#!/bin/bash #!/bin/bash
set -euo pipefail
IFS=$'\n\t'
. ${SCRIPTS:-/}start-utils . ${SCRIPTS:-/}start-utils
: ${EULA:=}
: ${PROXY:=}
: ${RCON_PASSWORD_FILE:=}
shopt -s nullglob shopt -s nullglob
#umask 002 #umask 002
export HOME=/data export HOME=/data
log "Running as uid=$(id -u) gid=$(id -g) with /data as '$(ls -lnd /data)'"
if [ ! -e /data/eula.txt ]; then if [ ! -e /data/eula.txt ]; then
if ! isTrue "$EULA"; then if ! isTrue "$EULA"; then
log "" log ""
@@ -28,15 +24,6 @@ if [ ! -e /data/eula.txt ]; then
fi fi
log "Running as uid=$(id -u) gid=$(id -g) with /data as '$(ls -lnd /data)'"
if ! touch /data/.verify_access; then
log "ERROR: /data doesn't seem to be writable. Please make sure attached directory is writable by uid=$(id -u)"
exit 2
fi
rm /data/.verify_access || true
if [[ $PROXY ]]; then if [[ $PROXY ]]; then
export http_proxy="$PROXY" export http_proxy="$PROXY"
export https_proxy="$PROXY" export https_proxy="$PROXY"
@@ -61,11 +48,7 @@ if [[ $RCON_PASSWORD_FILE ]]; then
log "" log ""
fi fi
if ! which java > /dev/null; then export SERVER_PROPERTIES=/data/server.properties
log "Fixing PATH to include java"
PATH="${PATH}:/usr/bin"
fi
export VERSIONS_JSON=https://launchermeta.mojang.com/mc/game/version_manifest.json export VERSIONS_JSON=https://launchermeta.mojang.com/mc/game/version_manifest.json
case "X$VERSION" in case "X$VERSION" in
@@ -112,7 +95,11 @@ case "${TYPE^^}" in
exec ${SCRIPTS:-/}start-deployFabric "$@" exec ${SCRIPTS:-/}start-deployFabric "$@"
;; ;;
FTB|CURSEFORGE) FTBA)
exec ${SCRIPTS:-/}start-deployFTBA "$@"
;;
CURSEFORGE|FTB)
exec ${SCRIPTS:-/}start-deployCF "$@" exec ${SCRIPTS:-/}start-deployCF "$@"
;; ;;
@@ -144,19 +131,11 @@ case "${TYPE^^}" in
exec ${SCRIPTS:-/}start-deployCatserver "$@" exec ${SCRIPTS:-/}start-deployCatserver "$@"
;; ;;
PURPUR)
exec ${SCRIPTS:-/}start-deployPurpur "$@"
;;
YATOPIA)
exec ${SCRIPTS:-/}start-deployYatopia "$@"
;;
*) *)
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 " CURSE_INSTANCE, CURSEFORGE, SPONGEVANILLA, TUINITY, PURPUR" log " CURSE_INSTANCE, CURSEFORGE, SPONGEVANILLA,"
log " CUSTOM, MAGMA, MOHIST, CATSERVER, YATOPIA" log " CUSTOM, MAGMA, MOHIST, CATSERVER"
exit 1 exit 1
;; ;;

View File

@@ -1,7 +1,6 @@
#!/bin/bash #!/bin/bash
. ${SCRIPTS:-/}start-utils . ${SCRIPTS:-/}start-utils
isDebugging && set -x
set -e set -e
@@ -59,41 +58,24 @@ function downloadSpigot {
;; ;;
esac esac
if [[ ${VERSION^^} = LATEST ]]; then
VANILLA_VERSION=$(restify https://getbukkit.org/download/spigot --attribute='property=og:title' | jq -r '.[0] | .attributes | select(.property == "og:title") | .content | split(" ") | .[-1]')
fi
if [[ -z $downloadUrl ]]; then if [[ -z $downloadUrl ]]; then
downloadUrl="https://cdn.getbukkit.org/${getbukkitFlavor}/${getbukkitFlavor}-${VANILLA_VERSION}.jar" downloadUrl="https://cdn.getbukkit.org/${getbukkitFlavor}/${getbukkitFlavor}-${VANILLA_VERSION}.jar"
fi fi
setServerVar
if [ -f $SERVER ]; then if [ -f $SERVER ]; then
# tell curl to only download when newer # tell curl to only download when newer
curlArgs="-z $SERVER" zarg="-z $SERVER"
fi
if isDebugging; then
curlArgs="$curlArgs -v"
fi fi
log "Downloading $match from $downloadUrl ..." log "Downloading $match from $downloadUrl ..."
curl -fsSL -o $SERVER $curlArgs "$downloadUrl" curl -fsSL -o $SERVER $zarg "$downloadUrl"
if [[ $? != 0 || $(grep -c "DOCTYPE html" $SERVER) != 0 ]]; then if [[ $? != 0 || $(grep -c "DOCTYPE html" $SERVER) != 0 ]]; then
cat <<EOF cat <<EOF
ERROR: failed to download from $downloadUrl ERROR: failed to download from $downloadUrl
Visit https://getbukkit.org/download/${getbukkitFlavor} to lookup the Visit https://getbukkit.org/download/${getbukkitFlavor} to lookup the
exact version, such as 1.4.6-R0.4-SNAPSHOT or 1.8-R0.1-SNAPSHOT-latest. exact version, such as 1.4.6-R0.4-SNAPSHOT or 1.8-R0.1-SNAPSHOT-LATEST
Click into the version entry to find the **exact** version, because something
like "1.8" is not sufficient according to their download naming.
EOF EOF
if isDebugging && [[ $(grep -c "DOCTYPE html" $SERVER) != 0 ]]; then
cat $SERVER
fi
# remove invalid download
rm $SERVER
exit 3 exit 3
fi fi
@@ -101,19 +83,17 @@ EOF
export JVM_OPTS export JVM_OPTS
} }
function setServerVar {
case "$TYPE" in case "$TYPE" in
*BUKKIT|*bukkit) *BUKKIT|*bukkit)
export SERVER=craftbukkit_server-${VANILLA_VERSION}.jar export SERVER=craftbukkit_server-${VANILLA_VERSION}.jar
;; ;;
*) *)
export SERVER=spigot_server-${VANILLA_VERSION}.jar export SERVER=spigot_server-${VANILLA_VERSION}.jar
;; ;;
esac esac
}
if isTrue "$BUILD_SPIGOT_FROM_SOURCE" || isTrue "$BUILD_FROM_SOURCE"; then if isTrue "$BUILD_SPIGOT_FROM_SOURCE" || isTrue "$BUILD_FROM_SOURCE"; then
setServerVar
if [ ! -f $SERVER ] || [ -n "$FORCE_REDOWNLOAD" ]; then if [ ! -f $SERVER ] || [ -n "$FORCE_REDOWNLOAD" ]; then
buildSpigotFromSource buildSpigotFromSource
fi fi
@@ -125,4 +105,5 @@ fi
export TYPE=SPIGOT export TYPE=SPIGOT
export SKIP_LOG4J_CONFIG=true export SKIP_LOG4J_CONFIG=true
exec ${SCRIPTS:-/}start-spiget "$@" # Continue to Final Setup
exec ${SCRIPTS:-/}start-finalSetupWorld $@

View File

@@ -4,30 +4,9 @@ set -e
. ${SCRIPTS:-/}start-utils . ${SCRIPTS:-/}start-utils
loadForgeVars() { export FTB_BASE_DIR=/data/FeedTheBeast
cfgFile=${1?} legacyJavaFixerUrl=http://ftb.cursecdn.com/FTB2/maven/net/minecraftforge/lex/legacyjavafixer/1.0/legacyjavafixer-1.0.jar
pat='^([^#;][^=]+)=[:space:]*([^;]*)' export TYPE=CURSEFORGE
while read -r line || [[ -n "$line" ]] ; do
if [[ $line =~ $pat ]]; then
#echo "MATCHED $line"
k=${BASH_REMATCH[1]}
v=${BASH_REMATCH[2]}
case $k in
FORGEURL)
forgeInstallerUrl="$v"
;;
esac
fi
done < "$cfgFile"
}
isDebugging && set -x
: ${FTB_BASE_DIR:=${CF_BASE_DIR:-/data/FeedTheBeast}}
export FTB_BASE_DIR
legacyJavaFixerUrl=https://ftb.forgecdn.net/FTB2/maven/net/minecraftforge/lex/legacyjavafixer/1.0/legacyjavafixer-1.0.jar
export TYPE=FEED-THE-BEAST
FTB_SERVER_MOD=${FTB_SERVER_MOD:-$CF_SERVER_MOD} FTB_SERVER_MOD=${FTB_SERVER_MOD:-$CF_SERVER_MOD}
@@ -35,7 +14,7 @@ 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 if ! isTrue ${USE_MODPACK_START_SCRIPT:-true}; then
if ! [ -f "${FTB_SERVER_MOD}" ]; then if ! [ -f ${FTB_SERVER_MOD} ]; then
log "ERROR unable to find requested modpack file ${FTB_SERVER_MOD}" log "ERROR unable to find requested modpack file ${FTB_SERVER_MOD}"
exit 2 exit 2
fi fi
@@ -48,7 +27,7 @@ if ! isTrue ${USE_MODPACK_START_SCRIPT:-true}; then
serverJar=$(find ${FTB_BASE_DIR} -not -name "forge*installer.jar" -name "forge*.jar") serverJar=$(find ${FTB_BASE_DIR} -not -name "forge*installer.jar" -name "forge*.jar")
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}
fi fi
else else
needsInstall=false needsInstall=false
@@ -58,40 +37,22 @@ if ! isTrue ${USE_MODPACK_START_SCRIPT:-true}; then
if $needsInstall; then if $needsInstall; then
log "Unpacking FTB server modpack ${FTB_SERVER_MOD} ..." log "Unpacking FTB server modpack ${FTB_SERVER_MOD} ..."
mkdir -p ${FTB_BASE_DIR} mkdir -p ${FTB_BASE_DIR}
unzip -o "${FTB_SERVER_MOD}" -d ${FTB_BASE_DIR} | awk '{printf "."} END {print ""}' unzip -o ${FTB_SERVER_MOD} -d ${FTB_BASE_DIR} | awk '{printf "."} END {print ""}'
serverJar=$(find ${FTB_BASE_DIR} -path "*/libraries/*" -prune -type f -o -not -name "forge*installer.jar" -name "forge*.jar") forgeInstallerJar=$(find ${FTB_BASE_DIR} -name "forge*installer.jar")
if [[ -z "$serverJar" ]]; then if [[ -z "${forgeInstallerJar}" ]]; then
log "ERROR Unable to find forge installer in modpack."
if [ -f "${FTB_BASE_DIR}/settings.cfg" ]; then log " Make sure you downloaded the server files."
loadForgeVars "${FTB_BASE_DIR}/settings.cfg" exit 2
if [[ $forgeInstallerUrl ]]; then
forgeInstallerJar="${FTB_BASE_DIR}/forge-installer.jar"
if ! curl -fsSL -o "$forgeInstallerJar" "$forgeInstallerUrl" ; then
log "ERROR failed to download Forge installer from $forgeInstallerUrl"
exit 2
fi
fi
else
forgeInstallerJar=$(find "${FTB_BASE_DIR}" -name "forge*installer.jar")
fi
if [[ -z "${forgeInstallerJar}" ]]; then
log "ERROR Unable to find forge installer in modpack"
log " or download using modpack config."
log " Make sure you downloaded the server files."
exit 2
fi
log "Installing forge server"
(cd $(dirname "${forgeInstallerJar}"); java -jar $(basename "${forgeInstallerJar}") --installServer)
fi fi
log "Installing forge server"
(cd $(dirname "${forgeInstallerJar}"); java -jar $(basename ${forgeInstallerJar}) --installServer) | awk '{printf "."} END {print ""}'
echo "${FTB_SERVER_MOD}" > $installMarker echo "${FTB_SERVER_MOD}" > $installMarker
fi fi
export SERVER=$(find ${FTB_BASE_DIR} -path "*/libraries/*" -prune -type f -o -not -name "forge*installer.jar" -name "forge*.jar") export SERVER=$(find ${FTB_BASE_DIR} -not -name "forge*installer.jar" -name "forge*.jar")
if [[ -z "${SERVER}" || ! -f "${SERVER}" ]]; then if [[ -z "${SERVER}" || ! -f "${SERVER}" ]]; then
log "ERROR unable to locate installed forge server jar" log "ERROR unable to locate installed forge server jar"
isDebugging && find ${FTB_BASE_DIR} -name "forge*.jar" isDebugging && find ${FTB_BASE_DIR} -name "forge*.jar"
@@ -128,7 +89,7 @@ fi
# 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
srv_modpack=${FTB_SERVER_MOD} srv_modpack=${FTB_SERVER_MOD}
if isURL "${srv_modpack}"; then if isURL ${srv_modpack}; then
case $srv_modpack in case $srv_modpack in
https://www.feed-the-beast.com/*/download|https://www.curseforge.com/minecraft/modpacks/*/download/*/file) https://www.feed-the-beast.com/*/download|https://www.curseforge.com/minecraft/modpacks/*/download/*/file)
;; ;;
@@ -146,19 +107,19 @@ if [[ $startScriptCount = 0 ]]; then
fi fi
srv_modpack=$downloaded srv_modpack=$downloaded
fi fi
if [[ "${srv_modpack:0:5}" == "data/" ]]; then if [[ ${srv_modpack:0:5} == "data/" ]]; then
# Prepend with "/" # Prepend with "/"
srv_modpack="/${srv_modpack}" srv_modpack=/${srv_modpack}
fi fi
if [[ ! "${srv_modpack:0:1}" == "/" ]]; then if [[ ! ${srv_modpack:0:1} == "/" ]]; then
# If not an absolute path, assume file is in "/data" # If not an absolute path, assume file is in "/data"
srv_modpack=/data/${srv_modpack} srv_modpack=/data/${srv_modpack}
fi fi
if [[ ! -f "${srv_modpack}" ]]; then if [[ ! -f ${srv_modpack} ]]; then
log "FTB server modpack ${srv_modpack} not found." log "FTB server modpack ${srv_modpack} not found."
exit 2 exit 2
fi fi
if [[ ! "${srv_modpack: -4}" == ".zip" ]]; then if [[ ! ${srv_modpack: -4} == ".zip" ]]; then
log "FTB server modpack ${srv_modpack} is not a zip archive." log "FTB server modpack ${srv_modpack} is not a zip archive."
log "Please set FTB_SERVER_MOD to a file with a .zip extension." log "Please set FTB_SERVER_MOD to a file with a .zip extension."
exit 2 exit 2
@@ -166,7 +127,7 @@ if [[ $startScriptCount = 0 ]]; then
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 ""}'
fi fi
if [[ $(find ${FTB_BASE_DIR} $entryScriptExpr | wc -l) = 0 ]]; then if [[ $(find ${FTB_BASE_DIR} $entryScriptExpr | wc -l) = 0 ]]; then
@@ -204,7 +165,7 @@ export FTB_SERVER_START=$(find "${FTB_BASE_DIR}" $entryScriptExpr)
export FTB_DIR=$(dirname "${FTB_SERVER_START}") export FTB_DIR=$(dirname "${FTB_SERVER_START}")
chmod a+x "${FTB_SERVER_START}" chmod a+x "${FTB_SERVER_START}"
grep fml.queryResult=confirm "${FTB_SERVER_START}" > /dev/null || \ grep fml.queryResult=confirm ${FTB_SERVER_START} > /dev/null || \
sed -i 's/-jar/-Dfml.queryResult=confirm -jar/' "${FTB_SERVER_START}" sed -i 's/-jar/-Dfml.queryResult=confirm -jar/' "${FTB_SERVER_START}"
sed -i 's/.*read.*Restart now/#\0/' "${FTB_SERVER_START}" sed -i 's/.*read.*Restart now/#\0/' "${FTB_SERVER_START}"
legacyJavaFixerPath="${FTB_DIR}/mods/legacyjavafixer.jar" legacyJavaFixerPath="${FTB_DIR}/mods/legacyjavafixer.jar"

View File

@@ -1,7 +1,6 @@
#!/bin/bash #!/bin/bash
. ${SCRIPTS:-/}start-utils . ${SCRIPTS:-/}start-utils
isDebugging && set -x
if isURL ${CUSTOM_SERVER}; then if isURL ${CUSTOM_SERVER}; then
filename=$(basename ${CUSTOM_SERVER}) filename=$(basename ${CUSTOM_SERVER})
@@ -18,16 +17,12 @@ if isURL ${CUSTOM_SERVER}; then
fi fi
elif [[ -f ${CUSTOM_SERVER} ]]; then elif [[ -f ${CUSTOM_SERVER} ]]; then
export SERVER=${CUSTOM_SERVER} log "Using custom server jar at ${CUSTOM_SERVER} ..."
elif [[ ${GENERIC_PACK} ]]; then
log "Using custom server jar from generic pack at ${CUSTOM_SERVER} ..."
export SERVER=${CUSTOM_SERVER} export SERVER=${CUSTOM_SERVER}
else else
log "CUSTOM_SERVER is not properly set to a URL or existing jar file" log "CUSTOM_SERVER is not properly set to a URL or existing jar file"
exit 2 exit 2
fi fi
export SKIP_LOG4J_CONFIG=true export SKIP_LOG4J_CONFIG=true

72
start-deployFTBA Normal file
View File

@@ -0,0 +1,72 @@
#!/bin/bash
ftbInstallMarker=".ftb-installed"
. ${SCRIPTS:-/}start-utils
isDebugging && set -x
set -e
if ! [[ -v FTB_MODPACK_ID ]]; then
log "ERROR FTB_MODPACK_ID is required with TYPE=FTB"
exit 1
fi
if ! [[ ${FTB_MODPACK_ID} =~ [0-9]+ ]]; then
log "ERROR FTB_MODPACK_ID needs to be numeric"
exit 1
fi
if ! [[ -v FTB_MODPACK_VERSION_ID ]]; then
if ! FTB_MODPACK_VERSION_ID=$(curl -fsSL https://api.modpacks.ch/public/modpack/${FTB_MODPACK_ID} | jq -r '.versions | sort_by(.updated)[-1].id'); then
log "ERROR unable to resolve latest modpack version ID for modpack ${FTB_MODPACK_ID}"
exit 1
fi
elif ! [[ ${FTB_MODPACK_VERSION_ID} =~ [0-9]+ ]]; then
log "ERROR FTB_MODPACK_VERSION_ID needs to be numeric"
exit 1
fi
if ! [ -f "${ftbInstallMarker}" ] || [ $(cat "${ftbInstallMarker}") != "${FTB_MODPACK_ID}=${FTB_MODPACK_VERSION_ID}" ]; then
ftbInstaller=/data/ftb-installer
if ! [[ -f "${ftbInstaller}" ]]; then
log "Downloading FTB installer"
curl -fsSL https://api.modpacks.ch/public/modpack/1/1/server/linux -o "${ftbInstaller}"
chmod +x "${ftbInstaller}"
fi
rm -rf forge*jar mods config libraries defaultconfigs changelogs
log "Installing modpack ID ${FTB_MODPACK_ID}, version ID ${FTB_MODPACK_VERSION_ID}"
${ftbInstaller} ${FTB_MODPACK_ID} ${FTB_MODPACK_VERSION_ID} --noscript --auto
rm -f forge*installer.jar
echo "${FTB_MODPACK_ID}=${FTB_MODPACK_VERSION_ID}" > ${ftbInstallMarker}
writeEula
else
log "FTB modpack ID ${FTB_MODPACK_ID}, version ID ${FTB_MODPACK_VERSION_ID} is ready to go"
fi
isDebugging && cat version.json
forgeVersion=$(jq -r '.targets[] | select(.name == "forge") | .version' version.json)
mcVersion=$(jq -r '.targets[] | select(.name == "minecraft") | .version' version.json)
variants=(
forge-${mcVersion}-${forgeVersion}.jar
forge-${mcVersion}-${forgeVersion}-universal.jar
forge-${mcVersion}-${forgeVersion}-${mcVersion}-universal.jar
)
for f in ${variants[@]}; do
if [ -f $f ]; then
export SERVER=$f
break
fi
done
if ! [ -v SERVER ]; then
log "ERROR unable to locate the installed forge server jar"
ls *.jar
exit 2
fi
# Continue to Final Setup
exec ${SCRIPTS:-/}start-finalSetupWorld $@

View File

@@ -7,34 +7,36 @@ export TYPE=FABRIC
FABRIC_INSTALLER=${FABRIC_INSTALLER:-} FABRIC_INSTALLER=${FABRIC_INSTALLER:-}
FABRIC_INSTALLER_URL=${FABRIC_INSTALLER_URL:-} FABRIC_INSTALLER_URL=${FABRIC_INSTALLER_URL:-}
FABRIC_INSTALLER_VERSION=${FABRIC_INSTALLER_VERSION:-${FABRICVERSION:-LATEST}} FABRICVERSION=${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." log "Checking Fabric version information."
case $FABRIC_INSTALLER_VERSION in case $FABRICVERSION in
LATEST) LATEST)
FABRIC_INSTALLER_VERSION=$(maven-metadata-release https://maven.fabricmc.net/net/fabricmc/fabric-installer/maven-metadata.xml) FABRIC_VERSION=$(maven-metadata-release https://maven.fabricmc.net/net/fabricmc/fabric-installer/maven-metadata.xml)
;;
*)
FABRIC_VERSION=$FABRICVERSION
;; ;;
esac esac
FABRIC_INSTALLER="/tmp/fabric-installer-${FABRIC_INSTALLER_VERSION}.jar" FABRIC_INSTALLER="/tmp/fabric-installer-$FABRIC_VERSION.jar"
markerVersion=$FABRIC_INSTALLER_VERSION
elif [[ -z $FABRIC_INSTALLER ]]; then elif [[ -z $FABRIC_INSTALLER ]]; then
FABRIC_INSTALLER="/tmp/fabric-installer.jar" FABRIC_INSTALLER="/tmp/fabric-installer.jar"
markerVersion=custom
elif [[ ! -e $FABRIC_INSTALLER ]]; then elif [[ ! -e $FABRIC_INSTALLER ]]; then
log "ERROR: the given Fabric installer doesn't exist : $FABRIC_INSTALLER" log "ERROR: the given Fabric installer doesn't exist : $FABRIC_INSTALLER"
exit 2 exit 2
fi fi
installMarker="/data/.fabric-installed-${VANILLA_VERSION}-${markerVersion}" installMarker="/data/.fabric-installed-${VANILLA_VERSION}-${FABRIC_VERSION:-manual}"
debug Checking for installMarker ${installMarker} debug Checking for installMarker ${installMarker}
if [[ ! -e $installMarker ]]; then if [[ ! -e $installMarker ]]; then
if [[ ! -e $FABRIC_INSTALLER ]]; then if [[ ! -e $FABRIC_INSTALLER ]]; then
if [[ -z $FABRIC_INSTALLER_URL ]]; then if [[ -z $FABRIC_INSTALLER_URL ]]; then
log "Downloading installer version $FABRIC_INSTALLER_VERSION" log "Downloading $FABRIC_VERSION"
downloadUrl="https://maven.fabricmc.net/net/fabricmc/fabric-installer/${FABRIC_INSTALLER_VERSION}/fabric-installer-${FABRIC_INSTALLER_VERSION}.jar" downloadUrl="https://maven.fabricmc.net/net/fabricmc/fabric-installer/$FABRIC_VERSION/fabric-installer-$FABRIC_VERSION.jar"
log "...trying $downloadUrl" log "...trying $downloadUrl"
curl -o $FABRIC_INSTALLER -fsSL $downloadUrl curl -o $FABRIC_INSTALLER -fsSL $downloadUrl
else else
@@ -47,17 +49,14 @@ if [[ ! -e $installMarker ]]; then
fi fi
if isDebugging; then if isDebugging; then
debug "Installing Fabric ${VANILLA_VERSION} using $FABRIC_INSTALLER" debug "Installing Fabric $FABRIC_VERSION using $FABRIC_INSTALLER with mcversion ${VANILLA_VERSION}"
else else
log "Installing Fabric using $FABRIC_INSTALLER" log "Installing Fabric $FABRIC_VERSION using $FABRIC_INSTALLER"
fi fi
tries=3 tries=3
set +e set +e
while ((--tries >= 0)); do while ((--tries >= 0)); do
java -jar $FABRIC_INSTALLER server \ java -jar $FABRIC_INSTALLER server -mcversion $VANILLA_VERSION -downloadMinecraft
-mcversion $VANILLA_VERSION \
-downloadMinecraft \
-dir /data
if [[ $? == 0 ]]; then if [[ $? == 0 ]]; then
break break
fi fi

View File

@@ -1,9 +1,8 @@
#!/bin/bash #!/bin/bash
. ${SCRIPTS:-/}start-utils . ${SCRIPTS:-/}start-utils
export TYPE=FORGE export TYPE=FORGE
: ${FORGEVERSION:=RECOMMENDED}
isDebugging && set -x
if [[ -z $FORGE_INSTALLER && -z $FORGE_INSTALLER_URL ]]; then if [[ -z $FORGE_INSTALLER && -z $FORGE_INSTALLER_URL ]]; then
norm=$VANILLA_VERSION norm=$VANILLA_VERSION
@@ -46,8 +45,6 @@ elif [[ -z $FORGE_INSTALLER ]]; then
elif [[ ! -e $FORGE_INSTALLER ]]; then elif [[ ! -e $FORGE_INSTALLER ]]; then
log "ERROR: the given Forge installer doesn't exist : $FORGE_INSTALLER" log "ERROR: the given Forge installer doesn't exist : $FORGE_INSTALLER"
exit 2 exit 2
else
shortForgeVersion=$VANILLA_VERSION-custom
fi fi
installMarker="/data/.forge-installed-$shortForgeVersion" installMarker="/data/.forge-installed-$shortForgeVersion"
@@ -100,11 +97,7 @@ if [ ! -e $installMarker ]; then
log "Finding installed server jar..." log "Finding installed server jar..."
unset -v latest unset -v latest
for file in *forge*.jar; do for file in *forge*.jar; do
if ! [[ $file =~ installer ]]; then [[ $file =~ installer ]] || [[ $file -nt $latest ]] && latest=$file
if [[ -z $latest ]] || [[ $file -nt $latest ]]; then
latest=$file
fi
fi
done done
if [[ -z $latest ]]; then if [[ -z $latest ]]; then
log "Unable to derive server jar for Forge" log "Unable to derive server jar for Forge"

View File

@@ -6,7 +6,6 @@ set -e
isDebugging && set -x isDebugging && set -x
requireVar VANILLA_VERSION requireVar VANILLA_VERSION
: ${MOHIST_BUILD:=lastSuccessfulBuild}
mohistJobs=https://ci.codemc.io/job/Mohist-Community/job/ mohistJobs=https://ci.codemc.io/job/Mohist-Community/job/
mohistJob=${mohistJobs}Mohist-${VANILLA_VERSION}/ mohistJob=${mohistJobs}Mohist-${VANILLA_VERSION}/
@@ -18,12 +17,12 @@ if ! curl -X HEAD -o /dev/null -fsSL "${mohistJob}"; then
exit 1 exit 1
fi fi
buildRelPath=$( latestBuildRelPath=$(
curl -fsSL "${mohistJob}${MOHIST_BUILD}/api/json" | curl -fsSL "${mohistJob}lastSuccessfulBuild/api/json" |
jq -r '.artifacts[0].relativePath' jq -r '.artifacts[0].relativePath'
) )
baseName=$(basename "${buildRelPath}") baseName=$(basename "${latestBuildRelPath}")
if [[ ${baseName} != *-server.jar* ]]; then if [[ ${baseName} != *-server.jar* ]]; then
log "ERROR: mohist build for ${VANILLA_VERSION} is not a valid server jar, found ${baseName}" log "ERROR: mohist build for ${VANILLA_VERSION} is not a valid server jar, found ${baseName}"
log " check https://ci.codemc.io/job/Mohist-Community/ for available versions" log " check https://ci.codemc.io/job/Mohist-Community/ for available versions"
@@ -35,7 +34,7 @@ export SERVER="/data/${baseName}"
if [ ! -f ${SERVER} ]; then if [ ! -f ${SERVER} ]; then
log "Downloading ${baseName}" log "Downloading ${baseName}"
curl -o "${SERVER}" -fsSL "${mohistJob}${MOHIST_BUILD}/artifact/${buildRelPath}" curl -o "${SERVER}" -fsSL "${mohistJob}lastSuccessfulBuild/artifact/${latestBuildRelPath}"
fi fi
export SKIP_LOG4J_CONFIG=true export SKIP_LOG4J_CONFIG=true

View File

@@ -1,79 +1,24 @@
#!/bin/bash #!/bin/bash
. ${SCRIPTS:-/}start-utils . ${SCRIPTS:-/}start-utils
set -o pipefail
isDebugging && set -x
if [[ $PAPER_DOWNLOAD_URL ]]; then : ${PAPERBUILD:=latest}
export SERVER=$(getFilenameFromUrl "${PAPER_DOWNLOAD_URL}") export SERVER=paper_server-${VANILLA_VERSION}-${PAPERBUILD}.jar
if [ -f "$SERVER" ]; then if [ -f "$SERVER" ] && ! isTrue "$FORCE_REDOWNLOAD"; then
zarg=(-z "$SERVER") zarg="-z '$SERVER'"
fi fi
echo "Preparing custom PaperMC jar from $PAPER_DOWNLOAD_URL" downloadUrl=${PAPER_DOWNLOAD_URL:-https://papermc.io/api/v1/paper/${VANILLA_VERSION}/${PAPERBUILD}/download}
log "Downloading Paper $VANILLA_VERSION (build $PAPERBUILD) from $downloadUrl ..."
curl -fsSL -o "$SERVER" "${zarg[@]}" "${PAPER_DOWNLOAD_URL}" if ! curl -fsSL -o "$SERVER" $zarg "$downloadUrl"; then
else log "ERROR: failed to download from $downloadUrl (status=$?)"
# PaperMC API v2 docs : https://papermc.io/api/docs/swagger-ui/index.html?configUrl=/api/openapi/swagger-config exit 3
build=${PAPERBUILD:=$(curl -fsSL "https://papermc.io/api/v2/projects/paper/versions/${VANILLA_VERSION}" -H "accept: application/json" \
| jq '.builds[-1]')}
case $? in
0)
;;
22)
versions=$(curl -fsSL "https://papermc.io/api/v2/projects/paper" -H "accept: application/json")
if [[ $VERSION = LATEST ]]; then
VANILLA_VERSION=$(echo "$versions" | jq -r '.versions[-1]')
log "WARN: using ${VANILLA_VERSION} since that's the latest provided by PaperMC"
# re-execute the current script with the newly computed version
exec "$0" "$@"
fi
log "ERROR: ${VANILLA_VERSION} is not published by PaperMC"
log " Set VERSION to one of the following: "
log " $(echo "$versions" | jq -r '.versions | join(", ")')"
exit 1
;;
*)
echo "ERROR: unknown error while looking up PaperMC version=${VANILLA_VERSION}"
exit 1
;;
esac
if [ $? != 0 ]; then
echo "ERROR: failed to lookup PaperMC build from version ${VANILLA_VERSION}"
exit 1
fi
export SERVER=$(curl -fsSL "https://papermc.io/api/v2/projects/paper/versions/${VANILLA_VERSION}/builds/${build}" -H "accept: application/json" \
| jq -r '.downloads.application.name')
if [ $? != 0 ]; then
echo "ERROR: failed to lookup PaperMC download file from version=${VANILLA_VERSION} build=${build}"
exit 1
fi
if [ -f "$SERVER" ]; then
zarg=(-z "$SERVER")
fi
log "Removing old PaperMC versions ..."
shopt -s nullglob
for f in paper-*.jar; do
[[ $f != $SERVER ]] && rm $f
done
log "Downloading PaperMC $VANILLA_VERSION (build $build) ..."
curl -fsSL -o "$SERVER" "${zarg[@]}" \
"https://papermc.io/api/v2/projects/paper/versions/${VANILLA_VERSION}/builds/${build}/downloads/${SERVER}" \
-H "accept: application/java-archive"
if [ $? != 0 ]; then
echo "ERROR: failed to download PaperMC from version=${VANILLA_VERSION} build=${build} download=${SERVER}"
exit 1
fi
fi fi
# Normalize on Spigot for downstream operations # Normalize on Spigot for downstream operations
export TYPE=SPIGOT export TYPE=SPIGOT
export SKIP_LOG4J_CONFIG=true export SKIP_LOG4J_CONFIG=true
exec ${SCRIPTS:-/}start-spiget "$@" # Continue to Final Setup
exec ${SCRIPTS:-/}start-finalSetupWorld $@

View File

@@ -1,38 +0,0 @@
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
. ${SCRIPTS:-/}start-utils
isDebugging && set -x
: ${VANILLA_VERSION:?}
: ${PURPUR_BUILD:=LATEST}
: ${FORCE_REDOWNLOAD:=false}
if [[ ${PURPUR_BUILD} == LATEST ]]; then
PURPUR_BUILD=$(curl -fsSL "https://purpur.pl3x.net/api/v1/purpur/${VANILLA_VERSION}" |
jq -r '.builds.latest' || echo "")
if [[ -z ${PURPUR_BUILD} ]]; then
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/"
exit 3
fi
fi
export SERVER="purpur-${VANILLA_VERSION}-${PURPUR_BUILD}.jar"
if [ ! -f "$SERVER" ] || isTrue "$FORCE_REDOWNLOAD"; then
downloadUrl="https://purpur.pl3x.net/api/v1/purpur/${VANILLA_VERSION}/${PURPUR_BUILD}/download"
log "Downloading Purpur from $downloadUrl ..."
if ! curl -fsSL -o "$SERVER" "$downloadUrl"; then
log "ERROR: failed to download from $downloadUrl (status=$?)"
exit 3
fi
fi
# Normalize on Spigot for later operations
export TYPE=SPIGOT
export SKIP_LOG4J_CONFIG=true
# Continue to Final Setup
exec ${SCRIPTS:-/}start-finalSetupWorld $@

View File

@@ -3,8 +3,6 @@
. ${SCRIPTS:-/}start-utils . ${SCRIPTS:-/}start-utils
export TYPE=spongevanilla export TYPE=spongevanilla
: ${SPONGEBRANCH:=STABLE}
: ${SPONGEVERSION:=}
# Parse branch # Parse branch
log "Choosing branch for Sponge" log "Choosing branch for Sponge"

View File

@@ -20,7 +20,7 @@ if [ ! -f "$SERVER" ] || [ -n "$FORCE_REDOWNLOAD" ]; then
fi fi
fi fi
# Normalize on Spigot for later operations # Normalize on Spigot for operations below
export TYPE=SPIGOT export TYPE=SPIGOT
# Continue to Final Setup # Continue to Final Setup

View File

@@ -1,30 +0,0 @@
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
. ${SCRIPTS:-/}start-utils
isDebugging && set -x
: ${VANILLA_VERSION:?}
: ${RELEASE:=stable}
: ${FORCE_REDOWNLOAD:=false}
requireEnum RELEASE stable latest
export SERVER="yatopia-${RELEASE}-${VANILLA_VERSION}.jar"
if [ ! -f "$SERVER" ] || isTrue "$FORCE_REDOWNLOAD"; then
downloadUrl="https://api.yatopiamc.org/v2/${RELEASE}Build/download?branch=ver/${VANILLA_VERSION}"
log "Downloading Yatopia from $downloadUrl ..."
if ! curl -fsSL -o "$SERVER" "$downloadUrl"; then
log "ERROR: failed to download from $downloadUrl (status=$?)"
exit 3
fi
fi
# Normalize on Spigot for later operations
export TYPE=SPIGOT
export SKIP_LOG4J_CONFIG=true
# Continue to Final Setup
exec ${SCRIPTS:-/}start-finalSetupWorld $@

View File

@@ -5,7 +5,7 @@
: ${ENV_VARIABLE_PREFIX:=CFG_} : ${ENV_VARIABLE_PREFIX:=CFG_}
if isTrue "${REPLACE_ENV_VARIABLES}"; then if isTrue "${REPLACE_ENV_VARIABLES}"; then
log "Replacing env variables in configs that match the prefix $ENV_VARIABLE_PREFIX ..." log "Replacing env variables in configs that match the prefix $ENV_VARIABLE_PREFIX..."
# File excludes # File excludes
fileExcludes= fileExcludes=
@@ -22,30 +22,28 @@ if isTrue "${REPLACE_ENV_VARIABLES}"; then
isDebugging && echo "Using find file exclusions: $fileExcludes" isDebugging && echo "Using find file exclusions: $fileExcludes"
isDebugging && echo "Using find directory exclusions: $dirExcludes" isDebugging && echo "Using find directory exclusions: $dirExcludes"
for name in $(compgen -v $ENV_VARIABLE_PREFIX); do while IFS='=' read -r name value ; do
# check if name of env variable matches the prefix # check if name of env variable matches the prefix
# sanity check environment variables to avoid code injections # sanity check environment variables to avoid code injections
# Read content from file environment if [[ "$name" = $ENV_VARIABLE_PREFIX* ]] \
if [[ $name = *"_FILE" ]]; then && [[ $value =~ ^[0-9a-zA-Z_:/=?.+\-]*$ ]] \
value=$(<${!name}) && [[ $name =~ ^[0-9a-zA-Z_\-]*$ ]]; then
name="${name%_FILE}" # Read content from file environment
else if [[ $name = *"_FILE" ]] && [[ -f $value ]]; then
value=${!name} name="${name/_FILE/}"
value=$(<$value)
fi
log "Replacing $name with $value ..."
find /data/ \
$dirExcludes \
-type f \
\( -name "*.yml" -or -name "*.yaml" -or -name "*.txt" -or -name "*.cfg" \
-or -name "*.conf" -or -name "*.properties" \) \
$fileExcludes \
-exec sed -i 's#${'"$name"'}#'"$value"'#g' {} \;
fi fi
done < <(env)
log "Replacing $name with $value ..."
value=${value//\\/\\\\}
value=${value//#/\\#}
find /data/ \
$dirExcludes \
-type f \
\( -name "*.yml" -or -name "*.yaml" -or -name "*.txt" -or -name "*.cfg" \
-or -name "*.conf" -or -name "*.properties" \) \
$fileExcludes \
-exec sed -i 's#${'"$name"'}#'"$value"'#g' {} \;
done
fi fi
exec ${SCRIPTS:-/}start-minecraftFinalSetup $@ exec ${SCRIPTS:-/}start-minecraftFinalSetup $@

View File

@@ -24,4 +24,4 @@ case "X$MODCONFIG" in
esac esac
fi fi
exec ${SCRIPTS:-/}start-finalSetupMounts $@ exec ${SCRIPTS:-/}start-finalSetupPlugins $@

View File

@@ -1,30 +1,18 @@
#!/bin/bash #!/bin/bash
set -e -o pipefail set -e
. ${SCRIPTS:-/}start-utils . ${SCRIPTS:-/}start-utils
if isDebugging; then
set -x
fi
# CURSE_URL_BASE used in manifest downloads below # CURSE_URL_BASE used in manifest downloads below
CURSE_URL_BASE=${CURSE_URL_BASE:-https://minecraft.curseforge.com/projects} CURSE_URL_BASE=${CURSE_URL_BASE:-https://minecraft.curseforge.com/projects}
# Remove old mods/plugins # Remove old mods/plugins
if isTrue ${REMOVE_OLD_MODS}; then if [ "$REMOVE_OLD_MODS" = "TRUE" ]; then
remove_mods_dest="/data/mods" if [ "$TYPE" = "SPIGOT" ]; then
case ${TYPE} in rm -rf /data/plugins/*
SPIGOT|BUKKIT|PAPER)
remove_mods_dest="/data/plugins"
;;
esac
# only try to remove existing mods dir
if [ -d "$remove_mods_dest" ]; then
log "Removing old mods in $remove_mods_dest..."
find $remove_mods_dest -mindepth 1 -maxdepth ${REMOVE_OLD_MODS_DEPTH:-16} -wholename "${REMOVE_OLD_MODS_INCLUDE:-*}" -not -wholename "${REMOVE_OLD_MODS_EXCLUDE}" -delete
else else
log "Directory $remove_mods_dest does not exist; removing nothing." rm -rf /data/mods/*
fi fi
fi fi
@@ -34,7 +22,7 @@ if [[ "$MODPACK" ]]; then
if [[ "${MODPACK}" == *.zip ]]; then if [[ "${MODPACK}" == *.zip ]]; then
downloadUrl="${MODPACK}" downloadUrl="${MODPACK}"
else else
downloadUrl=$(curl -Ls -o /dev/null -w %{effective_url} $MODPACK) downloadUrl=$(curl -Ls -o /dev/null -w %{url_effective} $MODPACK)
if ! [[ $downloadUrl == *.zip ]]; then if ! [[ $downloadUrl == *.zip ]]; then
log "ERROR Invalid URL given for MODPACK: $downloadUrl resolved from $MODPACK" log "ERROR Invalid URL given for MODPACK: $downloadUrl resolved from $MODPACK"
log " Must be HTTP or HTTPS and a ZIP file" log " Must be HTTP or HTTPS and a ZIP file"
@@ -70,38 +58,39 @@ fi
# If supplied with a URL for a plugin download it. # If supplied with a URL for a plugin download it.
if [[ "$MODS" ]]; then if [[ "$MODS" ]]; then
if [ "$TYPE" = "SPIGOT" ]; then
out_dir=/data/plugins
else
out_dir=/data/mods
fi
mkdir -p "$out_dir"
for i in ${MODS//,/ } for i in ${MODS//,/ }
do do
if isURL $i; then if isURL $i; then
log "Downloading mod/plugin $i ..." if [[ $i == *.jar ]]; then
if isValidFileURL jar "$i"; then EFFECTIVE_MOD_URL=$i
if ! curl -fsSL -o "${out_dir}/$(getFilenameFromUrl "${i}")" "${i}"; then
log "ERROR: failed to download from $i into $out_dir"
exit 2
fi
else else
effective_url=$(resolveEffectiveUrl "$i") EFFECTIVE_MOD_URL=$(curl -Ls -o /dev/null -w %{url_effective} $i)
if isValidFileURL jar "${effective_url}"; then if ! [[ $EFFECTIVE_MOD_URL == *.jar ]]; then
out_file=$(getFilenameFromUrl "${effective_url}") log "ERROR Invalid URL given in MODS: $EFFECTIVE_MOD_URL resolved from $i"
if ! curl -fsSL -o "${out_dir}/$out_file" "${effective_url}"; then log " Must be HTTP or HTTPS and a JAR file"
log "ERROR: failed to download from $i into $out_dir" exit 1
exit 2
fi
else
log "ERROR: $effective_url resolved from $i is not a valid jar URL"
exit 2
fi fi
fi fi
log "Downloading mod/plugin via HTTP"
log " from $EFFECTIVE_MOD_URL ..."
if ! curl -sSL -o /tmp/${EFFECTIVE_MOD_URL##*/} $EFFECTIVE_MOD_URL; then
log "ERROR: failed to download from $EFFECTIVE_MOD_URL to /tmp/${EFFECTIVE_MOD_URL##*/}"
exit 2
fi
if [ "$TYPE" = "SPIGOT" ]; then
mkdir -p /data/plugins
mv /tmp/${EFFECTIVE_MOD_URL##*/} /data/plugins/${EFFECTIVE_MOD_URL##*/}
else
mkdir -p /data/mods
mv /tmp/${EFFECTIVE_MOD_URL##*/} /data/mods/${EFFECTIVE_MOD_URL##*/}
fi
rm -f /tmp/${EFFECTIVE_MOD_URL##*/}
else else
log "ERROR Invalid URL given in MODS: $i" log "ERROR Invalid URL given in MODS: $i"
exit 2 exit 1
fi fi
done done
fi fi
@@ -111,7 +100,7 @@ if [[ "$MANIFEST" ]]; then
EFFECTIVE_MANIFEST_FILE=$MANIFEST EFFECTIVE_MANIFEST_FILE=$MANIFEST
elif isURL "$MANIFEST"; then elif isURL "$MANIFEST"; then
EFFECTIVE_MANIFEST_FILE=/tmp/manifest.json EFFECTIVE_MANIFEST_FILE=/tmp/manifest.json
EFFECTIVE_MANIFEST_URL=$(curl -Ls -o /dev/null -w %{effective_url} $MANIFEST) EFFECTIVE_MANIFEST_URL=$(curl -Ls -o /dev/null -w %{url_effective} $MANIFEST)
curl -Ls -o $EFFECTIVE_MANIFEST_FILE "$EFFECTIVE_MANIFEST_URL" curl -Ls -o $EFFECTIVE_MANIFEST_FILE "$EFFECTIVE_MANIFEST_URL"
else else
log "MANIFEST='$MANIFEST' is not a valid manifest url or location" log "MANIFEST='$MANIFEST' is not a valid manifest url or location"
@@ -132,7 +121,7 @@ case "X$EFFECTIVE_MANIFEST_FILE" in
do do
if [ ! -f $MOD_DIR/${p}_${f}.jar ] if [ ! -f $MOD_DIR/${p}_${f}.jar ]
then then
redirect_url="$(curl -Ls -o /dev/null -w %{effective_url} ${CURSE_URL_BASE}/${p})" redirect_url="$(curl -Ls -o /dev/null -w %{url_effective} ${CURSE_URL_BASE}/${p})"
url="$redirect_url/download/${f}/file" url="$redirect_url/download/${f}/file"
log Downloading curseforge mod $url log Downloading curseforge mod $url
# Manifest usually doesn't have mod names. Using id should be fine, tho # Manifest usually doesn't have mod names. Using id should be fine, tho
@@ -151,17 +140,17 @@ fi
if [[ "${GENERIC_PACK}" ]]; then if [[ "${GENERIC_PACK}" ]]; then
if isURL "${GENERIC_PACK}"; then if isURL "${GENERIC_PACK}"; then
log "Downloading generic pack ..." generic_pack_url=${GENERIC_PACK}
curl -fsSL -o /tmp/generic_pack.zip "${GENERIC_PACK}" GENERIC_PACK=/tmp/$(basename ${generic_pack_url})
GENERIC_PACK=/tmp/generic_pack.zip log "Downloading generic pack from ${generic_pack_url} ..."
curl -fsSL -o ${GENERIC_PACK} ${generic_pack_url}
fi fi
sum_file=/data/.generic_pack.sum sum_file=/data/.generic_pack.sum
if ! sha256sum -c ${sum_file} -s 2> /dev/null; then if ! sha256sum -c ${sum_file} -s 2> /dev/null; then
base_dir=/tmp/generic_pack_base base_dir=/tmp/generic_pack_base
mkdir -p ${base_dir} mkdir -p ${base_dir}
isDebugging && ls -l "${GENERIC_PACK}" unzip -q -d ${base_dir} ${GENERIC_PACK}
unzip -q -d ${base_dir} "${GENERIC_PACK}"
if [ -f /data/manifest.txt ]; then if [ -f /data/manifest.txt ]; then
log "Manifest exists from older generic pack, cleaning up ..." log "Manifest exists from older generic pack, cleaning up ..."
while read f; do while read f; do
@@ -179,7 +168,7 @@ if [[ "${GENERIC_PACK}" ]]; then
for d in $(find ${base_dir} -type d); do mkdir -p "$(sed "s#${base_dir}#/data#" <<< $d)"; done for d in $(find ${base_dir} -type d); do mkdir -p "$(sed "s#${base_dir}#/data#" <<< $d)"; done
for f in $(find ${base_dir} -type f); do cp -f "$f" "$(sed "s#${base_dir}#/data#" <<< $f)"; done for f in $(find ${base_dir} -type f); do cp -f "$f" "$(sed "s#${base_dir}#/data#" <<< $f)"; done
rm -rf ${base_dir} rm -rf ${base_dir}
sha256sum "${GENERIC_PACK}" > ${sum_file} sha256sum ${GENERIC_PACK} > ${sum_file}
fi fi
fi fi

View File

@@ -1,38 +0,0 @@
#!/bin/bash
. ${SCRIPTS:-/}start-utils
: ${PLUGINS_SYNC_UPDATE:=true}
isDebugging && set -x
if [ -d /plugins ]; then
case ${TYPE} in
SPIGOT|BUKKIT|PAPER|MAGMA)
mkdir -p /data/plugins
log "Copying plugins over..."
if isTrue ${PLUGINS_SYNC_UPDATE}; then
updateArg="--update"
fi
# Copy plugins over using rsync to allow deeply nested updates of plugins
rsync -a --out-format="update:%f:Last Modified %M" --prune-empty-dirs $updateArg /plugins /data
;;
esac
fi
# If any modules have been provided, copy them over
if [ -d /mods ]; then
log "Copying any mods over..."
mkdir -p /data/mods
rsync -a --out-format="update:%f:Last Modified %M" "${rsyncArgs[@]}" --prune-empty-dirs --update /mods /data
fi
: ${COPY_CONFIG_DEST:="/data/config"}
if [ -d /config ]; then
log "Copying any configs from /config to $COPY_CONFIG_DEST"
mkdir -p $COPY_CONFIG_DEST
rsync -a --out-format="update:%f:Last Modified %M" "${rsyncArgs[@]}" --prune-empty-dirs --update /config/ $COPY_CONFIG_DEST
fi
exec ${SCRIPTS:-/}start-finalSetupServerProperties $@

23
start-finalSetupPlugins Executable file
View File

@@ -0,0 +1,23 @@
#!/bin/bash
. ${SCRIPTS:-/}start-utils
: ${PLUGINS_SYNC_UPDATE:=true}
isDebugging && set -x
if [ -d /plugins ]; then
case ${TYPE} in
SPIGOT|BUKKIT|PAPER)
mkdir -p /data/plugins
log "Copying plugins over..."
if isTrue ${PLUGINS_SYNC_UPDATE}; then
updateArg="--update"
fi
# Copy plugins over using rsync to allow deeply nested updates of plugins
rsync -a --out-format="update:%f:Last Modified %M" --prune-empty-dirs $updateArg /plugins /data
;;
esac
fi
exec ${SCRIPTS:-/}start-finalSetupServerProperties $@

View File

@@ -2,8 +2,6 @@
. ${SCRIPTS:-/}start-utils . ${SCRIPTS:-/}start-utils
: ${SERVER_PROPERTIES:=/data/server.properties}
# FUNCTIONS # FUNCTIONS
function setServerProp { function setServerProp {
local prop=$1 local prop=$1
@@ -14,15 +12,10 @@ function setServerProp {
TRUE|FALSE) TRUE|FALSE)
var=${var,,} ;; var=${var,,} ;;
esac esac
if grep "${prop}" "$SERVER_PROPERTIES" > /dev/null; then log "Setting ${prop} to '${var}' in ${SERVER_PROPERTIES}"
log "Setting ${prop} to '${var}' in ${SERVER_PROPERTIES}" sed -i "/^${prop}\s*=/ c ${prop}=${var}" "$SERVER_PROPERTIES"
sed -i "/^${prop}\s*=/ c ${prop}=${var//\\/\\\\}" "$SERVER_PROPERTIES"
else
log "Adding ${prop} with '${var}' in ${SERVER_PROPERTIES}"
echo "${prop}=${var//\\/\\\\}" >> "$SERVER_PROPERTIES"
fi
else else
isDebugging && log "Skip setting ${prop}" log "Skip setting ${prop}"
fi fi
} }
@@ -31,10 +24,6 @@ function customizeServerProps {
log "Creating whitelist" log "Creating whitelist"
setServerProp "whitelist" "true" setServerProp "whitelist" "true"
setServerProp "white-list" "true" setServerProp "white-list" "true"
else
log "Disabling whitelist"
setServerProp "whitelist" "false"
setServerProp "white-list" "false"
fi fi
# If not provided, generate a reasonable default message-of-the-day, # If not provided, generate a reasonable default message-of-the-day,
@@ -80,7 +69,7 @@ function customizeServerProps {
setServerProp "max-world-size" "$MAX_WORLD_SIZE" setServerProp "max-world-size" "$MAX_WORLD_SIZE"
setServerProp "level-name" "$LEVEL" setServerProp "level-name" "$LEVEL"
setServerProp "level-seed" "$SEED" setServerProp "level-seed" "$SEED"
setServerProp "pvp" "${PVP}" setServerProp "pvp" "$PVP"
setServerProp "generator-settings" "$GENERATOR_SETTINGS" setServerProp "generator-settings" "$GENERATOR_SETTINGS"
setServerProp "online-mode" "$ONLINE_MODE" setServerProp "online-mode" "$ONLINE_MODE"
setServerProp "allow-flight" "$ALLOW_FLIGHT" setServerProp "allow-flight" "$ALLOW_FLIGHT"

View File

@@ -4,9 +4,6 @@
set -e set -e
isDebugging && set -x isDebugging && set -x
: ${LEVEL:=world}
export LEVEL
if [ $TYPE = "FEED-THE-BEAST" ]; then if [ $TYPE = "FEED-THE-BEAST" ]; then
worldDest=$FTB_DIR/$LEVEL worldDest=$FTB_DIR/$LEVEL
else else
@@ -14,13 +11,6 @@ else
fi fi
if [[ "$WORLD" ]] && ( isTrue "${FORCE_WORLD_COPY}" || [ ! -d "$worldDest" ] ); then if [[ "$WORLD" ]] && ( isTrue "${FORCE_WORLD_COPY}" || [ ! -d "$worldDest" ] ); then
if isTrue "${FORCE_WORLD_COPY}"; then
log "Removing existing world data in $worldDest ${worldDest}_nether ${worldDest}_the_end"
rm -rf "$worldDest" \
"${worldDest}_nether" \
"${worldDest}_the_end"
fi
if isURL $WORLD; then if isURL $WORLD; then
curl -fsSL "$WORLD" -o /tmp/world.zip curl -fsSL "$WORLD" -o /tmp/world.zip
zipSrc=/tmp/world.zip zipSrc=/tmp/world.zip
@@ -35,12 +25,7 @@ if [[ "$WORLD" ]] && ( isTrue "${FORCE_WORLD_COPY}" || [ ! -d "$worldDest" ] );
mkdir -p /tmp/world-data mkdir -p /tmp/world-data
(cd /tmp/world-data && unzip -o -q "$zipSrc") (cd /tmp/world-data && unzip -o -q "$zipSrc")
if [ "$TYPE" = "SPIGOT" ]; then baseDirs=$(find /tmp/world-data -name "level.dat" -exec dirname "{}" \;)
baseDirs=$(find /tmp/world-data -name "level.dat" -not -path "*_nether*" -not -path "*_the_end*" -exec dirname "{}" \;)
else
baseDirs=$(find /tmp/world-data -name "level.dat" -exec dirname "{}" \;)
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)"
@@ -53,11 +38,6 @@ 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
log "Copying end and 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"
fi
else else
log "Cloning world directory from $WORLD ..." log "Cloning world directory from $WORLD ..."
rsync --recursive --delete "${WORLD%/}"/ "$worldDest" rsync --recursive --delete "${WORLD%/}"/ "$worldDest"
@@ -66,8 +46,8 @@ if [[ "$WORLD" ]] && ( isTrue "${FORCE_WORLD_COPY}" || [ ! -d "$worldDest" ] );
if [ "$TYPE" = "SPIGOT" ]; then if [ "$TYPE" = "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" "/data/${LEVEL}_the_end"
[ -d "$worldDest/DIM-1" ] && mv -f "$worldDest/DIM-1" "${worldDest}_nether" [ -d "$worldDest/DIM-1" ] && mv -f "$worldDest/DIM-1" "/data/${LEVEL}_nether"
fi fi
fi fi

View File

@@ -1,41 +1,30 @@
#!/bin/bash #!/bin/bash
. ${SCRIPTS:-/}start-utils . ${SCRIPTS:-/}start-utils
isDebugging && set -x
if [ -n "$OPS" ]; then if [ -n "$OPS" ]; then
log "Updating ops" log "Setting/adding ops"
rm -f /data/ops.txt.converted rm -rf /data/ops.txt.converted
echo $OPS | awk -v RS=, '{print}' > /data/ops.txt echo $OPS | awk -v RS=, '{print}' > /data/ops.txt
fi fi
if isTrue "${OVERRIDE_OPS}"; then
log "Recreating ops.json file at server startup"
rm -f /data/ops.json
fi
if [ -n "$WHITELIST" ]; then if [ -n "$WHITELIST" ]; then
log "Updating whitelist" log "Setting whitelist"
rm -f /data/white-list.txt.converted rm -rf /data/white-list.txt.converted
echo $WHITELIST | awk -v RS=, '{print}' > /data/white-list.txt echo $WHITELIST | awk -v RS=, '{print}' > /data/white-list.txt
fi fi
if isTrue "${OVERRIDE_WHITELIST}"; then
log "Recreating whitelist.json file at server startup"
rm -f /data/whitelist.json
fi
if [ -n "$ICON" ]; then if [ -n "$ICON" -a ! -e server-icon.png ]; then
if [ ! -e server-icon.png ] || [ "${OVERRIDE_ICON}" == "TRUE" ]; then log "Using server icon from $ICON..."
log "Using server icon from $ICON..." # Not sure what it is yet...call it "img"
# Not sure what it is yet...call it "img" curl -sSL -o /tmp/icon.img $ICON
curl -sSL -o /tmp/icon.img $ICON specs=$(identify /tmp/icon.img | awk '{print $2,$3}')
specs=$(identify /tmp/icon.img | awk '{print $2,$3}') if [ "$specs" = "PNG 64x64" ]; then
if [ "$specs" = "PNG 64x64" ]; then mv /tmp/icon.img /data/server-icon.png
mv /tmp/icon.img /data/server-icon.png else
else log "Converting image to 64x64 PNG..."
log "Converting image to 64x64 PNG..." convert /tmp/icon.img -resize 64x64! /data/server-icon.png
convert /tmp/icon.img -resize 64x64! /data/server-icon.png fi
fi
fi
fi fi
if ! isTrue ${SKIP_LOG4J_CONFIG}; then if ! isTrue ${SKIP_LOG4J_CONFIG}; then
@@ -60,14 +49,32 @@ for j in $JSON_FILES; do
fi fi
done done
# If any modules have been provided, copy them over
if [ -d /mods ]; then
log "Copying any mods over..."
mkdir -p /data/mods
rsync -a --out-format="update:%f:Last Modified %M" --prune-empty-dirs --update /mods /data
fi
[ -d /data/config ] || mkdir /data/config
for c in /config/*
do
if [ -f "$c" ]; then
log Copying configuration $(basename "$c")
cp -rf "$c" /data/config
fi
done
EXTRA_ARGS=""
# Optional disable console # Optional disable console
if versionLessThan 1.14 && [[ ${CONSOLE,,} = false ]]; then if versionLessThan 1.14 && [[ ${CONSOLE,,} = false ]]; then
EXTRA_ARGS+=" --noconsole" EXTRA_ARGS+="--noconsole"
fi fi
# Optional disable GUI for headless servers # Optional disable GUI for headless servers
if [[ ${GUI} = false || ${GUI} = FALSE ]]; then if [[ ${GUI} = false || ${GUI} = FALSE ]]; then
EXTRA_ARGS+=" nogui" EXTRA_ARGS="${EXTRA_ARGS} nogui"
fi fi
# put these prior JVM_OPTS at the end to give any memory settings there higher precedence # put these prior JVM_OPTS at the end to give any memory settings there higher precedence
@@ -82,6 +89,7 @@ if [ -n "$JVM_DD_OPTS" ]; then
fi fi
if isTrue ${ENABLE_JMX}; then if isTrue ${ENABLE_JMX}; then
: ${JMX_HOST:=0.0.0.0}
: ${JMX_PORT:=7091} : ${JMX_PORT:=7091}
JVM_OPTS="${JVM_OPTS} JVM_OPTS="${JVM_OPTS}
-Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.local.only=false
@@ -89,8 +97,8 @@ if isTrue ${ENABLE_JMX}; then
-Dcom.sun.management.jmxremote.rmi.port=${JMX_PORT} -Dcom.sun.management.jmxremote.rmi.port=${JMX_PORT}
-Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.host=${JMX_BINDING:-0.0.0.0} -Dcom.sun.management.jmxremote.host=${JMX_HOST}
-Djava.rmi.server.hostname=${JMX_HOST:-localhost}" -Djava.rmi.server.hostname=${JMX_HOST}"
log "JMX is enabled. Make sure you have port forwarding for ${JMX_PORT}" log "JMX is enabled. Make sure you have port forwarding for ${JMX_PORT}"
fi fi
@@ -155,17 +163,17 @@ JVM_OPTS="-Xms${INIT_MEMORY} -Xmx${MAX_MEMORY} ${JVM_OPTS}"
function copyFilesForCurseForge() { function copyFilesForCurseForge() {
# copy player modification files unconditionally since their # copy player modification files unconditionally since their
# processing into json is additive anyway # processing into json is additive anyway
[ -f /data/ops.txt ] && cp -f /data/ops.txt "${FTB_DIR}/" [ -f /data/ops.txt ] && cp -f /data/ops.txt ${FTB_DIR}/
[ -f /data/white-list.txt ] && cp -f /data/white-list.txt "${FTB_DIR}/" [ -f /data/white-list.txt ] && cp -f /data/white-list.txt ${FTB_DIR}/
if [ ! -e "${FTB_DIR}/server-icon.png" -a -e /data/server-icon.png ]; then if [ ! -e "${FTB_DIR}/server-icon.png" -a -e /data/server-icon.png ]; then
cp -f /data/server-icon.png "${FTB_DIR}/" cp -f /data/server-icon.png ${FTB_DIR}/
fi fi
cp -f /data/eula.txt "${FTB_DIR}/" cp -f /data/eula.txt "${FTB_DIR}/"
} }
mcServerRunnerArgs="--stop-duration ${STOP_DURATION:-60}s" mcServerRunnerArgs="--stop-duration 60s"
if [[ ${TYPE} == "CURSE_INSTANCE" ]]; then if [[ ${TYPE} == "CURSE_INSTANCE" ]]; then
if isTrue ${DEBUG_EXEC}; then if isTrue ${DEBUG_EXEC}; then
set -x set -x
@@ -173,7 +181,7 @@ if [[ ${TYPE} == "CURSE_INSTANCE" ]]; then
exec mc-server-runner ${mcServerRunnerArgs} \ exec mc-server-runner ${mcServerRunnerArgs} \
--cf-instance-file "${CURSE_INSTANCE_JSON}" \ --cf-instance-file "${CURSE_INSTANCE_JSON}" \
java $JVM_XX_OPTS $JVM_OPTS $expandedDOpts -jar _SERVERJAR_ "$@" $EXTRA_ARGS java $JVM_XX_OPTS $JVM_OPTS $expandedDOpts -jar _SERVERJAR_ "$@" $EXTRA_ARGS
elif [[ ${TYPE} == "FEED-THE-BEAST" && "${SERVER}" ]]; then elif [[ ${TYPE} == "CURSEFORGE" && "${SERVER}" ]]; then
copyFilesForCurseForge copyFilesForCurseForge
cd "${FTB_DIR}" cd "${FTB_DIR}"
@@ -182,7 +190,7 @@ elif [[ ${TYPE} == "FEED-THE-BEAST" && "${SERVER}" ]]; then
set -x set -x
fi fi
exec mc-server-runner ${bootstrapArgs} ${mcServerRunnerArgs} java $JVM_XX_OPTS $JVM_OPTS $expandedDOpts -jar $(basename "${SERVER}") "$@" $EXTRA_ARGS exec mc-server-runner ${bootstrapArgs} ${mcServerRunnerArgs} java $JVM_XX_OPTS $JVM_OPTS $expandedDOpts -jar $(basename "${SERVER}") "$@" $EXTRA_ARGS
elif [[ ${TYPE} == "FEED-THE-BEAST" ]]; then elif [[ ${TYPE} == "CURSEFORGE" ]]; then
mcServerRunnerArgs="${mcServerRunnerArgs} --shell bash" mcServerRunnerArgs="${mcServerRunnerArgs} --shell bash"
copyFilesForCurseForge copyFilesForCurseForge

View File

@@ -1,58 +0,0 @@
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
. ${SCRIPTS:-/}start-utils
handleDebugMode
: ${SPIGET_RESOURCES:=}
containsJars() {
file=${1?}
pat='\.jar$'
while read -r line; do
if [[ $line =~ $pat ]]; then
return 0
fi
done <<< $(unzip -l "$file")
return 1
}
getResourceFromSpiget() {
resource=${1?}
log "Downloading resource ${resource} ..."
tmpfile="/tmp/${resource}.zip"
url="https://api.spiget.org/v2/resources/${resource}/download"
if ! curl -o "${tmpfile}" -fsSL -H "User-Agent: itzg/minecraft-server" "${extraCurlArgs[@]}" "${url}"; then
log "ERROR failed to download resource '${resource}' from ${url}"
exit 2
fi
mkdir -p /data/plugins
if containsJars "${tmpfile}"; then
log "Extracting contents of resource ${resource} into plugins"
unzip -o -q -d /data/plugins "${tmpfile}"
rm "${tmpfile}"
else
log "Moving resource ${resource} into plugins"
mv "${tmpfile}" "/data/plugins/${resource}.jar"
fi
}
if [[ ${SPIGET_RESOURCES} ]]; then
log "Getting plugins via Spiget"
IFS=',' read -r -a resources <<< "${SPIGET_RESOURCES}"
for resource in "${resources[@]}"
do
getResourceFromSpiget "${resource}"
done
fi
# Continue to Final Setup
exec ${SCRIPTS:-/}start-finalSetupWorld $@

View File

@@ -1,14 +1,8 @@
#!/bin/bash #!/bin/bash
function join_by() { function join_by { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; }
local d=$1
shift
echo -n "$1"
shift
printf "%s" "${@/#/$d}"
}
function isURL() { function isURL {
local value=$1 local value=$1
if [[ ${value:0:8} == "https://" || ${value:0:7} == "http://" ]]; then if [[ ${value:0:8} == "https://" || ${value:0:7} == "http://" ]]; then
@@ -18,121 +12,90 @@ function isURL() {
fi fi
} }
function isValidFileURL() { function isTrue {
suffix=${1:?Missing required suffix arg}
url=${2:?Missing required url arg}
[[ "$url" == http*://*.${suffix} || "$url" == http*://*.${suffix}\?* ]]
}
function resolveEffectiveUrl() {
url="${1:?Missing required url argument}"
if ! curl -Ls -o /dev/null -w %{url_effective} "$url"; then
log "ERROR failed to resolve effective URL from $url"
exit 2
fi
}
function getFilenameFromUrl() {
url="${1:?Missing required url argument}"
strippedOfQuery="${url%\?*}"
basename "$strippedOfQuery"
}
function isTrue() {
local value=${1,,} local value=${1,,}
result= result=
case ${value} in case ${value} in
true | on) true|on)
result=0 result=0
;; ;;
*) *)
result=1 result=1
;; ;;
esac esac
return ${result} return ${result}
} }
function isDebugging() { function isDebugging {
if isTrue "${DEBUG:-false}"; then if [[ -v DEBUG ]] && [[ ${DEBUG^^} = TRUE ]]; then
return 0 return 0
else else
return 1 return 1
fi fi
} }
function handleDebugMode() { function debug {
if isDebugging; then
set -x
extraCurlArgs=(-v)
fi
}
function debug() {
if isDebugging; then if isDebugging; then
log "DEBUG: $*" log "DEBUG: $*"
fi fi
} }
function logn() { function logn {
echo -n "[init] $*" echo -n "[init] $*"
} }
function log() { function log {
echo "[init] $*" echo "[init] $*"
} }
function logAutopause() { function logAutopause {
echo "[Autopause loop] $*" echo "[Autopause loop] $*"
} }
function logAutopauseAction() { function logAutopauseAction {
echo "[$(date -Iseconds)] [Autopause] $*" echo "[$(date -Iseconds)] [Autopause] $*"
} }
function normalizeMemSize() { function normalizeMemSize {
local scale=1 local scale=1
case ${1,,} in case ${1,,} in
*k) *k)
scale=1024 scale=1024;;
;; *m)
*m) scale=1048576;;
scale=1048576 *g)
;; scale=1073741824;;
*g)
scale=1073741824
;;
esac esac
val=${1:0:-1} val=${1:0: -1}
echo $((val * scale)) echo $(( val * scale ))
} }
function versionLessThan() { function versionLessThan {
local activeParts local activeParts
IFS=. read -ra activeParts <<<"${VANILLA_VERSION}" IFS=. read -ra activeParts <<< "${VANILLA_VERSION}"
local givenParts local givenParts
IFS=. read -ra givenParts <<<"$1" IFS=. read -ra givenParts <<< "$1"
if ((${#activeParts[@]} < 2)); then if (( ${#activeParts[@]} < 2 )); then
return 1 return 1
fi fi
if ((${#activeParts[@]} == 2)); then if (( ${#activeParts[@]} == 2 )); then
if ((activeParts[0] < givenParts[0])) || if (( activeParts[0] < givenParts[0] )) || \
((activeParts[0] == givenParts[0] && activeParts[1] < givenParts[1])); then (( activeParts[0] == givenParts[0] && activeParts[1] < givenParts[1] )); then
return 0 return 0
else else
return 1 return 1
fi fi
else else
if ((activeParts[0] < givenParts[0])) || if (( activeParts[0] < givenParts[0] )) || \
((activeParts[0] == givenParts[0] && activeParts[1] < givenParts[1])) || (( activeParts[0] == givenParts[0] && activeParts[1] < givenParts[1] )) || \
((activeParts[0] == givenParts[0] && activeParts[1] == givenParts[1] && activeParts[2] < givenParts[2])); then (( activeParts[0] == givenParts[0] && activeParts[1] == givenParts[1] && activeParts[2] < givenParts[2] )); then
return 0 return 0
else else
return 1 return 1
@@ -151,26 +114,11 @@ requireVar() {
fi fi
} }
requireEnum() {
var=${1?}
shift
for allowed in $*; do
if [[ ${!var} = $allowed ]]; then
return 0
fi
done
log "ERROR: $var must be set to one of $@"
# exit 1
}
function writeEula() { function writeEula() {
if ! echo "# Generated via Docker if ! echo "# Generated via Docker on $(date)
# $(date)
eula=${EULA,,} eula=${EULA,,}
" >/data/eula.txt; then " > /data/eula.txt; then
log "ERROR: unable to write eula to /data. Please make sure attached directory is writable by uid=${UID}" log "ERROR: unable to write eula to /data. Please make sure attached directory is writable by uid=${UID}"
exit 2 exit 2
fi fi
} }