# racked.ru — Minecraft server

> *experience the game the way it should have always been*

Self-hosted Purpur Minecraft server powering [racked.ru](https://racked.ru). Microsoft-free, privacy-first, fully open source. Deployed via Docker on Debian (`nullstone`, 192.168.0.100), public at `mc.racked.ru:25565`.

Companion projects:
- **server-client-launcher** — one-click connect, no manual modpack juggling. (Separate repo.)
- **client** — performance-optimized client (separate repo).

This repo is the **server** half. Configs, plugin manifest, deploy scripts. No plugin jars committed — acquired at boot from FOSS sources (see [PLUGINS.md](docs/PLUGINS.md)).

> *all software should be free and open-source* — see [MISSION.md](MISSION.md), [THANKS.md](THANKS.md)

## Stack

| Layer | Choice | Why |
|-------|--------|-----|
| Server jar | Purpur (latest stable build) | Paper fork w/ extra config knobs |
| Container | `itzg/minecraft-server:latest` | Auto-DL of jar + plugins via env |
| Host OS | Debian 13 | nullstone server |
| Network | Docker `proxy` external network | Shared w/ Traefik for future TLS reverse-proxy |
| Backup | tar.gz daily 02:00 via host cron | 7-day retention to `/opt/backups/` |

## Quick start

```bash
git clone <this-repo> minecraft-server
cd minecraft-server
mkdir -p /opt/docker/minecraft
cp -r config/* /opt/docker/minecraft/        # seed configs
cp docker-compose.yml /opt/docker/minecraft/
chmod -R 777 /opt/docker/minecraft            # see docs/PERMISSIONS.md (userns-remap quirk)
cd /opt/docker/minecraft && docker compose up -d
docker logs -f minecraft-mc                   # watch jar+plugin DL, world gen
```

First boot: ~3-5 min (Purpur jar DL, ~14 plugin DL, world gen).

## Docs

- [DEPLOY.md](docs/DEPLOY.md) — fresh deploy + migration from existing server
- [PLUGINS.md](docs/PLUGINS.md) — full plugin list, sources, slugs/IDs
- [PERMISSIONS.md](docs/PERMISSIONS.md) — userns-remap + chmod quirk
- [BACKUP.md](docs/BACKUP.md) — backup script + restore procedure
- [ROADMAP.md](docs/ROADMAP.md) — plugin acquisition overhaul: GH-first, lockfile, CI auto-update
- [TELEMETRY_AUDIT.md](TELEMETRY_AUDIT.md) — privacy audit: phoning-home disabled (bStats, update checks)
- [migrations/lands-to-landclaim.md](docs/migrations/lands-to-landclaim.md) — Lands (paid) → LandClaimPlugin (FOSS) migration

## Server config highlights

| Setting | Value |
|---------|-------|
| Difficulty | hard |
| Gamemode | survival |
| Max players | 69 |
| View distance | 20 chunks |
| Simulation distance | 10 chunks |
| Online mode | false (cracked clients allowed) |
| Spawn protection | 0 |
| RAM | 8G min, 16G max (18G hard cap) |
| RCON | enabled, port 25575, password `${RCON_PASSWORD}` |

Full settings in [`config/server.properties`](config/server.properties).

## Network

| Port | Proto | Use |
|------|-------|-----|
| 25565 | TCP | Minecraft client |
| 25575 | TCP | RCON (LAN-trusted only) |

LAN: `192.168.0.100:25565`. Tailscale: `100.64.0.2:25565`. Future public: `mc.s8n.ru` via Traefik (label commented out).

## Plugins (15 active)

Auto-pulled from Modrinth at boot:
LuckPerms, PlaceholderAPI, EssentialsX, WorldEdit, Simple Voice Chat, MiniMOTD, SkinsRestorer, CoreProtect, GrimAC, spark, DiscordSRV, **LandClaimPlugin** (replaces paid Lands), TAB.

Auto-pulled from Spigot:
ProtocolLib (ID 1997), Vault (ID 34315).

Manual install (no Modrinth/Spigot auto-source):
LoginSecurity, ComfyWhitelist, MarriageMaster, PhantomSMP, HelpCommand, ProAntiTab.

Premium (skipped, FOSS replacement preferred):
~~Lands~~ (replaced by LandClaimPlugin), CosmicGuard.

See [docs/PLUGINS.md](docs/PLUGINS.md) for source URLs.

## Roadmap / TODO

Living checklist. Priority tags: **[P0]** blocker / security, **[P1]** vision-aligned swap, **[P2]** improvement, **[P3]** nice-to-have.

### Infrastructure

- [x] Fix `loader=purpur` boot loop — workaround: `TYPE=CUSTOM` + direct Purpur jar URL + `MODRINTH_LOADER=paper`. Permanent fix still pending Phase 2.
- [x] Pin Purpur version (1.21.10) — no `LATEST` drift
- [x] Set MOTD to racked.ru tagline
- [ ] **[P1]** Public DNS: `mc.racked.ru` → TCPShield proxy (DDoS protection; do NOT point A record directly to home IP)
- [ ] **[P1]** Traefik TLS termination for RCON web UI (LAN-only first)
- [ ] **[P2]** Switch bind mount → named volume to kill `chmod 777` userns workaround
- [ ] **[P2]** `dns:` block in compose pointing 1.1.1.1 + LAN router (Tailscale ate `/etc/resolv.conf` precedent)
- [ ] **[P2]** Bluemap or Squaremap on `map.racked.ru` (browser map via Traefik)
- [ ] **[P2]** Prometheus exporter + Grafana dashboard (TPS, MSPT, RAM)
- [ ] **[P3]** Test instance on port 25566 sharing world snapshot — try plugin upgrades safely

### Plugin acquisition (per [ROADMAP.md](docs/ROADMAP.md))

- [ ] **[P0]** Phase 1: pin every plugin to specific version-id (no `latest` in env)
- [ ] **[P1]** Phase 2: `plugins.yml` manifest + `fetch-plugins.sh` (GH-first, Hangar/Modrinth/Spiget fallback)
- [ ] **[P1]** Phase 2: `plugins.lock` w/ sha256 per jar, committed
- [ ] **[P2]** Phase 3: GH Action — daily upstream check, auto-PR per update, license audit → `LICENSES.md`

### Plugin swaps (per [PLUGIN_ALTERNATIVES.md](docs/PLUGIN_ALTERNATIVES.md))

High priority — security, FOSS alignment, license clarity:
- [x] LoginSecurity → **AuthMe Reloaded** — done. Void `auth_limbo` END dimension, sealed barrier cell at spawn, `teleportUnAuthedToSpawn: true`, `hideInventory: true`, post-login `mvtp %p world` hook. Base-coord leak fixed.
- [x] ProAntiTab — **Keep** (verified: RayzsYT, GPL-2.0-or-later, FOSS, free, GH). Earlier "likely premium" guess was wrong.
- [x] Claim plugin → **Homestead** (Apache-2.0, FOSS, 75+ flags, sub-areas, BlueMap integration, free claiming)
- [x] WorldEdit → **FastAsyncWorldEdit (FAWE)** — done. v2.15.0, GPL-3.0, drop-in swap, CoreProtect integration auto-detected.
- [x] Vault → **VaultUnlocked** — done. TheNewEconomy fork, GH source, modrinth slug `vaultunlocked`, drop-in Vault API replacement.
- [ ] **[P3]** (deferred — later project) Add Matrix bridge alongside DiscordSRV — use existing Tuwunel homeserver (txt.s8n.ru) as FOSS comm channel

Medium priority — license/dependency cleanup:
- [x] CoreProtect-CE — **Keep** (acknowledged license exception; reliability > purity per operator). Revisit if/when Prism reaches feature parity on sign/container/entity rollback at scale.
- [ ] **[P2]** Verify license: TAB

Low priority — consolidation to native:
- [ ] **[P2]** Verify ComfyWhitelist license — keep if FOSS (provides name-based hot-reload whitelist w/o Mojang API; native `/whitelist` is UUID-based and unsafe on offline-mode). Swap to FOSS name-based alt if license unclear.
- [ ] **[P3]** Drop HelpCommand → native `/help` + `commands.yml`
- [ ] **[P3]** Drop PhantomSMP → native paper config + vanilla datapack
- [ ] **[P3]** Audit MarriageMaster usage — drop or fork under FOSS license

Phase 4 — long-term refactor:
- [ ] **[P3]** EssentialsX split into modular FOSS plugins (HuskHomes for teleport, etc)
- [ ] **[P3]** Evaluate dropping ProtocolLib in favor of PacketEvents-only stack
- [ ] **[P3]** PlaceholderAPI → MiniPlaceholders (Adventure-native) when ecosystem catches up
- [ ] **[P3]** Self-hosted skin server (replace Mojang/MineSkin dependency)

### Documentation

- [x] Per-plugin doc files under `docs/plugins/<name>.md` — all 18 active plugins documented (license, source, version, notes)
- [ ] **[P1]** `AGREEMENTS.md` — high-level overview of any custom dev-rights deals (no NDAs broken)
- [ ] **[P1]** Cross-link launcher repo in README + MISSION when public
- [ ] **[P2]** Cross-link client repo in README + MISSION when public
- [ ] **[P2]** `docs/SKIN_HOSTING.md` — once skin server self-hosted
- [ ] **[P3]** mkdocs site auto-built from `docs/` for racked.ru

### Community / process

- [ ] **[P1]** Publish to GitHub under racked-rust org (or chosen org name)
- [ ] **[P1]** CONTRIBUTING.md — describe FOSS-only plugin policy (per MISSION.md)
- [ ] **[P2]** Issue templates: plugin-suggestion, license-concern, bug, feature
- [ ] **[P2]** PR template — license check checkbox, vision-alignment checkbox
- [ ] **[P3]** Discussion category for plugin proposals

### Backlog (deferred, low priority)

- [ ] **[P3-deferred]** Self-host LuckPerms web editor + bytebin on `perms.racked.ru` — eliminates Cloudflare dep that bit us during a CF outage (web editor failed; in-game `/lp` commands still worked). Both components are MIT FOSS (`github.com/LuckPerms/web`, `github.com/lucko/bytebin`). Workaround for now: use `/lp` commands only, skip GUI entirely. Revisit when other Phase 4 work is done — small QoL win, big setup cost.

### Done

- [x] Backup old server → `_archive/minecraft-old-2026-04-27.tar.gz`
- [x] Migrate Lands (paid) → LandClaimPlugin (FOSS) — see [migrations/lands-to-landclaim.md](docs/migrations/lands-to-landclaim.md)
- [x] Drop LitePlaytimeRewards (upstream dead since 2021)
- [x] Drop CosmicGuard (premium, can't audit) — GrimAC covers anti-cheat
- [x] Document MISSION + THANKS + plugin policy
- [x] Plugin alternatives audit — see [PLUGIN_ALTERNATIVES.md](docs/PLUGIN_ALTERNATIVES.md)
- [x] Drop DiscordSRV (Discord = mission-misaligned proprietary platform)
- [x] Migrate old world (4.2G overworld + nether + end) from archive to new server
- [x] Restore selective plugin configs from old (LuckPerms perms+groups, CoreProtect history, EssentialsX userdata, MiniMOTD, voicechat, SkinsRestorer, GrimAC, ProAntiTab, WorldEdit, PlaceholderAPI, spark)
- [x] Restore player state files (ops.json, banned-players, banned-ips, whitelist, usercache)
- [x] TAB v5 → v6 schema migration (visuals preserved, 0 warnings on reload)
- [x] Document `racked.ru` as the project (MISSION.md, THANKS.md w/ author attributions, README rebrand)
- [x] AuthMe void limbo dimension (`auth_limbo`) — sealed barrier cell, no coord leaks, post-login TP to overworld
- [x] Public access confirmed — port forward 25565 → 82.31.156.86 working
- [x] LandClaimPlugin Wilderness actionbar silenced
- [x] Disk cleanup — freed 11G+ (old backups, Docker build cache, staging dirs)

## License

Configs + scripts in this repo: MIT. Plugin jars are not redistributed here — they're acquired at deploy time from upstream sources, each under its own license. See [THANKS.md](THANKS.md) for per-plugin license attribution.
