Skip to main content
Docker Swarm provides native clustering and orchestration capabilities for deploying containerized Minecraft servers across multiple nodes with high availability.

Overview

Docker Swarm offers several advantages for Minecraft server deployment:

Native Clustering

Built-in orchestration without external dependencies

Service Management

Declarative service definitions with automatic reconciliation

Rolling Updates

Zero-downtime updates with configurable strategies

Load Balancing

Built-in ingress load balancing for services
While Swarm provides orchestration, remember that Minecraft servers are stateful and typically run as single replicas.

Initialize Swarm

First, initialize a Swarm cluster:
1

Initialize the manager node

docker swarm init
This outputs a join token for worker nodes.
2

Add worker nodes (optional)

On each worker node:
docker swarm join --token SWMTKN-1-xxx manager-ip:2377
3

Verify cluster

docker node ls

Stack Deployment

Basic Stack

Create a minecraft-stack.yml file:
minecraft-stack.yml
version: '3.8'

services:
  minecraft:
    image: itzg/minecraft-server:latest
    ports:
      - "25565:25565"
    volumes:
      - minecraft-data:/data
    environment:
      EULA: "TRUE"
      TYPE: PAPER
      VERSION: "1.21.4"
      MEMORY: "4G"
      DIFFICULTY: normal
      MAX_PLAYERS: 50
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.role == manager
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 120s
      update_config:
        parallelism: 1
        delay: 10s
        failure_action: rollback
        monitor: 60s
    networks:
      - minecraft

volumes:
  minecraft-data:
    driver: local

networks:
  minecraft:
    driver: overlay
1

Deploy the stack

docker stack deploy -c minecraft-stack.yml mc
2

Verify deployment

docker stack services mc
docker service ls
3

View logs

docker service logs -f mc_minecraft

Stack with RCON

Add RCON web admin to your stack:
minecraft-stack-rcon.yml
version: '3.8'

services:
  minecraft:
    image: itzg/minecraft-server
    ports:
      - "25565:25565"
    volumes:
      - minecraft-data:/data
    environment:
      EULA: "TRUE"
      TYPE: PAPER
      MEMORY: "4G"
      ENABLE_RCON: "TRUE"
      RCON_PASSWORD_FILE: /run/secrets/rcon_password
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.labels.minecraft == true
      restart_policy:
        condition: on-failure
    secrets:
      - rcon_password
    networks:
      - minecraft

  rcon:
    image: itzg/rcon
    ports:
      - "4326:4326"
      - "4327:4327"
    volumes:
      - rcon-data:/opt/rcon-web-admin/db
    environment:
      RWA_USERNAME: admin
      RWA_PASSWORD_FILE: /run/secrets/rcon_admin_password
      RWA_RCON_HOST: minecraft
      RWA_RCON_PASSWORD_FILE: /run/secrets/rcon_password
    deploy:
      replicas: 1
    secrets:
      - rcon_password
      - rcon_admin_password
    networks:
      - minecraft
    depends_on:
      - minecraft

volumes:
  minecraft-data:
  rcon-data:

networks:
  minecraft:
    driver: overlay
    attachable: true

secrets:
  rcon_password:
    external: true
  rcon_admin_password:
    external: true
Create the secrets before deploying:
echo "your-rcon-password" | docker secret create rcon_password -
echo "admin-panel-password" | docker secret create rcon_admin_password -

docker stack deploy -c minecraft-stack-rcon.yml mc

Deploy Configuration

Placement Constraints

Control where services run:
deploy:
  placement:
    constraints:
      # Run on manager nodes only
      - node.role == manager
      
      # Run on nodes with specific label
      - node.labels.minecraft == true
      
      # Run on nodes with SSD storage
      - node.labels.storage == ssd
      
      # Multiple constraints
      - node.role == worker
      - node.labels.region == us-east
Set node labels:
docker node update --label-add minecraft=true node-1
docker node update --label-add storage=ssd node-1

Resource Limits

Define resource reservations and limits:
deploy:
  resources:
    reservations:
      cpus: '2.0'
      memory: 4G
    limits:
      cpus: '4.0'
      memory: 8G

Restart Policies

