MCM is a modern, high-performance, self-hosted Minecraft server management panel. Built with a lightweight Go backend and a responsive React / Vite frontend, MCM orchestrates Minecraft servers as sibling Docker or Podman containers on the host using lightweight, security-hardened Eclipse Temurin Alpine OpenJDK/JRE images.
Each Minecraft server container runs with MCM's custom native lifecycle entrypoint script (DefaultEntryScript), providing interactive console FIFO pipes, graceful shutdown traps (SIGTERM/SIGINT), headless Java configuration, and automated installer execution for Forge and NeoForge. MCM supports both direct host-port publication (for zero-proxy overhead, raw performance, and UDP/TCP support) and private container networking (mcm-network) with optional host ports for seamless multi-server proxy setups (e.g., Velocity or BungeeCord).
Use the included mcmctl command on a Linux host with systemd. Run it as your
normal user. Its guided installer walks through configuration, builds the
complete panel with Podman or Docker, installs a user service, and starts the app.
Go, Node.js, and pnpm are supplied by the build image.
On Debian/Ubuntu, install the host dependencies:
sudo apt update
sudo apt install -y podman uidmap slirp4netns fuse-overlayfs git curl util-linuxOn Fedora:
sudo dnf install -y podman git curl util-linuxThen install MCM:
git clone https://github.com/ChokunPlayZ/Minecraft-Container-Manager.git
cd Minecraft-Container-Manager
./mcmctl installThe terminal wizard walks through the engine and API socket, storage, panel
address, Minecraft ports, timezone, passkeys, HTTPS, default server limits,
optional S3/CurseForge credentials, and login protection. Press Enter to keep
each default. Review all settings and revisit any step before saving; type
:cancel at any prompt to exit without saving. Existing settings and session
secrets are kept, and credential input is hidden in the terminal.
Flags such as --runtime podman, --data-dir /absolute/path, and --port 9090
set the wizard's defaults. Use --non-interactive for unattended installation;
without a terminal the installer also uses existing settings, flags, and defaults.
Use --interactive to explicitly request the wizard with redirected input.
Open https://YOUR_SERVER_IP:8080 (or your configured address) and complete
onboarding. MCM generates a self-signed certificate by default; trust its public certificate or accept the
browser warning on first use. Open port 8080 and
any published Minecraft ports in the host firewall if you connect remotely.
For a host already running Docker, use ./mcmctl install --runtime docker with
an account that can access its Docker daemon.
Already have this checkout or a failed mcm.service from the earlier setup?
Run ./mcmctl install --runtime podman from the updated project directory.
It creates the previously missing ~/.config/mcm/mcm.env and replaces the user
service with the managed installation. Existing settings and credentials
are preserved. If your server data is elsewhere, include its actual path:
./mcmctl install --runtime podman --data-dir /absolute/path/to/existing/dataKeep using the same engine for existing Minecraft containers. If moving from a
Compose panel, stop that panel first and pass its existing host data directory
with --data-dir; run only one panel against that directory.
From the checkout, use:
| Task | Command |
|---|---|
| Check status | ./mcmctl status |
| Follow logs | ./mcmctl logs |
| Start / stop / restart | ./mcmctl start / ./mcmctl stop / ./mcmctl restart |
| Edit settings step by step | ./mcmctl config (offers a restart after saving) |
| Open settings in a text editor | ./mcmctl config --editor, then ./mcmctl restart |
| Download and install updates | ./mcmctl update |
| Build local changes | ./mcmctl update --local |
| Back up panel settings and database | ./mcmctl backup |
| Restore the last panel backup and version | ./mcmctl rollback |
| Enable / disable automatic startup | ./mcmctl enable / ./mcmctl disable |
| Uninstall while keeping data | ./mcmctl uninstall |
The command is also installed at ~/.local/bin/mcmctl for use outside the
checkout. Updates build before stopping the panel, save the installed version
and panel database, and restore them if the new version cannot become ready.
Minecraft containers continue running during a panel update.
Settings live in ~/.config/mcm/mcm.env; the default database and server files
live in ~/.local/share/mcm. Guided changes save a copy of the previous settings
under ~/.config/mcm/backups. The installer enables the user service and tries
to enable lingering so it starts at boot and continues after logout. If your
host requires administrator authorization, it prints the one command to finish
that step. Keep the source checkout: update uses its current Git branch.
See installation and operations for prerequisites, configuration, updates, backups, rollback, and troubleshooting. The Compose instructions below are alternatives for people who want to run the panel in a container.
- Extensive Flavor Support: Out-of-the-box support for 23 server platforms:
- Bukkit / Paper Ecosystem: Paper, Purpur, Folia, Pufferfish, Leaf, Spigot, and Vanilla.
- Mod Loaders: Fabric, Quilt, Forge, NeoForge, and SpongeVanilla/SpongeForge.
- Hybrid Mod + Plugin Engines: Youer, Mohist (Legacy), Ketting, and Crucible.
- High-Performance Proxies: Velocity, Waterfall, and BungeeCord.
- Limbo & Queue Servers: Limbo and NanoLimbo.
- Bridges & Custom: GeyserMC Standalone and Custom Server JARs.
- Dynamic Java Runtime Selector: Automatically select and run Java 8, 11, 17, or 21 (
eclipse-temurin:<version>-jre-alpine) based on Minecraft version requirements, with built-in recommendations and automatic runtime image pulling. - In-Place Version Switching: Upgrade or switch server types and builds with built-in version metadata and confirmation safeguards.
- Modrinth & CurseForge Integration: Browse, search, and 1-click install popular modpacks directly from Modrinth and CurseForge catalogs.
- Deep Modpack Inspection: Automatically detects Minecraft version, mod loader, loader build, and recommended Java runtime before installation.
- Asynchronous Task Progress Tracking: Live task progress monitoring (SSE stream and polling) for modpack downloads, extraction, and archiving.
- Client-Only Mod Sanitization: Automatically scans and strips client-only mods (e.g. shaders, GUI optimizations, client audio mods) from server-side installations.
- Stale Binary Cleanup: Automatically purges obsolete loaders, launch scripts, and stale jar files when switching modpack engines or loaders.
- User-Required File Notifications: Flags mods or assets that require manual download due to licensing constraints and guides the administrator through the setup.
- Version Locking & Updates: Lock modpacks to specific versions to prevent configuration drift, with support for seamless upgrades.
- Version Update Helper: Dedicated assistant to guide administrators through upgrading Minecraft versions, server loaders, and modpacks with compatibility checks and pre-update backup prompts.
- Automated Mod Updates: Scans installed mods against Modrinth and CurseForge, checks for available updates with request coalescing, and offers 1-click batch updating.
- Mod Dependency Resolution: Discovers missing required and optional dependencies before installation and installs them in one click via
ModDependenciesDialog. - Mod Jar Picker: Select exact builds or releases when upgrading or installing specific mods.
- Multi-Provider Catalog: Browse and search tens of thousands of mods and plugins across 4 major repositories:
- Modrinth: Mods, plugins, and datapacks with loader detection, server-side-only filtering (
onlyServerSide), and infinite scroll. - PaperMC Hangar: Curated Paper, Purpur, and Folia plugins.
- SpigotMC (via Spiget): Over 100,000 Bukkit and Spigot plugins.
- CurseForge: Expansive catalog of mods and server addons.
- Modrinth: Mods, plugins, and datapacks with loader detection, server-side-only filtering (
- Mod Management: Enable/disable mods with
.disabledtoggling, view installed metadata, and delete mods. - One-Click Modlist Export: Download a shareable
.txtlist from Installed Mods or Plugins, including server details, installed versions, filenames, enabled/disabled status, and known catalog links. Exports include the full list regardless of search filters and are available with read-only access.
- Dashboard Host Resources: Live CPU, memory, and network usage summed across active managed server containers, with CPU and memory compared against the Docker or Podman host's capacity. The resource viewer refreshes every five seconds and shows available, used, and total space on the filesystem containing
MCM_DATA_DIR. Available disk space excludes filesystem reservations and remains visible when the runtime is offline. Container usage excludes other host processes; it is not a sum of configured limits. - Live Container Resource Metrics: Real-time stats polled directly from the Docker daemon:
- CPU Utilization %: Shown as a share of the whole host in both live cards and performance charts: 100% means all logical CPU cores are busy. CPU quotas remain labeled in cores. For example, Docker-style 397% on an eight-core host displays as 49.6%.
- Memory Usage & Limits: Real-time memory consumption, limits, and usage percentage.
- Network I/O: Live incoming (
rx) and outgoing (tx) network throughput. - Block / Disk I/O: Real-time disk read and write bytes.
- Server Uptime Tracking: Tracks server start timestamps (
started_at) and displays live, human-readable uptime (e.g.,3d 4h 12m) on dashboard cards and server headers. - ServerStatsGrid: Clean, visual metrics dashboard available directly on the server overview and management pages.
- Performance History: The server's Performance tab charts CPU, memory, connected players, TPS, and median tick time. Background samples are stored in SQLite every 30 seconds and retained for 7 days, with 1-hour, 6-hour, 24-hour, and 7-day views. CPU and memory are always collected quietly. Player and tick metrics are off by default, including for existing servers. Choose RCON polling or Console commands per server to opt in. Console mode prints
listandspark tpsoutput every 30 seconds; RCON mode reads replies directly and never falls back to the console. RCON must be enabled with a password and reachable through a shared container network or an existing RCON TCP port binding; MCM does not expose ports or enable RCON automatically. Collection errors appear beside the selector. Longer windows average resource/tick readings and show peak player counts. Missing readings appear as gaps, and turning collection off preserves earlier history. - Spark Reports: Detects enabled spark plugins/mods from their metadata or filenames, and bundled spark on Paper 1.21.1+. Capture a 60-second profile and open its returned link, or open a profiler that is already running. Manual report capture remains available when automatic collection is off, writes to the console, and uploads the report to spark's viewer when requested. Capture progress and the latest result survive navigation. Automatic TPS and median tick duration require spark and an enabled collection mode.
- Dedicated Container Network (
mcm-network): Sibling containers join an isolated Docker bridge network where each container is addressable by its internal hostname (mcm-<server-id>). - Proxy Config Editor: Built-in visual editor and configuration generator for Velocity (
velocity.toml) and BungeeCord / Waterfall (config.yml). - Optional Host Ports: Run backend servers entirely private on the internal Docker network with zero exposed host ports, routing all player traffic securely through your proxy.
- Lifecycle Controls: Start, Graceful Stop (
SIGTERMwithstop/end/shutdowncommands piped to console), Restart, and Force-Kill (SIGKILL). - Dashboard Controls: Start or stop a server from its fleet row. The action menu includes Restart, server-specific Backups, Copy server, and Force kill with confirmation.
- Rebuild Warning System: Automatically detects when server configuration changes (Java runtime, memory limits, CPU quotas, port bindings) require container recreation and displays an actionable rebuild banner.
- 1-Click Container Rebuild: Recreate sibling containers on demand without data loss to apply updated configuration, memory limits, or base images. If online, the server is gracefully shut down first to cleanly save world data, the container is recreated, and it is automatically booted back up.
- Instant Server Duplication / Cloning: 1-click server cloning (
POST /api/servers/:id/copy) that duplicates server data, configurations, mods, and plugins while automatically allocating fresh host ports. - Server Export & Import: Export a server as ZIP, then use Import server beside Create server on the Servers page. New exports include the server type, version, build, RAM, Java and resource limits in
mcm-export.json. Leave the name blank to retain the exported name, or enter a replacement. For older exports, enter a name, then open Server settings in the import dialog and supply the original type and version; RAM defaults to 2048 MB and Java is selected automatically. Imports restore all archived files into a new stopped server, assign a free game port (or no host port when private), and create the default automatic backup schedule. Container identities and additional host-port bindings are not reused; configure additional ports before starting. Limits: 2 GiB compressed, 8 GiB extracted, 100,000 entries. Unsafe paths, links, duplicate entries and damaged archives are rejected, and failed imports are cleaned up. Stop the source server before exporting for a consistent world save.
- Real-Time Streaming: Live server logs streamed directly to the browser using Server-Sent Events (SSE).
- Last-Event-ID Resumption: Seamlessly reconnects to log streams after network hiccups without duplicate messages or log gaps.
- Interactive Command Input: Send console commands directly to the running server via native FIFO stdin pipe (
/tmp/console.in) with RCON fallback. - Smart Auto-Scroll: Sticky bottom-scrolling that pauses automatically when scrolling up to inspect past logs.
- Saved Log Browser: Open the server's Logs tab to read files from
logs/andcrash-reports/, including.log.gzrotations and logs inside.tar,.tar.gz, and.tgzarchives, without extracting them. Search, line numbers, wrapping, and pagination help inspect saved output. Previews show the first 2 MiB; search applies to that preview.
- Open a Java game server’s Worlds tab to browse its saved worlds, dimensions, saved seed, Minecraft version and disk usage. Proxies and standalone Geyser servers do not store Java worlds.
- Create worlds with numeric or text seeds, default/superflat/large-biomes/amplified generation and optional structures. Leave the seed blank for a random seed. Make a world active, then start the server to generate it. Generation settings stay editable until
level.datexists; existing terrain retains its saved seed. - Import ZIP accepts a Java world with
level.dat, either at the archive root or inside a folder. Matching Bukkit<world>_netherand<world>_the_endfolders are imported and exported with the main world. Imports use a new folder name and never overwrite existing folders. Limits: 2 GiB compressed, 8 GiB unpacked, 100,000 entries. Unsafe paths, symbolic links, duplicate files and invalid metadata are rejected before the imported world becomes available. - Make active updates
level-nameand generation settings inserver.properties, preserving unrelated properties. Switching takes effect on the next start. World imports, exports, switches, seed edits, deletions and chunk resets require a stopped server and a confirmed inactive container; startup waits for world operations on that server. - Manage chunks inspects paged region files by dimension, including modded dimension folders. The 32 × 32 map selects individual generated chunks or all generated chunks in the selected region. Coordinate-range inputs support precise selection on touch screens, with a visible list of all selected chunk coordinates. Arrow keys move between cells; Space selects. Resetting removes the selected terrain, entity and point-of-interest entries so Minecraft regenerates the chunks when visited. Other chunk payloads are unchanged. Resetting makes sectors reusable and does not immediately shrink region files.
- Chunk resets first copy every affected region and external chunk payload to
.mcm-world-backups/<id>/, with areset.jsonmanifest. To recover, stop the server and use Files to copy the backed-up paths over their original paths. World deletion moves the inactive world and its dimension folders to.mcm-world-trash/<id>/; restore the folders to the server root using Files. These recovery folders remain until manually removed and count toward disk usage. The active world cannot be deleted.
- Open Players → Player data to find saved player files by cached name, UUID or world, including offline players. Quick fields edit health, food, saturation, XP, game mode, dimension and position when those tags exist; inventory, ender chest and abilities open in the full tag browser. Names come from the server's local
usercache.json, whitelist and operator list. - In Files, open
.dat,.dat_old,.nbt,.schematic,.schemor.litematicfiles directly. Open as NBT works with other filenames too. Browse and search every Java Edition NBT tag type, edit named values and numeric arrays, add compound children or homogeneous list items, and remove tags. This also coverslevel.dat, structures, saved world data and mod NBT files. - GZIP, zlib and uncompressed documents retain their compression and tag types. Signed 64-bit integers keep their full precision. Limits: 16 MiB on disk and after decompression, 64 nesting levels, 100,000 tags and 1,000,000 collection elements. Bedrock little-endian data and region containers (
.mca/.mcr) are not standalone Java NBT documents. - Browsing is available while running. Saving requires a stopped server, an inactive container and no active background task. Each save checks the opened file's content revision, writes an exact copy to
<filename>.mcm-nbt-<id>.bak, then replaces the original atomically. Conflicts retain local edits and require reload before another save. Backups remain beside the file until removed; use Download previous version or Files to retrieve them. To restore, stop the server and upload the backup under the original filename.
- Open a server's Schedules tab to schedule a backup, console command, start, stop, graceful restart, or Action chain.
- An action chain runs its steps in order. Add console commands, backups (with a separate storage target for each backup), start/stop/restart actions, and Wait steps of 1–3600 seconds. Use the arrow buttons to reorder steps and the remove button to delete a step. Chains support up to 50 steps. For example: console command
broadcast "Backup Starting"→ console commandsave-all→ Create backup → Wait → console commandbroadcast "Backup Complete". Use commands supported by your server; vanilla Minecraft announcements usesay. - A chain waits for each action to return, including the complete backup operation. Console steps finish when sent to the server; Minecraft command output is not parsed for success or completion. If a step fails, times out, or panics, the remaining steps are skipped and the last result identifies the failed step. Each command or power action has a 10-minute limit; each backup has a 30-minute limit. Wait steps are interruptible when the panel shuts down. Starting a container does not mean Minecraft has finished loading: add a wait after a backup, start, or restart before sending a console command.
- Choose midnight, hourly, every 30 minutes, weekly, or monthly presets, or enter a standard five-field cron expression (
minute hour day month weekday). For example,0 0 * * *runs at midnight and*/15 * * * *runs every 15 minutes. Names such asmidnight,daily, and@hourlyare also accepted by the API. - Choose Fixed interval to repeat every whole number of minutes, independent of the time of day. The API accepts expressions such as
@every 720m(12 hours) or@every 95m. - New tasks default to the existing
TZenvironment setting (UTCwhen unset or invalid). Each task saves its timezone and allows an override. Midnight follows the selected zone, including daylight saving changes. - Edit, pause/resume, and delete tasks; inspect the next run, last result, and error details. Console commands require a running server. Restart follows the manual restart behavior and also starts a stopped server.
- Backup tasks let you choose Panel default, Local disk, or Remote (S3) storage and use the server’s retention policy, with the same progress, notifications, and stop/resume behavior as manual backups. Remote backups use the panel’s configured S3-compatible endpoint and bucket. Existing automatic backup settings migrate to schedule entries, preserving enabled or paused state, minute intervals, and the panel’s default storage. New servers start with an enabled 12-hour backup schedule. Manage all automatic backups in Schedules; the old server backup settings are replaced by schedule tasks.
- Schedules persist in SQLite and run while the panel is online, within the five-second polling cadence. Missed runs are skipped after panel downtime. A task cannot overlap its own previous execution within the panel process, and pausing or deleting a task leaves an already running execution to finish. Failed runs are recorded and wait for the next scheduled occurrence.
App Settings in the main navigation contains shared installation controls: updates, DNS providers, port allocation, Discord notifications, and the CurseForge API key. Changes apply to all panel users.
Open User Settings from your profile in the sidebar or the avatar on mobile to manage your email, password, two-factor authentication, and passkeys. Appearance contains the theme preference, which is saved in the current browser and also available from the header theme menu.
App settings remain at /settings; personal settings are at /user-settings. Existing /settings?tab=account links redirect to User Settings.
Enable App Settings → Updates → Enable nightly update checks to check server software, plugins, and mods at 00:00 in the panel timezone (TZ, UTC by default). This is off by default. Check now starts an immediate fleet scan after opting in; scans never install updates or restart servers.
Saved results survive panel restarts. Servers with available updates display an Update Available badge on the dashboard and server page. Successful software catalog lookups also remember published versions and builds, including lookups while browsing releases, creating a server, or changing its software. These discoveries immediately mark matching servers as outdated, even with nightly checks off. Previously known newer releases are retained if a later lookup fails or returns older data. Builds are compared only within the same software type and game version. The server page shows the software version/build and plugin/mod update count, with actions to review them. Opening the installed plugins/mods list reads saved results; use its re-check action for an explicit refresh. Changing software settings or installed artifacts invalidates corresponding scan results; saved catalog discoveries are compared against the new software settings.
Each fleet scan starts with a fresh shared response cache. Repeated provider requests, including failures, are reused throughout that scan. Modrinth hash results are reused even when servers have overlapping but different mod lists; game version and loader filters stay separate. Software catalog responses are shared too. Failed checks retain previously known updates and show a warning.
Software checks compare published stable versions and builds for the installed version when a build is pinned. Platforms without a supported live catalog (including custom jars) show an explanation. Unrecognized plugin/mod jars may not be identifiable. Configure the shared CurseForge key in App Settings → CurseForge (requires settings.manage), or set CURSEFORGE_API_KEY on the panel as a fallback. Browsing, installs, manual checks, and nightly scans all use this server-side key; it is never returned to browsers. Previously browser-only keys must be entered once in the shared settings. Removing the saved key restores the environment fallback. The panel must be running at midnight; missed scans are not replayed on startup.
Authenticated endpoints: GET /api/updates reads saved status and results, PUT /api/updates/settings saves { "enabled": true }, and POST /api/updates/check starts a scan and returns 202. Manual and scheduled fleet scans cannot overlap. GET /api/servers/:id/mods/updates?cached=true reads saved/in-memory results without contacting catalogs. Mutating endpoints use existing CSRF protection.
Open App Settings → Notifications to connect a Discord channel:
- In Discord, open the channel's Settings → Integrations → Webhooks, create a webhook, and copy its URL.
- Paste the URL into MCM and use Send test message to check delivery. You can test before saving or enabling notifications.
- Enable notifications, choose the events to send, and save.
Event switches apply to all servers: server starts, stops, crashes, server operation errors, backup completion, and backup failure. Manual actions, scheduled server actions, and automatic backups use the same notifications. A restart sends a stop followed by a start when those events are selected. Start notifications mean the container has started; Minecraft may still be loading.
MCM checks container status every five seconds while the panel process is running, including when no browser is open. An unexpected container exit sends one crash alert with its exit code; deliberate stops and force stops use the stop event. Failed runtime inspections do not count as crashes. Events during panel downtime and exits between polling checks cannot be replayed.
Notifications are disabled by default. Settings persist in the panel database and take effect without a restart. The webhook URL contains a secret: it is stored in the database, hidden from settings responses, and omitted from delivery errors. Leave its field blank to keep the saved URL, enter a replacement, or choose Remove saved webhook and save to disconnect. Treat database backups as containing this credential.
Delivery runs through a bounded background queue with HTTP timeouts and bounded retries for Discord rate limits. Discord delivery failures are logged and do not fail server or backup operations. The queue is held in memory, so pending events do not survive a panel restart and may be dropped if the queue fills. Messages disable mentions. Standard HTTPS Discord webhook URLs and optional thread_id queries are supported; arbitrary hosts and redirects are rejected. See the Discord webhook API for channel and thread requirements.
The authenticated API exposes GET/PUT /api/notifications/discord and POST /api/notifications/discord/test. Save enabled, an array of events (server_started, server_stopped, server_crashed, server_error, backup_completed, backup_failed), and optionally webhook_url. Omitting the URL preserves it; an empty URL clears it when disabled. Reads return enabled, configured, and events. The test endpoint accepts {} for the saved webhook or { "webhook_url": "…" } for an unsaved URL. Mutating requests require the existing session and CSRF protection.
- Live Player Roster: Real-time list of online players with 3D player head avatars (powered by Minotar).
- Player Moderation: Quick actions to Kick, Ban, Pardon, OP, De-OP, or Whitelist players.
- Whitelist & OP Panels: Searchable and manageable whitelist and operator rosters with customizable OP permission levels (1–4).
- Interactive "Give Item" Dialog: Integrated Minecraft item catalog search, count selection, enchantment options, and custom NBT editing.
- Interactive Property Editor: Configure key gameplay settings (difficulty, gamemode, PvP, view distance, flight, spawn protection, hardcore, simulation distance, etc.) with intuitive UI toggles.
- Raw Configuration Mode: Direct editing of the
server.propertiestext file when raw precision is needed. - Visual MOTD Designer: Design server MOTDs with color pickers, Minecraft formatting codes (
§a,§l, etc.), and a real-time server list ping preview.
- Server File Explorer: Navigate the server data volume directly from the browser.
- File Transfers: Upload single or multiple files simultaneously with progress tracking, or download files directly.
- Inline Text Editor: Edit configuration files (
yml,json,properties,toml,txt) directly in the browser. - Archive Operations: Create zip archives and extract zip files in place.
- Remote Download: Fetch remote files or datapacks directly from an external URL.
- RFC 2782 DNS SRV Management: Automatically registers, updates, and removes
_minecraft._tcpSRV records via Cloudflare, Porkbun, DigitalOcean, or Amazon Route 53. - Custom Subdomains & Apex Routing: Route players through custom subdomains (e.g.,
survival.example.com) or apex root domains (@->example.com) without exposing non-standard port numbers. - One-Click Direct Join Badge: Displays active join addresses on the server overview with instant clipboard copying.
- Port Pool Management: Configure and validate host port allocation ranges (
MCM_PORT_RANGE), monitor available vs. allocated ports, and prevent port collision conflicts. - Automatic Lifecycle Cleanup: Removing a server automatically deregisters its DNS record with the original provider. Custom SRV names persist across stop/start cycles, record removal, and server renames.
- Dedicated Backup Manager: Open Backups to select a server, manage archives, search by name, filter by local or S3 storage, and open its Schedules tab to manage automatic backups. The server's Backups tab remains available.
- Separate Backup Media: Store local archives and temporary backup files on another disk or mounted share with
MCM_BACKUP_DIR. Existing local archives remain accessible. - Object Store Integration: Archive server data directories to compressed
.tar.gzarchives stored in any S3-compatible object store (AWS S3, MinIO, Cloudflare R2, DigitalOcean Spaces). - Automated Scheduling & Retention: Configure backups in Schedules and set each server’s count, age, and trash expiry limits in Backups → Retention. Preview cleanup before running it, protect important snapshots, and recover removed backups from Trash.
- Instant Restore: One-click in-place snapshot restoration.
- Live Backup Progress: Real-time SSE progress events and progress bars during backup creation.
- Backup Downloads & Uploads: Download backup snapshots directly from storage or upload external archives for restoration.
- Multi-Factor Authentication (MFA):
- TOTP Two-Factor Authentication: Authenticator app enrollment with QR code generation.
- WebAuthn / Passkeys: Hardware security keys (YubiKey), Apple Touch ID / Face ID, and Windows Hello.
- Multi-User Administration: Manage panel user accounts, user creation, password updates, and user deletion.
- Hardening: Built-in double-submit CSRF cookie protection, brute-force login lockout (5 failed attempts / 15 min), and sliding-window rate limiting.
- Native TLS Support: HTTPS on the configured panel port, with a persistent, automatically renewed self-signed certificate when no certificate is supplied.
-
Copy the environment template and configure storage and runtime settings:
cp .env.example .env # Review storage paths and runtime settings in .env -
Ensure the Minecraft server runtime base image is available:
docker pull eclipse-temurin:21-jre-alpine
MCM automatically pulls
eclipse-temurin:<version>-jre-alpine(for Java 8, 11, 17, or 21) on demand when servers using those versions are created. The default runtime image is configurable viaMCM_SERVER_IMAGE. -
Build and start the panel:
docker compose up -d --build
-
Access the panel: Open
https://localhost:8080in your browser and complete the initial onboarding setup. Trust the generated public certificate or accept the self-signed certificate warning on first use.
The panel container mounts /var/run/docker.sock so it can manage Minecraft server containers on the host. Minecraft servers bind host ports within MCM_PORT_RANGE (default 25565-25665).
MCM_DATA_DIR_HOST: Host directory (default${PWD}/datanext todocker-compose.yml) mounted into the panel container at/datafor the SQLite database and server data. This is also the host-side path MCM binds into each Minecraft server container.PUID/PGID: Set to match your host user (e.g.1000:1000or501:20on macOS). The image entrypoint prepares data ownership with these values. On Linux it uses the mounted runtime socket's group as the panel process group when dropping toPUID, so files retain your user ownership and the panel can access the socket. An explicit Composeuser:override must grant socket access itself.
Both Compose services forward the documented S3, login, request-limit and default resource settings from .env.
New Minecraft containers inherit the panel process's UID/GID. Their startup step prepares required tools and repairs ownership of /data as root, then drops privileges before running server installers or Java. This keeps automatically generated mod configs editable in the panel. Set PUID to a nonzero UID to use this behavior. Custom server images must provide su-exec or gosu, or an Alpine/Debian package manager to install one.
After upgrading from a version that ran Minecraft as root, use Rebuild container for each existing server. Rebuilding preserves its data, replaces the old container, and applies the ownership repair at its next start. Restarting the old container alone does not update its startup settings. This runs Minecraft as a non-root user; running the Docker daemon itself in rootless mode is a separate host configuration.
For a native Linux installation, use
./mcmctl install --backup-dir /mnt/backup-drive/mcm, or set
MCM_BACKUP_DIR in the managed configuration and restart. See
separate backup media for migration
and mount setup. The Local disk backup target uses the selected directory.
For Docker or Podman Compose, create a dedicated directory on the mounted
media, set its absolute host path in .env, and add the backup override:
MCM_BACKUP_DIR_HOST=/mnt/backup-drive/mcmdocker compose -f docker-compose.yml -f compose.backups.yml up -d --build
# Or, with Podman:
podman compose -f podman-compose.yml -f compose.backups.yml up -d --buildThe override mounts that directory at /backups and sets MCM_BACKUP_DIR
for the panel. Keep using both Compose files for subsequent deployments.
The host directory must already exist and the media must be mounted before
starting the panel. Container startup applies PUID/PGID ownership to the
backup directory as well as the data directory. Server containers only need
the server data mount.
Local backups, uploads, restores, and retention use the configured backup
directory. Temporary archives for local and S3 operations stay in its .tmp
subdirectory, keeping large staging files off the system temporary disk.
Existing backups under MCM_DATA_DIR/backups can still be downloaded,
restored, or pruned. To relocate them, stop the panel and copy their server-ID
directories to the new backup root without changing filenames. The panel
database remains in its original location.
Backup uploads accept validated .tar.gz snapshots (up to 2 GiB compressed,
8 GiB expanded, 100,000 entries). Backups briefly stop and then resume an
originally running server to capture consistent files. Restores stop the server,
stage and validate the archive, replace the complete data tree, and retain the
previous tree under servers/.mcm-recovery-* for recovery. A restored server
remains stopped until an administrator starts it.
- Direct Connections: Each server container can publish its game port directly to the host network within
MCM_PORT_RANGE(default25565-25665). - Extra Ports: Additional ports (TCP/UDP) can be allocated per server from the Server Settings tab (e.g., Bedrock/Geyser UDP ports, Voice Chat UDP, or Dynmap/BlueMap WebUI ports).
- Internal Proxy Networking: When running behind a reverse proxy (e.g. Velocity or BungeeCord), backend servers can disable host port binding. Sibling containers on the
mcm-networkbridge communicate directly using themcm-<server-id>hostname, eliminating unnecessary port exposure on the host firewall.
Select Podman with MCM_CONTAINER_RUNTIME=podman. MCM uses Podman's
Docker-compatible API
for server creation, lifecycle controls, networking, console commands, logs, and
resource metrics. Docker remains the default runtime.
Enable the API socket as the user that will own the panel and server data:
systemctl --user enable --now podman.socket
cp .env.example .env
# Review storage paths and runtime settings in .env.
export MCM_PODMAN_SOCKET="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/podman/podman.sock"
podman compose -f podman-compose.yml up -d --buildThe standalone podman-compose.yml selects Podman regardless of the runtime
setting in .env. It mounts the API socket, uses a shared SELinux label for
server data, and disables the panel's SELinux process label as required for
socket access. It runs the panel as UID/GID 0 inside the rootless container,
which maps to the invoking host user and keeps the socket and data accessible.
Minecraft containers preserve that ownership mapping. Run the panel and its
server containers through the same user's Podman service.
MCM_PODMAN_SOCKET is an absolute filesystem path, such as
/run/user/1000/podman/podman.sock, without unix://. The prefix belongs only
in API endpoint variables such as MCM_CONTAINER_HOST. The Compose file requires
MCM_DATA_DIR_HOST to be set to the absolute host data directory, and defaults the
socket path to /run/podman/podman.sock if MCM_PODMAN_SOCKET is unset. Its variable
expressions are kept flat for compatibility with older podman-compose providers.
The copied .env template sets MCM_DATA_DIR_HOST to ${PWD}/data; retain your
existing value if you already keep server data elsewhere.
If podman-compose reports unknown mount option /run/podman/podman.sock, update
podman-compose.yml to this version, set MCM_PODMAN_SOCKET as shown above, ensure
MCM_DATA_DIR_HOST is configured in .env, and retry.
The previous file used nested default expressions that older providers left
partially expanded inside the socket mount.
podman compose requires an installed Compose provider, such as podman-compose
or Docker Compose. For a rootful deployment, enable podman.socket with
sudo systemctl enable --now podman.socket and set
MCM_PODMAN_SOCKET=/run/podman/podman.sock; UID/GID 0 then means host root.
Rootless resource limits require cgroup v2 with CPU and memory controllers
delegated to the user service.
With the rootless socket enabled, launch the built binary as the same user:
MCM_CONTAINER_RUNTIME=podman ./mcmThe default endpoint is unix://$XDG_RUNTIME_DIR/podman/podman.sock (falling back
to /run/user/<uid>/podman/podman.sock) for non-root processes and
unix:///run/podman/podman.sock for root. MCM preserves file ownership with
Podman's keep-id mapping when the API reports rootless mode. Installers and
Java then run as the panel's UID/GID.
To override the endpoint, set MCM_CONTAINER_HOST. The resolution order is
MCM_CONTAINER_HOST, DOCKER_HOST, then (in Podman mode) CONTAINER_HOST, followed
by the runtime's default socket. Clear an existing DOCKER_HOST when switching
to Podman's default. Absolute socket paths such as
/run/user/1000/podman/podman.sock are automatically prefixed with unix://.
Other endpoints must use a transport supported by the Docker client, such as
unix:// or tcp://; use a locally forwarded socket for an SSH connection.
For a Linux user service, use the managed installation above. It builds and installs the binary, creates the required environment file, and enables the socket and service automatically. Do not also start a Compose panel against the same data directory.
Start your Podman machine and point a directly running panel at its forwarded socket:
podman machine start
export MCM_CONTAINER_RUNTIME=podman
export MCM_CONTAINER_HOST="unix://$(podman machine inspect --format '{{.ConnectionInfo.PodmanSocket.Path}}')"
./mcmMCM_DATA_DIR_HOST must refer to the same data directory on the machine running
Podman. For a VM, share that directory with write access; for a remote host,
provide shared storage. Containerized panels must mount the VM-side Podman
socket, not the macOS forwarding socket.
Podman image references are normalized to Docker Hub (docker.io/library/ for
Eclipse Temurin), so automatic pulls do not depend on short-name registry search
configuration. Explicit registries, digests, and localhost/ images are preserved.
Switching engines does not move existing containers. Stop servers before switching, keep the same server data path, and let MCM recreate containers in the selected engine. Start only one panel against a given database/data directory.
Use ./mcmctl install --runtime podman or ./mcmctl install --runtime docker
on Linux with systemd. The panel runs directly as your user; Minecraft servers
run through the selected container engine. Container engines inside LXC require
host support for the necessary namespaces, mounts, and cgroups.
If LXC prevents Podman or Docker from running, resolve that at the LXC host
before installing MCM. Check the chosen engine's info command as the same
user who will run the panel. See operations for the complete
service lifecycle and recovery commands.
| Variable | Default | Description |
|---|---|---|
MCM_ADDR |
:8080 |
Listen address for the web and REST API server. |
MCM_PORT_RANGE |
25565-25665 |
Host port pool allocated to Minecraft servers. |
MCM_DATA_DIR_HOST |
${PWD}/data |
Docker: host directory bind-mounted into the panel at /data and into each server container. |
MCM_DATA_DIR |
/data (Docker) / ./data (bare metal) |
Process-side data directory used for SQLite database and server data. |
MCM_BACKUP_DIR |
$MCM_DATA_DIR/backups |
Process-side directory for local backup archives and temporary backup/restore files. May be on separate media; compose.backups.yml sets /backups. |
MCM_BACKUP_DIR_HOST |
(empty) | Existing absolute host backup directory mounted at /backups when using compose.backups.yml. |
MCM_DB_PATH |
$MCM_DATA_DIR/mcm.db |
SQLite database file location. |
DOCKER_HOST |
Runtime-specific socket | API endpoint for Docker or Podman. Docker defaults to unix:///var/run/docker.sock; Podman defaults are described above. |
MCM_CONTAINER_RUNTIME |
docker |
Container engine: docker or podman. |
MCM_CONTAINER_HOST |
(empty) | API endpoint override for either engine; takes priority over DOCKER_HOST. |
CONTAINER_HOST |
(empty) | Podman endpoint fallback when MCM_CONTAINER_HOST and DOCKER_HOST are unset. |
MCM_PODMAN_SOCKET |
/run/podman/podman.sock |
Absolute host socket path mounted by podman-compose.yml, without unix://; set explicitly for rootless or VM deployments. |
PUID / PGID |
1000 / 1000 |
UID/GID the panel runs as and applies to the data directory. |
MCM_TRUSTED_PROXIES |
(empty) | Comma-separated trusted reverse proxy IPs/CIDRs for client IP forwarding. Sessions use random tokens whose hashes are persisted in SQLite. |
MCM_HTTP_ONLY |
false |
Serve plain HTTP instead of native HTTPS, for local development or a TLS-terminating reverse proxy. Cannot be combined with supplied certificate paths. |
MCM_TLS |
false |
Force Secure cookies when using HTTP behind an HTTPS reverse proxy. Native HTTPS always enables Secure cookies. |
MCM_TLS_CERT |
(empty) | Path to TLS certificate (PEM). Without a supplied pair, MCM generates and reuses $MCM_DATA_DIR/tls/cert.pem and key.pem. |
MCM_TLS_KEY |
(empty) | Path to TLS private key (PEM). |
MCM_TLS_REDIRECT |
false |
Redirect plain HTTP to HTTPS on the same MCM_ADDR port (301). Only applies to native HTTPS. |
MCM_LOGIN_MAX_ATTEMPTS |
5 |
Maximum failed login attempts allowed before lockout. |
MCM_LOGIN_LOCKOUT |
15m |
Lockout duration after exceeding failed login attempts. |
MCM_RATE_LIMIT_MAX |
100 |
Maximum state-changing requests permitted per client per window. |
MCM_RATE_LIMIT_WINDOW |
1m |
Sliding window duration for rate limiting. |
MCM_DEFAULT_CPU_LIMIT |
0 |
Default CPU cores limit for new servers (0 = unlimited). |
MCM_DEFAULT_MEMORY_MB |
0 |
Default memory limit in MB for new servers (0 = configured server RAM + 2 GiB). |
MCM_SERVER_IMAGE |
eclipse-temurin:21-jre-alpine |
Base Docker image used for server containers (Java 8, 11, 17, 21 pulled dynamically). |
MCM_WEB_AUTHN_RPID |
localhost |
WebAuthn Relying Party ID (effective domain). |
MCM_WEB_AUTHN_RP_ORIGIN |
Derived | Allowed WebAuthn origins (comma-separated, e.g. https://mc.example.com). |
MCM_WEB_AUTHN_RP_NAME |
Minecraft Container Manager |
Display name presented during Passkey registration. |
MCM_S3_ENDPOINT |
(empty) | S3-compatible object store endpoint (e.g. http://minio:9000). Empty disables S3 storage; local backups remain available. |
MCM_S3_ACCESS_KEY |
(empty) | Access key for S3 backup storage. |
MCM_S3_SECRET_KEY |
(empty) | Secret key for S3 backup storage. |
MCM_S3_BUCKET |
(empty) | S3 bucket used for server backup archives. |
MCM_S3_REGION |
us-east-1 |
S3 region for signing requests. |
TZ |
UTC |
Container and server timezone. |
MCM serves HTTPS on MCM_ADDR by default, including existing installations after
an upgrade. For the first upgrade from an HTTP-default version, pull this checkout
and run ./mcmctl update --local using the updated script; the old installed
script only checks HTTP readiness. When MCM_TLS_CERT and MCM_TLS_KEY are empty, it stores a self-signed
ECDSA certificate and private key under $MCM_DATA_DIR/tls. The private key is
readable only by the panel's user. The certificate covers localhost, the host's
name and LAN addresses, the configured listen host, and the configured WebAuthn
RP ID/origin hosts. It is reused across restarts and renewed at startup when fewer
than 30 days remain or required hostnames change. Certificates last one year.
Trust tls/cert.pem on your client devices to remove the browser warning; keep
tls/key.pem private. For a public certificate, set both PEM paths. In Compose,
mount those files into the panel and use their container-side paths. Invalid or
incomplete supplied certificates cause startup to fail.
MCM_ADDR controls the only panel listener. Set MCM_TLS_REDIRECT=true to redirect
plain HTTP to HTTPS on that same port. For example, http://mc.example.com:8080/login
redirects to https://mc.example.com:8080/login, preserving the path and query.
The legacy MCM_TLS_REDIRECT_ADDR setting is ignored; MCM never opens a separate
redirect port. With redirects disabled, plain HTTP receives an HTTPS-required
error. For plain HTTP service, set
MCM_HTTP_ONLY=true; behind an HTTPS reverse proxy, also set MCM_TLS=true and
configure MCM_WEB_AUTHN_RPID and MCM_WEB_AUTHN_RP_ORIGIN for the public URL.
Configurable via the App Settings UI or PUT /api/settings:
| Setting Key | Default | Description |
|---|---|---|
dns_provider |
cloudflare |
cloudflare, porkbun, digitalocean, or route53. Credentials are retained separately for each provider. |
dns_publish |
false |
Master toggle to enable SRV DNS management. |
dns_domain |
(empty) | Apex zone domain name (e.g. example.com). |
dns_zone |
(empty) | Cloudflare Zone ID (32-character hexadecimal string). |
dns_api_token |
(empty) | Cloudflare API token with Zone:Read and DNS:Edit permissions. |
dns_porkbun_api_token |
(empty) | Porkbun API key. Enable API access for the domain. |
dns_porkbun_api_secret |
(empty) | Porkbun secret API key. |
dns_porkbun_zone |
dns_domain |
Registered zone domain, e.g. example.com; can differ from a base domain such as games.example.com. |
dns_digitalocean_api_token |
(empty) | DigitalOcean token with domain read/create/update/delete permissions. |
dns_digitalocean_zone |
dns_domain |
Zone domain in DigitalOcean Networking. |
dns_route53_api_token |
(empty) | AWS access key ID. |
dns_route53_api_secret |
(empty) | AWS secret access key. |
dns_route53_session_token |
(empty) | Optional STS session token for temporary AWS credentials. |
dns_route53_zone |
(empty) | Public hosted zone ID. IAM permissions: route53:GetHostedZone, route53:ListResourceRecordSets, and route53:ChangeResourceRecordSets. |
dns_host |
(empty) | Target A/AAAA host pointing to the panel host IP (falls back to dns_domain). |
dns_service |
_minecraft |
Service name according to RFC 2782. |
dns_proto |
_tcp |
Protocol name according to RFC 2782. |
dns_ttl |
120 |
DNS record TTL in seconds (1 = Auto on Cloudflare). Clamped to 600 on Porkbun and 30 on DigitalOcean. |
port_range_start |
25565 |
Start of the port allocation pool range. |
port_range_end |
25665 |
End of the port allocation pool range. |
MCM exposes a clean JSON REST API along with Server-Sent Events (SSE) for console and task progress streaming.
| Method | Path | Description |
|---|---|---|
GET |
/api/auth/csrf |
Fetch CSRF protection token. |
GET |
/api/onboarding/status |
Check if initial setup/onboarding has completed. |
POST |
/api/onboarding |
Create initial administrator account. |
POST |
/api/auth/login |
Authenticate with email/password (and TOTP code if enabled). |
POST |
/api/auth/logout |
Invalidate current session. |
GET |
/api/auth/me |
Fetch authenticated user profile. |
GET |
/api/auth/totp |
Get TOTP two-factor enrollment status. |
POST |
/api/auth/totp/enroll |
Begin TOTP enrollment and generate secret/URI. |
POST |
/api/auth/totp/enroll/confirm |
Confirm TOTP code and enable two-factor auth. |
POST |
/api/auth/totp/disable |
Disable TOTP two-factor authentication. |
POST |
/api/passkey/register/begin |
Begin WebAuthn passkey registration ceremony. |
POST |
/api/passkey/register/finish |
Finalize WebAuthn passkey credential storage. |
GET |
/api/passkey |
List registered passkeys for current user. |
DELETE |
/api/passkey |
Delete a registered passkey. |
POST |
/api/passkey/login/begin |
Begin WebAuthn passkey authentication ceremony. |
POST |
/api/passkey/login/finish |
Finalize WebAuthn passkey login. |
Use Users to create accounts, select a role, assign servers, disable sign-in, or edit individual permissions. The four roles are:
| Role | Access |
|---|---|
| Administrator | Every server and all panel administration. |
| Operator | Operates assigned servers; edits configuration, files, mods and worlds; manages players, schedules and profiling; creates and downloads backups. Cannot delete servers, restore/delete backups, or administer the panel. |
| Viewer | Reads assigned server status, console, logs, players, installed content, worlds, backup lists, schedules and monitoring. Cannot change server data or download files/backups. |
| Custom | An explicit selection from 39 capabilities, grouped by feature. |
Existing accounts retain administrator access when the database migrates. Onboarding creates an administrator. New API accounts default to Viewer with no server access. Select individual servers or enable All current and future servers. The same permissions apply to every assigned server; global panel capabilities are independent of server selection.
The API checks capabilities and server scope on every authenticated request, including backup downloads/deletion and console/task/backup streams. Server lists and update-check results exclude inaccessible servers. Access changes revoke the target account’s sessions, preserving the acting session only when editing your own active account. Open event streams recheck access within five seconds. Disabled accounts cannot use passwords, passkeys, or existing sessions. The database prevents disabling, deleting, or demoting the last active administrator. Every active user can still edit their own email/password and manage their own MFA/passkeys.
Permissions for creating servers require access to all servers. Copying also requires servers.create and files.read. Server capabilities require servers.view. Managing persistent schedules requires servers.power, console.write, and backups.create; saved schedules remain shared server automation until paused or removed. Player OP/de-OP actions additionally require ops.manage, and custom player commands require console.write.
The permission descriptions identify sensitive capabilities: file access and archives can contain secrets; writing files, restoring backups, installing content, and console commands grant broad control over an assigned Minecraft server. users.manage includes creating administrators and resetting other users’ passwords. settings.manage includes shared credentials, while panel.update and updates.manage control application updates and global update checks respectively.
GET /api/auth/me, login, and onboarding responses include role, effective permissions, all_servers, server_ids, and disabled. GET /api/permissions supplies the permission catalog, presets, and available server assignments to users with users.manage. Create or update accounts with an optional complete access object:
{
"email": "operator@example.com",
"password": "choose-a-strong-password",
"access": {
"role": "custom",
"permissions": ["servers.view", "servers.power", "console.read"],
"all_servers": false,
"server_ids": ["server-uuid"],
"disabled": false
}
}On PATCH, omit access to preserve permissions. An included access object replaces the policy; unknown roles, unknown permissions, and nonexistent server assignments are rejected. Missing authentication returns 401; insufficient capabilities or server scope return 403 with error code forbidden. Shared settings and user administration are protected independently from server operations.
| Method | Path | Description |
|---|---|---|
GET |
/api/servers |
List accessible Minecraft servers with status and uptime. |
POST |
/api/servers |
Create a new server (flavor, version, build, RAM, CPU, ports, java_version). |
POST |
/api/servers/import |
Import an exported server ZIP using multipart file and optional JSON settings fields (name, server_type, version, build, ram_mb, java_version, no_host_port). Requires servers.create and CSRF protection. |
GET |
/api/servers/:id |
Get server configuration, container state, and rebuild warning status. |
PATCH |
/api/servers/:id |
Update server configuration (RAM, CPU, ports, java_version). |
DELETE |
/api/servers/:id |
Delete server and remove container/data volume. |
POST |
/api/servers/:id/start |
Start server container. |
POST |
/api/servers/:id/stop |
Gracefully stop server container. |
POST |
/api/servers/:id/restart |
Restart server container. |
POST |
/api/servers/:id/kill |
Force-kill unresponsive server process (SIGKILL). |
POST |
/api/servers/:id/recreate |
Recreate container from runtime image and sync configuration changes. |
POST |
/api/servers/:id/copy |
Duplicate/clone server data, configuration, and plugins to a new server. |
GET |
/api/servers/:id/export |
Download server files and portable settings as ZIP (.zip). |
GET |
/api/servers/:id/status |
Lightweight status polling endpoint. |
GET |
/api/servers/:id/stats |
Real-time container resource metrics (CPU %, memory, net I/O, disk I/O). |
GET |
/api/servers/:id/console |
Stream real-time console logs via Server-Sent Events (SSE) with Last-Event-ID. |
GET |
/api/servers/:id/logs |
List saved server logs; pass ?path=logs/archive.tar.gz to list log members in a tar archive. |
GET |
/api/servers/:id/logs/content |
Preview a plain or gzip-compressed log using ?path=...; add &entry=... for a tar archive member. Returns content, truncation state, and preview limit. |
POST |
/api/servers/:id/console/command |
Send command to server stdin FIFO pipe (with RCON fallback). |
GET |
/api/servers/:id/install |
Get installed version and available upgrade builds. |
POST |
/api/servers/:id/install |
Trigger server version or build upgrade. |
GET |
/api/jars/:kind/versions |
Fetch upstream Minecraft versions for a given server type. |
GET |
/api/jars/:kind/versions/:v/builds |
Fetch builds for a specific version. |
GET |
/api/system/java-versions |
List available Java runtime versions supported by the system. |
GET |
/api/system/capacity |
Get runtime CPU/memory capacity, aggregate measured server usage, and data-directory filesystem space. Requires authentication. Runtime, usage, and disk failures are reported independently so available readings remain visible. |
| Method | Path | Description |
|---|---|---|
POST |
/api/modpack/inspect |
Inspect an external modpack to detect loader, version, and requirements. |
GET |
/api/servers/:id/modpack |
Get currently installed modpack metadata and version lock state. |
POST |
/api/servers/:id/modpack/inspect |
Inspect modpack compatibility against a specific server. |
POST |
/api/servers/:id/modpack/install |
Trigger asynchronous modpack installation or version change. |
DELETE |
/api/servers/:id/modpack |
Uninstall modpack configuration from server. |
| Method | Path | Description |
|---|---|---|
GET |
/api/servers/:id/mods/updates |
Fetch cached or detected updates for installed mods. |
POST |
/api/servers/:id/mods/updates/check |
Check for updates across Modrinth and CurseForge catalogs. |
GET |
/api/servers/:id/mods/upgrade-check |
Check mod compatibility for upgrading the server's Minecraft version. |
POST |
/api/servers/:id/mods/upgrade-apply |
Apply version upgrade across mods and server platform. |
GET |
/api/servers/:id/mods/:name/versions |
Fetch all available versions and jar files for a specific mod. |
POST |
/api/servers/:id/mods/:name/update |
Update a specific mod jar to a target version. |
POST |
/api/servers/:id/mods/sanitize-client-only |
Scan and remove client-only mods from the server. |
| Method | Path | Description |
|---|---|---|
GET |
/api/servers/:id/tasks/progress |
Poll active background task progress (modpack install, zip, etc.). |
GET |
/api/servers/:id/tasks/events |
Stream live task progress events via Server-Sent Events (SSE). |
| Method | Path | Description |
|---|---|---|
GET |
/api/servers/:id/schedules |
List recurring tasks, next run, and last result. |
POST |
/api/servers/:id/schedules |
Create a task with name, action (backup, command, start, stop, restart, chain), command (for command tasks), optional backup_target ("" for panel default, local, or s3; backup tasks only), steps (for chains; see below), cron, optional timezone (defaults to TZ), and optional enabled (defaults to true). |
PUT |
/api/servers/:id/schedules/:scheduleId |
Replace task configuration; include enabled. |
PATCH |
/api/servers/:id/schedules/:scheduleId |
Pause or resume with {"enabled": false} or {"enabled": true}. |
DELETE |
/api/servers/:id/schedules/:scheduleId |
Delete a task and cancel its future runs. |
For action: "chain", supply an ordered steps array of 1–50 objects. Each step has an action of command, backup, start, stop, restart, or delay. Command steps require command; backup steps accept optional backup_target; delay steps require integer delay_seconds from 1 to 3600. Nested chains are rejected. For example:
{
"name": "Announced backup",
"action": "chain",
"cron": "midnight",
"timezone": "Asia/Bangkok",
"enabled": true,
"steps": [
{ "action": "command", "command": "say Backup Starting" },
{ "action": "command", "command": "save-all" },
{ "action": "backup", "backup_target": "local" },
{ "action": "delay", "delay_seconds": 60 },
{ "action": "command", "command": "say Backup Complete" }
]
}| Method | Path | Description |
|---|---|---|
GET |
/api/servers/:id/players |
List online players with player head avatars. |
POST |
/api/servers/:id/players/:name/command |
Run player command (kick, ban, pardon, op, give item). |
GET |
/api/servers/:id/ops |
List operator accounts and permission levels. |
POST |
/api/servers/:id/ops |
Add an operator with permission level (1–4). |
DELETE |
/api/servers/:id/ops/:name |
Remove operator status. |
GET |
/api/servers/:id/whitelist |
List whitelisted players. |
POST |
/api/servers/:id/whitelist |
Add player to whitelist. |
DELETE |
/api/servers/:id/whitelist/:name |
Remove player from whitelist. |
| Method | Path | Description |
|---|---|---|
GET |
/api/servers/:id/mods |
List installed mods or plugins with enablement status. |
POST |
/api/servers/:id/mods |
Upload mod/plugin jar file. |
POST |
/api/servers/:id/mods/download |
Download mod/plugin directly from catalog URL. |
PATCH |
/api/servers/:id/mods/:name |
Toggle mod/plugin enabled or disabled (.disabled). |
DELETE |
/api/servers/:id/mods/:name |
Delete mod/plugin jar file. |
| Method | Path | Description |
|---|---|---|
GET |
/api/servers/:id/worlds |
List worlds, active world and whether world writes are available. |
POST |
/api/servers/:id/worlds |
Create a world with name, string seed, level_type and generate_structures. |
POST |
/api/servers/:id/worlds/import |
Import a ZIP using multipart name and file fields. |
PUT |
/api/servers/:id/worlds/:world |
Update an ungenerated world’s seed and generation settings. |
POST |
/api/servers/:id/worlds/:world/activate |
Select the world for the next server start. |
GET |
/api/servers/:id/worlds/:world/export |
Download a world and matching Bukkit dimensions as ZIP. |
DELETE |
/api/servers/:id/worlds/:world |
Move an inactive world to recovery storage; returns recovery_path. |
GET |
/api/servers/:id/worlds/:world/regions?dimension=world&offset=0 |
List up to 100 region headers for a dimension ID returned by the world list. |
GET |
/api/servers/:id/worlds/:world/chunks?dimension=world&x=0&z=0 |
List generated chunks and saved timestamps in a region. |
POST |
/api/servers/:id/worlds/:world/chunks/reset |
Reset chunks (unique local indices z * 32 + x, 0–1023) in dimension, region_x, region_z; returns count and recovery_path. |
GET |
/api/servers/:id/properties |
Fetch current parsed server.properties. |
PUT |
/api/servers/:id/properties |
Update server.properties content. |
| Method | Path | Description |
|---|---|---|
GET |
/api/servers/:id/files |
List files and directories in server volume. |
GET |
/api/servers/:id/files/download |
Download file from server. |
GET |
/api/servers/:id/files/content |
Read text file content and its revision for inline editing. |
PUT |
/api/servers/:id/files/content |
Save edited text; pass expected_revision from the read response to check for changes. An empty revision requires a new file. A 409 file_changed response includes the current file in current for comparison. |
POST |
/api/servers/:id/files/upload |
Upload one or more files. |
POST |
/api/servers/:id/files/archive |
Create a zip archive of selected files/folders. |
POST |
/api/servers/:id/files/unzip |
Extract a zip archive in place. |
POST |
/api/servers/:id/files/from_url |
Download a remote file directly to the server data directory. |
DELETE |
/api/servers/:id/files |
Delete file or directory. |
POST |
/api/servers/:id/files/mkdir |
Create a new directory. |
POST |
/api/servers/:id/files/rename |
Rename a file or directory. |
| Method | Path | Description |
|---|---|---|
GET |
/api/servers/:id/backups |
List active backups, trash, and the effective retention policy for a server. |
GET |
/api/servers/:id/backups/retention |
Read policy and cleanup preview (to_trash, to_purge, trash_bytes, purge_bytes). |
PUT |
/api/servers/:id/backups/retention |
Save integer keep_count (0–100000), max_age_days (0–36500), and trash_retention_days (0–36500). Returns the updated preview. |
POST |
/api/servers/:id/backups/cleanup |
Apply the saved policy now. Returns counts trashed and purged. |
DELETE |
/api/servers/:id/backups/trash |
Permanently delete all trash for this server without changing active backups. |
POST |
/api/servers/:id/backup |
Trigger an immediate manual backup snapshot. |
GET |
/api/servers/:id/backups/progress |
Poll active backup operation progress. |
GET |
/api/servers/:id/backups/events |
Stream live backup progress events via SSE. |
POST |
/api/servers/:id/backups/upload |
Upload an existing backup archive (.tar.gz). |
POST |
/api/servers/:id/restore/:backupId |
Restore a backup snapshot in place. |
GET |
/api/backups/:backupId/download |
Download backup archive file from storage. |
DELETE |
/api/backups/:backupId |
Move an unprotected backup to recoverable trash. |
POST |
/api/backups/:backupId/recover |
Recover a trashed backup; completed snapshots become protected. Does not change the live server world. |
PATCH |
/api/backups/:backupId/protect |
Set protected (boolean) on an active, completed snapshot. |
DELETE |
/api/backups/:backupId/purge |
Permanently remove a trashed archive and its record. |
Count and age limits apply to completed, unprotected snapshots across local and S3 storage. Protected snapshots are additional to the count limit. The newest successful backup always stays available, even beyond the age limit. Failed and pending records never displace successful history. A count or age limit of 0 disables that limit; trash expiry of 0 keeps trash until it is explicitly emptied. Servers without a custom policy inherit the existing backup_retention count setting and default to 30 days of trash with no age limit.
Saving a policy does not immediately run cleanup. Policies run after successful backups/uploads, at panel startup, and hourly, including servers without scheduled backups. Trash expiry uses the current policy and the time each backup entered trash; changing expiry also affects existing trash. Trashed archives remain on their original local disk or S3 object store and continue consuming space until permanently deleted. Failed storage deletions preserve the database record for retry. Trash must be recovered before downloading or restoring a snapshot. Retention changes, protection, recovery, and permanent deletion require the server-scoped backups.delete capability; reading settings and previews requires backups.read.
Choose the provider under App Settings → DNS Providers and use Test Connection before enabling publishing. Provider API references: Cloudflare, Porkbun, DigitalOcean, Route 53. Route 53 supports simple SRV records in public hosted zones on the global AWS endpoint.
POST /api/dns/test accepts optional provider, api_token, api_secret, session_token, zone, and domain fields. Missing credentials use that provider's saved values. GET /api/servers/{id}/dns includes the saved subdomain even when no record is published. Use @ for the apex domain. Removing the published record preserves this address preference; deleting the server removes it.
| Method | Path | Description |
|---|---|---|
GET |
/api/dns |
List all active DNS records and DNS provider connection status. |
POST |
/api/dns/test |
Test saved or supplied DNS provider credentials and zone connectivity (also works while publishing is disabled). |
GET |
/api/servers/:id/dns |
Get DNS record status and join address for a server. |
POST |
/api/servers/:id/dns |
Publish or update an SRV record for a server. |
DELETE |
/api/servers/:id/dns |
Remove an SRV record for a server. |
| Method | Path | Description |
|---|---|---|
GET |
/api/users |
List all registered user accounts. |
GET |
/api/permissions |
Read capability catalog, role presets and server assignments (users.manage). |
POST |
/api/users |
Create an account with optional access policy (users.manage). |
PATCH |
/api/users/:id |
Update your own email/password, or manage another account and its access with users.manage. |
DELETE |
/api/users/:id |
Delete user account and associated passkeys/sessions. |
GET |
/api/ports/available |
Check available host ports in allocation range. |
GET |
/api/settings |
Fetch global panel settings (DNS, port range). |
PUT |
/api/settings |
Update global panel settings. |
GET |
/api/curseforge/settings |
Read shared CurseForge availability and credential source, never the key. |
PUT |
/api/curseforge/settings |
Save { "api_key": "..." }; an empty string removes the saved key. Requires settings.manage and CSRF protection. |
GET |
/api/curseforge/mods/... |
Search and read CurseForge files/download URLs using the shared server-side key, caching, and rate limits. |
POST |
/api/curseforge/mods |
Batch CurseForge project lookups using the shared key. Requires CSRF protection. |
GET |
/api/runtime/status |
Get selected engine (runtime), API reachability, and runtime image status. |
GET |
/api/docker/status |
Compatibility alias for /api/runtime/status. |
GET |
/api/proxy |
Cached and rate-limited reverse proxy for catalog APIs. |
POST |
/api/proxy |
POST requests through external catalog proxy. |
GET |
/healthz |
Liveness health check probe (200 OK). |
GET |
/readyz |
Readiness probe checking database and container runtime connectivity (legacy check keys: docker and docker_image). |
.
├── cmd/mcm/ # Main Go application entrypoint
├── internal/
│ ├── api/ # HTTP routes, middlewares, SSE console/task streams, and handlers
│ ├── auth/ # Password hashing, sessions, TOTP, and WebAuthn passkeys
│ ├── backups/ # S3 client and backup/restore archive engine
│ ├── config/ # Environment variable parsing and defaults
│ ├── db/ # SQLite connection and migration runner
│ ├── dns/ # Cloudflare, Porkbun, DigitalOcean, and Route 53 SRV records
│ ├── docker/ # Docker engine client, container provisioning, and resource metrics
│ ├── jars/ # Version and build metadata resolution for 22 server platforms
│ ├── ports/ # Host port allocation pool manager and validator
│ ├── proxy/ # Cached, rate-limited reverse proxy for catalog APIs
│ ├── rcon/ # Minecraft RCON client implementation
│ ├── servers/ # Server entity store, modpacks, mod updates, tasks, and state transitions
│ └── web/ # Embedded production frontend assets
├── migrations/ # SQL schema migrations (SQLite)
├── web/ # React / Vite frontend application
│ ├── src/
│ │ ├── api/ # Typed API client, rate-limited fetchers, and upstream catalog adapters
│ │ ├── components/ # UI components (Console, Modpacks, Mod Updates, Stats Grid, Proxy Editor, etc.)
│ │ ├── routes/ # TanStack Router page routes (Dashboard, Server Detail, App Settings, User Settings, Users)
│ │ └── styles/ # CSS design system and theme tokens
│ └── tests/ # Vitest test suite for web components and utilities
├── deploy/ # Service examples and installer regression tests
├── mcmctl # Linux install, service management, update, and recovery
├── Dockerfile # Multi-stage production build (Node -> Go -> Final Alpine)
└── docker-compose.yml # Docker Compose configuration
Run make verify from the repository root for the complete quality gate:
Go static and formatting checks, backend tests, race tests, deployment tests,
and frontend type checks, lint, tests and production build. Install frontend
dependencies with pnpm --dir web install --frozen-lockfile first. The committed
GitHub Actions workflow runs the same gate.
The running binary's commit and build time appear under App Settings → Updates →
Panel software and in mcm --version. Managed Linux installations can check
and install panel updates from that page, with a persistent log and automatic
reconnection during restart. See panel updates for
requirements and build metadata for container deployments.
Ensure Go 1.26+ is installed (see go.mod):
# Build binary
go build ./...
# Run backend tests
go test ./...cd web
# Install dependencies
npm install
# Run dev server with hot reload
npm run dev
# Run Vitest test suite
npm run test
# Typecheck and production build
npm run typecheck
npm run buildDuring the multi-stage Docker build, web/dist is compiled and embedded directly into internal/web/dist, producing a single self-contained binary.
- Java runtimes provided by Eclipse Temurin Alpine OpenJDK images.
- Mod & plugin catalog integrations powered by Modrinth, PaperMC Hangar, SpigotMC / Spiget, and CurseForge.
- Player head avatars provided by Minotar.