Skip to main content

Why Docker Compose?

Docker Compose makes it easier to manage your Minecraft server by:
  • Storing configuration in a version-controlled file
  • Simplifying updates and reconfiguration
  • Managing multiple services (server, backups, proxies)
  • Enabling easy deployment and portability
For long-running servers, Docker Compose is highly recommended over plain docker run commands as it allows for incremental reconfiguration and image upgrades.

Basic setup

1

Create a project directory

Create a new directory for your Minecraft server:
mkdir minecraft-server
cd minecraft-server
2

Create compose.yaml

Create a file named compose.yaml with the following content:
compose.yaml
services:
  mc:
    image: itzg/minecraft-server:latest
    pull_policy: daily
    tty: true
    stdin_open: true
    ports:
      - "25565:25565"
    environment:
      EULA: "TRUE"
    volumes:
      - ./data:/data
    restart: unless-stopped
3

Start the server

Run the server with Docker Compose:
docker compose up -d
The -d flag runs the server in detached mode (background).
4

Connect to your server

Point your Minecraft client at localhost:25565 or your server’s IP address.

Managing your server

View logs

Follow the server logs in real-time:
docker compose logs -f

Check status

View the status of your services:
docker compose ps

Stop the server

Stop the server gracefully:
docker compose stop

Start the server

Start a stopped server:
docker compose start

Apply configuration changes

After editing compose.yaml, apply changes:
docker compose up -d

Restart the server

Restart the server (useful for updates when using VERSION=LATEST):
docker compose restart

Remove the server

Stop and remove containers (data in volumes is preserved):
docker compose down

Configuration examples

Paper server with plugins

Run a Paper server with 4GB RAM:
compose.yaml
services:
  mc:
    image: itzg/minecraft-server:latest
    pull_policy: daily
    tty: true
    stdin_open: true
    ports:
      - "25565:25565"
    environment:
      EULA: "TRUE"
      TYPE: PAPER
      VERSION: 1.20.4
      MEMORY: 4G
      MAX_PLAYERS: 50
      VIEW_DISTANCE: 12
      DIFFICULTY: normal
      MODE: survival
      MOTD: "Welcome to my Paper server!"
    volumes:
      - ./data:/data
    restart: unless-stopped

Modded server with CurseForge

Automatic modpack installation from CurseForge:
compose.yaml
services:
  mc:
    image: itzg/minecraft-server:latest
    pull_policy: daily
    tty: true
    stdin_open: true
    ports:
      - "25565:25565"
    environment:
      EULA: "TRUE"
      MODPACK_PLATFORM: AUTO_CURSEFORGE
      CF_API_KEY: ${CF_API_KEY}
      CF_PAGE_URL: https://www.curseforge.com/minecraft/modpacks/all-the-mods-9
      MEMORY: 6G
    volumes:
      - ./data:/data
    restart: unless-stopped
Get a CurseForge API key from console.curseforge.com and store it in a .env file:
.env
CF_API_KEY=your-api-key-here

Modrinth modpack

Run a Modrinth modpack:
compose.yaml
services:
  mc:
    image: itzg/minecraft-server:latest
    pull_policy: daily
    tty: true
    stdin_open: true
    ports:
      - "25565:25565"
    environment:
      EULA: "TRUE"
      MODPACK_PLATFORM: MODRINTH
      MODRINTH_MODPACK: /modpacks/modpack-file.mrpack
    volumes:
      - ./data:/data
      - ./modpacks:/modpacks:ro
    restart: unless-stopped

Bedrock-compatible server

Use GeyserMC to allow Bedrock Edition players:
compose.yaml
services:
  mc:
    image: itzg/minecraft-server:latest
    pull_policy: daily
    tty: true
    stdin_open: true
    environment:
      EULA: "TRUE"
      TYPE: PAPER
      PLUGINS: |
        https://download.geysermc.org/v2/projects/geyser/versions/latest/builds/latest/downloads/spigot
        https://download.geysermc.org/v2/projects/floodgate/versions/latest/builds/latest/downloads/spigot
    ports:
      - "25565:25565"  # Java Edition
      - "19132:19132/udp"  # Bedrock Edition
    volumes:
      - ./data:/data
    restart: unless-stopped

High-performance server

Optimized configuration for larger servers:
compose.yaml
services:
  mc:
    image: itzg/minecraft-server:latest
    pull_policy: daily
    tty: true
    stdin_open: true
    ports:
      - "25565:25565"
    environment:
      EULA: "TRUE"
      TYPE: PAPER
      VERSION: LATEST
      MEMORY: 8G
      MAX_PLAYERS: 100
      VIEW_DISTANCE: 15
      SIMULATION_DISTANCE: 10
      LEVEL_TYPE: LARGEBIOMES
      MAX_BUILD_HEIGHT: 320
      DIFFICULTY: hard
      ENABLE_COMMAND_BLOCK: "true"
      SPAWN_PROTECTION: 0
    volumes:
      - ./data:/data
    restart: unless-stopped

