本文属于「自托管 Docker 部署实战」系列(共 35 篇),第 20 篇。 示例中的 IP(192.0.2.10)、域名(example.com)、密码均为占位符,请按实际环境替换。

它是什么

自建的 Minecraft「挂机」面板:面板容器通过挂载宿主机的 docker.sock,为每个账号拉起一个 HeadlessMC 无头客户端容器,实现批量挂机/挂时长。附带一个可选的测试服务器。

前置条件

  • 一台 Linux 服务器(1C1G 起步;Java 类应用建议 2C4G 以上);
  • 已安装 Docker 与 Compose v2,执行 docker compose version 有版本号输出;
  • 所有示例里的 IP / 域名 / 密码都是占位符,实际部署请替换成自己的。
# 安装 Docker(已安装可跳过)
curl -fsSL https://get.docker.com | sh

# 目录约定:一个服务一个目录,后文的 ./data 均指栈目录内
mkdir -p /srv/docker/active/<stack> && cd /srv/docker/active/<stack>

镜像地址

mcafk-panel:1.0.0                      # 自建,源码构建
3arthqu4ke/headlessmc:latest           # 无头客户端
itzg/minecraft-server:latest           # 测试服(profile: test)

目录结构

/srv/docker/active/mc-afk/
├── docker-compose.yml
├── panel/                # 面板源码(构建上下文)
├── data/                 # 账号/服务器/客户端配置
├── jdk/                  # Temurin 8/17/21
└── testserver/           # 测试服世界

部署步骤

# docker-compose.yml
name: mc-afk-panel

services:
  panel:
    build:
      context: ./panel
    image: mcafk-panel:1.0.0
    container_name: mcafk-panel
    restart: unless-stopped
    ports:
      - "${PANEL_PORT:-8060}:8060"
    environment:
      TZ: Asia/Shanghai
      PANEL_PORT: "8060"
      # 容器内路径必须与宿主机路径一致:拉起的子容器 bind mount 由宿主机解析
      DATA_DIR: /srv/docker/active/mc-afk/data
      PANEL_TOKEN: "${PANEL_TOKEN:-}"
      HMC_IMAGE: "3arthqu4ke/headlessmc:latest"
      HMC_HOME_MOUNT: "/home/default"
      HMC_WORK_MOUNT: "/work"
      HMC_JDK_DIR: "/srv/docker/active/mc-afk/jdk"
      HMC_JDK_MOUNT: "/usr/lib/jvm"
    volumes:
      - ./data:/srv/docker/active/mc-afk/data
      - ./jdk:/srv/docker/active/mc-afk/jdk:ro
      # 高危:面板通过它操作宿主 docker
      - /var/run/docker.sock:/var/run/docker.sock
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8060/api/health"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 20s

  testserver:
    image: itzg/minecraft-server:latest
    container_name: mcafk-testserver
    profiles: ["test"]
    restart: unless-stopped
    ports:
      - "25565:25565"
    environment:
      EULA: "TRUE"
      ONLINE_MODE: "FALSE"
      TYPE: VANILLA
      VERSION: "${TEST_MC_VERSION:-LATEST}"
      MEMORY: 2G
      MOTD: "mcafk test server"
      SPAWN_PROTECTION: 0
    volumes:
      - ./testserver:/data
docker compose up -d --build
docker compose --profile test up -d   # 需要测试服时再起

关键配置

  • DATA_DIR 与宿主机路径必须完全一致:面板把路径原样传给宿主机 docker daemon,路径不一致 = 子容器挂到空目录;
  • docker.sock 是硬需求,面板靠它创建/销毁子容器;
  • HMC_JDK_DIR 要给 HeadlessMC 提供 8/17/21 多版本 JDK,按客户端版本自动选;
  • PANEL_TOKEN 为空表示免口令,内网也建议设一个。

注意事项

  • docker.sock ≈ root 权限,面板被拿下等于整机沦陷,务必加口令并只在内网;
  • 挂机违反部分服务器规则,封号风险自担;
  • HeadlessMC 容器会吃 CPU,开几十个号前先压测;
  • 面板镜像自建,升级要重新 build,记得保留 data/。

备份与升级

# 面板数据:账号/服务器/客户端配置
tar czf "mcafk-data-$(date +%F).tar.gz" ./data

# 升级 = 重新构建镜像
docker compose up -d --build

# 回滚:代码切回旧版本后重新 build
  • ./jdk 不用备份,重装即可;
  • 子容器由面板动态创建,升级前先停掉所有挂机实例,升级后再逐个拉起。