A mobile-first control center for Minecraft Bedrock servers.
Manage worlds, players, rules, access, backups, and structured gameplay statistics without living in a server console.
Important
CraftControl targets trusted private networks. Local authentication and CSRF protection are active, but TLS termination and restricted Docker access remain deployment requirements. Do not expose port 8082 directly to the Internet.
- Purpose-built controls for server properties, gamerules, time, weather, permissions, packs, and lifecycle operations.
- Permanent player profiles with aliases, sessions, play time, deaths, permissions, and individual telemetry.
- Global activity, death, ranking, block, combat, exploration, and 7/30-day analytics.
- A companion Behavior Pack for authoritative kills, blocks, damage, distance, dimensions, and structured deaths.
- Coordinated world and SQLite backups with verification, retention, offline restore, and recovery copies.
- Player-backed owner, operator, and viewer accounts with opaque sessions and session-bound CSRF tokens.
- A responsive interface in Portuguese, English, and Spanish with original CraftControl pixel-art icons.
CraftControl Server remains useful without the optional CraftControl Telemetry Pack, Prometheus, Grafana, Loki, or any external observability service.
The six primary areas are task-oriented:
| Area | Responsibility |
|---|---|
| Home | Server health, online players, freshness, and shortcuts |
| World | World identity, generation, time, weather, and cycles |
| Players | Permanent profiles, sessions, access, permissions, and individual telemetry |
| Data | Activity, deaths, rankings, blocks, combat, exploration, and periods |
| Rules | Gameplay, interface, mobs, drops, commands, fire, TNT, and regeneration |
| Server | CraftControl Telemetry Pack, network, performance, backups, and container lifecycle |
The profile includes a browser-local appearance preference; see Color themes.
Navigation is encoded in the URL, so refreshing a browser preserves the active area. Persistent setting changes enter a review drawer; lightning-marked gamerules apply immediately.
Restart-required changes are tracked as server operations. A failed operation is
reconciled read-only against Bedrock's effective server.properties before the
panel refreshes its settings: requested values are never shown as applied until
they are observed. See Operation lifecycle.
An operation opens in a global drawer. It can be dismissed without interrupting the server work; a persistent indicator keeps its live status and reopens the same drawer from any area of the application.
The Host Agent probes Bedrock immediately after restart and then uses capped exponential backoff (1–10 seconds) while waiting for health. The configured operation deadline remains authoritative; status updates remain independent of the probe cadence.
CraftControl is a monorepo with two independently deployable containerized application services, not a set of microservices. The backend remains a modular monolith; an optional systemd host agent is a separate host-level execution boundary.
flowchart TD
client["CraftControl Client<br/>browser"]
subgraph docker["Docker Engine / Compose"]
frontend["CraftControl Client<br/>Nginx · static UI · API/SSE proxy"]
server["CraftControl Server<br/>Flask modular monolith<br/>API · event broker · SSE"]
bedrock["Minecraft Bedrock Server<br/>optional CraftControl Telemetry Pack"]
daemon["Docker Engine<br/>container events"]
frontend --> server
end
agent["CraftControl Host Agent<br/>systemd · outside Docker"]
client --> frontend
server -->|"when HOST_AGENT_URL is set:<br/>configuration and restart workflow"| agent
agent -->|"Compose, filesystem, health probe"| bedrock
server -->|"allowlisted Bedrock console;<br/>lifecycle fallback"| bedrock
bedrock -. "logs and optional telemetry" .-> server
daemon -. "container events" .-> server
CraftControl Client owns the public origin. Nginx serves static assets and proxies /api/*, including unbuffered Server-Sent Events, to the private CraftControl Server. The Client has no persistent or privileged mounts. The Server owns durable state (SQLite), Bedrock files, coordinated backups, console operations, log streaming, and Docker events.
CraftControl has three runtime boundaries: the CraftControl Client (Nginx container serving static assets and proxying the API), the CraftControl Server (Flask modular monolith inside Docker managing state, auth, and Bedrock operations), and the CraftControl Host Agent (craftcontrol-host-agent, a systemd service running on the Docker host outside all containers).
When the CraftControl Host Agent is configured (HOST_AGENT_URL is set), server lifecycle operations — PREPARATION (writing configuration), RESTART (restarting the Compose service), and HEALTH_WAIT (polling the transport-aware Bedrock readiness probe: RakNet ping for transport=raknet, console-log evidence for transport=nethernet on Bedrock 1.26.50+) — are delegated to it over an authenticated HTTP channel. The agent handles Docker socket access for those three stages so the CraftControl Server does not need to execute them directly; the Docker socket remains mounted in the Server for Bedrock console attachment, log streaming, and Docker events, which are not part of the Host Agent contract. Without the Host Agent, the Server performs all lifecycle operations directly.
The host agent is intentionally not a Docker container. Containerizing it would require either mounting the Docker socket into the container (defeating least-privilege isolation) or using privileged host mounts with elevated network namespaces. Running it as a systemd service on the host gives Docker socket access through OS-level group membership without exposing the socket to the container network or the backend image.
The backend intentionally runs one Gunicorn worker with multiple threads. Its event broker, supervisors, refresh lock, and SSE delivery are process-local; multiple workers would duplicate those responsibilities.
flowchart TD
repo["CraftControl repository"] --> apps["apps/"]
apps --> frontend["apps/client/ — Nginx image, HTML, CSS, and native ES modules"]
apps --> backend["apps/server/ — Flask image, composition root, and Python application"]
repo --> services["services/bedrock-proxy/ — independently deployed systemd service"]
repo --> contracts["packages/contracts/ — canonical OpenAPI 3.1 contract and generated types"]
repo --> telemetry["packs/telemetry/ — embedded Behavior Pack and lifecycle assets"]
repo --> versions["versions.env — tested frontend/backend release pair"]
Root Python links and the combined image are compatibility overlays. They preserve existing tooling and emergency rollback while migration continues; new application code belongs under apps/.
The frontend uses browser-native ES modules with no bundler or build-time framework.
flowchart TD
static["apps/client/static/"] --> app["app.js — minimal bootstrap"]
static --> js["js/"]
js --> composition["composition.js — dependency assembly and application startup"]
js --> core["core/ — state, DOM, routing, navigation, and invalidation"]
js --> components["components/ — shared feedback and time presentation"]
js --> features["features/ — auth, settings, world, rules, server, players, analytics"]
js --> i18n["i18n/ — PT, EN, ES catalogs and localized game terminology"]
Feature modules own their markup, bindings, and local state; core/ modules do not import features/. See Architecture for dependency rules, event consistency, deliberate non-goals, and the incremental target layout.
flowchart TD
manager["apps/server/controlplane/"] --> composition["composition.py — manual production dependency injection"]
manager --> http["http/ — HTTP mapping grouped by domain"]
manager --> players["players/ — player application use cases"]
manager --> auth["auth/ — accounts, sessions, roles, CSRF, and audit"]
manager --> operations["operations/ — backup, restore, and operational workflows"]
manager --> runtime["runtime/ — log, Docker-event, and reconciliation supervisors"]
manager --> ports["ports.py — structural external-boundary contracts"]
Routes translate HTTP requests and responses. Use cases coordinate behavior. Repositories own persistence. See apps/server/controlplane/README.md for the full package layout and architecture rules.
packages/contracts/openapi.json is the canonical OpenAPI 3.1 business contract. Generated client declarations live at apps/client/static/js/api-contract.d.ts; the quality gate rejects stale declarations.
Authenticated installations expose:
/api/openapi.json— machine-readable contract;/api/docs— Swagger UI using the current session;/api/events— persisted and live Server-Sent Events./api/diagnostics— owner-only local telemetry and SSE diagnostics; it does not require an observability stack.
Persistence diagnostics report SQLite connection wait, bounded retry pressure, final contention failures, and database size without exposing database contents or filesystem paths. Only idempotent reads may retry after transient SQLite contention; writes fail without automatic retry.
GET /api/operations returns bounded, paginated operation history through a one-based page query parameter and a limit page size from 1 to 100 (default 10).
Swagger attaches the session-bound CSRF token to unsafe “Try it out” requests and never bypasses role capabilities. There is no arbitrary shell or console endpoint.
CraftControl follows Bedrock logs and Docker lifecycle events, commits durable evidence to SQLite, publishes changes through SSE, performs targeted refreshes, and runs a full safety reconciliation every 15 minutes by default. Stale information remains visible and marked instead of being replaced by false empty data.
flowchart LR
logs["Bedrock logs"] --> broker["event broker"]
docker["Docker events"] --> broker
operations["Manager operations"] --> broker
broker --> sqlite["SQLite"] --> sse["SSE"] --> browser["browser"]
broker --> reconciliation["targeted reconciliation"]
The optional CraftControl Telemetry Pack (0.4.0) emits schema-versioned JSON and supports authoritative snapshots plus incremental events. Snapshots can recover lifetime aggregates after downtime; they cannot recreate every missed event, timestamp, cause, or coordinate.
See Architecture for the event and consistency model, and CraftControl Telemetry Pack integration for the lifecycle and recovery runbook.
CraftControl requires Docker Engine with the Compose plugin and an existing
itzg/minecraft-bedrock-server deployment. It runs alongside the Bedrock
project and must be deployed with its guarded commands. Never run a bare docker compose up from a development checkout. Coordinated releases prepare both versioned images before recreating either service and attempt image builds up to three times.
See Installation for prerequisites, expected directory layout, configuration, cutover, access, post-install checks, and troubleshooting.
The optional Host Agent has a supported idempotent prerequisite installer. Run
it as root after installing the systemd service; it verifies the agent account,
Docker access, scoped ACLs, the .env ACL watcher, and the systemd sandbox
without restarting Bedrock. See Host Agent.
CraftControl is configured through environment variables (MANAGER_PORT, MINECRAFT_CONTAINER, DATABASE_PATH, HOST_AGENT_URL, TZ, and others) and reads versions.env for the tested frontend/backend release pair.
See Configuration for the full variable reference, Bedrock configuration authority rules, and host-agent timeout settings.
Panel accounts attach to players Bedrock has already observed. Three roles — Viewer, Operator, and Owner — control access to settings, lifecycle commands, and user management. Minecraft permission and CraftControl role are independent.
Generate the first one-time owner code after that player has joined Bedrock:
docker compose -f docker-compose.split.yml exec craftcontrol-backend \
craftcontrol auth bootstrap --player VonCrushEvery authenticated mutation requires a CSRF token tied to the exact session and a valid same-origin request. See Local authentication and authorization for the full capability matrix, invitation flow, and session policy.
SQLite stores permanent profiles, aliases, presence, sessions, accumulated play time, permissions, deaths, event history, and optional structured telemetry. Disconnecting a player closes or infers the session; it never deletes the profile.
The Players area consolidates one player’s lifetime totals and breakdowns before recent evidence: kills by creature, blocks by type, exploration by dimension, sessions, deaths, and technical history. The Data area provides server-wide filtered and paginated views. Structured and derived deaths are deduplicated for display while raw evidence remains private.
Creature, block, projectile, navigation, action, state, and metric icons use original bundled SVG pixel art. Game identifiers are localized in Portuguese, English, and Spanish, with a localized neutral fallback for unknown identifiers. See Visual system rules.
An owner can export what the panel shows as JSON or CSV: player profiles, sessions, activity and deaths, plus the analytics rankings, periods, blocks, combat and exploration aggregates. Exports never contain XUIDs, tokens, addresses or raw server evidence, are bounded by documented ceilings and refused rather than truncated, and every attempt is audited. See Data exports.
CraftControl does not own the Minecraft world. The world remains in the Bedrock project; manager state lives in manager.db. SQLite migrations are transactional and create an immutable database backup before the first pending migration.
Use coordinated commands instead of copying a live database or world:
docker compose -f docker-compose.split.yml exec craftcontrol-backend craftcontrol backup create
docker compose -f docker-compose.split.yml exec craftcontrol-backend craftcontrol backup list
docker compose -f docker-compose.split.yml exec craftcontrol-backend craftcontrol backup verify BACKUP_IDWhen Bedrock is running, the backup service holds saves only for the copy window and resumes them even after failure. Recovery sets include the world, SQLite database, server configuration, allowlists, permissions, Behavior Pack files, checksums, and a versioned manifest. Restore is deliberately offline and creates a pre-restore recovery copy.
See Coordinated backup and restore and Database migrations.
versions.env pins the tested frontend/backend pair. Deploy both or only the changed component:
bin/deploy-craftcontrol-release --check
bin/deploy-craftcontrol-release
bin/deploy-craftcontrol-frontend
bin/deploy-craftcontrol-backend
bin/deploy-craftcontrol-frontend --rollback VERSION
bin/deploy-craftcontrol-backend --rollback VERSION
bin/deploy-craftcontrol-release --rollback FRONTEND_VERSION BACKEND_VERSIONFrontend deployment proves that the backend container is unchanged. Backend deployment creates and verifies a coordinated backup, checks SQLite and persistent mounts, and proves the frontend container was not recreated. bin/cutover-craftcontrol-split performs the one-time split cutover and retains the combined image as the explicit emergency compatibility path.
The interface reads /version.json from the frontend and release metadata from the backend, keeping image activation separate from Behavior Pack installation and runtime response timestamps.
CraftControl uses Python 3.12, Flask, Gunicorn, SQLite, Docker SDK for Python, Nginx, and dependency-free browser JavaScript.
bin/check-frontend # JS syntax, i18n, interaction and visual-contract tests
bin/check-backend # Python application and persistence tests
bin/check-bedrock-proxy # Standalone host-agent tests and coverage report
bin/check-contracts # OpenAPI, route surface, Swagger, generated declarations
bin/check-integration # Compose builds, split runtime, architecture and deploy safety
bin/check # complete local gateGitHub Actions and Gitea Actions run the six quality gates independently. Successful Gitea main runs deploy automatically through the repository-scoped homelab runner. See Contributing for commit conventions and PR workflow. See apps/server/controlplane/README.md for the backend package layout and test infrastructure reference. See Development setup for prerequisites, environment configuration, and common development tasks.
Current safeguards include local player-backed accounts, role capabilities, hashed one-time credentials, revocable opaque sessions, login throttling, security audit records, session-bound CSRF, origin validation, strict command allowlists, input validation, atomic configuration writes, hidden XUIDs, and no-new-privileges.
Remaining hardening work:
- replace direct Docker socket access with a restricted operations gateway;
- document and automate a supported TLS/reverse-proxy boundary;
- continue removing compatibility overlays after tested migration windows;
- expand community installation, diagnostics, and release automation.
For the full threat model, current safeguards, and hardening roadmap see docs/security.md. To report a vulnerability privately see SECURITY.md.
See CONTRIBUTING.md for branch naming, PR title format, metadata requirements, Conventional Commits, quality gate, and CodeRabbit interaction.
If you use Codex, install the global cody-dr portable workflow plugin for
issue authoring, delivery, reviews, and findings handling. CraftControl does
not shadow those lifecycle skills locally; the plugin discovers the shared
project profile automatically.
| Skill | When to use |
|---|---|
backend |
Padrões Python: DI, Protocols, is None, composition root e fakes |
frontend |
Padrões JS: injeção de deps, ESM, i18n e testes |
manage-project |
Gerencia issues nos GitHub Project boards |
manage-milestone |
Gerencia milestones e audita backlog |
The local skills complement the plugin: Codex continues to follow AGENTS.md
and the security instructions. A request to execute an issue
até o PR (inclusive via link) autoriza branch, commit, push e abertura do PR;
merge e deploy continuam exigindo pedido explícito.
The tool-neutral .dr-agents/craftcontrol/PROFILE.md
contains the safeguards specific to Cody DR and Claudio DR reviews. Provide the
profile path explicitly with the requested PR/ref — it does not load
automatically. The profile augments generic review skills and does not trigger
review by itself.
Copyright 2026 Danilo Ramos.
CraftControl is licensed under the Apache License 2.0. The license applies to the original CraftControl source code, documentation, Telemetry Pack, and visual assets contained in this repository unless a file states otherwise.
CraftControl is independent and is not affiliated with Mojang Studios or Microsoft. Minecraft is a trademark of Microsoft Corporation.