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,64 @@
|
||||
# Authentication flow
|
||||
|
||||
The server runs with `online-mode=false` so offline launchers (TLauncher, etc.) can
|
||||
join. That disables Mojang's account verification, so this stack layers two gates on
|
||||
top:
|
||||
|
||||
1. **Whitelist** (vanilla) — only approved usernames can connect at all
|
||||
2. **EasyAuth** (Fabric mod) — every player must `/register` a password once, then
|
||||
`/login` on every join. Unauthenticated players are frozen, invisible to the world,
|
||||
and kicked after a timeout.
|
||||
|
||||
## The approval lifecycle
|
||||
|
||||
```
|
||||
you approve a name ──► whitelisted + "pending" + countdown starts (default 2 min)
|
||||
│
|
||||
├─ player joins and /register-s in time ──► "registered" (permanent access)
|
||||
│
|
||||
└─ countdown lapses ──► whitelist entry removed ──► "expired"
|
||||
(re-approve any time to restart the window)
|
||||
```
|
||||
|
||||
The panel enforces this automatically: a background watcher reconciles the pending list
|
||||
against EasyAuth's registered accounts every 5 seconds and revokes lapsed windows.
|
||||
|
||||
### Why the short window matters
|
||||
|
||||
While a name is whitelisted but unregistered, anyone who knows the name could join and
|
||||
claim it. The window shrinks that exposure to a couple of minutes, and you control
|
||||
exactly when it opens — approve while your friend is sitting in the launcher. If someone
|
||||
does sneak in and register a name that isn't theirs, just **Revoke** it (removes the
|
||||
account + whitelist entry) and approve again.
|
||||
|
||||
## In-game commands (players)
|
||||
|
||||
| Command | What it does |
|
||||
|---|---|
|
||||
| `/register <pass> <pass>` | Create your password (first join only) |
|
||||
| `/login <pass>` | Log in (every join) |
|
||||
| `/account` | Change password, manage sessions |
|
||||
| `/logout` | Log out manually |
|
||||
|
||||
## Panel actions (Access & Auth page)
|
||||
|
||||
| Action | Effect |
|
||||
|---|---|
|
||||
| Approve | Whitelist + open registration window |
|
||||
| Re-open window | Same, for an expired/revoked name |
|
||||
| Reset password | Sets a temporary password (shown once) and kicks them to re-login |
|
||||
| Revoke | Whitelist entry + EasyAuth account deleted, player kicked |
|
||||
| Import whitelist | Adopt names whitelisted outside the panel |
|
||||
|
||||
## Storage
|
||||
|
||||
EasyAuth stores password hashes in its own database under
|
||||
`data/mc/mods/EasyAuth/` (included in backups). The panel's approval state lives in
|
||||
`data/dashboard/craftdeck.db`. The two are reconciled via RCON (`auth list`,
|
||||
`auth remove`, `auth update`), so there's no fragile file coupling.
|
||||
|
||||
## Tuning
|
||||
|
||||
- **Window length**: Settings → "Player registration window" (0.5–120 minutes)
|
||||
- **EasyAuth options** (kick timeout, session lifetime, password rules):
|
||||
Files → `config/EasyAuth/` — edit and restart the server
|
||||
@@ -0,0 +1,57 @@
|
||||
# Backups & restore
|
||||
|
||||
## What runs automatically
|
||||
|
||||
The `backup` sidecar (itzg/mc-backup) tars the entire server data directory to
|
||||
`data/backups/world-<timestamp>.tgz`:
|
||||
|
||||
- flushes the world to disk first (`save-all`), safe while players are online
|
||||
- interval: `BACKUP_INTERVAL` in `.env` (default `24h`)
|
||||
- retention: `BACKUP_RETENTION_DAYS` (default `7`) — older tars are pruned
|
||||
- excludes caches and logs
|
||||
|
||||
Safety backups are also taken automatically before config applies (when enabled) and
|
||||
world resets.
|
||||
|
||||
## Manual backup
|
||||
|
||||
- Panel: Backups page → **Back up now**
|
||||
- CLI: `docker exec mc-backup backup now`
|
||||
|
||||
## Restoring
|
||||
|
||||
Panel: Backups page → **Restore** → type `restore`. The panel stops the server,
|
||||
extracts the tar over the data directory, and starts the server again. Everything since
|
||||
that backup is lost.
|
||||
|
||||
CLI fallback (panel down):
|
||||
|
||||
```bash
|
||||
./scripts/restore.sh data/backups/world-20260710-050000.tgz
|
||||
```
|
||||
|
||||
## Off-site copies (recommended)
|
||||
|
||||
`data/backups/` is just files — sync it anywhere:
|
||||
|
||||
```bash
|
||||
# example: nightly rsync to another machine (add to the host's crontab)
|
||||
0 6 * * * rsync -a --delete /path/to/minecraft/data/backups/ backup-host:/srv/mc-backups/
|
||||
```
|
||||
|
||||
You can also download any backup from the panel (⬇ button) before risky experiments.
|
||||
|
||||
## Disaster recovery (new machine)
|
||||
|
||||
```bash
|
||||
git clone <repo> minecraft && cd minecraft
|
||||
./scripts/setup.sh # fresh secrets — friends keep their passwords,
|
||||
# those live in the world data, not in .env
|
||||
mkdir -p data/backups && cp <your-backup>.tgz data/backups/
|
||||
docker compose up -d # let it initialize once
|
||||
./scripts/restore.sh data/backups/<your-backup>.tgz
|
||||
```
|
||||
|
||||
The backup contains the world, mods, configs, and the EasyAuth database, so player
|
||||
registrations survive. Panel state (approval history, metrics) lives in
|
||||
`data/dashboard/` — include it in your off-site sync if you want it back too.
|
||||
@@ -0,0 +1,66 @@
|
||||
# Mods & modpacks
|
||||
|
||||
## Why Fabric
|
||||
|
||||
- First loader to support new Minecraft versions (26.x drops land on Fabric within days)
|
||||
- The best server-side performance ecosystem (Lithium, FerriteCore, spark)
|
||||
- EasyAuth (the auth system) is Fabric-only
|
||||
- Server-side-only mods are invisible to players — vanilla and TLauncher clients join
|
||||
without installing anything
|
||||
|
||||
NeoForge/Forge are supported by the same stack (`SERVER_TYPE` in `.env`) but trail new
|
||||
versions and would require replacing the auth mod, so Fabric is the default.
|
||||
|
||||
## The default mod set
|
||||
|
||||
| Mod | Job | Players need it? |
|
||||
|---|---|---|
|
||||
| fabric-api | required by most Fabric mods | no |
|
||||
| easyauth | password authentication | no |
|
||||
| spark | TPS/ping profiling (powers the Lag page) | no |
|
||||
| lithium | game-logic optimization | no |
|
||||
| ferrite-core | memory-usage reduction | no |
|
||||
|
||||
## Adding mods
|
||||
|
||||
**Panel way (recommended):** Mods page → search Modrinth → **Add** → **Apply changes**.
|
||||
The search is pre-filtered to Fabric mods compatible with your exact server version.
|
||||
Watch the **"needs client install"** badge — server-side mods are safe for everyone;
|
||||
client-required mods mean every friend must install the same mod or they can't join.
|
||||
|
||||
**Manual way:** drop a `.jar` into `data/mc/mods/` (Files page → mods → Upload) and
|
||||
restart the server.
|
||||
|
||||
## How auto-update works
|
||||
|
||||
Managed mods are pinned by *project slug*, not version, in `.env`:
|
||||
|
||||
```
|
||||
MODRINTH_PROJECTS=fabric-api,easyauth,spark,lithium,ferrite-core
|
||||
```
|
||||
|
||||
Every time the server container (re)starts, the itzg image resolves each slug to the
|
||||
**newest release compatible with your Minecraft version** and downloads it. So:
|
||||
|
||||
- "Update all mods" = restart the server (Mods page → Update all & restart)
|
||||
- Upgrading Minecraft automatically brings the matching mod builds with it
|
||||
|
||||
Manually uploaded jars are yours to update — the resolver doesn't touch them.
|
||||
|
||||
## Switching to a modpack later
|
||||
|
||||
1. Pick a **Modrinth** modpack (e.g. Adrenaline, Simply Optimized) and note its slug
|
||||
2. Configuration page → set `MODRINTH_MODPACK` to the slug → Save → Apply
|
||||
(take the safety backup — modpacks change world generation!)
|
||||
3. Every player installs the same modpack client-side (Modrinth App → install pack →
|
||||
play). Offline-launcher users need a launcher that supports Modrinth packs, or
|
||||
manual mod installation.
|
||||
|
||||
To go back: clear `MODRINTH_MODPACK`, Apply. Keep `MODRINTH_PROJECTS` as your
|
||||
server-side base either way. CurseForge packs also work (`CF_SLUG` env — needs a
|
||||
CurseForge API key; see the itzg image docs), but Modrinth is smoother.
|
||||
|
||||
## Removing a mod
|
||||
|
||||
Mods page → managed list → 🗑 (or delete the jar) → Apply. `fabric-api` and `easyauth`
|
||||
are locked — the auth system depends on them.
|
||||
@@ -0,0 +1,56 @@
|
||||
# Networking
|
||||
|
||||
## Ports
|
||||
|
||||
| Port | Service | Exposure |
|
||||
|---|---|---|
|
||||
| 25565/tcp | Minecraft | Internet (port-forward this on your router) |
|
||||
| 8080/tcp | Dashboard | **LAN/VPN only — never port-forward** |
|
||||
| 25575/tcp | RCON | Docker-internal only (not published at all) |
|
||||
|
||||
## Letting friends connect
|
||||
|
||||
1. Give the server machine a static LAN IP (router → DHCP reservation)
|
||||
2. Router → port forwarding → external `25565` → `<server-lan-ip>:25565`
|
||||
3. Friends connect to your public IP (`curl ifconfig.me`), or set up free dynamic DNS
|
||||
(DuckDNS et al.) so they can use a stable name like `yourname.duckdns.org`
|
||||
|
||||
Whitelist + EasyAuth handle the "random people found my server" problem — that's what
|
||||
they're for.
|
||||
|
||||
## Keeping the dashboard private
|
||||
|
||||
The dashboard is deliberately not hardened for the open internet (it controls Docker).
|
||||
Reach it from outside your LAN with **Tailscale** (free, ~5 minutes):
|
||||
|
||||
```bash
|
||||
# on the server
|
||||
curl -fsSL https://tailscale.com/install.sh | sh
|
||||
sudo tailscale up
|
||||
```
|
||||
|
||||
Install Tailscale on your phone/laptop, log into the same account, and the panel is at
|
||||
`http://<server-tailscale-ip>:8080` from anywhere — encrypted, invisible to everyone
|
||||
else. (WireGuard works just as well if you prefer to self-host the VPN.)
|
||||
|
||||
Optionally pin the port binding to specific interfaces in `.env`/compose, and firewall
|
||||
the host:
|
||||
|
||||
```bash
|
||||
sudo ufw allow 25565/tcp
|
||||
sudo ufw allow from 192.168.0.0/16 to any port 8080 proto tcp # LAN only
|
||||
sudo ufw enable
|
||||
```
|
||||
|
||||
## If you later want the panel on a domain
|
||||
|
||||
Put Caddy (or Traefik/nginx) in front for TLS + an extra auth layer, and keep 8080
|
||||
unpublished. This repo doesn't ship that by default — open an issue with your domain
|
||||
setup and add a `caddy` service; the panel works fine behind a reverse proxy
|
||||
(plain HTTP upstream, cookie auth).
|
||||
|
||||
## "Is it my internet or the server?"
|
||||
|
||||
Performance & Lag page. Server-side lag shows as low TPS / high MSPT (affects everyone
|
||||
equally); player-side lag shows as high ping for that player only. The page gives a
|
||||
plain-English verdict and per-player ping history so you can settle the argument.
|
||||
@@ -0,0 +1,72 @@
|
||||
# Troubleshooting
|
||||
|
||||
## Server won't start
|
||||
|
||||
**Check the Console page first** (or `docker logs mc --tail 100`).
|
||||
|
||||
| Symptom in logs | Fix |
|
||||
|---|---|
|
||||
| `EULA` complaints | `EULA=TRUE` is set by compose — make sure you didn't override it |
|
||||
| A mod failed to resolve for your version | Remove that slug on the Mods page, Apply. (New MC version + mod hasn't updated yet.) |
|
||||
| `OutOfMemoryError` | Lower `MC_VIEW_DISTANCE`, or raise `MC_MEMORY`/`MC_CONTAINER_MEM_LIMIT` if the host has headroom |
|
||||
| Port already in use | Something else on 25565 — change `MC_PORT` in `.env` |
|
||||
| Crash right after "Done" | A mod conflict — disable recently added jars (Mods page → power icon) |
|
||||
|
||||
## A friend can't join
|
||||
|
||||
Work down this list:
|
||||
|
||||
1. **"Not whitelisted"** → their username isn't approved (or the window expired and
|
||||
auto-revoked them). Access & Auth → approve/re-open. Username must match **exactly**
|
||||
(case matters in TLauncher).
|
||||
2. **Joins but immediately kicked** → they didn't `/register` or `/login` in time —
|
||||
EasyAuth kicks unauthenticated players after a timeout. Tell them to type faster or
|
||||
raise the timeout in `config/EasyAuth/`.
|
||||
3. **"Connection timed out"** → networking: is 25565 port-forwarded? Are they using
|
||||
your *public* IP? Does `docker compose ps` show `mc` healthy?
|
||||
4. **Wrong password loop** → Access & Auth → **Reset password**, share the temporary
|
||||
one privately.
|
||||
|
||||
## Panel shows "Offline" but the server is up
|
||||
|
||||
The dashboard container can't reach the Docker socket or RCON:
|
||||
|
||||
```bash
|
||||
docker compose ps # is mc-dashboard running?
|
||||
docker logs mc-dashboard --tail 50
|
||||
docker compose up -d --force-recreate dashboard
|
||||
```
|
||||
|
||||
If you changed `RCON_PASSWORD` in `.env`, Apply/recreate **both** `mc` and `dashboard`
|
||||
so they agree.
|
||||
|
||||
## Forgot the panel password
|
||||
|
||||
```bash
|
||||
docker compose stop dashboard
|
||||
rm data/dashboard/craftdeck.db # wipes panel users/settings/history — NOT the world
|
||||
# set PANEL_ADMIN_PASSWORD in .env to a fresh value
|
||||
docker compose up -d dashboard
|
||||
```
|
||||
|
||||
Player approvals are re-importable afterwards (Access & Auth → Import whitelist).
|
||||
|
||||
## Lag
|
||||
|
||||
Performance & Lag page tells you *who* is lagging (server vs a player's connection).
|
||||
If it's the server: check the CPU/memory charts, run the spark health report, lower
|
||||
view/simulation distance, or add more RAM. If it's one player: it's their network —
|
||||
nothing to fix server-side.
|
||||
|
||||
## Disk filling up
|
||||
|
||||
Backups page shows total backup size; lower `BACKUP_RETENTION_DAYS`. The panel also
|
||||
raises a low-disk alert below 2 GB free.
|
||||
|
||||
## Nuke everything and start over (keeps nothing)
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
rm -rf data
|
||||
./scripts/setup.sh && docker compose up -d
|
||||
```
|
||||
@@ -0,0 +1,39 @@
|
||||
# Updating
|
||||
|
||||
## Upgrading Minecraft (e.g. 26.2 → 26.3)
|
||||
|
||||
1. **Configuration** page → change `Minecraft version` → **Save**
|
||||
2. **Apply** with *"Take a safety backup first"* enabled
|
||||
3. The server container is recreated: the new server jar, a matching Fabric loader, and
|
||||
fresh builds of every managed mod are downloaded automatically
|
||||
|
||||
If a managed mod has no build for the new version yet, the server won't start — check
|
||||
the Console page for which one, remove it from the Mods page (or wait a few days), and
|
||||
Apply again. Worlds upgrade forward automatically; **there is no downgrade** — that's
|
||||
what the safety backup is for.
|
||||
|
||||
Command-line equivalent:
|
||||
|
||||
```bash
|
||||
sed -i 's/^MC_VERSION=.*/MC_VERSION=26.3/' .env
|
||||
docker exec mc-backup backup now
|
||||
docker compose up -d mc
|
||||
```
|
||||
|
||||
## Updating mods only
|
||||
|
||||
Mods page → **Update all & restart**. (Any server restart re-resolves managed mods.)
|
||||
|
||||
## Updating the panel / images
|
||||
|
||||
```bash
|
||||
git pull
|
||||
docker compose pull # new itzg server + backup images
|
||||
docker compose build dashboard
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## Snapshots / release candidates
|
||||
|
||||
`MC_VERSION` accepts any version the launcher knows (`26.3-rc-1`, `26.3-snapshot-3`…).
|
||||
Mods rarely support snapshots — expect to trim the mod list if you try them.
|
||||
Reference in new issue
Block a user