The control centre for Luna Network: every Minecraft server across every machine in the cluster, with its plugins, worlds, config, ports and players, managed from one web console or a terminal.
State, health checks, tick rate, memory and player count for every backend and the proxy, live, without opening a shell on any of the machines.
Verbs apply to the selection, so restarting nine servers is one action. A verb that cannot run on what you picked stays visible and disabled, with the reason next to it.
Per instance: what it runs, which machine owns it, the Java profile and heap it launched with, the address the proxy routes to, and the process behind it.
Name, software, version, heap, machine, and optionally a world zip to start from. luna downloads the build, allocates a port, writes the forwarding secret, registers the server with Velocity and deploys every plugin whose target rule matches it.
Paper, Folia, Purpur, Fabric, Forge, NeoForge, Pumpkin, Youer and AsyncYouer are all a pick in the same dropdown.
Each step reports as it runs, and a failure names the step that broke instead of leaving you to work out what got half done.
CPU, memory, players, tick rate, tick duration, JVM heap, loaded chunks and entities, sampled every five seconds and kept for an hour, with ninety days of uptime history above them.
Tick rate and heap are read from inside the server rather than from the outside of its process, so they match what players feel. A backend that Paper paused for being empty reads as paused, not as a stall.
Every thread of the server process, shaded by the CPU it spent over the last sample, with the busiest ones named. When one core is pinned, this is where you find out by what.
The log streams live, with a command line into the running server.
Each server gets the newest build compatible with the Minecraft version it runs, or the version you pinned. Plugin folders stay in step without anyone touching them.
Targets are rules rather than lists: *paper covers every Paper backend, including ones that do not exist yet. Updates stay on their channel and never move a server backwards. A jar swapped on a running server is staged and renamed in one step, so the server never reads a half-written file.
Search and install from Modrinth, Hangar and CurseForge, plus Smithed for data packs. The source is recorded, so update checks still work months later.
Fabric, Forge and NeoForge mods share the pool model with plugins: one entry, one version per Minecraft line, deployed to whichever modded backends target it. Jars that appear in an instance directory without a pool entry are listed as unmanaged, with their state read from the boot log.
Data packs are pooled too and land in each target world; servers pick them up on the next restart or a /minecraft:reload.
Real ranges, real choices, validated before anything reaches disk. Every key without a form field is still there in the raw table below.
The keys that wire proxy forwarding are shown but locked, because editing one by hand breaks every login on that backend while the server still looks healthy.
Any file in an instance, edited in Monaco from the browser. A value you keep retyping becomes a placeholder backed by one variable, and luna renders the file from its template on every start.
When a plugin rewrites a managed config, the rewrite is reported as drift and kept beside the file, so a regenerated config is never lost quietly.
Variables layer builtin, global, machine, instance. Rotating a database password is one edit and a restart rather than nine files.
Secrets are masked wherever they appear. Revealing one is recorded with the scope and the time, never with the value.
Per variable: which layer wins on each instance, which config files and plugin templates read it, and every change that was made to it.
Allocation comes from named pools and is tracked per machine, because two hosts can both bind 25565.
Deleting a server releases its port. An audit flags duplicates, configs that drifted from the registry, and addresses the proxy disagrees with.
Pools are cluster-wide so a provision can land on any machine; a machine sets only the range it hands out.
[servers] and [forced-hosts] are generated from the instance registry and diffed against disk before anything is saved.
Only the sections luna owns get replaced, so the rest of velocity.toml survives. A backend on another machine gets its LAN address filled in.
A follower joins the cluster and its servers appear on the same screens. Instances are launched onto it from the same form.
Reachability is TCP-probed from the primary rather than inferred from the control link. Followers upgrade themselves from the primary's binary; a follower on a mismatched build stays on the map as quarantined until it does.
Per machine: checks, resource headroom, owned instances and the build each daemon is running.
luna installs JDKs itself, one copy per machine and architecture. An instance pins one of them or runs on the machine's own Java. Flag sets are Java profiles you edit once and hand to many servers, and a Java agent is one more field on the instance.
Back up a world while the server runs. Restore, replace with an uploaded zip, or reset to a fresh one when it is stopped. A pinned backup is never pruned, and any archive can be re-read to check its checksum.
The dimensions, their sizes and the seed are on the same screen.
Everyone the network has seen, with first and last seen, the backend they were last on, playtime, sessions and auth type.
Recorded across the network rather than per server, so support is a lookup instead of a search through every backend's logs.
Balance, playtime by backend, chat, commands, permissions and moderation history on one page. The skin turns.
Every play session the proxy recorded, as a calendar and as a list.
Bans, whitelist and operators for every server on one screen, with the log of who did what to whom. An IP ban at the network level is enforced by the proxy, so a scanner never reaches a backend.
Each instance has its own Players & access tab for the players on it right now, with health, food, location and ping, and everything said or run there.
LuckPerms groups from one shared database, so a promotion lands on every server at once.
Group detail lists every node it carries, including what it inherits, with contexts and expiry.
Resource packs stack by priority, are scoped per server, and apply on a proxy reload.
Rules exclude as well as include, so *, !create is the whole network except the modded server. A tracked pack can move to an older release when the new one misbehaves.
The chest players open with /servers, edited as a chest: MiniMessage names, and tooltips drawn the way the client draws them, with live status filled in.
/public needs no sign-in: players online, servers up, fleet load, a map image for every server that renders one, and thirty days of uptime per server. Each server has its own page with its live map.
Player heads and skins are drawn by the console itself, at a URL other software can point at.
Start, stop or restart on a cron expression, a fixed time or a rate. Nothing depends on a shell staying open.
Every run is kept with its outcome, so a restart that failed last Tuesday is on the record. Stops are graceful.
The compiled binary, with the completion engine the shell uses: Tab completion, ghost text and the same history. Everything the console cannot do yet is a command away.
The drawer shortens the page instead of covering it, and commands typed there are attributed to the signed-in account.
Alt+S indexes instances, addon groups, packs, schedules, ports, proxy routes, players, machines, runtimes and variables.
Enter opens the hit. Objects without a page of their own hand their term to the table that lists them.
The console is gated; the CLI is not. Passwords are argon2id-hashed, access keys exist for scripts and can be revoked on their own, and a Minecraft profile can be linked to an account. Wrong password, unknown user and disabled account all answer alike, and repeated failures lock the account.
Who may sign in, who is signed in right now, and everything done to those accounts.
A journal of what luna itself did on each machine: the daemon, the console's own routes, the CLI and the sign-in path, in monthly files.
luna-console is built to run the luna ecosystem, and it leans on it. Without a copy of the luna suite of plugins and mods, the instance, addon, network and fleet screens still work; the player, permission and economy screens will be empty.
The host needs GNU screen, and MariaDB and RabbitMQ if you want the player-facing screens to have anything in them. luna can install Java on each machine itself. Everything else ships in one compiled binary.
sudo luna setup # install this machine: user, root, config, unit, start
luna setup --dry-run # every change it would make, making none
luna daemon run # the daemon that owns the cluster
luna web --host 0.0.0.0 # the console, on 8330
Building from source needs Bun:
bun install
bun run build # compile the single binary -> dist/luna
cd web && bun run build # the console bundle
docker build -t luna . # or the published image: binary + console + JRE + screen
Warning
This repository is public for transparency and to ship release artifacts to the machines that run it. It is not open source, and none of the above is permission to run it. See the licence below before you clone it.
This project does not take outside contributions. Issues and pull requests will be closed unread, and there is no roadmap to sign up to. Read the code if it is useful to you. The licence does not grant permission to build on it.
Copyright (c) 2026 Belikhun. All rights reserved.
Publishing this source does not place it in the public domain and does not make it open source. No permission is granted to any person to use, copy, modify, merge, publish, distribute, sublicense, create derivative works of, or sell this software or any part of it, in any form, without prior written permission from the copyright holder. Viewing the source, and the forking mechanics GitHub's Terms of Service afford to public repositories hosted there, are permitted. Nothing further is.
Third-party components are not covered by that notice. This includes the vendored assets under web/static/ and every dependency resolved at build time.
The full text is in LICENSE.


































