From 9f50df534cf77da0c57279600280ed2104872d29 Mon Sep 17 00:00:00 2001 From: nicolas Date: Sun, 13 Sep 2026 22:06:00 +0200 Subject: [PATCH] Initial commit: Minecraft Java & Bedrock crossplay server setup --- .env.example | 37 ++++ .gitignore | 5 + DEPLOY-ORACLE.md | 265 ++++++++++++++++++++++++ README.md | 202 ++++++++++++++++++ config/plugins/Geyser-Spigot/config.yml | 45 ++++ deploy/minecraft-crossplay.tar.gz | Bin 0 -> 10966 bytes docker-compose.yml | 97 +++++++++ scripts/check-crossplay.py | 130 ++++++++++++ 8 files changed, 781 insertions(+) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 DEPLOY-ORACLE.md create mode 100644 README.md create mode 100644 config/plugins/Geyser-Spigot/config.yml create mode 100644 deploy/minecraft-crossplay.tar.gz create mode 100644 docker-compose.yml create mode 100644 scripts/check-crossplay.py diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..01caa5f --- /dev/null +++ b/.env.example @@ -0,0 +1,37 @@ +# Stellschrauben fuer den Crossplay-Server. +# Nach jeder Aenderung: docker compose up -d + +# Minecraft-/Paper-Version. LATEST = jeweils neueste stabile Version. +# Fest pinnen (z.B. 26.2) macht Updates planbar - empfohlen im Dauerbetrieb. +MC_VERSION=LATEST + +# Arbeitsspeicher fuer die JVM (Xms=Xmx). Faustregel: 4-8G fuer eine +# Handvoll Spieler, nie mehr als ~50-60% des Host-RAM. +MC_MEMORY=4G + +# Ports auf dem Host. Container-intern bleibt es immer 25565/19132. +JAVA_PORT=25565 +BEDROCK_PORT=19132 + +# server.properties +MC_MOTD=Crossplay Server - Java & Bedrock +MC_DIFFICULTY=normal +MC_MAX_PLAYERS=20 +MC_VIEW_DISTANCE=10 +MC_SIMULATION_DISTANCE=8 + +# Operatoren: Java-Namen kommagetrennt. Bedrock-Spieler kommen mit ihrem +# Floodgate-Namen inkl. Praefix, also z.B. .MeinGamertag +MC_OPS=PlayerName + +# Whitelist. Erst auf true stellen, wenn unten der richtige Name drin steht - +# sonst sperrst du dich vom eigenen Server aus. +# MC_WHITELIST nimmt nur Java-Profilnamen (kommagetrennt). Bedrock-Spieler +# kommen per con-cli "fwhitelist add " dazu. +MC_WHITELIST_ENABLED=true +MC_WHITELIST=PlayerName + +# Passwort fuer RCON (nur containerintern erreichbar, kein Host-Port). +RCON_PASSWORD=change_this_to_a_secure_password + +TZ=Europe/Berlin diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f3b8ce --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.env +*.log +.DS_Store +Thumbs.db + diff --git a/DEPLOY-ORACLE.md b/DEPLOY-ORACLE.md new file mode 100644 index 0000000..6d8ad30 --- /dev/null +++ b/DEPLOY-ORACLE.md @@ -0,0 +1,265 @@ +# Deployment: Oracle Cloud (Ampere A1) auf minecraft.djnizz.at + +Anleitung fuer den Umzug des lokal getesteten Stacks auf die bestehende +OCI-Instanz. Alles per Hand, kein Automatismus. + +## Ausgangslage + +| | | +|---|---| +| Ziel-Host | `130.61.230.183` | +| DNS | `minecraft.djnizz.at` → `130.61.230.183` (A-Record bei helloly, **existiert bereits**) | +| Shape | Ampere A1, ARM64 | +| SSH-Key | `C:\Users\nicol\Documents\oracle free private key.ppk` | +| Paket | `deploy/minecraft-crossplay.tar.gz` | + +Geprueft: DNS loest korrekt auf, die Ports 25565/TCP und 19132/UDP sind von +aussen aktuell noch dicht — erwartbar, es laeuft ja noch nichts. + +**ARM ist kein Problem.** `itzg/minecraft-server` ist multiarch und bringt +`linux/arm64` mit; Paper, Geyser und Floodgate sind reines Java. + +**Caddy wird nicht gebraucht.** Minecraft spricht ein eigenes Protokoll ueber +rohes TCP, Bedrock zusaetzlich UDP — beides kann ein HTTP-Reverse-Proxy nicht +sinnvoll weiterreichen. Die Container-Ports werden direkt veroeffentlicht. +80/443 bleiben unberuehrt, es gibt keine Kollision. + +## 1. SSH-Key nutzbar machen + +Die `.ppk` ist PuTTY-Format, `scp`/`ssh` von Windows koennen damit nichts +anfangen. Entweder mit `pscp`/WinSCP arbeiten oder einmalig konvertieren: + +```powershell +puttygen "$HOME\Documents\oracle free private key.ppk" -O private-openssh -o "$HOME\.ssh\oracle_mc.key" +``` + +Danach Rechte einschraenken, sonst verweigert OpenSSH den Key: + +```powershell +icacls "$HOME\.ssh\oracle_mc.key" /inheritance:r /grant:r "$($env:USERNAME):(R)" +``` + +Der Login-User haengt am Image: Ubuntu → `ubuntu`, Oracle Linux → `opc`. + +## 2. Paket hochladen und entpacken + +```powershell +scp -i "$HOME\.ssh\oracle_mc.key" "deploy\minecraft-crossplay.tar.gz" ubuntu@130.61.230.183:~/ +``` + +```powershell +ssh -i "$HOME\.ssh\oracle_mc.key" ubuntu@130.61.230.183 +``` + +Auf dem Server: + +```bash +mkdir -p ~/docker && tar xzf ~/minecraft-crossplay.tar.gz -C ~/docker/ && cd ~/docker/minecraft-crossplay && ls -la +``` + +Docker liegt durch den Caddy-Stack schon vor. Kurz gegenpruefen: + +```bash +docker version --format '{{.Server.Version}}' && docker compose version +``` + +## 3. Ports in OCI oeffnen (der eigentliche Knackpunkt) + +Das ist in der Praxis die Ursache fuer die meisten „Server nicht erreichbar"- +Faelle. In der OCI-Konsole: + +**Networking → Virtual Cloud Networks → → Security Lists → +Default Security List → Add Ingress Rules** + +Zwei Regeln, beide *stateful* (Haken bei „Stateless" NICHT setzen): + +| Source CIDR | IP Protocol | Destination Port Range | +|---|---|---| +| `0.0.0.0/0` | TCP | `25565` | +| `0.0.0.0/0` | UDP | `19132` | + +Haengt an der VNIC deiner Instanz eine **Network Security Group**, muessen die +beiden Regeln dort hinein statt in die Security List — sonst greifen sie nicht. + +Die UDP-Regel wird gerne vergessen. Ohne sie funktioniert Java einwandfrei und +Bedrock gar nicht. + +## 4. Firewall auf der Instanz + +Von Docker veroeffentlichte Ports gehen per DNAT an der `INPUT`-Kette vorbei, +deshalb laeuft das meist ohne Zutun. Erst testen (Schritt 6), und nur wenn es +scheitert, hier nachziehen. + +Welche Firewall aktiv ist: + +```bash +systemctl is-active firewalld; sudo iptables -S INPUT | head +``` + +**Oracle Linux (firewalld):** + +```bash +sudo firewall-cmd --permanent --add-port=25565/tcp --add-port=19132/udp && sudo firewall-cmd --reload +``` + +**Ubuntu (iptables + netfilter-persistent):** + +```bash +sudo iptables -I INPUT 5 -p tcp --dport 25565 -j ACCEPT && sudo iptables -I INPUT 6 -p udp --dport 19132 -j ACCEPT && sudo netfilter-persistent save +``` + +## 5. Konfiguration anpassen + +In `~/docker/minecraft-crossplay/.env`: + +* `MC_MEMORY` — im Paket auf `8G` gesetzt. Die Instanz hat 24 GB, davon gehen + Caddy und der uebrige Kram ab; 8 GB sind fuer eine private Runde reichlich. +* `MC_OPS` — dein Java-Name, sonst hast du auf dem Server keine Rechte. +* `MC_MOTD` — steht auf `djnizz.at - Java & Bedrock`. +* `RCON_PASSWORD` — im Paket bereits neu erzeugt, nicht identisch mit lokal. + +## 6. Starten und pruefen + +```bash +cd ~/docker/minecraft-crossplay && docker compose up -d && docker compose logs -f +``` + +Fertig, sobald `Started Geyser on UDP port 19132` und `Done (…)! For help, type +"help"` erscheinen. Erster Start dauert einige Minuten (Paper, Plugins, Welt). + +Danach **von deinem Windows-Rechner aus** — das ist der ehrliche Test, weil er +den kompletten Weg inklusive Security List prueft: + +```bash +python "scripts/check-crossplay.py" minecraft.djnizz.at +``` + +Beide Abschnitte muessen `OK` melden. Kommt bei Java ein Timeout, fehlt die +TCP-Regel; kommt er nur bei Bedrock, fehlt die UDP-Regel. + +## 7. Verbinden + +* **Java Edition:** `minecraft.djnizz.at` (Port 25565 ist Standard, muss nicht + mitgegeben werden) +* **Bedrock Edition:** Adresse `minecraft.djnizz.at`, Port `19132` +* **Konsolen** (PS/Xbox/Switch) koennen keine freie Adresse eintragen — dort + fuehrt der Weg ueber BedrockConnect oder eine DNS-Umleitung im Heimnetz. + +### Zum SRV-Record + +Ein SRV-Record (`_minecraft._tcp.minecraft.djnizz.at`) lohnt nur, wenn Java auf +einem anderen Port als 25565 laufen soll — dann koennen Java-Spieler die +Portangabe weglassen. **Bedrock wertet keine SRV-Records aus**, dort muss der +Port immer 19132 sein oder manuell eingetippt werden. Bei der jetzigen +Konfiguration brauchst du also keinen. + +## 8. Betrieb + +**Wichtig — reservierte IP:** Ist die Public IP der Instanz *ephemeral*, aendert +sie sich beim Stoppen/Starten der VM und der A-Record bei helloly zeigt ins +Leere. In der OCI-Konsole unter *Instance → Attached VNICs → IPv4 Addresses* auf +**Reserved** umstellen, falls noch nicht geschehen. + +Autostart nach Reboot deckt `restart: unless-stopped` ab, solange der +Docker-Dienst selbst aktiviert ist: + +```bash +sudo systemctl is-enabled docker +``` + +Konsole und Backup laufen wie lokal (siehe [README.md](README.md)): + +```bash +docker compose exec minecraft rcon-cli +``` + +```bash +docker compose exec minecraft rcon-cli save-all && docker run --rm -v mc-crossplay_mc-data:/data -v "$PWD":/backup alpine tar czf /backup/mc-backup-$(date +%F).tar.gz -C /data . +``` + +Ein Cronjob dafuer ist auf einem oeffentlich erreichbaren Server keine schlechte +Idee. + +## 9. Oeffentlicher Server: Whitelist + +Sobald die Ports offen sind, findet dich jeder Scanner. Die Whitelist ist im +Stack bereits verkabelt und wird ueber die `.env` gesteuert: + +``` +MC_WHITELIST_ENABLED=true +MC_WHITELIST=Nizz_05 +``` + +`MC_WHITELIST` nimmt **nur Java-Profilnamen** - itzg loest sie beim Start ueber +PlayerDB/Mojang in UUIDs auf. Ein Xbox-Gamertag scheitert an diesem Lookup und +landet still nicht in der Liste. Trag hier also nie einen Bedrock-Namen ein. + +### Bedrock-Spieler auf die Whitelist + +Erster Versuch ueber den Gamertag - Floodgate strippt einen fuehrenden Punkt +selbst: + +```bash +docker compose exec minecraft rcon-cli "fwhitelist add Nizz05" +``` + +Das schlaegt oft fehl, weil Floodgate den Gamertag ueber die oeffentliche +GeyserMC-API in eine XUID aufloest und die nur Accounts kennt, die dort schon +mal abgefragt wurden. **Achtung:** ueber RCON kommt in beiden Faellen *keine* +Ausgabe zurueck - Floodgate schickt seine Antworten ueber ein eigenes +Message-System, das den RCON-Aufrufer nicht erreicht. Leerer Output heisst also +nicht „hat geklappt". Maszgeblich ist immer: + +```bash +docker compose exec minecraft rcon-cli "whitelist list" +``` + +Der zuverlaessige Weg fuehrt ueber die Floodgate-UUID. Der Spieler verbindet +sich einmal bei abgeschalteter Whitelist (`whitelist off`), danach steht er im +User-Cache: + +```bash +docker compose exec minecraft cat /data/usercache.json +``` + +Die UUID hat die Form `00000000-0000-0000-XXXX-XXXXXXXXXXXX`: die oberen 64 Bit +sind null (daran erkennt Floodgate seine eigenen IDs), die hinteren 16 +Hex-Stellen sind die Xbox-XUID. Damit: + +```bash +docker compose exec minecraft rcon-cli "fwhitelist add 00000000-0000-0000-XXXX-XXXXXXXXXXXX" +``` + +In `whitelist list` taucht der Eintrag danach als **`unknown`** auf, nicht unter +dem Gamertag - Floodgate traegt beim Hinzufuegen per UUID fest `"unknown"` als +Namen ein. Rein kosmetisch, geprueft wird gegen die UUID. + +`EXISTING_WHITELIST_FILE: MERGE` in der `docker-compose.yml` sorgt dafuer, dass +diese Eintraege einen Neustart ueberleben. Ohne das wuerde die `whitelist.json` +bei jedem Start auf den Inhalt von `MC_WHITELIST` zusammengestrichen - und die +Bedrock-Spieler waeren wieder draussen. + +**Reihenfolge beachten:** erst eintragen, dann scharf schalten. Operatoren +umgehen die Whitelist zwar, aber darauf sollte man sich nicht verlassen. + +## 10. Troubleshooting + +**Von aussen keine Verbindung, lokal auf dem Server aber schon** — dann liegt es +an OCI. Auf dem Server gegenpruefen: + +```bash +docker compose exec minecraft rcon-cli list +``` + +Antwortet das, laeuft der Server und es fehlt die Security-List-Regel oder die +Instanz-Firewall blockt. + +**Bedrock timeoutet, Java geht** — die UDP-Regel fehlt. Sicher der haeufigste +Fall. + +**IP hat sich geaendert** — A-Record bei helloly nachziehen und die Public IP +auf reserved umstellen. + +**Container startet in Schleife, Log sagt „requires Java 25 or above"** — das +Image-Tag wurde auf eine aeltere JVM zurueckgesetzt. Es muss +`stable-java25` oder neuer bleiben. diff --git a/README.md b/README.md new file mode 100644 index 0000000..c1210a3 --- /dev/null +++ b/README.md @@ -0,0 +1,202 @@ +# Minecraft Crossplay-Server (Java + Bedrock) + +Ein PaperMC-Server im Container, der per **GeyserMC** zusaetzlich Bedrock-Clients +(Konsole, Handy, Windows-10-Edition) annimmt. **Floodgate** authentifiziert diese +Spieler ueber Xbox Live, ein gekaufter Java-Account ist fuer sie nicht noetig. + +Es bleibt ein **Java-Server**: Redstone, Kampfsystem und Mob-Verhalten folgen den +Java-Mechaniken. Geyser sitzt als Uebersetzungsschicht dazwischen. + +``` +Java-Client ──TCP 25565──┐ + ├──► PaperMC (Java-Server) +Bedrock-Client ─UDP 19132─┴──► Geyser ──► Floodgate ──► Xbox-Live-Auth +``` + +## Dateien + +| Datei | Zweck | +|---|---| +| `docker-compose.yml` | Der Stack: Image, Ports, Plugins, server.properties | +| `.env` | Alle Stellschrauben (Version, RAM, Ports, MOTD, Ops, RCON-Passwort) | +| `config/plugins/Geyser-Spigot/config.yml` | Geyser-Vorgabe, u.a. `auth-type: floodgate` | + +Die Welt und alle Plugin-Daten liegen im Docker-Volume `mc-crossplay_mc-data`, +nicht im Projektordner (deutlich schnellere I/O unter Docker Desktop). + +## Schnellstart + +```bash +docker compose up -d +``` + +Der erste Start dauert ein paar Minuten: Paper-Jar, Geyser und Floodgate werden +geladen und die Welt wird generiert. + +Logs mitlesen: + +```bash +docker compose logs -f +``` + +Fertig ist der Server, sobald `Started Geyser on UDP port 19132` und danach +`Done (…)! For help, type "help"` in den Logs stehen. + +Getestet mit Paper 26.2, Geyser 2.11.1 und Floodgate 2.2.5: Java-Ping auf +25565/TCP und RakNet-Ping auf 19132/UDP antworten beide, MOTD und Spielerzahl +werden vom Java-Server an die Bedrock-Serverliste durchgereicht. + +## Verbinden + +* **Java Edition:** Adresse ``, Port `25565` +* **Bedrock Edition:** Server hinzufuegen, Adresse ``, Port `19132` +* **Vom selben Rechner:** `localhost` bzw. `127.0.0.1` + +Auf Konsolen (Switch, PS, Xbox) laesst sich oft keine freie Serveradresse +eintragen. Ueblicher Weg dort: DNS-Umleitung im Heimnetz oder ein Dienst wie +BedrockConnect. + +Bedrock-Spieler erscheinen mit einem Punkt vor dem Namen, z.B. `.MeinGamertag`. +Das ist der Floodgate-Praefix; er verhindert Namenskollisionen mit Java-Accounts. +Aendern laesst er sich in `plugins/floodgate/config.yml` (`username-prefix`). + +## Firewall (Windows) + +Docker Desktop oeffnet die Ports nur lokal. Fuer Zugriff aus dem LAN muessen +beide Ports durch die Windows-Firewall — in einer **Admin-PowerShell**: + +```powershell +New-NetFirewallRule -DisplayName "Minecraft Java 25565" -Direction Inbound -Protocol TCP -LocalPort 25565 -Action Allow +``` + +```powershell +New-NetFirewallRule -DisplayName "Minecraft Bedrock 19132" -Direction Inbound -Protocol UDP -LocalPort 19132 -Action Allow +``` + +Fuer Zugriff aus dem Internet zusaetzlich im Router portforwarden: +**25565/TCP** und **19132/UDP**. Bedrock laeuft ueber UDP — ein reines +TCP-Forwarding reicht nicht. + +## Erreichbarkeit pruefen + +Sobald der Router-Port offen ist, testet Geyser die Erreichbarkeit von aussen +selbst — das fragt einen oeffentlichen GeyserMC-Testdienst an, uebermittelt also +deine oeffentliche IP und den Port dorthin: + +```bash +docker compose exec minecraft rcon-cli "geyser connectiontest" +``` + +## Betrieb + +```bash +docker compose ps +``` + +Serverkonsole (Befehle wie `op`, `whitelist`, `save-all`): + +```bash +docker compose exec minecraft rcon-cli +``` + +Einzelner Befehl: + +```bash +docker compose exec minecraft rcon-cli op DeinName +``` + +Sauber stoppen (die Welt wird gespeichert, bis zu 2 Minuten Zeit): + +```bash +docker compose down +``` + +## Updates + +* **Geyser/Floodgate:** werden bei jedem Containerstart in der aktuellsten + Version geladen. Nach einem Bedrock-Update also einfach + `docker compose restart` — Geyser zieht dann den passenden Build nach. +* **Paper/Minecraft:** `MC_VERSION` in der `.env` steht auf `LATEST`. Fuer einen + planbaren Betrieb besser fest pinnen, z.B. `MC_VERSION=26.2`. +* **Image:** `docker compose pull && docker compose up -d` + +## Weitere Plugins + +URL in `docker-compose.yml` unter `PLUGINS` als weitere Zeile ergaenzen, dann +`docker compose up -d`. Aus der Liste entfernte Plugins werden beim naechsten +Start auch aus dem `plugins`-Ordner geloescht. + +Fuer Bedrock-Spieler gilt: Plugins moeglichst simpel halten. Komplexe +Chest-GUI-Menues (Auktionshaeuser, Shop-Menues) funktionieren ueber Geyser oft +nur fehlerhaft. Plugins mit Formular-Unterstuetzung fuer Bedrock sind die +bessere Wahl. + +## Konfiguration aendern + +* **server.properties:** ueber die `.env` bzw. die Environment-Variablen in + `docker-compose.yml`. Direkte Aenderungen an der `server.properties` im Volume + werden bei diesen Werten beim naechsten Start ueberschrieben. +* **Geyser:** `config/plugins/Geyser-Spigot/config.yml` bearbeiten, dann + `docker compose restart`. Die Datei aus dem Projektordner gewinnt, sobald sie + neuer ist als die im Volume. +* **Alles andere (Floodgate, weitere Plugins):** liegt im Volume. Anschauen mit + +```bash +docker compose exec minecraft cat /data/plugins/floodgate/config.yml +``` + + Dauerhaft vorgeben laesst es sich, indem man die Datei unter + `config/plugins//` im gleichen Pfadaufbau ablegt. + +## Backup + +Welt und Plugin-Daten aus dem Volume in eine Datei sichern: + +```bash +docker run --rm -v mc-crossplay_mc-data:/data -v "$PWD":/backup alpine tar czf /backup/mc-backup.tar.gz -C /data . +``` + +Vorher `docker compose exec minecraft rcon-cli save-all` ausfuehren oder den +Server stoppen, damit die Welt konsistent auf der Platte liegt. + +## Deployment in die Oracle Cloud + +Der Umzug auf die OCI-Instanz hinter `minecraft.djnizz.at` ist in +[DEPLOY-ORACLE.md](DEPLOY-ORACLE.md) beschrieben. + +## Bekannte Einschraenkungen + +* Bedrock unterstuetzt nicht alle Java-Features grafisch 1:1 (bestimmte + Bannermuster, manche Offhand-Interaktionen) — kleine optische Abweichungen + sind normal. +* Geyser erzeugt einen leichten CPU-Overhead pro Bedrock-Spieler. Auf moderner + Hardware faellt das nicht ins Gewicht. +* Bedrock-Spieler haben keine Java-Chatsignatur, deshalb ist + `enforce-secure-profile=false` gesetzt. Ohne das fliegen sie beim Chatten raus. + +## Troubleshooting + +**Bedrock-Client findet den Server nicht** — meist die Firewall oder ein +fehlendes UDP-Forwarding. Test vom Host aus: + +```bash +docker compose exec minecraft sh -c "netstat -uln | grep 19132" +``` + +**„Unable to connect to world"** — pruefen, ob Geyser sauber gestartet ist: + +```bash +docker compose logs | grep -i geyser +``` + +**Container startet in einer Schleife neu, Log sagt „requires Java 25 or +above"** — dann zeigt das Image-Tag auf eine zu alte JVM. Minecraft 26.x braucht +Java 25, das Tag in `docker-compose.yml` muss `stable-java25` (oder neuer) +bleiben. + +**Bedrock-Spieler wird nach Java-Account gefragt** — dann greift `auth-type` +nicht. Kontrolle: + +```bash +docker compose exec minecraft grep -A2 "^java:" /data/plugins/Geyser-Spigot/config.yml +``` diff --git a/config/plugins/Geyser-Spigot/config.yml b/config/plugins/Geyser-Spigot/config.yml new file mode 100644 index 0000000..d623629 --- /dev/null +++ b/config/plugins/Geyser-Spigot/config.yml @@ -0,0 +1,45 @@ +# Geyser-Konfiguration (Vorgabe aus dem Projektordner) +# ---------------------------------------------------- +# Diese Datei wird beim Containerstart nach +# /data/plugins/Geyser-Spigot/config.yml kopiert. Geyser ergaenzt beim ersten +# Start alle hier nicht gesetzten Optionen mit ihren Standardwerten (samt +# Kommentaren) in der Datei im Volume. +# +# Aenderungen hier + `docker compose restart` uebersteuern die Datei im Volume, +# weil diese Datei dann neuer ist. + +bedrock: + # 0.0.0.0 = im Container an allen Interfaces lauschen; die Absicherung + # macht das Port-Mapping in docker-compose.yml bzw. die Firewall. + address: 0.0.0.0 + # Container-interner Bedrock-Port. Der nach aussen sichtbare Port wird in + # der .env ueber BEDROCK_PORT gesetzt - diesen Wert hier nicht anfassen. + port: 19132 + clone-remote-port: false + +java: + # Der Kern des Ganzen: Bedrock-Spieler werden ueber Floodgate/Xbox Live + # authentifiziert und brauchen keinen gekauften Java-Account. + # Moegliche Werte: floodgate | online | offline + auth-type: floodgate + +motd: + # MOTD und Spielerzahl vom Java-Server uebernehmen, damit beide Editionen + # in der Serverliste dasselbe anzeigen. + passthrough-motd: true + passthrough-player-counts: true + # Zeile 1 wird bei passthrough-motd: true vom Java-Server ueberschrieben, + # Zeile 2 nicht - die kommt immer von hier. + primary-motd: "Crossplay Server" + secondary-motd: "Java & Bedrock" + +gameplay: + # Name, den Bedrock-Clients im Pause-/Einstellungsmenue sehen. + server-name: "Crossplay Server" + # Bedrock nutzt weiterhin 1.8-Kampfmechanik; blendet einen simulierten + # Cooldown-Indikator ein, damit das Java-Kampfsystem bedienbar bleibt. + show-cooldown: title + show-coordinates: true + +# Wird von Geyser beim Start ggf. hochgezaehlt/migriert - nicht manuell aendern. +config-version: 5 diff --git a/deploy/minecraft-crossplay.tar.gz b/deploy/minecraft-crossplay.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..d1b658a4be3f770b05ee3deee5beab88609787ea GIT binary patch literal 10966 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 E0LW9T(*OVf literal 0 HcmV?d00001 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..852d5db --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,97 @@ +# Minecraft Crossplay-Server: Java Edition + Bedrock Edition +# ---------------------------------------------------------- +# Basis : PaperMC (Java-Server, Plugin-faehig) +# Bruecke: GeyserMC uebersetzt Bedrock-Pakete -> Java-Protokoll +# Auth : Floodgate authentifiziert Bedrock-Spieler ueber Xbox Live, +# d.h. Konsolen-/Mobile-Spieler brauchen KEINEN Java-Account. +# +# Alle Stellschrauben liegen in .env + +name: mc-crossplay + +services: + minecraft: + # Minecraft 26.x setzt Java 25 voraus - Tag nicht auf java21 zuruecksetzen. + image: itzg/minecraft-server:stable-java25 + container_name: mc-crossplay + restart: unless-stopped + # noetig, damit die Server-Konsole via `docker attach` bedienbar bleibt + stdin_open: true + tty: true + + ports: + - "${JAVA_PORT:-25565}:25565/tcp" # Java Edition (TCP) + - "${BEDROCK_PORT:-19132}:19132/udp" # Bedrock Edition via Geyser (UDP!) + + environment: + # --- Mojang EULA ------------------------------------------------- + EULA: "TRUE" + + # --- Server-Software --------------------------------------------- + TYPE: "PAPER" + VERSION: "${MC_VERSION:-LATEST}" + + # --- Speicher / JVM ---------------------------------------------- + INIT_MEMORY: "${MC_MEMORY:-4G}" + MAX_MEMORY: "${MC_MEMORY:-4G}" + USE_AIKAR_FLAGS: "true" + + # --- Plugins ------------------------------------------------------ + # Immer der aktuellste Build. Wichtig, weil Bedrock-Clients (Konsole, + # Handy) sich selbst updaten und Geyser hinterherziehen muss. + # Eigene Plugins hier einfach als weitere Zeile (URL) ergaenzen. + PLUGINS: | + https://download.geysermc.org/v2/projects/geyser/versions/latest/builds/latest/downloads/spigot + https://download.geysermc.org/v2/projects/floodgate/versions/latest/builds/latest/downloads/spigot + + # --- Konfigurations-Seeding --------------------------------------- + # Inhalt von ./config wird nach /data kopiert, also z.B. + # ./config/plugins/Geyser-Spigot/config.yml -> /data/plugins/Geyser-Spigot/config.yml + COPY_CONFIG_DEST: "/data" + + # --- server.properties -------------------------------------------- + MOTD: "${MC_MOTD:-Crossplay Server - Java & Bedrock}" + DIFFICULTY: "${MC_DIFFICULTY:-normal}" + MAX_PLAYERS: "${MC_MAX_PLAYERS:-20}" + VIEW_DISTANCE: "${MC_VIEW_DISTANCE:-10}" + SIMULATION_DISTANCE: "${MC_SIMULATION_DISTANCE:-8}" + SPAWN_PROTECTION: "0" + OPS: "${MC_OPS:-}" + + # --- Whitelist ---------------------------------------------------- + # MC_WHITELIST nimmt ausschliesslich *Java*-Profilnamen auf - itzg loest + # sie beim Start via PlayerDB/Mojang in UUIDs auf. Xbox-Gamertags von + # Bedrock-Spielern lassen sich hier NICHT eintragen, die kommen ueber + # `rcon-cli "fwhitelist add "` direkt von Floodgate dazu. + ENABLE_WHITELIST: "${MC_WHITELIST_ENABLED:-false}" + ENFORCE_WHITELIST: "${MC_WHITELIST_ENABLED:-false}" + WHITELIST: "${MC_WHITELIST:-}" + # MERGE ist hier entscheidend: ohne das wuerde die whitelist.json bei + # jedem Start auf MC_WHITELIST reduziert - und alle per fwhitelist + # eingetragenen Bedrock-Spieler waeren wieder raus. + EXISTING_WHITELIST_FILE: "MERGE" + + # Muss TRUE bleiben: Floodgate haengt sich in die Online-Auth ein. + ONLINE_MODE: "TRUE" + # Muss false sein: Bedrock-Spieler haben keine Java-Chat-Signatur und + # wuerden sonst beim Chatten rausfliegen. + ENFORCE_SECURE_PROFILE: "false" + + # --- Fernsteuerung / Betrieb --------------------------------------- + ENABLE_RCON: "true" + RCON_PASSWORD: "${RCON_PASSWORD:?RCON_PASSWORD fehlt - bitte in .env setzen}" + TZ: "${TZ:-Europe/Berlin}" + # Zeit fuers saubere Speichern der Welt beim Stoppen + STOP_DURATION: "120" + + volumes: + # Welt + Plugin-Daten in einem Named Volume (schnelle I/O, auch unter + # Docker Desktop/WSL2). Zugriff via `docker compose cp` oder Backup s. README. + - mc-data:/data + # Vorgegebene Konfigurationsdateien, versionierbar im Projektordner + - ./config:/config:ro + + stop_grace_period: 2m + +volumes: + mc-data: diff --git a/scripts/check-crossplay.py b/scripts/check-crossplay.py new file mode 100644 index 0000000..154c28c --- /dev/null +++ b/scripts/check-crossplay.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 +"""Prueft, ob Java- und Bedrock-Endpunkt eines Crossplay-Servers antworten. + + python scripts/check-crossplay.py # localhost + python scripts/check-crossplay.py minecraft.djnizz.at # Live-Server + +Der Java-Test spricht das Server-List-Ping-Protokoll, der Bedrock-Test einen +RakNet Unconnected Ping - also genau das, was die echten Clients tun. +""" +import json +import os +import socket +import struct +import sys +import time + +HOST = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1" +JAVA_PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 25565 +BEDROCK_PORT = int(sys.argv[3]) if len(sys.argv) > 3 else 19132 +TIMEOUT = 10 + + +def _varint(n): + out = b"" + while True: + b = n & 0x7F + n >>= 7 + out += bytes([b | (0x80 if n else 0)]) + if not n: + return out + + +def _read_varint(sock): + n = 0 + for i in range(5): + b = sock.recv(1) + if not b: + raise EOFError("Verbindung vorzeitig geschlossen") + n |= (b[0] & 0x7F) << (7 * i) + if not b[0] & 0x80: + return n + raise ValueError("VarInt zu lang") + + +def java_ping(host, port): + s = socket.create_connection((host, port), timeout=TIMEOUT) + try: + host_b = host.encode() + # Handshake: Protokollversion ist beim Status-Ping beliebig + payload = (b"\x00" + _varint(772) + _varint(len(host_b)) + host_b + + struct.pack(">H", port) + _varint(1)) + s.sendall(_varint(len(payload)) + payload) + s.sendall(_varint(1) + b"\x00") # Status Request + _read_varint(s) # Paketlaenge + _read_varint(s) # Paket-ID + n = _read_varint(s) # JSON-Laenge + data = b"" + while len(data) < n: + chunk = s.recv(n - len(data)) + if not chunk: + break + data += chunk + return json.loads(data.decode("utf-8")) + finally: + s.close() + + +RAKNET_MAGIC = bytes([0x00, 0xFF, 0xFF, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFD, 0xFD, 0xFD, 0xFD, 0x12, 0x34, 0x56, 0x78]) + + +def bedrock_ping(host, port): + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.settimeout(TIMEOUT) + try: + pkt = (b"\x01" + struct.pack(">Q", int(time.time() * 1000)) + + RAKNET_MAGIC + os.urandom(8)) + s.sendto(pkt, (host, port)) + data, _ = s.recvfrom(4096) + if data[0] != 0x1C: + raise ValueError(f"unerwartete Antwort-ID 0x{data[0]:02x}") + strlen = struct.unpack(">H", data[33:35])[0] + return data[35:35 + strlen].decode("utf-8", "replace") + finally: + s.close() + + +def main(): + print(f"Ziel: {HOST} (Java {JAVA_PORT}/TCP, Bedrock {BEDROCK_PORT}/UDP)\n") + failed = False + + print("=== Java Edition (TCP) ===") + try: + j = java_ping(HOST, JAVA_PORT) + version = j.get("version", {}) + desc = j.get("description") + if isinstance(desc, dict): + desc = desc.get("text", "") or "".join( + e.get("text", "") for e in desc.get("extra", [])) + players = j.get("players", {}) + print(f" OK {version.get('name')} (Protokoll {version.get('protocol')})") + print(f" MOTD {desc!r}") + print(f" Spieler {players.get('online')}/{players.get('max')}") + except Exception as e: + failed = True + print(f" FEHLER {type(e).__name__}: {e}") + print(" -> Security List (TCP 25565), Instanz-Firewall, Container laeuft?") + + print("\n=== Bedrock Edition (UDP, RakNet) ===") + try: + fields = bedrock_ping(HOST, BEDROCK_PORT).split(";") + labels = ["Edition", "MOTD Zeile 1", "Protokoll", "Version", "Spieler", + "Max. Spieler", "Server-GUID", "MOTD Zeile 2", "Gamemode"] + print(" OK") + for label, value in zip(labels, fields): + print(f" {label:<13} {value}") + except Exception as e: + failed = True + print(f" FEHLER {type(e).__name__}: {e}") + print(" -> Security List (UDP 19132!), Geyser gestartet?") + + print() + if failed: + print("Mindestens ein Endpunkt antwortet nicht.") + sys.exit(1) + print("Beide Editionen erreichbar.") + + +if __name__ == "__main__": + main()