{"id":13608130,"url":"https://github.com/itzg/docker-mc-backup","last_synced_at":"2025-04-09T05:12:33.186Z","repository":{"id":37182886,"uuid":"175860513","full_name":"itzg/docker-mc-backup","owner":"itzg","description":"Provides a side-car container to backup itzg/minecraft-server world data","archived":false,"fork":false,"pushed_at":"2024-09-29T16:01:52.000Z","size":135,"stargazers_count":317,"open_issues_count":38,"forks_count":52,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-10-12T18:53:22.714Z","etag":null,"topics":["backup","docker-image","hacktoberfest","minecraft"],"latest_commit_sha":null,"homepage":"https://hub.docker.com/r/itzg/mc-backup","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/itzg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"custom":["https://www.buymeacoffee.com/itzg","https://paypal.me/itzg"]}},"created_at":"2019-03-15T17:03:29.000Z","updated_at":"2024-10-07T10:48:41.000Z","dependencies_parsed_at":"2023-12-01T15:30:32.484Z","dependency_job_id":"20a41012-6dae-483d-b492-47c07cdbf05b","html_url":"https://github.com/itzg/docker-mc-backup","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itzg%2Fdocker-mc-backup","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itzg%2Fdocker-mc-backup/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itzg%2Fdocker-mc-backup/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itzg%2Fdocker-mc-backup/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/itzg","download_url":"https://codeload.github.com/itzg/docker-mc-backup/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247980844,"owners_count":21027808,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backup","docker-image","hacktoberfest","minecraft"],"created_at":"2024-08-01T19:01:24.525Z","updated_at":"2025-04-09T05:12:33.168Z","avatar_url":"https://github.com/itzg.png","language":"Shell","funding_links":["https://www.buymeacoffee.com/itzg","https://paypal.me/itzg"],"categories":["Shell","hacktoberfest"],"sub_categories":[],"readme":"[![Docker Pulls](https://img.shields.io/docker/pulls/itzg/mc-backup.svg)](https://hub.docker.com/r/itzg/mc-backup)\n[![Build](https://github.com/itzg/docker-mc-backup/actions/workflows/build.yml/badge.svg)](https://github.com/itzg/docker-mc-backup/actions/workflows/build.yml)\n[![Discord](https://img.shields.io/discord/660567679458869252?label=Discord\u0026logo=discord)](https://discord.gg/DXfKpjB)\n\nProvides a side-car container to back up [itzg/minecraft-server](https://github.com/itzg/docker-minecraft-server) server data. Backups are coordinated automatically by using RCON to flush data, pause writes, and resume after backup is completed. \n\n**This does NOT support Bedrock edition. Use [a community provided solution](https://github.com/itzg/docker-minecraft-bedrock-server#community-solutions) for that.**\n\n## Environment variables\n\n### Common variables\n\n- `SRC_DIR`=/data\n- `BACKUP_NAME`=world\n- `BACKUP_METHOD`=tar  : [see below](#backup-methods)\n- `INITIAL_DELAY`=2m\n- `BACKUP_INTERVAL`=24h\n- `BACKUP_ON_STARTUP`=true : Set to false to skip first backup on startup.\n- `PAUSE_IF_NO_PLAYERS`=false\n- `PLAYERS_ONLINE_CHECK_INTERVAL`=5m\n- `PRUNE_BACKUPS_DAYS`=7\n- `PRUNE_BACKUPS_COUNT`= -disabled unless set (only works with tar/rsync)\n- `PRUNE_RESTIC_RETENTION`=--keep-within 7d\n- `RCON_HOST`=localhost\n- `RCON_PORT`=25575\n- `RCON_PASSWORD`=minecraft\n- `RCON_PASSWORD_FILE`: Can be set to read the RCON password from a file. Overrides `RCON_PASSWORD` if both are set.\n- `RCON_RETRIES`=5 : Set to a negative value to retry indefinitely\n- `RCON_RETRY_INTERVAL`=10s\n- `SERVER_HOST`=`RCON_HOST` : Can be set if the game and RCON are accessible on different addresses.\n- `SERVER_PORT`=25565\n- `INCLUDES`=. : comma separated list of include patterns relative to directory specified by `SRC_DIR` where `.` specifies all of that directory should be included in the backup. \n\n  **For Restic** the default is the value of `SRC_DIR` to remain backward compatible with previous images.\n- `EXCLUDES`=\\*.jar,cache,logs,\\*.tmp : commas separated list of file patterns to exclude from the backup. To disable exclusions, set to an empty string.\n- `EXCLUDES_FILE`: Can be set to read the list of excludes (one per line) from a file. Can be used with `EXCLUDES` to add more excludes.\n- `RESTIC_ADDITIONAL_TAGS`=mc_backups : additional tags to apply to the backup. Set to an empty string to disable additional tags.\n- `RESTIC_VERBOSE`=false : set to \"true\" to enable verbose output during restic backup operation\n- `TZ` : Can be set to the timezone to use for logging\n- `PRE_SAVE_ALL_SCRIPT`, `PRE_BACKUP_SCRIPT`, `PRE_SAVE_ON_SCRIPT`, `POST_BACKUP_SCRIPT`, `*_SCRIPT_FILE`: See [Backup scripts](#backup-scripts)\n\nIf `PRUNE_BACKUPS_DAYS` is set to a positive number, it'll delete old `.tgz` backup files from `DEST_DIR`. By default deletes backups older than a week.\n\nIf `BACKUP_INTERVAL` is set to 0 or smaller, script will run once and exit.\n\nBoth `INITIAL_DELAY` and `BACKUP_INTERVAL` accept times in `sleep` format: `NUMBER[SUFFIX] NUMBER[SUFFIX] ...`.\nSUFFIX may be 's' for seconds (the default), 'm' for minutes, 'h' for hours or 'd' for days.\n\nExamples:\n- `BACKUP_INTERVAL`=\"1.5d\" -\u003e backup every one and a half days (36 hours)\n- `BACKUP_INTERVAL`=\"2h 30m\" -\u003e backup every two and a half hours\n- `INITIAL_DELAY`=\"120\" -\u003e wait 2 minutes before starting\n\nThe `PAUSE_IF_NO_PLAYERS` option lets you pause backups if no players are online.\n\nIf `PAUSE_IF_NO_PLAYERS`=\"true\" and there are no players online after a backup is made, then instead of immediately scheduling the next backup, the script will start checking the server's player count every `PLAYERS_ONLINE_CHECK_INTERVAL` (defaults to 5 minutes). Once a player joins the server, the next backup will be scheduled in `BACKUP_INTERVAL`.\n\n`EXCLUDES` is a comma-separated list of glob(3) patterns to exclude from backups. By default excludes all jar files (plugins, server files), logs folder and cache (used by i.e. PaperMC server).\n\n### Backup methods\n\nSet `BACKUP_METHOD` to one of the following, where the default is `tar`.\n\n#### `tar`\n\n- `DEST_DIR`=/backups\n- `LINK_LATEST`=false\n- `TAR_COMPRESS_METHOD`=gzip\n- `ZSTD_PARAMETERS`=-3 --long=25 --single-thread\n\n`LINK_LATEST` is a true/false flag that creates a symbolic link to the latest backup.\n\n`TAR_COMPRESS_METHOD` is the compression method used by tar. Valid value: gzip bzip2 zstd\n\n`ZSTD_PARAMETERS` sets the parameters for `zstd` compression. The `--long` parameter affects RAM requirements for both compression and decompression (the default of 25 means 2^25 bytes = 32 MB).\n\n#### `rsync`\n\n- `DEST_DIR`=/backups\n- `LINK_LATEST`=false\n\n`LINK_LATEST` is a true/false flag that creates a symbolic link to the latest backup.\n\n#### `restic`\n\nSee [restic documentation](https://restic.readthedocs.io/en/latest/030_preparing_a_new_repo.html) on what variables are needed to be defined.\nAt least one of `RESTIC_PASSWORD*` variables need to be defined, along with `RESTIC_REPOSITORY`.\n\nUse the `RESTIC_ADDITIONAL_TAGS` variable to define a space separated list of additional restic tags. The backup will always be tagged with the value of `BACKUP_NAME`. e.g.: `RESTIC_ADDITIONAL_TAGS=mc_backups foo bar` will tag your backup with `foo`, `bar`, `mc_backups` and the value of `BACKUP_NAME`.\n\nBy default, the hostname, typically the container/pod's name, will be used as the Restic backup's hostname. That can be overridden by setting `RESTIC_HOSTNAME` \n\nYou can fine tune the retention cycle of the restic backups using the `PRUNE_RESTIC_RETENTION` variable. Take a look at the [restic documentation](https://restic.readthedocs.io/en/latest/060_forget.html) for details.\n\n\u003e **_EXAMPLE_**  \n\u003e Setting `PRUNE_RESTIC_RETENTION` to `--keep-daily 7 --keep-weekly 5 --keep-monthly 12 --keep-yearly 75` will keep the most recent 7 daily snapshots, then 4 (remember, 7 dailies already include a week!) last-day-of-the-weeks and 11 or 12 last-day-of-the-months (11 or 12 depends if the 5 weeklies cross a month). And finally 75 last-day-of-the-year snapshots. All other snapshots are removed.\n\n| :warning: | When using restic as your backup method, make sure that you fix your container hostname to a constant value! Otherwise, each time a container restarts it'll use a different, random hostname which will cause it not to rotate your backups created by previous instances! |\n|-----------|---|\n\n| :warning: | When using restic, at least one of `HOSTNAME` or `BACKUP_NAME` must be unique, when sharing a repository. Otherwise other instances using the same repository might prune your backups prematurely. |\n|-----------|---|\n\n| :warning: | SFTP restic backend is not directly supported. Please use RCLONE backend with SFTP support. |\n|-----------|---|\n\n- Information about required S3 permissions [can be found here](https://restic.readthedocs.io/en/latest/080_examples.html)\n\n#### `rclone`\nRclone acts as the `tar` backup method but automatically moves the compressed files to a remote drive via [rclone](https://rclone.org/).\n\nThere are a few special environment variables for the rclone method.\n\n- `RCLONE_REMOTE` is the name of the remote you've configured in your rclone.conf, see [remote setup](https://rclone.org/remote_setup/).\n- `RCLONE_COMPRESS_METHOD`=gzip\n- `DEST_DIR`=/backups is the container path where the archive is temporarily created\n- `RCLONE_DEST_DIR` is the directory on the remote\n\nOther parameters such as `PRUNE_BACKUPS_DAYS`, `ZSTD_PARAMETERS`, and `BACKUP_NAME` are all used as well.\n\n**Note** that you will need to place your rclone config file in `/config/rclone/rclone.conf`.\nThis can be done by adding it through docker-compose,\n\n```yaml\n- ./rclone.config:/config/rclone/rclone.conf:ro\n```\nor by running the config wizard in a container and mounting the volume.\n```shell\ndocker run -it --rm -v rclone-config:/config/rclone rclone/rclone config\n```\n\nthen you must bind the volume **for the mc-backup process**\n```yaml\nvolumes:\n  - rclone-config:/config/rclone\n```\n**and the service**\n```yaml\nvolumes:\n  rclone-config:\n    external: true\n```\n\n## Volumes\n\n- `/data` :\n  Should be attached read-only to the same volume as the `/data` of the `itzg/minecraft-server` container\n- `/backups` :\n  The volume where incremental tgz files will be created, if using tar backup method.\n\n## Restoring tar backups\n\nThis image includes a script called `restore-backup` which will:\n1. Check if the `$SRC_DIR` (default is `/data`) is empty\n2. and if any files are available in `$DEST_DIR` (default is `/backups`), \n3. then un-tars the newest one into `$SRC_DIR`\n\nThe [compose file example](#docker-compose) shows creating an \"init container\" to run the restore\n\n## Restoring rsync backups\n\nThis image includes a script called `restore-rsync-backup` which will:\n1. Check if the `$SRC_DIR` (default is `/data`) is empty\n2. and if any folders are available in `$DEST_DIR` (default is `/backups`), \n3. then rsyncs back the newest one into `$SRC_DIR`\n\nThe [compose file example](#docker-compose) shows creating an \"init container\" to run the restore\n\n## On-demand backups\n\nIf you would like to kick off a backup prior to the next backup interval, you can `exec` the command `backup now` within the running backup container. For example, using the [Docker Compose example](examples/docker-compose.yml) where the service name is `backups`, the exec command becomes:\n\n```shell\ndocker-compose exec backups backup now\n```\n\nThis mechanism can also be used to avoid a long running container completely by running a temporary container, such as:\n\n```shell\ndocker run --rm ...data and backup -v args... itzg/mc-backup backup now\n```\n\n## Backup scripts\n\nThe `PRE_SAVE_ALL_SCRIPT`, `PRE_BACKUP_SCRIPT`, `PRE_SAVE_ON_SCRIPT`, and `POST_BACKUP_SCRIPT`, variables may be set to a bash script to run before and after the backup process.\nPotential use-cases include sending notifications, or replicating a restic repository to a remote store.\n\nThe backup waits for the server to respond to a rcon \"save-on\" command before running the scripts. After, the `PRE_SAVE_ALL_SCRIPT` is run, followed by rcon \"save-off\" and \"save-all\" commands. The, the `PRE_BACKUP_SCRIPT` is run, followed by the backup process. Then, the `PRE_SAVE_ON_SCRIPT` is run, followed by a rcon \"save-on\" command. Finally, the `POST_BACKUP_SCRIPT` is run.\n\nAlternatively `PRE_SAVE_ALL_SCRIPT_FILE` `PRE_BACKUP_SCRIPT_FILE`, `PRE_SAVE_ON_SCRIPT_FILE`, and `POST_BACKUP_SCRIPT_FILE` may be set to the path of a script that has been mounted into the container. The file must be executable.\n\nNote that `*_FILE` variables will be overridden by their non-FILE versions if both are set.\n\nSome notes:\n\n- When specifying the script directly in Docker compose files any `$` that are being used to refer to environment variables must be doubled up (i.e. `$$`) else Compose will try to substitute them\n\n### Example\n\nWith an executable file called `post-backup.sh` next to the compose file with the following contents\n\n```sh\necho \"Backup from $RCON_HOST to $DEST_DIR finished\"\n```\n\nand the following compose definition\n\n```yaml\nversion: '3.7'\n\nservices:\n  mc:\n    image: itzg/minecraft-server\n    ports:\n      - \"25565:25565\"\n    environment:\n      EULA: \"TRUE\"\n      TYPE: PAPER\n    volumes:\n      - mc:/data\n  backups:\n    image: itzg/mc-backup\n    environment:\n      BACKUP_INTERVAL: \"2h\"\n      RCON_HOST: mc\n      PRE_BACKUP_SCRIPT: |\n        echo \"Before backup!\"\n        echo \"Also before backup from $$RCON_HOST to $$DEST_DIR\"\n      POST_BACKUP_SCRIPT_FILE: /post-backup.sh\n    volumes:\n      # mount the same volume used by server, but read-only\n      - mc:/data:ro\n      # use a host attached directory so that it in turn can be backed up\n      # to external/cloud storage\n      - ./mc-backups:/backups\n      - ./post-backup.sh:/post-backup.sh:ro\n\nvolumes:\n  mc: {}\n\n```\n\n## Example\n\n### Kubernetes\n\nAn example StatefulSet deployment is provided [in this repository](test-deploy.yaml).\n\nThe important part is the containers definition of the deployment:\n\n```yaml\ncontainers:\n  - name: mc\n    image: itzg/minecraft-server\n    env:\n      - name: EULA\n        value: \"TRUE\"\n    volumeMounts:\n      - mountPath: /data\n        name: data\n  - name: backup\n    image: mc-backup\n    imagePullPolicy: Never\n    securityContext:\n      runAsUser: 1000\n    env:\n      - name: BACKUP_INTERVAL\n        value: \"2h 30m\"\n    volumeMounts:\n      - mountPath: /data\n        name: data\n        readOnly: true\n      - mountPath: /backups\n        name: backups\n```\n\n### Docker Compose\n\n```yaml\nversion: \"3.8\"\n\nservices:\n  mc:\n    image: itzg/minecraft-server:latest\n    ports:\n      - \"25565:25565\"\n    environment:\n      EULA: \"TRUE\"\n      TYPE: PAPER\n    depends_on:\n      restore-backup:\n        condition: service_completed_successfully\n    volumes:\n      - ./mc-data:/data\n  # \"init\" container for mc to restore the data volume when empty    \n  restore-backup:\n    # Same image as mc, but any base image with bash and tar will work\n    image: itzg/mc-backup\n    restart: \"no\"\n    entrypoint: restore-tar-backup\n    volumes:\n      # Must be same mount as mc service, needs to be writable\n      - ./mc-data:/data\n      # Must be same mount as backups service, but can be read-only\n      - ./mc-backups:/backups:ro\n  backups:\n    image: itzg/mc-backup\n    depends_on:\n      mc:\n        condition: service_healthy\n    environment:\n      BACKUP_INTERVAL: \"2h\"\n      RCON_HOST: mc\n      # since this service waits for mc to be healthy, no initial delay is needed\n      INITIAL_DELAY: 0\n    volumes:\n      - ./mc-data:/data:ro\n      - ./mc-backups:/backups\n```\n\n### Restic with rclone\n\nSetup the rclone configuration for the desired remote location\n```shell\ndocker run -it --rm -v rclone-config:/config/rclone rclone/rclone config\n```\n\nSetup the `itzg/mc-backup` container with the following specifics\n- Set `BACKUP_METHOD` to `restic`\n- Set `RESTIC_PASSWORD` to a restic backup repository password to use\n- Use `rclone:` as the prefix on the `RESTIC_REPOSITORY`\n- Append the rclone config name, colon (`:`), and specific sub-path for the config type\n\nIn the following example `CFG_NAME` and `BUCKET_NAME` need to be changed to specifics for the rclone configuration you created:\n```yaml\nversion: \"3\"\n\nservices:\n  mc:\n    image: itzg/minecraft-server\n    environment:\n      EULA: \"TRUE\"\n    ports:\n      - 25565:25565\n    volumes:\n      - mc:/data\n  backup:\n    image: itzg/mc-backup\n    environment:\n      RCON_HOST: mc\n      BACKUP_METHOD: restic\n      RESTIC_PASSWORD: password\n      RESTIC_REPOSITORY: rclone:CFG_NAME:BUCKET_NAME\n    volumes:\n      # mount volume pre-configured using a host mounted file\n      - ./rclone.conf:/config/rclone/rclone.conf\n      # or configure one into a named volume using\n      # docker run -it --rm -v rclone-config:/config/rclone rclone/rclone config\n      # and change the above to\n      # - rclone-config:/config/rclone\n      - mc:/data:ro\n      - backups:/backups\n\nvolumes:\n# Uncomment this if using the config step above\n#  rclone-config:\n#    external: true\n  mc: {}\n  backups: {}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitzg%2Fdocker-mc-backup","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fitzg%2Fdocker-mc-backup","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitzg%2Fdocker-mc-backup/lists"}