├── .github ├── FUNDING.yml └── workflows │ └── docker-image.yml ├── merge.sh ├── healthcheck.sh ├── Examples ├── config.yml └── docker-compose.yml ├── render.sh ├── README.md ├── LICENSE ├── doc ├── RESTORING.md ├── VARIABLES.md ├── PERMISSIONS.md └── TOOL_CONFIG.md ├── Template.dockerfile └── CHANGELOG.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | #github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 2 | custom: 3 | - https://ko-fi.com/J3J3KMBP 4 | - https://paypal.me/Biticus 5 | -------------------------------------------------------------------------------- /merge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Merges the Manifests for 4 | 5 | tag=$1 6 | 7 | docker manifest $tag 8 | 9 | docker manifest create $tag \ 10 | --amend $tag-amd64 \ 11 | --amend $tag-arm64 \ 12 | 13 | docker manifest push $tag 14 | -------------------------------------------------------------------------------- /healthcheck.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Backup Job Healthcheck 4 | # 5 | # Used by the docker container 6 | 7 | set -uo pipefail 8 | 9 | if [ "${DEBUG:-false}" == "true" ]; then 10 | set -x 11 | fi 12 | 13 | : "${DATA_DIR:=/backups}" 14 | 15 | if [ ! -e "${DATA_DIR}/.service_is_healthy" ]; then 16 | exit 1 17 | fi 18 | 19 | exit 0 20 | -------------------------------------------------------------------------------- /Examples/config.yml: -------------------------------------------------------------------------------- 1 | containers: 2 | bedrock: 3 | - name: bedrock_private 4 | worlds: 5 | - /bedrock_private/worlds/PrivateWorld 6 | - name: bedrock_public 7 | worlds: 8 | - /bedrock_public/worlds/PublicWorld 9 | java: 10 | - name: java_public 11 | worlds: 12 | - /java_public/PublicJavaWorld 13 | schedule: 14 | interval: 3h 15 | trim: 16 | trimDays: 2 17 | keepDays: 14 18 | minKeep: 14 19 | -------------------------------------------------------------------------------- /render.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Renders the final Dockerfiles for building 4 | 5 | set -euo pipefail 6 | 7 | renderPlatforms=${1:-all} 8 | 9 | baseimage_arm64="swiftarm/swift:5.5.2-ubuntu-21.04" 10 | baseimage_amd64="swift:5.5.2" 11 | 12 | function render { 13 | sedStr=" 14 | s!%%BASE_IMAGE%%!$image!g; 15 | " 16 | 17 | sed -r "$sedStr" $1 18 | } 19 | 20 | if [ "$renderPlatforms" == "all" ]; then 21 | arches=(arm64 amd64) 22 | else 23 | arches=($renderPlatforms) 24 | fi 25 | 26 | for arch in ${arches[*]}; do 27 | echo Creating "$arch.dockerfile" 28 | if [ -e $arch.dockerfile ]; then 29 | rm $arch.dockerfile 30 | fi 31 | 32 | image=baseimage_$arch 33 | eval image=\${$image} 34 | echo Using Base Image: $image 35 | echo Rendering... 36 | render Template.dockerfile > $arch.dockerfile 37 | done -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docker-minecraft-bedrock-backup 2 | 3 | [![Docker Pulls](https://img.shields.io/docker/pulls/kaiede/minecraft-bedrock-backup.svg)](https://hub.docker.com/r/kaiede/minecraft-bedrock-backup) 4 | 5 | Docker container for configuring backups of the Minecraft [Bedrock](https://hub.docker.com/r/itzg/minecraft-bedrock-server) and [Java](https://hub.docker.com/r/itzg/minecraft-server) docker containers provided by itzg. 6 | 7 | This container uses https://github.com/Kaiede/Bedrockifier as the service and command line tool to do all the work. 8 | 9 | **To make development easier this repo has been merged with Bedrockifier, and is now archived. Please bring all issues to https://github.com/Kaiede/Bedrockifier** 10 | 11 | ### Credits 12 | 13 | This was built in part by understanding how itzg/mc-backup works for Java, and is offered under similar license: https://github.com/itzg/docker-mc-backup 14 | 15 | 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Adam Thayer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /doc/RESTORING.md: -------------------------------------------------------------------------------- 1 | # Restoring Backups 2 | 3 | The backups are stored as .mcworld files, which also happen to be zip files. It makes it possible to restore a backup doing something like this: 4 | 5 | * `docker-compose stop` 6 | * `cd /opt/bedrock/server/worlds` 7 | * `mv MyWorld MyWorld.bak` 8 | * `mkdir MyWorld` 9 | * `cd MyWorld` 10 | * `unzip /opt/bedrock/backups/MyWorld-.mcworld` 11 | * `docker-compose start` 12 | * Delete MyWorld.bak once everything is confirmed working 13 | 14 | In this example, `/opt/bedrock/server` is the data folder for the minecraft server container, and `/opt/bedrock/backups` is the backup folder for the backup container. 15 | 16 | ### Future Improvements 17 | 18 | `BedrockifierCLI` can also pack and unpack worlds quite easily. At the moment running it from the docker container is a catch-22 if the backup container is dependent on the server containers. You don't want the server to be running when restoring a backup, but the backup container depends on the servers so it can make the backup. 19 | 20 | A future improvement here would be to figure out a process to make the restoration process less manual. 21 | -------------------------------------------------------------------------------- /doc/VARIABLES.md: -------------------------------------------------------------------------------- 1 | # Configuration Variables 2 | 3 | Below is a full list of variables that can be provided as environment variables in the `docker-compose.yml` file to the backup container. 4 | 5 | ### Core Variables 6 | 7 | * `TZ`: This sets the timezone. It is optional, but it will use GMT if not set. 8 | 9 | ### Security/Permissions Variables 10 | 11 | * `UID`: User to run the backup as, overriding the owner of the `/backups` folder. 12 | * `GID`: Group to run the backup as, overriding the group of the `/backups` folder. 13 | 14 | ### Optional Variables 15 | 16 | * `CONFIG_FILE`: Use this in the rare case that you want to use something other than `config.yml` as the file name of your backup configuration. 17 | * `DATA_DIR`: Use this when you want to change the location of the `/backups` directory to something different within the container. The main reason you might want to do that is if you are using a named volume for backups from multiple sources, and want your minecraft backups to live in a subfolder of that volume. 18 | 19 | ### Deprecated Settings 20 | 21 | * `BACKUP_INTERVAL`: This configures how often the backups are run. It has been replaced by the schedule configuration in the `config.yml` file. 22 | 23 | -------------------------------------------------------------------------------- /Template.dockerfile: -------------------------------------------------------------------------------- 1 | ###### BUILDER 2 | FROM %%BASE_IMAGE%% as builder 3 | WORKDIR /project 4 | 5 | ARG COMMIT 6 | ARG CACHEBUST 7 | 8 | RUN apt-get install -y \ 9 | git 10 | 11 | RUN echo "$CACHEBUST" 12 | RUN git clone https://github.com/Kaiede/BedrockifierCLI.git /project 13 | RUN git checkout ${COMMIT} 14 | RUN swift build -j 1 -c release 15 | 16 | ###### RUNTIME CONTAINER 17 | FROM %%BASE_IMAGE%%-slim 18 | WORKDIR /opt/bedrock 19 | 20 | ARG ARCH 21 | 22 | RUN apt-get update && \ 23 | DEBIAN_FRONTEND=noninteractive apt-get install -y \ 24 | docker.io \ 25 | && apt-get clean \ 26 | && rm -rf /var/lib/apt/lists/* 27 | 28 | ENTRYPOINT ["/usr/local/bin/entrypoint-demoter", "--match", "/backups", "--debug", "--stdin-on-term", "stop", "/opt/bedrock/bedrockifierd"] 29 | HEALTHCHECK --start-period=1m CMD bash /opt/bedrock/healthcheck.sh 30 | 31 | ARG EASY_ADD_VERSION=0.7.0 32 | ADD https://github.com/itzg/easy-add/releases/download/${EASY_ADD_VERSION}/easy-add_linux_${ARCH} /usr/local/bin/easy-add 33 | RUN chmod +x /usr/local/bin/easy-add 34 | 35 | RUN easy-add --var version=0.2.1 --var app=entrypoint-demoter --file {{.app}} --from https://github.com/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_linux_${ARCH}.tar.gz 36 | 37 | COPY --from=builder /project/.build/release/bedrockifier-tool . 38 | COPY --from=builder /project/.build/release/bedrockifierd . 39 | COPY ./healthcheck.sh . 40 | 41 | -------------------------------------------------------------------------------- /doc/PERMISSIONS.md: -------------------------------------------------------------------------------- 1 | # Configuring Permissions 2 | 3 | Permissions in simple cases can be handled automatically, but in many cases, there is a need for users to configure the permissions manually. 4 | 5 | ### Default Behavior 6 | 7 | The service uses a tool called `entrypoint-demoter` to avoid running the service as root. By default it will automatically demote the service to the user and group that owns your backups directory. 8 | 9 | In many cases you can use a regular user that has been added to the docker group. This is how I setup my personal server on a virtual machine. It makes things easier when you want to restore backups or otherwise manage the backups manually. 10 | 11 | ### Overriding User/Group of the Backup Tool 12 | 13 | In cases where you need to override the user and group that is picked for you by `entrypoint-demoter`. The user must be part of the docker group, or otherwise have access to attach to the server containers. This also will have problems when running Docker rootless. To do the override, set the `UID` and `GID` environment variables in your `docker-compose.yml` file. 14 | 15 | ### Overriding Permissions on Backed Up Worlds 16 | 17 | In the `config.json`, there is a feature that allows you to override the user, group, and permissions for the backups. It is only recommended to do this if you absolutely have to, such as running it on a NAS device that requires specific ownership and permissions. Trimming may break if the tool loses write access to the backup files. Use with caution. 18 | 19 | **Using chown requires running the service as root which is not recommended!** 20 | 21 | ``` 22 | ... 23 | "ownership": { 24 | "chown": ":", 25 | "permissions": "644" 26 | } 27 | ... 28 | ``` 29 | -------------------------------------------------------------------------------- /Examples/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | backup: 5 | image: kaiede/minecraft-bedrock-backup 6 | restart: always 7 | depends_on: 8 | - "public" 9 | - "private" 10 | environment: 11 | TZ: "America/Los_Angeles" 12 | tty: true 13 | volumes: 14 | - /var/run/docker.sock:/var/run/docker.sock 15 | - /opt/bedrock/backups:/backups 16 | - /opt/bedrock/private:/bedrock_private 17 | - /opt/bedrock/public:/bedrock_public 18 | - /opt/java/public:/java_public 19 | 20 | manymine: 21 | image: illiteratealliterator/manymine 22 | restart: always 23 | container_name: manymine 24 | ports: 25 | - '19132:19132/udp' 26 | volumes: 27 | - /var/run/docker.sock:/var/run/docker.sock 28 | 29 | private: 30 | image: itzg/minecraft-bedrock-server 31 | restart: always 32 | container_name: bedrock_private 33 | environment: 34 | EULA: "TRUE" 35 | ports: 36 | - 60601:19132/udp 37 | volumes: 38 | - /opt/bedrock/private:/data 39 | stdin_open: true 40 | tty: true 41 | labels: 42 | - manymine.enable=true 43 | 44 | public: 45 | image: itzg/minecraft-bedrock-server 46 | restart: always 47 | container_name: bedrock_public 48 | environment: 49 | EULA: "TRUE" 50 | ports: 51 | - 60602:19132/udp 52 | volumes: 53 | - /opt/bedrock/public:/data 54 | stdin_open: true 55 | tty: true 56 | labels: 57 | - manymine.enable=true 58 | 59 | java_public 60 | image: itgz/minecraft-server 61 | restart: always 62 | container_name: java_public 63 | environment: 64 | EULA: "TRUE" 65 | LEVEL: "PublicJavaWorld" 66 | ports: 67 | - 25565:25565 68 | volumes: 69 | - /opt/java/public:/data 70 | stdin_open: true 71 | tty: true 72 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | #### v1.1 - Jan 7th, 2022 2 | - Updated to Swift 5.5.2 compiler. 3 | - Converted to a service instead of a script running a tool in a loop. This enables the new scheduler features. 4 | - Java containers can now be backed up, using the new `containers` settings in the configuration file. 5 | - Configuration parsing now supports YAML format, and defaults to 'config.yml'. For compatibility, 'config.json' will be checked as a fallback. 6 | - Configuration file now has a `schedule` section which replaces the environment variables. 7 | - `interval` is the same as before. 8 | - `startupDelay` delays the first backup by the interval given, instead of running it on startup. 9 | - `daily` performs a single daily backup, mutually exclusive with `interval`. 10 | - `onPlayerLogin` performs a backup whenever a player logs in. 11 | - `onPlayerLogout` performs a backup whenever a player logs out. 12 | - `onLastLogout` performs a backup whenever the last player logs out. 13 | - `minInterval` throttles event/interval backups to a maximum of one during the minimum interval (i.e. 4h means one backup every 4h maximum). 14 | - Logging is now less verbose. There is a `loggingLevel` option in the configuration to make it verbose again for diagnostic purposes. 15 | 16 | The following has been deprecated. They still currently work today, but are not expected to be supported at some point in the future. 17 | - DEPRECATED: The "BACKUP_INTERVAL" environment variable is now part of the configuration file. 18 | - DEPRECATED: The "servers" settings in the configuration file is now "containers" with support for Bedrock and Java. 19 | - DEPRECATED: JSON configuration files have been deprecated in favor of YAML configuration files. 20 | 21 | #### v1.0.3 - Dec 21st, 2021 22 | - Updated to Swift 5.5 compiler. 23 | - The property "tty: true" is no longer required on the server container. 24 | - New "ownership" configuration for the backup allows changing the owner, group, and permissions on backups written. Changing the owner and group requires running as root, which isn't recommended. Trimming also may not work properly if the backup tool loses write access. Use with caution. 25 | 26 | #### v1.0.2 - Dec 13th, 2021 27 | - Container no longer exits when a backup fails, avoiding a restart loop. 28 | - A running container will be marked unhealthy if backups are failing. 29 | 30 | #### v1.0.1 Dec 1st, 2021 31 | - Fixes for 1.18 servers that caused recurring backups. 32 | -------------------------------------------------------------------------------- /doc/TOOL_CONFIG.md: -------------------------------------------------------------------------------- 1 | # Backup Tool Config File 2 | 3 | ``` 4 | containers: 5 | bedrock: 6 | - name: 7 | worlds: 8 | - 9 | java: 10 | - name: 11 | worlds: 12 | - 13 | schedule: 14 | interval: 15 | trim: 16 | trimDays: 2 17 | keepDays: 14 18 | minKeep: 2 19 | loggingLevel: [debug or trace] 20 | ownership: 21 | chown: 1000:1001 22 | permissions: 644 23 | ``` 24 | 25 | ### Containers 26 | 27 | This section lists all the servers to be backed up, and informs the tool how to talk to docker, and where to find the worlds. It is split into `bedrock` and `java`. Put Bedrock servers under `bedrock` and Java servers under `java` and it will properly back each type up in the correct way. 28 | 29 | * ``: This is the name of the docker container to be backed up. Something like `minecraft_server` as an example. It needs to match the name visible in `docker ps`, or the `container_name` setting in docker-compose.yml. 30 | 31 | * ``: This is the internal path to the world folder you want to backup. For example, if you mapped `/opt/bedrock/server` to `/server` in your `docker-compose.yml`, then this path should be `/server/worlds/` 32 | 33 | ### Schedule 34 | 35 | * `interval`: This is the timing on backups, specified in hours, minutes, or seconds. So you can use values like: `600s`, `60m` or `3h` to set how often the backup is kicked off. 36 | 37 | ### Trim 38 | 39 | Trimming backups allows you control how much disk space is used by backups by deleting old backups, and only keeping daily backups after a certain number of days. 40 | 41 | It is controlled by the following settings: 42 | 43 | * `keepDays`: This is how many days of backups to keep. Setting this to 14 days means no backups after 14 days are kept, unless kept by minKeep. 44 | 45 | * `trimDays`: How many days to keep of backups before trimming them down. Setting this to 2 days, with a 3 hour backup interval means that for the last 2 days, you'll keep all the 3 hour backups. After 2 days, the backups will get trimmed down to just a single daily backup, up to the keepDays limit. 46 | 47 | * `minKeep`: A minimum number of backups to keep. This is useful if you switch worlds on your server, as it will make sure you always have a couple backups of any world even if it hasn't been used in a while. This will override keepDays, and let you keep at least this many backups indefinitely. 48 | 49 | ### Logging Level 50 | 51 | * `loggingLevel`: This can be set to `debug` or `trace` to enable extra logging for diagnostic purposes. In most cases, it's fine to leave it out of your config file unless reporting a bug. 52 | 53 | ### Ownership 54 | 55 | This is meant for the rare cases where files on disk need to be a very specific user and group, and/or have specific permissions. NAS devices being one example. It allows you to tell the service how to set ownership and permissions on the backups written to disk. 56 | 57 | This functionality may break trimming of backups if it causes the service to no longer be able to have write permissions to the backups. Use with caution. 58 | 59 | * `chown`: This sets the owner and group on backed up mcworld files. It works much like the `chown` command's argument, but only accepts ids, not names. **Using this requires the service to run as root which is not recommended.** 60 | 61 | * `permissions`: Sets unix permissions for the backed up files. This is the standard POSIX bitmask in string form. 62 | -------------------------------------------------------------------------------- /.github/workflows/docker-image.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | release: 9 | types: 10 | - published 11 | 12 | env: 13 | docker_tag: ${{ github.event_name != 'release' && 'test' || 'latest' }} 14 | 15 | jobs: 16 | arm64: 17 | runs-on: ubuntu-latest 18 | if: github.repository == 'Kaiede/docker-minecraft-bedrock-backup' 19 | 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v2 23 | 24 | - name: Set up QEMU 25 | uses: docker/setup-qemu-action@master 26 | with: 27 | platforms: arm64 28 | 29 | - name: Set up Docker Buildx 30 | id: buildx 31 | uses: docker/setup-buildx-action@master 32 | 33 | - name: Login to DockerHub 34 | if: github.event_name != 'pull_request' 35 | uses: docker/login-action@v1 36 | with: 37 | username: ${{ secrets.DOCKER_USER }} 38 | password: ${{ secrets.DOCKER_PASSWORD }} 39 | 40 | - name: Get current date 41 | id: date 42 | run: echo "::set-output name=date::$(date +%s)" 43 | 44 | - name: Render Dockerfiles 45 | run: bash render.sh all 46 | 47 | - name: Build arm64 48 | uses: docker/build-push-action@v2 49 | with: 50 | builder: ${{ steps.buildx.outputs.name }} 51 | context: . 52 | file: ./arm64.dockerfile 53 | platforms: linux/arm64 54 | push: ${{ github.event_name != 'pull_request' }} 55 | tags: kaiede/minecraft-bedrock-backup:${{ env.docker_tag }}-arm64 56 | build-args: | 57 | CACHEBUST=${{ steps.date.outputs.date }} 58 | COMMIT=main 59 | ARCH=arm64 60 | 61 | amd64: 62 | runs-on: ubuntu-latest 63 | if: github.repository == 'Kaiede/docker-minecraft-bedrock-backup' 64 | 65 | steps: 66 | - name: Checkout 67 | uses: actions/checkout@v2 68 | 69 | - name: Set up Docker Buildx 70 | id: buildx 71 | uses: docker/setup-buildx-action@master 72 | 73 | - name: Login to DockerHub 74 | if: github.event_name != 'pull_request' 75 | uses: docker/login-action@v1 76 | with: 77 | username: ${{ secrets.DOCKER_USER }} 78 | password: ${{ secrets.DOCKER_PASSWORD }} 79 | 80 | - name: Get current date 81 | id: date 82 | run: echo "::set-output name=date::$(date +%s)" 83 | 84 | - name: Render Dockerfiles 85 | run: bash render.sh all 86 | 87 | - name: Build amd64 88 | uses: docker/build-push-action@v2 89 | with: 90 | builder: ${{ steps.buildx.outputs.name }} 91 | context: . 92 | file: ./amd64.dockerfile 93 | platforms: linux/amd64 94 | push: ${{ github.event_name != 'pull_request' }} 95 | tags: kaiede/minecraft-bedrock-backup:${{ env.docker_tag }}-amd64 96 | build-args: | 97 | CACHEBUST=${{ steps.date.outputs.date }} 98 | COMMIT=main 99 | ARCH=amd64 100 | 101 | merge-tags: 102 | needs: ['arm64', 'amd64'] 103 | runs-on: ubuntu-latest 104 | if: github.event_name != 'pull_request' && github.repository == 'Kaiede/docker-minecraft-bedrock-backup' 105 | 106 | steps: 107 | - name: Checkout 108 | uses: actions/checkout@v2 109 | 110 | - name: Login to DockerHub 111 | if: github.event_name != 'pull_request' 112 | uses: docker/login-action@v1 113 | with: 114 | username: ${{ secrets.DOCKER_USER }} 115 | password: ${{ secrets.DOCKER_PASSWORD }} 116 | 117 | - name: Merge Manifests 118 | if: github.event_name != 'pull_request' 119 | run: bash merge.sh kaiede/minecraft-bedrock-backup:${{ env.docker_tag }} 120 | --------------------------------------------------------------------------------