Minecraft 26.2 Fabric server stack with CraftDeck management panel
- docker-compose: itzg/minecraft-server (Fabric, offline mode, whitelist enforced, Modrinth-managed mods), itzg/mc-backup sidecar, custom dashboard - Gated auth for offline mode: approve username -> whitelisted with a short registration window -> EasyAuth /register + /login; auto-revoke on expiry - CraftDeck panel (Next.js 16, zero native deps): live console (SSE), players & stats, lag diagnostics (server TPS vs player ping via spark), performance graphs, Modrinth mod search/manager, backups & restore, sandboxed file browser/editor, .env config editor with compose apply, cron schedules, Discord alerts, scrypt-hashed panel login - scripts/setup.sh generates secrets; docs/ covers auth, mods, updating, backups, networking (Tailscale), troubleshooting Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
commit
279d137ce5
98 files changed
+9925
No files matched your search
@@ -0,0 +1,59 @@
|
||||
import { inspectContainer, containerEnv } from "@/server/docker";
|
||||
import { listOnlinePlayers } from "@/server/mc";
|
||||
import { db } from "@/server/db";
|
||||
import { env } from "@/server/env";
|
||||
import { getWorldSizeBytes } from "@/server/sampler";
|
||||
import { readWorldInfo } from "@/server/playerstats";
|
||||
import { ok, handle } from "@/server/api";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export async function GET() {
|
||||
return handle(async () => {
|
||||
let container;
|
||||
let dockerAvailable = true;
|
||||
try {
|
||||
container = await inspectContainer(env.mcContainer);
|
||||
} catch {
|
||||
dockerAvailable = false;
|
||||
container = { exists: false, running: false, status: "unknown" as const };
|
||||
}
|
||||
|
||||
let players: { online: number; max: number; names: string[] } = { online: 0, max: 0, names: [] };
|
||||
let version: string | null = null;
|
||||
let serverType: string | null = null;
|
||||
if (container.running) {
|
||||
try {
|
||||
players = await listOnlinePlayers();
|
||||
} catch {}
|
||||
try {
|
||||
const cenv = await containerEnv(env.mcContainer);
|
||||
version = cenv["VERSION"] ?? null;
|
||||
serverType = cenv["TYPE"] ?? null;
|
||||
} catch {}
|
||||
}
|
||||
|
||||
const latest = db()
|
||||
.prepare("SELECT * FROM metrics ORDER BY ts DESC LIMIT 1")
|
||||
.get() as Record<string, number | null> | undefined;
|
||||
|
||||
const pendingCount = (
|
||||
db().prepare("SELECT COUNT(*) AS n FROM approved_players WHERE status = 'pending'").get() as { n: number }
|
||||
).n;
|
||||
|
||||
return ok({
|
||||
dockerAvailable,
|
||||
container,
|
||||
players,
|
||||
version,
|
||||
serverType,
|
||||
metrics: latest ?? null,
|
||||
pendingApprovals: pendingCount,
|
||||
world: readWorldInfo(getWorldSizeBytes()),
|
||||
uptimeMs:
|
||||
container.running && "startedAt" in container && container.startedAt
|
||||
? Date.now() - new Date(container.startedAt).getTime()
|
||||
: null,
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user