Advanced configurations

Using named volumes

Use Docker-managed named volumes instead of bind mounts:
compose.yaml
services:
  mc:
    image: itzg/minecraft-server:latest
    pull_policy: daily
    tty: true
    stdin_open: true
    ports:
      - "25565:25565"
    environment:
      EULA: "TRUE"
      TYPE: PAPER
      MEMORY: 4G
    volumes:
      - mc-data:/data
    restart: unless-stopped

volumes:
  mc-data:

Multiple servers

Run multiple Minecraft servers on the same host:
compose.yaml
services:
  vanilla:
    image: itzg/minecraft-server:latest
    pull_policy: daily
    tty: true
    stdin_open: true
    ports:
      - "25565:25565"
    environment:
      EULA: "TRUE"
      MOTD: "Vanilla Server"
    volumes:
      - vanilla-data:/data
    restart: unless-stopped

  modded:
    image: itzg/minecraft-server:latest
    pull_policy: daily
    tty: true
    stdin_open: true
    ports:
      - "25566:25565"
    environment:
      EULA: "TRUE"
      TYPE: FABRIC
      MOTD: "Modded Server"
      MEMORY: 6G
    volumes:
      - modded-data:/data
    restart: unless-stopped

volumes:
  vanilla-data:
  modded-data:

Server with RCON web admin

Add RCON web interface for remote administration:
compose.yaml
services:
  minecraft:
    image: itzg/minecraft-server:latest
    pull_policy: daily
    tty: true
    stdin_open: true
    ports:
      - "25565:25565"
    environment:
      EULA: "TRUE"
      TYPE: PAPER
      MEMORY: 4G
      ENABLE_RCON: "true"
      RCON_PASSWORD: "changeme"
    volumes:
      - mc-data:/data
    restart: unless-stopped

  rcon:
    image: itzg/rcon
    ports:
      - "4326:4326"
      - "4327:4327"
    volumes:
      - rcon-data:/opt/rcon-web-admin/db
    restart: unless-stopped

volumes:
  mc-data:
  rcon-data:

With automatic backups

Integrate with itzg/mc-backup for scheduled backups:
compose.yaml
services:
  mc:
    image: itzg/minecraft-server:latest
    pull_policy: daily
    tty: true
    stdin_open: true
    ports:
      - "25565:25565"
    environment:
      EULA: "TRUE"
      TYPE: PAPER
      MEMORY: 4G
    volumes:
      - ./data:/data
    restart: unless-stopped

  backup:
    image: itzg/mc-backup
    environment:
      BACKUP_INTERVAL: "2h"
      PRUNE_BACKUPS_DAYS: 7
      RCON_HOST: mc
      RCON_PASSWORD: "changeme"
    volumes:
      - ./data:/data:ro
      - ./backups:/backups
    depends_on:
      - mc
    restart: unless-stopped

Common environment variables

Here are frequently used environment variables in compose files:
EULA: "TRUE"  # Required
TYPE: PAPER  # VANILLA, PAPER, SPIGOT, FORGE, FABRIC, etc.
VERSION: 1.20.4  # LATEST, SNAPSHOT, or specific version
MEMORY: 4G  # RAM allocation

Best practices

1

Use version control

Store your compose.yaml and configuration in Git for easy rollback and collaboration.
2

Set pull_policy

Use pull_policy: daily to automatically check for image updates:
services:
  mc:
    pull_policy: daily
3

Use .env for secrets

Store API keys and passwords in a .env file (add to .gitignore):
.env
CF_API_KEY=your-api-key
RCON_PASSWORD=secure-password
4

Enable restart policy

Always set a restart policy for production:
restart: unless-stopped
5

Regular backups

Implement automated backups of your data directory or use the mc-backup container.
Do not commit sensitive information like API keys or passwords to version control. Use .env files and add them to .gitignore.

Configurator tool

If you prefer an interactive tool to generate your compose.yaml file, check out setupmc.com’s configurator. It provides a form interface that supports most image variables and generates the compose file in real-time.

Troubleshooting

Server won’t start

Check the logs for errors:
docker compose logs
Common issues:
  • Missing EULA: "TRUE"
  • Port 25565 already in use
  • Insufficient memory allocated
  • Invalid configuration values

Permission errors

If using bind mounts on Linux, you may need to fix permissions:
sudo chown -R 1000:1000 ./data
Or for rootless/SELinux systems, add :Z to volumes:
volumes:
  - ./data:/data:Z

Container keeps restarting

View logs to identify the issue:
docker compose logs --tail=50
Temporarily disable auto-restart to debug:
restart: "no"

Next steps

Full documentation

Explore advanced features like mods, plugins, autopause, and more

Examples repository

Browse 40+ ready-to-use example configurations

GitHub repository

View source code and report issues

Discord community

Get help from the community

Build docs developers (and LLMs) love