Configure service restart behavior:
deploy:
  restart_policy:
    condition: on-failure    # on-failure, any, or none
    delay: 5s               # Delay between restarts
    max_attempts: 3         # Max restart attempts
    window: 120s            # Window to evaluate restart

Update Configuration

Control how updates are applied:
deploy:
  update_config:
    parallelism: 1          # Update 1 task at a time
    delay: 10s              # Wait 10s between updates
    failure_action: rollback # rollback, pause, or continue
    monitor: 60s            # Monitor period
    max_failure_ratio: 0.3  # Max failures before rollback
    order: stop-first       # stop-first or start-first

Advanced Stack Configurations

Multiple Servers Stack

Run multiple Minecraft servers:
multi-server-stack.yml
version: '3.8'

services:
  survival:
    image: itzg/minecraft-server
    ports:
      - "25565:25565"
    volumes:
      - survival-data:/data
    environment:
      EULA: "TRUE"
      TYPE: PAPER
      MEMORY: "4G"
      DIFFICULTY: hard
      LEVEL_TYPE: DEFAULT
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.labels.server == survival
    networks:
      - minecraft

  creative:
    image: itzg/minecraft-server
    ports:
      - "25566:25565"
    volumes:
      - creative-data:/data
    environment:
      EULA: "TRUE"
      TYPE: PAPER
      MEMORY: "2G"
      MODE: creative
      DIFFICULTY: peaceful
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.labels.server == creative
    networks:
      - minecraft

  minigames:
    image: itzg/minecraft-server
    ports:
      - "25567:25565"
    volumes:
      - minigames-data:/data
    environment:
      EULA: "TRUE"
      TYPE: SPIGOT
      MEMORY: "3G"
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.labels.server == minigames
    networks:
      - minecraft

volumes:
  survival-data:
  creative-data:
  minigames-data:

networks:
  minecraft:
    driver: overlay

Stack with Monitoring

Add monitoring services:
minecraft-monitored-stack.yml
version: '3.8'

services:
  minecraft:
    image: itzg/minecraft-server
    ports:
      - "25565:25565"
    volumes:
      - minecraft-data:/data
    environment:
      EULA: "TRUE"
      TYPE: PAPER
      MEMORY: "4G"
      ENABLE_JMX: "TRUE"
      JMX_PORT: 7091
    deploy:
      replicas: 1
    networks:
      - minecraft
      - monitoring

  prometheus:
    image: prom/prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.role == manager
    networks:
      - monitoring

  grafana:
    image: grafana/grafana
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana
    environment:
      GF_SECURITY_ADMIN_PASSWORD: admin
    deploy:
      replicas: 1
    networks:
      - monitoring

volumes:
  minecraft-data:
  prometheus-data:
  grafana-data:

networks:
  minecraft:
    driver: overlay
  monitoring:
    driver: overlay

Service Management

Deploy and Update

# Deploy new stack
docker stack deploy -c minecraft-stack.yml mc

# Update stack (apply changes)
docker stack deploy -c minecraft-stack.yml mc

# Force update service
docker service update --force mc_minecraft

# Update service image
docker service update --image itzg/minecraft-server:java21 mc_minecraft

Scaling

Don’t scale Minecraft servers beyond 1 replica - they maintain state and cannot be load balanced.
For auxiliary services:
# Scale RCON service (if stateless)
docker service scale mc_rcon=3

Rollback

# Rollback to previous version
docker service rollback mc_minecraft

# Check rollback status
docker service ps mc_minecraft

Remove Stack

# Remove entire stack
docker stack rm mc

# Verify removal
docker stack ls
docker service ls

Secrets Management

Swarm secrets provide secure credential storage:
1

Create secrets

# From stdin
echo "my-password" | docker secret create rcon_password -

# From file
docker secret create server_properties ./server.properties
2

Use in stack

services:
  minecraft:
    secrets:
      - rcon_password
      - source: server_properties
        target: /data/server.properties

secrets:
  rcon_password:
    external: true
  server_properties:
    external: true
3

Access in container

Secrets are mounted at /run/secrets/<secret_name>
environment:
  RCON_PASSWORD_FILE: /run/secrets/rcon_password

List and Remove Secrets

# List secrets
docker secret ls

# Inspect secret (metadata only)
docker secret inspect rcon_password

# Remove secret
docker secret rm rcon_password

