Compare commits

..

23 Commits

Author SHA1 Message Date
Geoff Bourne
9affd5e446 Auto-merging via docker-versions-create 2020-08-09 13:07:09 -05:00
Geoff Bourne
fbca7982c5 Auto-merging via docker-versions-create 2020-07-26 08:29:57 -05:00
Geoff Bourne
ce6ce0adbc Auto-merging via docker-versions-create 2020-07-18 18:40:24 -05:00
Geoff Bourne
5e0e7999a9 Auto-merging via docker-versions-create 2020-07-11 13:13:26 -05:00
Geoff Bourne
34e661267d Auto-merging via docker-versions-create 2020-07-10 17:11:28 -05:00
Geoff Bourne
55a539860e Auto-merging via docker-versions-create 2020-07-04 14:57:53 -05:00
Geoff Bourne
26b5647ca2 Auto-merging via docker-versions-create 2020-06-20 15:44:49 -05:00
Geoff Bourne
bfdb5c075b Auto-merging via docker-versions-create 2020-06-19 13:26:45 -05:00
Geoff Bourne
bd4a184ad7 Auto-merging via docker-versions-create 2020-05-20 08:14:52 -05:00
Geoff Bourne
156786dacf Auto-merging via docker-versions-create 2020-05-02 09:34:17 -05:00
Geoff Bourne
92186c9c8e Auto-merging via docker-versions-create 2020-04-25 12:10:54 -05:00
Geoff Bourne
74ee8a621c Auto-merging via docker-versions-create 2020-04-17 21:28:57 -05:00
Geoff Bourne
64345b0d82 Auto-merging via docker-versions-create 2020-04-11 08:51:46 -05:00
Geoff Bourne
5b45c4ea4e Auto-merging via docker-versions-create 2020-04-10 11:08:53 -05:00
Geoff Bourne
a15e608421 Auto-merging via docker-versions-create 2020-04-03 13:31:40 -05:00
Geoff Bourne
f4561b7a3b Auto-merging via docker-versions-create 2020-04-03 13:28:52 -05:00
Geoff Bourne
c6f0042686 Auto-merging via docker-versions-create 2020-04-02 17:47:41 -05:00
Geoff Bourne
79aabf82ff Auto-merging via docker-versions-create 2020-03-30 08:32:02 -05:00
Geoff Bourne
89b60c7706 Auto-merging via docker-versions-create 2020-03-26 20:54:13 -05:00
Geoff Bourne
4b4cbdfce1 Auto-merging via docker-versions-create 2020-02-01 08:53:03 -06:00
Geoff Bourne
a424346d0c Auto-merging via docker-versions-create 2020-01-17 08:29:12 -06:00
Geoff Bourne
fad48505d7 Auto-merging via docker-versions-create 2019-11-16 09:31:01 -06:00
Geoff Bourne
a535fb7873 Add adoptopenjdk/openjdk11:alpine-jre variant 2019-11-16 09:09:55 -06:00
40 changed files with 347 additions and 945 deletions

View File

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

View File

@@ -1,82 +0,0 @@
name: Build and publish multiarch
on:
push:
branches:
- multiarch
- java8-multiarch
- multiarch-latest
- java15
- test/multiarch/*
tags:
- "[0-9]+.[0-9]+.[0-9]+-multiarch"
- "[0-9]+.[0-9]+.[0-9]+-multiarch-latest"
- "[0-9]+.[0-9]+.[0-9]+-java15"
jobs:
docker-buildx:
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v2.2.0
- name: Prepare
id: prep
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 }}-
- 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:
branches:
- master
- java8
- openj9
- openj9-11
- openj9-nightly
- adopt11
- test/*
- adopt13
tags:
- "[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-11"
- "[0-9]+.[0-9]+.[0-9]+-openj9-nightly"
- "[0-9]+.[0-9]+.[0-9]+-adopt11"
- "[0-9]+.[0-9]+.[0-9]+-adopt13"
jobs:
test:
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
@@ -30,68 +28,20 @@ jobs:
build:
needs:
- test
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Prepare
id: prep
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
- name: Build and push Docker images
uses: docker/build-push-action@v1.1.0
with:
repository: itzg/minecraft-server
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
# ensure latest base image is used
pull: true
# publish
tag_with_ref: true
tag_with_sha: false
cache_froms: itzg/minecraft-server:latest
add_git_labels: true
labels: org.opencontainers.image.url=https://github.com/itzg/docker-minecraft-server,org.opencontainers.image.documentation=https://github.com/itzg/docker-minecraft-server
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 }}

View File

@@ -1,11 +0,0 @@
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,28 +1,32 @@
FROM adoptopenjdk:15-jre
FROM adoptopenjdk/openjdk11:alpine-jre
LABEL org.opencontainers.image.authors="Geoff Bourne <itzgeoff@gmail.com>"
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \
apt-get install -y \
imagemagick \
gosu \
sudo \
net-tools \
curl wget \
jq \
dos2unix \
mysql-client \
tzdata \
rsync \
nano \
unzip \
knockd \
ttf-dejavu \
&& apt-get clean
# upgrade all packages since alpine jre8 base image tops out at 8u212
RUN apk -U --no-cache upgrade
RUN addgroup --gid 1000 minecraft \
&& adduser --system --shell /bin/false --uid 1000 --ingroup minecraft --home /data minecraft
RUN apk add --no-cache -U \
openssl \
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
@@ -30,9 +34,9 @@ EXPOSE 25565 25575
# hook into docker BuildKit --platform support
# see https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope
ARG TARGETOS
ARG TARGETARCH
ARG TARGETVARIANT
ARG TARGETOS=linux
ARG TARGETARCH=amd64
ARG TARGETVARIANT=""
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
@@ -51,7 +55,7 @@ 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
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
RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \
@@ -66,12 +70,11 @@ COPY log4j2.xml /tmp/log4j2.xml
WORKDIR /data
ENV UID=1000 GID=1000 \
MEMORY="1G" \
TYPE=VANILLA VERSION=LATEST \
ENABLE_RCON=true RCON_PORT=25575 RCON_PASSWORD=minecraft \
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 \
AUTOPAUSE_PERIOD=10 AUTOPAUSE_KNOCK_INTERFACE=eth0
JVM_XX_OPTS="-XX:+UseG1GC" MEMORY="1G" \
TYPE=VANILLA VERSION=LATEST FORGEVERSION=RECOMMENDED SPONGEBRANCH=STABLE SPONGEVERSION= FABRICVERSION=LATEST LEVEL=world \
PVP=true DIFFICULTY=easy ENABLE_RCON=true RCON_PORT=25575 RCON_PASSWORD=minecraft \
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 AUTOPAUSE_PERIOD=10
COPY start* /
COPY health.sh /

193
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 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)
[![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)
[![](https://img.shields.io/badge/Donate-Buy%20me%20a%20coffee-orange.svg)](https://www.buymeacoffee.com/itzg)
@@ -116,24 +116,8 @@ to map a directory on your host machine to the container's `/data` directory, su
docker run -d -v /path/on/host:/data ...
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 CONTAINER_ID` to pick up the new configuration.
As example, using Docker compose, create the following `docker-compose.yml` in its own directory and the container will automatically create/attach the relative directory `data` to the container:
```yaml
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
```
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
@@ -160,31 +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.
| Tag name | Java version | Linux | JVM Type | Architecture |
| -------------- | -------------|--------|----------|-------------------|
| latest | 11 | Alpine | Hotspot | amd64 |
| java8 | 8 | Alpine | Hotspot | amd64 |
| java8-multiarch | 8 | Debian | Hotspot | amd64,arm64,armv7 |
| java15 | 15 | Debian | Hotspot | amd64,arm64,armv7 |
| adopt11 | 11 | Alpine | Hotspot | amd64 |
| 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 |
| Tag name | Description | Linux |
| -------------- | ------------------------------------------- | ------------ |
| latest | **Default**. Uses Java version 8 update 212 | Alpine Linux |
| adopt13 | Uses Java version 13 latest update | Alpine Linux |
| adopt11 | Uses Java version 11 latest update | Alpine Linux |
| openj9 | Uses Eclipse OpenJ9 JVM | Alpine Linux |
| openj9-nightly | Uses Eclipse OpenJ9 JVM testing builds | Alpine Linux |
| multiarch | Uses Java version 8 latest update | Debian Linux |
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.
### Deprecated Image Tags
The following image tags have been deprecated and are no longer receiving updates:
- adopt13
- adopt14
- adopt15
- openj9-nightly
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.
## Healthcheck
@@ -206,22 +179,22 @@ 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`.
## Autopause
## 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. Non-vanilla versions might have their own configuration file, you might have to disable their watchdogs separately (e.g. PAPER Servers).
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.
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
@@ -232,7 +205,7 @@ Enable the Autopause functionality by setting:
-e ENABLE_AUTOPAUSE=TRUE
```
The following environment variables define the behaviour of auto-pausing:
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)
@@ -241,8 +214,6 @@ describes the time between server start and the pausing of the process, when no
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.
## Deployment Templates and Examples
@@ -255,19 +226,14 @@ describes period of the daemonized state machine, that handles the pausing of th
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
Enable [Forge server](http://www.minecraftforge.net/wiki/) mode by adding a `-e TYPE=FORGE` to your command-line.
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`.
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/)
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 \
-e TYPE=FORGE \
-e VERSION=1.12.2 -e FORGEVERSION=14.23.5.2854 \
-e TYPE=FORGE -e FORGEVERSION=10.13.4.1448 \
-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
@@ -330,17 +296,13 @@ 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. If you want old mods to be removed as the `/mods` content is updated, then add `-e REMOVE_OLD_MODS=TRUE`. If you are running a `BUKKIT` distribution this will affect all files inside the `plugins/` directory. You can fine tune the removal process by specifing 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 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.
`/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.
You can specify the destination of the configs that are located inside the `/config` mount by setting the `COPY_CONFIG_DEST` variable. The configs are copied recursivly to the `/data/config` directory by default. If a file was updated directly inside the `/data/*` directoy and is newer than the file in the `/config/*` mount it will not be overriden.
> For example: `-v ./config:/config -e COPY_CONFIG_DEST=/data` will allow you to copy over your `bukkit.yml` and so on directly into the server directory.
### Replacing variables inside configs
@@ -459,9 +421,9 @@ 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 Paper server
## Running a PaperSpigot server
Enable Paper server mode by adding a `-e TYPE=PAPER` to your command-line.
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`.
@@ -470,7 +432,7 @@ but you can also choose to run a specific build with `-e PAPERBUILD=205`.
-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:
If you are hosting your own copy of PaperSpigot you can override the download URL with:
- -e PAPER_DOWNLOAD_URL=<url>
@@ -487,30 +449,6 @@ A [Tuinity](https://github.com/Spottedleaf/Tuinity) server, which is a fork of P
> **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
@@ -539,12 +477,12 @@ A [Catserver](http://catserver.moe/) type server can be used with
## 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).
> **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](https://www.feed-the-beast.com/modpack) and using the "ID" displayed next to the name
- `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
@@ -588,12 +526,6 @@ The following example uses `/modpacks` as the container path as the pre-download
-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`.
@@ -625,31 +557,29 @@ Just change it with `SPONGEBRANCH`, such as:
## 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`.
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 \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
```
$ 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
A specific installer version can be requested using `FABRIC_INSTALLER_VERSION`.
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:
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 ...
```
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:
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 ...
```
docker run -d -v /path/on/host:/data ... \
-e FABRIC_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:
In order to add mods, you have two options.
### Using the /data volume
@@ -800,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.
> 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
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 ...
> 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
A server icon can be configured using the `ICON` variable. The image will be automatically
@@ -819,10 +743,6 @@ downloaded, scaled, and converted from any other image format:
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
To use rcon use the `ENABLE_RCON` and `RCON_PASSORD` variables.
@@ -989,7 +909,7 @@ environment variable set to `false`, such as
### Level Type and Generator Settings
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
- FLAT
@@ -997,8 +917,6 @@ be configured by setting `LEVEL_TYPE` to an expected type, for example
- AMPLIFIED
- CUSTOMIZED
- 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).
@@ -1129,18 +1047,19 @@ is passed to `docker run`.
### 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
- `INIT_MEMORY`: independently sets the initial heap size
- `MAX_MEMORY`: independently sets the max heap size
- `MEMORY`, "1G" by default, can be used to adjust both initial (`Xms`) and max (`Xmx`)
memory settings of the JVM
- `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
> 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
General JVM options can be passed to the Minecraft Server invocation by passing a `JVM_OPTS`
@@ -1185,10 +1104,6 @@ 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
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.
## Running on RaspberryPi
To run this image on a RaspberryPi 3 B+, 4, or newer, use the image tag

View File

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

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

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

@@ -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>.

View File

@@ -2,48 +2,23 @@
. /autopause/autopause-fcns.sh
. ${SCRIPTS:-/}start-utils
. /start-utils
autopause_error_loop() {
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."
sudo /usr/sbin/knockd -c /tmp/knockd-config.cfg -d
if [ $? -ne 0 ] ; then
while :
do
sleep 1800
logAutopause "Autopause failed to initialize."
if [[ -n $(ps -o comm | grep java) ]] ; then
break
fi
sleep 0.1
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 "Probable cause: Unable to attach to interface \"$AUTOPAUSE_KNOCK_INTERFACE\"."
autopause_error_loop
logAutopause "Possible cause: docker's host network mode."
logAutopause "Recreate without host mode or disable autopause functionality."
logAutopause "Stopping server."
killall -SIGTERM java
exit 1
fi
STATE=INIT

View File

@@ -5,19 +5,15 @@ current_uptime() {
}
java_running() {
[[ $( ps -ax -o stat,comm | grep 'java' | awk '{ print $1 }') =~ ^S.*$ ]]
}
java_process_exists() {
[[ -n "$(ps -ax -o comm | grep 'java')" ]]
[[ $( ps -a -o stat,comm | grep 'java' | awk '{ print $1 }') =~ ^S.*$ ]]
}
rcon_client_exists() {
[[ -n "$(ps -ax -o comm | grep 'rcon-cli')" ]]
[[ -n "$(ps -a -o comm | grep 'rcon-cli')" ]]
}
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() {
@@ -33,7 +29,7 @@ java_clients_connected() {
# remember, that the host network mode does not work with autopause because of the knockd utility
for (( i=0; i<${#connections[@]}; i++ ))
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
return 0
fi

View File

@@ -3,10 +3,10 @@
[unpauseMCServer-server]
sequence = 25565
seq_timeout = 1
command = /usr/sbin/gosu minecraft:minecraft /autopause/resume.sh
command = /sbin/su-exec minecraft:minecraft /autopause/resume.sh
tcpflags = syn
[unpauseMCServer-rcon]
sequence = 25575
seq_timeout = 1
command = /usr/sbin/gosu minecraft:minecraft /autopause/resume.sh
command = /sbin/su-exec minecraft:minecraft /autopause/resume.sh
tcpflags = syn

View File

@@ -2,7 +2,7 @@
. /start-utils
if [[ $( ps -ax -o stat,comm | grep 'java' | awk '{ print $1 }') =~ ^S.*$ ]] ; then
if [[ $( ps -a -o stat,comm | grep 'java' | awk '{ print $1 }') =~ ^S.*$ ]] ; then
# save world
rcon-cli save-all >/dev/null
@@ -17,5 +17,5 @@ if [[ $( ps -ax -o stat,comm | grep 'java' | awk '{ print $1 }') =~ ^S.*$ ]] ; t
# finally pause the process
logAutopauseAction "Pausing Java process"
pkill -STOP java
killall -q -STOP java
fi

View File

@@ -2,7 +2,7 @@
. /start-utils
if [[ $( ps -ax -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"
pkill -CONT java
killall -q -CONT java
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

View File

@@ -5,7 +5,7 @@
if isTrue "${DISABLE_HEALTHCHECK}"; then
echo "Healthcheck disabled"
exit 0
elif isTrue "${ENABLE_AUTOPAUSE}" && [[ "$( ps -ax -o stat,comm | grep 'java' | awk '{ print $1 }')" =~ ^T.*$ ]]; then
elif isTrue "${ENABLE_AUTOPAUSE}" && [[ "$( ps -a -o stat,comm | grep 'java' | awk '{ print $1 }')" =~ ^T.*$ ]]; then
echo "Java process suspended by Autopause function"
exit 0
else

2
start
View File

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

View File

@@ -46,15 +46,10 @@ if ! [[ $AUTOPAUSE_TIMEOUT_INIT =~ ^[0-9]+$ ]] ; then
export AUTOPAUSE_TIMEOUT_INIT
log "Warning: AUTOPAUSE_TIMEOUT_INIT is not numeric, set to 600 (seconds)"
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)"
elif [[ -z "$MAX_TICK_TIME" ]] ; then
else
if versionLessThan 1.8.1; then
# 10 years
MAX_TICK_TIME=315360000000

View File

@@ -1,20 +1,12 @@
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
. ${SCRIPTS:-/}start-utils
: ${EULA:=}
: ${PROXY:=}
: ${RCON_PASSWORD_FILE:=}
shopt -s nullglob
#umask 002
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 ! isTrue "$EULA"; then
log ""
@@ -30,6 +22,15 @@ if [ ! -e /data/eula.txt ]; then
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
export http_proxy="$PROXY"
export https_proxy="$PROXY"
@@ -94,10 +95,6 @@ case "${TYPE^^}" in
;;
FORGE)
log "**********************************************************************"
log "WARNING: The image tag itzg/minecraft-server:java8 is recommended"
log " since some mods require Java 8"
log "**********************************************************************"
exec ${SCRIPTS:-/}start-deployForge "$@"
;;
@@ -105,15 +102,7 @@ case "${TYPE^^}" in
exec ${SCRIPTS:-/}start-deployFabric "$@"
;;
FTBA)
exec ${SCRIPTS:-/}start-deployFTBA "$@"
;;
FTB|CURSEFORGE)
log "**********************************************************************"
log "WARNING: The image tag itzg/minecraft-server:java8 is recommended"
log " since some mods require Java 8"
log "**********************************************************************"
exec ${SCRIPTS:-/}start-deployCF "$@"
;;
@@ -145,19 +134,11 @@ case "${TYPE^^}" in
exec ${SCRIPTS:-/}start-deployCatserver "$@"
;;
PURPUR)
exec ${SCRIPTS:-/}start-deployPurpur "$@"
;;
YATOPIA)
exec ${SCRIPTS:-/}start-deployYatopia "$@"
;;
*)
log "Invalid type: '$TYPE'"
log "Must be: VANILLA, FORGE, BUKKIT, SPIGOT, PAPER, FTBA (multiarch-only),"
log " CURSE_INSTANCE, CURSEFORGE, SPONGEVANILLA, TUINITY, PURPUR"
log " CUSTOM, MAGMA, MOHIST, CATSERVER, YATOPIA"
log " CURSE_INSTANCE, CURSEFORGE, SPONGEVANILLA,"
log " CUSTOM, MAGMA, MOHIST, CATSERVER"
exit 1
;;

View File

@@ -1,7 +1,6 @@
#!/bin/bash
. ${SCRIPTS:-/}start-utils
isDebugging && set -x
set -e
@@ -59,24 +58,16 @@ function downloadSpigot {
;;
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
downloadUrl="https://cdn.getbukkit.org/${getbukkitFlavor}/${getbukkitFlavor}-${VANILLA_VERSION}.jar"
fi
setServerVar
if [ -f $SERVER ]; then
# tell curl to only download when newer
curlArgs="-z $SERVER"
fi
if isDebugging; then
curlArgs="$curlArgs -v"
zarg="-z $SERVER"
fi
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
cat <<EOF
@@ -85,13 +76,6 @@ ERROR: failed to download from $downloadUrl
exact version, such as 1.4.6-R0.4-SNAPSHOT or 1.8-R0.1-SNAPSHOT-LATEST
EOF
if isDebugging && [[ $(grep -c "DOCTYPE html" $SERVER) != 0 ]]; then
cat $SERVER
fi
# remove invalid download
rm $SERVER
exit 3
fi
@@ -99,19 +83,17 @@ EOF
export JVM_OPTS
}
function setServerVar {
case "$TYPE" in
*BUKKIT|*bukkit)
export SERVER=craftbukkit_server-${VANILLA_VERSION}.jar
;;
*)
export SERVER=spigot_server-${VANILLA_VERSION}.jar
;;
esac
}
case "$TYPE" in
*BUKKIT|*bukkit)
export SERVER=craftbukkit_server-${VANILLA_VERSION}.jar
;;
*)
export SERVER=spigot_server-${VANILLA_VERSION}.jar
;;
esac
if isTrue "$BUILD_SPIGOT_FROM_SOURCE" || isTrue "$BUILD_FROM_SOURCE"; then
setServerVar
if [ ! -f $SERVER ] || [ -n "$FORCE_REDOWNLOAD" ]; then
buildSpigotFromSource
fi

View File

@@ -3,13 +3,10 @@
set -e
. ${SCRIPTS:-/}start-utils
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=CURSEFORGE
export FTB_BASE_DIR=/data/FeedTheBeast
legacyJavaFixerUrl=http://ftb.cursecdn.com/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}
@@ -17,7 +14,7 @@ log "Looking for Feed-The-Beast / CurseForge server modpack."
requireVar FTB_SERVER_MOD
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}"
exit 2
fi
@@ -30,7 +27,7 @@ if ! isTrue ${USE_MODPACK_START_SCRIPT:-true}; then
serverJar=$(find ${FTB_BASE_DIR} -not -name "forge*installer.jar" -name "forge*.jar")
if [[ "${serverJar}" ]]; then
rm -rf $(dirname "${serverJar}")/{mods,*.jar,libraries,resources,scripts,config}
rm -rf $(dirname "${serverJar}")/{mods,*.jar,libraries,resources,scripts}
fi
else
needsInstall=false
@@ -40,25 +37,22 @@ if ! isTrue ${USE_MODPACK_START_SCRIPT:-true}; then
if $needsInstall; then
log "Unpacking FTB server modpack ${FTB_SERVER_MOD} ..."
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")
if [[ -z "$serverJar" ]]; then
forgeInstallerJar=$(find ${FTB_BASE_DIR} -name "forge*installer.jar")
if [[ -z "${forgeInstallerJar}" ]]; then
log "ERROR Unable to find forge installer in modpack."
log " Make sure you downloaded the server files."
exit 2
fi
log "Installing forge server"
(cd $(dirname "${forgeInstallerJar}"); java -jar $(basename "${forgeInstallerJar}") --installServer) | awk '{printf "."} END {print ""}'
forgeInstallerJar=$(find ${FTB_BASE_DIR} -name "forge*installer.jar")
if [[ -z "${forgeInstallerJar}" ]]; then
log "ERROR Unable to find forge installer in modpack."
log " Make sure you downloaded the server files."
exit 2
fi
log "Installing forge server"
(cd $(dirname "${forgeInstallerJar}"); java -jar $(basename ${forgeInstallerJar}) --installServer) | awk '{printf "."} END {print ""}'
echo "${FTB_SERVER_MOD}" > $installMarker
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
log "ERROR unable to locate installed forge server jar"
isDebugging && find ${FTB_BASE_DIR} -name "forge*.jar"
@@ -95,7 +89,7 @@ fi
# this allows saving just the world separate from the rest of the data directory
if [[ $startScriptCount = 0 ]]; then
srv_modpack=${FTB_SERVER_MOD}
if isURL "${srv_modpack}"; then
if isURL ${srv_modpack}; then
case $srv_modpack in
https://www.feed-the-beast.com/*/download|https://www.curseforge.com/minecraft/modpacks/*/download/*/file)
;;
@@ -113,19 +107,19 @@ if [[ $startScriptCount = 0 ]]; then
fi
srv_modpack=$downloaded
fi
if [[ "${srv_modpack:0:5}" == "data/" ]]; then
if [[ ${srv_modpack:0:5} == "data/" ]]; then
# Prepend with "/"
srv_modpack="/${srv_modpack}"
srv_modpack=/${srv_modpack}
fi
if [[ ! "${srv_modpack:0:1}" == "/" ]]; then
if [[ ! ${srv_modpack:0:1} == "/" ]]; then
# If not an absolute path, assume file is in "/data"
srv_modpack=/data/${srv_modpack}
fi
if [[ ! -f "${srv_modpack}" ]]; then
if [[ ! -f ${srv_modpack} ]]; then
log "FTB server modpack ${srv_modpack} not found."
exit 2
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 "Please set FTB_SERVER_MOD to a file with a .zip extension."
exit 2
@@ -133,7 +127,7 @@ if [[ $startScriptCount = 0 ]]; then
log "Unpacking FTB server modpack ${srv_modpack} ..."
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
if [[ $(find ${FTB_BASE_DIR} $entryScriptExpr | wc -l) = 0 ]]; then
@@ -171,7 +165,7 @@ export FTB_SERVER_START=$(find "${FTB_BASE_DIR}" $entryScriptExpr)
export FTB_DIR=$(dirname "${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/.*read.*Restart now/#\0/' "${FTB_SERVER_START}"
legacyJavaFixerPath="${FTB_DIR}/mods/legacyjavafixer.jar"

View File

@@ -17,16 +17,12 @@ if isURL ${CUSTOM_SERVER}; then
fi
elif [[ -f ${CUSTOM_SERVER} ]]; then
export SERVER=${CUSTOM_SERVER}
elif [[ ${GENERIC_PACK} ]]; then
log "Using custom server jar from generic pack at ${CUSTOM_SERVER} ..."
log "Using custom server jar at ${CUSTOM_SERVER} ..."
export SERVER=${CUSTOM_SERVER}
else
log "CUSTOM_SERVER is not properly set to a URL or existing jar file"
exit 2
fi
export SKIP_LOG4J_CONFIG=true

View File

@@ -1,72 +0,0 @@
#!/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|unique[] | select(.name == "forge") | .version' version.json)
mcVersion=$(jq -r '.targets|unique[] | 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_URL=${FABRIC_INSTALLER_URL:-}
FABRIC_INSTALLER_VERSION=${FABRIC_INSTALLER_VERSION:-${FABRICVERSION:-LATEST}}
FABRICVERSION=${FABRICVERSION:-LATEST}
if [[ -z $FABRIC_INSTALLER && -z $FABRIC_INSTALLER_URL ]]; then
log "Checking Fabric version information."
case $FABRIC_INSTALLER_VERSION in
case $FABRICVERSION in
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
FABRIC_INSTALLER="/tmp/fabric-installer-${FABRIC_INSTALLER_VERSION}.jar"
markerVersion=$FABRIC_INSTALLER_VERSION
FABRIC_INSTALLER="/tmp/fabric-installer-$FABRIC_VERSION.jar"
elif [[ -z $FABRIC_INSTALLER ]]; then
FABRIC_INSTALLER="/tmp/fabric-installer.jar"
markerVersion=custom
elif [[ ! -e $FABRIC_INSTALLER ]]; then
log "ERROR: the given Fabric installer doesn't exist : $FABRIC_INSTALLER"
exit 2
fi
installMarker="/data/.fabric-installed-${VANILLA_VERSION}-${markerVersion}"
installMarker="/data/.fabric-installed-${VANILLA_VERSION}-${FABRIC_VERSION:-manual}"
debug Checking for installMarker ${installMarker}
if [[ ! -e $installMarker ]]; then
if [[ ! -e $FABRIC_INSTALLER ]]; then
if [[ -z $FABRIC_INSTALLER_URL ]]; then
log "Downloading installer version $FABRIC_INSTALLER_VERSION"
downloadUrl="https://maven.fabricmc.net/net/fabricmc/fabric-installer/${FABRIC_INSTALLER_VERSION}/fabric-installer-${FABRIC_INSTALLER_VERSION}.jar"
log "Downloading $FABRIC_VERSION"
downloadUrl="https://maven.fabricmc.net/net/fabricmc/fabric-installer/$FABRIC_VERSION/fabric-installer-$FABRIC_VERSION.jar"
log "...trying $downloadUrl"
curl -o $FABRIC_INSTALLER -fsSL $downloadUrl
else
@@ -47,9 +49,9 @@ if [[ ! -e $installMarker ]]; then
fi
if isDebugging; then
debug "Installing Fabric ${VANILLA_VERSION} using $FABRIC_INSTALLER"
debug "Installing Fabric $FABRIC_VERSION using $FABRIC_INSTALLER with mcversion ${VANILLA_VERSION}"
else
log "Installing Fabric using $FABRIC_INSTALLER"
log "Installing Fabric $FABRIC_VERSION using $FABRIC_INSTALLER"
fi
tries=3
set +e

View File

@@ -1,8 +1,8 @@
#!/bin/bash
. ${SCRIPTS:-/}start-utils
export TYPE=FORGE
: ${FORGEVERSION:=RECOMMENDED}
if [[ -z $FORGE_INSTALLER && -z $FORGE_INSTALLER_URL ]]; then
norm=$VANILLA_VERSION

View File

@@ -1,73 +1,19 @@
#!/bin/bash
. ${SCRIPTS:-/}start-utils
set -o pipefail
isDebugging && set -x
if [[ $PAPER_DOWNLOAD_URL ]]; then
export SERVER=$(getFilenameFromUrl "${PAPER_DOWNLOAD_URL}")
: ${PAPERBUILD:=latest}
export SERVER=paper_server-${VANILLA_VERSION}-${PAPERBUILD}.jar
if [ -f "$SERVER" ]; then
zarg=(-z "$SERVER")
fi
if [ -f "$SERVER" ] && ! isTrue "$FORCE_REDOWNLOAD"; then
zarg="-z '$SERVER'"
fi
echo "Preparing custom PaperMC jar from $PAPER_DOWNLOAD_URL"
curl -fsSL -o "$SERVER" "${zarg[@]}" "${PAPER_DOWNLOAD_URL}"
else
# PaperMC API v2 docs : https://papermc.io/api/docs/swagger-ui/index.html?configUrl=/api/openapi/swagger-config
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 ..."
paperJarSearchString=${SERVER/$build/[0-9]*}
find . -maxdepth 1 -name "$paperJarSearchString" ! -name "$SERVER" -delete -print
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
downloadUrl=${PAPER_DOWNLOAD_URL:-https://papermc.io/api/v1/paper/${VANILLA_VERSION}/${PAPERBUILD}/download}
log "Downloading Paper $VANILLA_VERSION (build $PAPERBUILD) from $downloadUrl ..."
if ! curl -fsSL -o "$SERVER" $zarg "$downloadUrl"; then
log "ERROR: failed to download from $downloadUrl (status=$?)"
exit 3
fi
# Normalize on Spigot for downstream operations
@@ -75,4 +21,4 @@ export TYPE=SPIGOT
export SKIP_LOG4J_CONFIG=true
# Continue to Final Setup
exec ${SCRIPTS:-/}start-finalSetupWorld "$@"
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
export TYPE=spongevanilla
: ${SPONGEBRANCH:=STABLE}
: ${SPONGEVERSION:=}
# Parse branch
log "Choosing branch for Sponge"

View File

@@ -20,7 +20,7 @@ if [ ! -f "$SERVER" ] || [ -n "$FORCE_REDOWNLOAD" ]; then
fi
fi
# Normalize on Spigot for later operations
# Normalize on Spigot for operations below
export TYPE=SPIGOT
# 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

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

View File

@@ -1,30 +1,18 @@
#!/bin/bash
set -e -o pipefail
set -e
. ${SCRIPTS:-/}start-utils
if isDebugging; then
set -x
fi
# CURSE_URL_BASE used in manifest downloads below
CURSE_URL_BASE=${CURSE_URL_BASE:-https://minecraft.curseforge.com/projects}
# Remove old mods/plugins
if isTrue ${REMOVE_OLD_MODS}; then
remove_mods_dest="/data/mods"
case ${TYPE} in
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
if [ "$REMOVE_OLD_MODS" = "TRUE" ]; then
if [ "$TYPE" = "SPIGOT" ]; then
rm -rf /data/plugins/*
else
log "Directory $remove_mods_dest does not exist; removing nothing."
rm -rf /data/mods/*
fi
fi
@@ -34,7 +22,7 @@ if [[ "$MODPACK" ]]; then
if [[ "${MODPACK}" == *.zip ]]; then
downloadUrl="${MODPACK}"
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
log "ERROR Invalid URL given for MODPACK: $downloadUrl resolved from $MODPACK"
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 [[ "$MODS" ]]; then
if [ "$TYPE" = "SPIGOT" ]; then
out_dir=/data/plugins
else
out_dir=/data/mods
fi
mkdir -p "$out_dir"
for i in ${MODS//,/ }
do
if isURL $i; then
log "Downloading mod/plugin $i ..."
if isValidFileURL jar "$i"; then
if ! curl -fsSL -o "${out_dir}/$(getFilenameFromUrl "${i}")" "${i}"; then
log "ERROR: failed to download from $i into $out_dir"
exit 2
fi
if [[ $i == *.jar ]]; then
EFFECTIVE_MOD_URL=$i
else
effective_url=$(resolveEffectiveUrl "$i")
if isValidFileURL jar "${effective_url}"; then
out_file=$(getFilenameFromUrl "${effective_url}")
if ! curl -fsSL -o "${out_dir}/$out_file" "${effective_url}"; then
log "ERROR: failed to download from $i into $out_dir"
exit 2
fi
else
log "ERROR: $effective_url resolved from $i is not a valid jar URL"
exit 2
EFFECTIVE_MOD_URL=$(curl -Ls -o /dev/null -w %{url_effective} $i)
if ! [[ $EFFECTIVE_MOD_URL == *.jar ]]; then
log "ERROR Invalid URL given in MODS: $EFFECTIVE_MOD_URL resolved from $i"
log " Must be HTTP or HTTPS and a JAR file"
exit 1
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
log "ERROR Invalid URL given in MODS: $i"
exit 2
exit 1
fi
done
fi
@@ -111,7 +100,7 @@ if [[ "$MANIFEST" ]]; then
EFFECTIVE_MANIFEST_FILE=$MANIFEST
elif isURL "$MANIFEST"; then
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"
else
log "MANIFEST='$MANIFEST' is not a valid manifest url or location"
@@ -132,7 +121,7 @@ case "X$EFFECTIVE_MANIFEST_FILE" in
do
if [ ! -f $MOD_DIR/${p}_${f}.jar ]
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"
log Downloading curseforge mod $url
# Manifest usually doesn't have mod names. Using id should be fine, tho
@@ -151,17 +140,17 @@ fi
if [[ "${GENERIC_PACK}" ]]; then
if isURL "${GENERIC_PACK}"; then
log "Downloading generic pack ..."
curl -fsSL -o /tmp/generic_pack.zip "${GENERIC_PACK}"
GENERIC_PACK=/tmp/generic_pack.zip
generic_pack_url=${GENERIC_PACK}
GENERIC_PACK=/tmp/$(basename ${generic_pack_url})
log "Downloading generic pack from ${generic_pack_url} ..."
curl -fsSL -o ${GENERIC_PACK} ${generic_pack_url}
fi
sum_file=/data/.generic_pack.sum
if ! sha256sum -c ${sum_file} -s 2> /dev/null; then
base_dir=/tmp/generic_pack_base
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
log "Manifest exists from older generic pack, cleaning up ..."
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 f in $(find ${base_dir} -type f); do cp -f "$f" "$(sed "s#${base_dir}#/data#" <<< $f)"; done
rm -rf ${base_dir}
sha256sum "${GENERIC_PACK}" > ${sum_file}
sha256sum ${GENERIC_PACK} > ${sum_file}
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

@@ -13,7 +13,7 @@ function setServerProp {
var=${var,,} ;;
esac
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 "Skip setting ${prop}"
fi
@@ -69,7 +69,7 @@ function customizeServerProps {
setServerProp "max-world-size" "$MAX_WORLD_SIZE"
setServerProp "level-name" "$LEVEL"
setServerProp "level-seed" "$SEED"
setServerProp "pvp" "${PVP}"
setServerProp "pvp" "$PVP"
setServerProp "generator-settings" "$GENERATOR_SETTINGS"
setServerProp "online-mode" "$ONLINE_MODE"
setServerProp "allow-flight" "$ALLOW_FLIGHT"

View File

@@ -4,9 +4,6 @@
set -e
isDebugging && set -x
: ${LEVEL:=world}
export LEVEL
if [ $TYPE = "FEED-THE-BEAST" ]; then
worldDest=$FTB_DIR/$LEVEL
else
@@ -28,12 +25,7 @@ if [[ "$WORLD" ]] && ( isTrue "${FORCE_WORLD_COPY}" || [ ! -d "$worldDest" ] );
mkdir -p /tmp/world-data
(cd /tmp/world-data && unzip -o -q "$zipSrc")
if [ "$TYPE" = "SPIGOT" ]; then
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
baseDirs=$(find /tmp/world-data -name "level.dat" -exec dirname "{}" \;)
count=$(echo "$baseDirs" | wc -l)
if [[ $count -gt 1 ]]; then
baseDir="$(echo "$baseDirs" | sed -n ${WORLD_INDEX:-1}p)"
@@ -46,11 +38,6 @@ if [[ "$WORLD" ]] && ( isTrue "${FORCE_WORLD_COPY}" || [ ! -d "$worldDest" ] );
exit 1
fi
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
log "Cloning world directory from $WORLD ..."
rsync --recursive --delete "${WORLD%/}"/ "$worldDest"

View File

@@ -3,40 +3,28 @@
. ${SCRIPTS:-/}start-utils
if [ -n "$OPS" ]; then
log "Updating ops"
rm -f /data/ops.txt.converted
log "Setting/adding ops"
rm -rf /data/ops.txt.converted
echo $OPS | awk -v RS=, '{print}' > /data/ops.txt
if isTrue "${OVERRIDE_OPS}"; then
log "Recreating ops.json file at server startup"
rm -f /data/ops.json
fi
fi
if [ -n "$WHITELIST" ]; then
log "Updating whitelist"
rm -f /data/white-list.txt.converted
log "Setting whitelist"
rm -rf /data/white-list.txt.converted
echo $WHITELIST | awk -v RS=, '{print}' > /data/white-list.txt
if isTrue "${OVERRIDE_WHITELIST}"; then
log "Recreating whitelist.json file at server startup"
rm -f /data/whitelist.json
fi
fi
if [ -n "$ICON" ]; then
if [ ! -e server-icon.png ] || [ "${OVERRIDE_ICON}" == "TRUE" ]; then
log "Using server icon from $ICON..."
# Not sure what it is yet...call it "img"
curl -sSL -o /tmp/icon.img $ICON
specs=$(identify /tmp/icon.img | awk '{print $2,$3}')
if [ "$specs" = "PNG 64x64" ]; then
mv /tmp/icon.img /data/server-icon.png
else
log "Converting image to 64x64 PNG..."
convert /tmp/icon.img -resize 64x64! /data/server-icon.png
fi
fi
if [ -n "$ICON" -a ! -e server-icon.png ]; then
log "Using server icon from $ICON..."
# Not sure what it is yet...call it "img"
curl -sSL -o /tmp/icon.img $ICON
specs=$(identify /tmp/icon.img | awk '{print $2,$3}')
if [ "$specs" = "PNG 64x64" ]; then
mv /tmp/icon.img /data/server-icon.png
else
log "Converting image to 64x64 PNG..."
convert /tmp/icon.img -resize 64x64! /data/server-icon.png
fi
fi
if ! isTrue ${SKIP_LOG4J_CONFIG}; then
@@ -61,6 +49,23 @@ for j in $JSON_FILES; do
fi
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
if versionLessThan 1.14 && [[ ${CONSOLE,,} = false ]]; then
@@ -158,22 +163,17 @@ JVM_OPTS="-Xms${INIT_MEMORY} -Xmx${MAX_MEMORY} ${JVM_OPTS}"
function copyFilesForCurseForge() {
# copy player modification files unconditionally since their
# processing into json is additive anyway
[ -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/ops.txt ] && cp -f /data/ops.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
cp -f /data/server-icon.png "${FTB_DIR}/"
cp -f /data/server-icon.png ${FTB_DIR}/
fi
cp -f /data/eula.txt "${FTB_DIR}/"
}
if ! which java > /dev/null; then
log "Fixing PATH to include java"
PATH="${PATH}:/opt/java/openjdk/bin"
fi
mcServerRunnerArgs="--stop-duration ${STOP_DURATION:-60}s"
mcServerRunnerArgs="--stop-duration 60s"
if [[ ${TYPE} == "CURSE_INSTANCE" ]]; then
if isTrue ${DEBUG_EXEC}; then
set -x
@@ -181,7 +181,7 @@ if [[ ${TYPE} == "CURSE_INSTANCE" ]]; then
exec mc-server-runner ${mcServerRunnerArgs} \
--cf-instance-file "${CURSE_INSTANCE_JSON}" \
java $JVM_XX_OPTS $JVM_OPTS $expandedDOpts -jar _SERVERJAR_ "$@" $EXTRA_ARGS
elif [[ ${TYPE} == "CURSEFORGE" && "${SERVER}" ]]; then
elif [[ ${TYPE} == "FEED-THE-BEAST" && "${SERVER}" ]]; then
copyFilesForCurseForge
cd "${FTB_DIR}"
@@ -190,7 +190,7 @@ elif [[ ${TYPE} == "CURSEFORGE" && "${SERVER}" ]]; then
set -x
fi
exec mc-server-runner ${bootstrapArgs} ${mcServerRunnerArgs} java $JVM_XX_OPTS $JVM_OPTS $expandedDOpts -jar $(basename "${SERVER}") "$@" $EXTRA_ARGS
elif [[ ${TYPE} == "CURSEFORGE" ]]; then
elif [[ ${TYPE} == "FEED-THE-BEAST" ]]; then
mcServerRunnerArgs="${mcServerRunnerArgs} --shell bash"
copyFilesForCurseForge

View File

@@ -1,14 +1,8 @@
#!/bin/bash
function join_by() {
local d=$1
shift
echo -n "$1"
shift
printf "%s" "${@/#/$d}"
}
function join_by { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; }
function isURL() {
function isURL {
local value=$1
if [[ ${value:0:8} == "https://" || ${value:0:7} == "http://" ]]; then
@@ -18,114 +12,90 @@ function isURL() {
fi
}
function isValidFileURL() {
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() {
function isTrue {
local value=${1,,}
result=
case ${value} in
true | on)
result=0
;;
*)
result=1
;;
true|on)
result=0
;;
*)
result=1
;;
esac
return ${result}
}
function isDebugging() {
if [[ -v DEBUG ]] && [[ ${DEBUG^^} == TRUE ]]; then
function isDebugging {
if [[ -v DEBUG ]] && [[ ${DEBUG^^} = TRUE ]]; then
return 0
else
return 1
fi
}
function debug() {
function debug {
if isDebugging; then
log "DEBUG: $*"
fi
}
function logn() {
function logn {
echo -n "[init] $*"
}
function log() {
function log {
echo "[init] $*"
}
function logAutopause() {
function logAutopause {
echo "[Autopause loop] $*"
}
function logAutopauseAction() {
function logAutopauseAction {
echo "[$(date -Iseconds)] [Autopause] $*"
}
function normalizeMemSize() {
function normalizeMemSize {
local scale=1
case ${1,,} in
*k)
scale=1024
;;
*m)
scale=1048576
;;
*g)
scale=1073741824
;;
*k)
scale=1024;;
*m)
scale=1048576;;
*g)
scale=1073741824;;
esac
val=${1:0:-1}
echo $((val * scale))
val=${1:0: -1}
echo $(( val * scale ))
}
function versionLessThan() {
function versionLessThan {
local activeParts
IFS=. read -ra activeParts <<<"${VANILLA_VERSION}"
IFS=. read -ra activeParts <<< "${VANILLA_VERSION}"
local givenParts
IFS=. read -ra givenParts <<<"$1"
IFS=. read -ra givenParts <<< "$1"
if ((${#activeParts[@]} < 2)); then
if (( ${#activeParts[@]} < 2 )); then
return 1
fi
if ((${#activeParts[@]} == 2)); then
if ((activeParts[0] < givenParts[0])) ||
((activeParts[0] == givenParts[0] && activeParts[1] < givenParts[1])); then
if (( ${#activeParts[@]} == 2 )); then
if (( activeParts[0] < givenParts[0] )) || \
(( activeParts[0] == givenParts[0] && activeParts[1] < givenParts[1] )); then
return 0
else
return 1
fi
else
if ((activeParts[0] < givenParts[0])) ||
((activeParts[0] == givenParts[0] && activeParts[1] < givenParts[1])) ||
((activeParts[0] == givenParts[0] && activeParts[1] == givenParts[1] && activeParts[2] < givenParts[2])); then
if (( activeParts[0] < givenParts[0] )) || \
(( activeParts[0] == givenParts[0] && activeParts[1] < givenParts[1] )) || \
(( activeParts[0] == givenParts[0] && activeParts[1] == givenParts[1] && activeParts[2] < givenParts[2] )); then
return 0
else
return 1
@@ -144,26 +114,11 @@ requireVar() {
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() {
if ! echo "# Generated via Docker
# $(date)
if ! echo "# Generated via Docker on $(date)
eula=${EULA,,}
" >/data/eula.txt; then
log "ERROR: unable to write eula to /data. Please make sure attached directory is writable by uid=${UID}"
exit 2
fi
" > /data/eula.txt; then
log "ERROR: unable to write eula to /data. Please make sure attached directory is writable by uid=${UID}"
exit 2
fi
}