Configs

Configs are similar to secrets but for non-sensitive data:
# Create config
docker config create server_properties ./server.properties
services:
  minecraft:
    configs:
      - source: server_properties
        target: /data/server.properties
        mode: 0440

configs:
  server_properties:
    external: true

Networking

Overlay Networks

Overlay networks span multiple nodes:
networks:
  minecraft:
    driver: overlay
    attachable: true  # Allow non-swarm containers to connect
    driver_opts:
      encrypted: "true"  # Encrypt network traffic

Published Ports

services:
  minecraft:
    ports:
      # Long syntax
      - target: 25565      # Container port
        published: 25565   # Host port
        protocol: tcp
        mode: host         # host or ingress
Mode differences:
  • ingress (default): Load balanced across all nodes
  • host: Direct binding to host port
Use mode: host for Minecraft to ensure clients connect to the same server instance.

Volume Management

Named Volumes

volumes:
  minecraft-data:
    driver: local
    driver_opts:
      type: nfs
      o: addr=nfs-server.example.com,rw
      device: ":/path/to/data"

Volume Drivers

Use volume plugins for distributed storage:
# Install NFS volume plugin
docker plugin install --grant-all-permissions vieux/sshfs
volumes:
  minecraft-data:
    driver: vieux/sshfs
    driver_opts:
      sshcmd: "user@server:/path"
      password: "password"

Monitoring and Logs

Service Logs

# Follow service logs
docker service logs -f mc_minecraft

# Last 100 lines
docker service logs --tail 100 mc_minecraft

# Logs since timestamp
docker service logs --since 2024-01-01T00:00:00 mc_minecraft

# Include timestamps
docker service logs --timestamps mc_minecraft

Service Status

# List all services
docker service ls

# Inspect service
docker service inspect mc_minecraft

# Service tasks (replicas)
docker service ps mc_minecraft

# Service details
docker service inspect --pretty mc_minecraft

Stack Information

# List stacks
docker stack ls

# Stack services
docker stack services mc

# Stack tasks
docker stack ps mc

High Availability

Manager Node Quorum

For production, use 3 or 5 manager nodes:
# On additional manager nodes
docker swarm join-token manager
Quorum requirements:
  • 3 managers: tolerates 1 failure
  • 5 managers: tolerates 2 failures
  • 7 managers: tolerates 3 failures

Node Availability

# Drain node (no new tasks)
docker node update --availability drain node-1

# Activate node
docker node update --availability active node-1

# Pause node (stop scheduling)
docker node update --availability pause node-1

Backup and Disaster Recovery

Backup Data

# Find volume location
docker volume inspect mc_minecraft-data

# Create backup
docker run --rm -v mc_minecraft-data:/data -v $(pwd):/backup \
  alpine tar czf /backup/minecraft-backup.tar.gz /data

Restore Data

# Restore from backup
docker run --rm -v mc_minecraft-data:/data -v $(pwd):/backup \
  alpine tar xzf /backup/minecraft-backup.tar.gz -C /

Best Practices

Use Placement Constraints

Pin stateful services to specific nodes to ensure data persistence

Implement Health Checks

Add health checks to detect and recover from failures automatically

Manage Secrets Securely

Use Docker secrets for passwords and sensitive configuration

Monitor Resources

Set resource limits and monitor usage to prevent node exhaustion

Use Overlay Networks

Leverage overlay networks for secure multi-node communication

Regular Backups

Implement automated backup strategies for world data

Troubleshooting

Service Won’t Start

# Check service status
docker service ps --no-trunc mc_minecraft

# View logs
docker service logs mc_minecraft

# Inspect service
docker service inspect mc_minecraft

Networking Issues

# List networks
docker network ls

# Inspect network
docker network inspect mc_minecraft

# Test connectivity
docker run --rm --network mc_minecraft alpine ping minecraft

Volume Issues

# List volumes
docker volume ls

# Inspect volume
docker volume inspect mc_minecraft-data

# Check volume contents
docker run --rm -v mc_minecraft-data:/data alpine ls -la /data

Next Steps

Deployment Examples

Explore more deployment configurations and patterns

Kubernetes

Compare with Kubernetes deployment options

Additional Resources

Build docs developers (and LLMs) love