Warum ein eigenes Gameserver-Panel?
Einen einzelnen Minecraft- oder Valheim-Server bekommt man mit Docker Compose schnell zum Laufen. Sobald aber mehrere Spiele, mehrere Instanzen oder Mitspieler dazukommen, die jeweils eine eigene Konsole, eigene Backups und einen eigenen SFTP-Zugang brauchen, wird das Verwalten von Hand schnell unübersichtlich.
Ein Gameserver-Panel löst genau das. Es bietet eine Weboberfläche zum Erstellen und Starten von Gameservern. Jeder Server bekommt seine eigene Konsole und einen eigenen SFTP-Zugang, Backups und Versionsupgrades sind nur einen Klick entfernt.
Pelican ist ein modernes Open-Source-Panel, das aus der Pterodactyl-Community entstanden ist und 2024 als eigenständiges Projekt gestartet wurde. Es besteht aus zwei Komponenten: dem Panel (Weboberfläche und Datenbank) und Wings (dem Daemon, der die eigentlichen Gameserver in Docker-Containern ausführt). In dieser Anleitung laufen beide auf demselben dataforest Seed.
Pelican befindet sich aktuell (Mai 2026) noch in der Beta (Panel v1.0.0-beta34, Wings v1.0.0-beta25). Das Projekt wird aktiv gepflegt und produktiv eingesetzt, der Docker-Installationspfad ist laut offizieller Doku aber noch „work in progress". Die hier beschriebenen Schritte funktionieren mit den aktuellen Images, können sich mit kommenden Releases aber ändern.
Wenn ein einzelner Gameserver für eine kleine Gruppe genügt und kein Panel gewünscht ist, ist der Minecraft-Direkt-Setup-Guide die einfachere Wahl.
Konzepte in Kürze
Fünf Begriffe tauchen im Pelican-Umfeld immer wieder auf:
- Panel: die Weboberfläche, gebaut mit Laravel. Hier verwalten Sie Benutzer, Nodes und Server. Die Daten liegen in einer SQL-Datenbank.
- Wings: der Daemon, der die Gameserver tatsächlich ausführt. Wings läuft auf jedem Host, der Gameserver bereitstellt, spricht mit der Docker-Engine und startet, stoppt und überwacht die einzelnen Gameserver-Container. In diesem Tutorial läuft Wings auf demselben Seed wie das Panel.
- Node: aus Panel-Sicht eine Wings-Installation. In dieser Anleitung gibt es genau einen Node, nämlich Ihren lokalen Seed. Bei verteilten Setups mit mehreren Seeds sind es entsprechend mehrere Nodes.
- Allocation: eine reservierte IP-und-Port-Kombination, die einem Gameserver zugewiesen wird. Jeder Gameserver braucht mindestens eine.
- Egg: eine Vorlage, die definiert, welche Software wie installiert und gestartet wird (Minecraft, Rust, Valheim, ARK …). Pelican pflegt eine offizielle Egg-Sammlung, eigene lassen sich ebenfalls bauen.
Voraussetzungen
- Ein Seed in der dataforest Cloud. Empfohlen sind 4 CPU und 8 GB RAM, weil Panel, Wings, MariaDB und ein bis zwei Gameserver gemeinsam laufen. Java-Gameserver wie Minecraft mögen außerdem 2 bis 4 GB Swap, um nicht direkt OOM-Kills zu kassieren, wenn der JVM-Heap kurz spikt. Auf dem Seed mit
swapon --showprüfen, falls leer mit einer Swapfile nachrüsten. - SSH-Zugriff auf den Seed.
- Eine Domain mit zwei A-Records (IPv4) auf den Seed, zum Beispiel
panel.example.comundwings.example.com. Beide brauchen wir, weil Caddy pro Subdomain ein eigenes Let's-Encrypt-Zertifikat holt und Wings als eigenständiger Dienst auf einer separaten Domain läuft. Setzen Sie die DNS-Einträge, bevor Sie den Stack starten, sonst schlägt die Zertifikatsausstellung fehl. IPv6 (AAAA-Records) ist nicht Teil dieses Setups; die Allocations und der Caddy-Stack sind hier auf IPv4 angelegt.
Docker installieren
Verbinden Sie sich per SSH mit dem Seed und installieren Sie Docker mit dem offiziellen Skript. Es erkennt das Betriebssystem automatisch und richtet Docker inklusive Docker Compose ein:
curl -fsSL https://get.docker.com | sh
Falls die Meldung Could not get lock /var/lib/dpkg/lock-frontend erscheint, läuft im Hintergrund noch ein automatisches Systemupdate. Warten Sie eine Minute und versuchen Sie es erneut.
Projektverzeichnis und Wings-Verzeichnisse anlegen
Wings braucht ein paar Verzeichnisse direkt auf dem Host, um sie in die Gameserver-Container zu mounten. Die müssen vorher existieren. Legen Sie das Projektverzeichnis und die Wings-Pfade an:
mkdir -p /opt/pelican && cd /opt/pelican
mkdir -p /etc/pelican /var/lib/pelican /var/log/pelican /tmp/pelican
Was die einzelnen Pfade machen:
/opt/pelican: Projektverzeichnis, hier landendocker-compose.yml,.envundCaddyfile./etc/pelican: Wings-Konfiguration, kommt später alsconfig.ymlaus dem Panel./var/lib/pelican: Gameserver-Volumes und ihre Backups, eine eigene Subdirectory pro Server./var/log/pelican: Wings-Logs (separat von den Docker-Logs)./tmp/pelican: temporäre Dateien beim Installieren neuer Gameserver.
Alle weiteren Dateien dieses Tutorials liegen unter /opt/pelican.
Secrets in einer .env-Datei sammeln
Passwörter gehören nicht in die docker-compose.yml. Wir legen sie in einer separaten .env-Datei ab, in zwei Schritten: zuerst die Werte, die zu Ihrem Setup gehören (Domains, E-Mail), danach zwei generierte Zufalls-Passwörter für die Datenbank.
1. Domains und E-Mail eintragen. Datei anlegen und befüllen:
nano /opt/pelican/.env
Mit folgendem Inhalt (Domains und E-Mail durch Ihre eigenen Werte ersetzen):
PANEL_DOMAIN=panel.example.com
WINGS_DOMAIN=wings.example.com
ACME_EMAIL=admin@example.com
Let's Encrypt nutzt die Adresse für Ablauf-Benachrichtigungen, daher bitte eine echte verwenden.
2. Zufalls-Passwörter anhängen. Statt selbst Passwörter auszudenken, lassen wir openssl rand zwei 32-Byte-Zufallswerte erzeugen (256 Bit Entropie) und hängen sie an die .env an:
cat >> /opt/pelican/.env <<EOF
DB_ROOT_PASSWORD=$(openssl rand -base64 32)
DB_PASSWORD=$(openssl rand -base64 32)
EOF
chmod 600 /opt/pelican/.env
Der $(openssl rand -base64 32)-Aufruf wird vom Shell beim Schreiben ausgewertet, in der .env landen also zwei zufällige Base64-Strings (kein openssl mehr in der Datei). Diese Passwörter müssen Sie nirgendwo manuell eingeben: Docker Compose reicht sie automatisch durch. Pelican fragt später im Setup-Assistenten nach dem DB_PASSWORD, das holen Sie dann einfach aus der .env (grep DB_PASSWORD /opt/pelican/.env).
docker-compose.yml erstellen
Der gesamte Stack (Caddy, Panel, MariaDB und Wings) läuft in einer einzigen Compose-Datei. Erstellen Sie /opt/pelican/docker-compose.yml:
nano /opt/pelican/docker-compose.yml
Mit folgendem Inhalt (kann unverändert übernommen werden):
services:
caddy:
image: caddy:2-alpine
restart: always
ports:
- "80:80"
- "443:443"
environment:
PANEL_DOMAIN: "${PANEL_DOMAIN}"
WINGS_DOMAIN: "${WINGS_DOMAIN}"
ACME_EMAIL: "${ACME_EMAIL}"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
networks:
- default
- wings0
depends_on:
- panel
panel:
image: ghcr.io/pelican-dev/panel:latest
restart: always
environment:
XDG_DATA_HOME: /pelican-data
APP_URL: "https://${PANEL_DOMAIN}"
BEHIND_PROXY: "true"
TRUSTED_PROXIES: "172.16.0.0/12,192.168.0.0/16,10.0.0.0/8"
volumes:
- pelican_data:/pelican-data
- pelican_logs:/var/www/html/storage/logs
depends_on:
- db
db:
image: mariadb:11
restart: always
environment:
MARIADB_ROOT_PASSWORD: "${DB_ROOT_PASSWORD}"
MARIADB_DATABASE: panel
MARIADB_USER: pelican
MARIADB_PASSWORD: "${DB_PASSWORD}"
volumes:
- db_data:/var/lib/mysql
wings:
image: ghcr.io/pelican-dev/wings:latest
restart: always
tty: true
environment:
TZ: "UTC"
WINGS_UID: 988
WINGS_GID: 988
WINGS_USERNAME: pelican
ports:
- "2022:2022"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
- "/var/lib/docker/containers/:/var/lib/docker/containers/"
- "/etc/pelican/:/etc/pelican/"
- "/var/lib/pelican/:/var/lib/pelican/"
- "/var/log/pelican/:/var/log/pelican/"
- "/tmp/pelican/:/tmp/pelican/"
- "/etc/ssl/certs:/etc/ssl/certs:ro"
networks:
- wings0
volumes:
caddy_data:
caddy_config:
pelican_data:
pelican_logs:
db_data:
networks:
wings0:
name: wings0
driver: bridge
ipam:
config:
- subnet: "172.21.0.0/16"
driver_opts:
com.docker.network.bridge.name: wings0
Ein paar Punkte zur Konfiguration:
- Caddy hängt in zwei Netzen (
defaultundwings0), weil es als Reverse Proxy sowohl das Panel (im Standardnetz) als auch Wings (imwings0-Netz) erreichen muss. PANEL_DOMAIN,WINGS_DOMAINundACME_EMAILwerden ins Caddy-Container-Environment durchgereicht. Die.env-Datei nutzt Docker Compose nur für Variablen in der Compose-Datei selbst (${VAR}-Syntax). Der Caddyfile braucht die Werte zur Laufzeit im Container, sonst bleibt{$PANEL_DOMAIN}leer und Caddy bricht mitunrecognized global option: reverse_proxyab.BEHIND_PROXY: "true"ist entscheidend. Das Pelican-Panel-Image bringt einen internen Caddy mit. Ohne dieses Flag aktiviert er bei einerhttps://-APP_URLautomatisch HTTPS und versucht selbst, ein Let's-Encrypt-Zertifikat zu holen. Hinter einem zweiten Reverse Proxy funktioniert das nicht. MitBEHIND_PROXY=truesetzt der Entrypoint internauto_https offund bindet den Server an Port 80 (plain HTTP). Externes Caddy übernimmt dann die TLS-Terminierung.TRUSTED_PROXIESlistet die privaten IP-Bereiche der Docker-Bridges, denen das PanelX-Forwarded-Header glauben soll. Ohne diesen Wert schlagen Datei-Uploads im Panel mit 413-Fehlern fehl, weil Laravel die HTTPS-Verbindung von außen sonst nicht als solche erkennt. Das Pelican-Image formatiert den Wert intern als Caddy-trusted_proxies static-Direktive.- Vom Wings-Container ist nach außen nur der SFTP-Port 2022 erreichbar. Die Daemon-API auf Port 8080 bleibt intern in
wings0. Den HTTPS-Zugriff darauf erledigt Caddy unterwings.example.com. - Wie spricht das Panel mit Wings? Pelican konfiguriert pro Node einen Connect-Port
443und ruft die Daemon-API alshttps://wings.example.comauf. Der Request geht also vom Panel-Container raus auf die öffentliche Seed-IP, kommt bei Caddy wieder rein und wird über daswings0-Netz zuwings:8080weitergeleitet. Auf einem normalen Seed funktioniert dieser „Hairpin"-Pfad ohne Zusatzkonfiguration. Restriktive ausgehende Firewalls (z. B. mit erzwungenem Proxy für ausgehenden HTTPS-Verkehr) müssten diesen Pfad freigeben. pelican_datasorgt dafür, dass die Panel-Konfiguration (samtAPP_KEY) Container-Neustarts übersteht.- Gameserver-Container-Ports (etwa 25565 für Minecraft) tauchen später nicht in der Compose-Datei auf. Wings reicht die Ports beim Erstellen eines Gameservers dynamisch durch den gemounteten Docker-Socket weiter.
Caddyfile erstellen
Caddy bekommt pro Subdomain einen Block. Let's-Encrypt-Zertifikate holt es sich automatisch und verlängert sie auch ohne Zutun. Erstellen Sie /opt/pelican/Caddyfile:
nano /opt/pelican/Caddyfile
Mit folgendem Inhalt:
{
email {$ACME_EMAIL}
}
{$PANEL_DOMAIN} {
reverse_proxy panel:80
}
{$WINGS_DOMAIN} {
reverse_proxy wings:8080
}
Der globale Block setzt die E-Mail-Adresse für Let's-Encrypt-Registrierungen. Für jede Subdomain folgt ein einfacher reverse_proxy-Block. WebSockets für Live-Konsole und Datei-Manager funktionieren mit Caddy ohne zusätzliche Konfiguration.
Panel-Stack starten
Wir starten in dieser Reihenfolge: erst Caddy, Panel und Datenbank, später dann Wings. Wings braucht eine Konfigurationsdatei, die im nächsten Schritt im Panel generiert wird. Erst danach lohnt es sich, Wings zu starten.
docker compose up -d caddy panel db
Beim ersten Start zieht Docker die Images (etwa 600 MB für diese drei Services) und Caddy beantragt die TLS-Zertifikate. Verfolgen Sie den Fortschritt:
docker compose logs -f caddy panel
Sobald Caddy certificate obtained successfully für beide Domains meldet und das Panel betriebsbereit ist, können Sie die Log-Ansicht mit Ctrl+C verlassen.
Wenn Caddy keine Zertifikate bekommt, sind in den allermeisten Fällen die DNS-Records noch nicht propagiert oder zeigen auf die falsche IP. Prüfen Sie: dig +short panel.example.com.
Panel initialisieren
Öffnen Sie https://panel.example.com/installer im Browser. Wichtig: der Pfad /installer muss explizit dran sein, sonst landen Sie direkt auf der Login-Seite, weil das Panel auf der Wurzel keine automatische Weiterleitung zum Installer setzt. Der Installer führt Sie durch mehrere Schritte:
- Umgebungs-Check: Pelican prüft, ob alle Abhängigkeiten verfügbar sind.
- App-Konfiguration und Admin-Benutzer (auf derselben Seite):
- App Name:
Pelican(oder ein eigener Name) - App URL: Ihre Panel-Domain inklusive Protokoll, z. B.
https://panel.example.com - Admin User: E-Mail, Benutzername und Passwort des ersten Admins
- App Name:
- Datenbank: als Treiber
MariaDBauswählen und eintragen:- Host:
db - Port:
3306 - Datenbank:
panel - Benutzer:
pelican - Passwort: der Wert von
DB_PASSWORDaus Ihrer.env. Heraussuchen mitgrep DB_PASSWORD /opt/pelican/.env.
- Host:
- Eggs auswählen: an dieser Stelle bietet Pelican eine Liste mit verfügbaren Stock-Eggs zum Direkt-Import (Minecraft, Rust, Valheim, ARK …). Sie können hier beliebig viele auswählen. Für dieses Tutorial wechseln wir beispielhaft zur Kategorie Minecraft und wählen Paper aus, weil wir damit später einen Minecraft-Server anlegen. Weitere Eggs lassen sich auch nach dem Setup jederzeit nachladen.
- Cache: Default (
Filesystem) stehen lassen. - Queue: Default (
Database) stehen lassen. - Session: Default (
Filesystem) stehen lassen.
Nach dem letzten Schritt landen Sie im Login. Melden Sie sich mit den Admin-Daten an.

APP_KEY sichern
Bevor wir weitermachen, sichern Sie einmal den APP_KEY. Mit diesem Schlüssel verschlüsselt Laravel sensible Daten wie Sessions, gespeicherte Tokens und einige Datenbankfelder. Geht der Key verloren, sind diese Daten nach einem Restore nicht mehr lesbar, selbst wenn das DB-Backup vorhanden ist. Holen Sie den Wert deshalb jetzt heraus und legen Sie ihn an einem sicheren Ort ab (Passwortmanager, verschlüsselte Notiz):
docker compose exec panel grep APP_KEY /pelican-data/.env
Den Key brauchen Sie im Alltag nicht, aber spätestens bei einem Restore auf einem neuen Seed ist er entscheidend.
Panel neustarten
Starten Sie anschließend einmal den Panel-Container neu:
docker compose restart panel
Hintergrund: Laravel cacht Konfigurations- und Routen-Werte in komprimierten PHP-Dateien. Der Installer schreibt zwar .env und Datenbankwerte korrekt, der bereits laufende PHP-Prozess (inkl. Queue-Worker und Scheduler) liest sie aber nicht von selbst neu. Ohne Neustart kann es passieren, dass spätere Hintergrund-Jobs (Egg-Importe, Backup-Tasks) auf alte Defaults laufen und scheitern. Ein einmaliger restart nach Abschluss des Installers vermeidet das.
Wings-Node im Panel anlegen
Im Panel öffnen Sie Admin → Nodes → Auf das große + drücken und folgendes eintragen:
- Domain Name:
wings.example.com - Display Name:
local-seed(oder ein anderer Bezeichner) - Communicate over SSL:
HTTPS with (reverse) proxy(dritter Eintrag im Dropdown). Damit setzt Pelican automatisch: Listen-Port8080(interner Port, auf den Wings bindet), Connect-Port443(den das Panel über Caddy nutzt), Schemehttpsund das Behind-Proxy-Flag.
Im nächsten Schritt füllen wir die Ressourcen aus, die der Node insgesamt an Gameserver vergeben darf:
- Memory:
Begrenzt· RAM Limit6144MiB · Überbelegung0% - Disk:
Begrenzt· Speicherplatz Limit51200MiB (≈ 50 GB, an Ihren Seed anpassen) · Überbelegung0% - CPU:
Begrenzt· CPU Limit400% (entspricht 4 Kernen à 100 %) · Überbelegung0%
Die Werte sind für den empfohlenen 4-CPU/8-GB-Seed gedacht: 6 GB RAM für Gameserver lassen rund 2 GB für Panel, Wings, MariaDB und das Host-System frei. Bei Überbelegung 0 % verteilt Pelican exakt das, was physisch vorhanden ist. Höhere Werte ergeben nur für kommerzielle Hoster mit Überbuchung Sinn, im Privat-Setup ist 0 % richtig.
Speichern. Pelican legt den Node an. Direkt danach wechseln Sie in den Reiter Konfigurationsdatei des neuen Nodes. Dort liegt eine generierte YAML-Konfiguration für Wings. Alles, was wir hier nicht extra erwähnt haben, lassen wir auf dem Default-Wert.

Kopieren Sie diese YAML auf den Seed:
nano /etc/pelican/config.yml
Inhalt aus dem Panel einfügen und speichern. In der generierten Datei steht api.ssl.enabled: false schon richtig drin, weil Wings intern HTTP spricht und Caddy das TLS terminiert.
Wings starten
Jetzt, wo die Konfiguration liegt, kann Wings starten:
docker compose up -d wings
Den Start verfolgen:
docker compose logs -f wings
Wings meldet sich beim Panel an und schickt von da an regelmäßig Heartbeats. Unter Admin → Nodes sollte nach wenigen Sekunden ein grüner Punkt am Node erscheinen. Bleibt der Punkt rot, hilft die Fehlerbehebung weiter unten.
Allocation hinzufügen
Damit ein Gameserver einen Port bekommt, brauchen Sie mindestens eine Allocation. Wechseln Sie im Panel zum Node und öffnen Sie den Reiter Allocations:
- IP Address: die öffentliche IPv4 Ihres Seeds. Wings läuft im Container und kennt die Host-IPs nicht von sich aus, das Dropdown zeigt deshalb nur Container-interne Adressen wie
172.21.0.3. Klicken Sie rechts neben dem Dropdown auf das Tastatur-Symbol, tragen Sie dort die Seed-IP ein und bestätigen Sie. Docker auf dem Host kann an diese IP binden, weil sie tatsächlich auf einer Host-Schnittstelle liegt. - Ports:
25565für Minecraft, oder ein Port-Bereich wie25565-25570, wenn Sie mehrere Server planen
Klicken Sie auf Absenden. Die Allocation taucht in der Liste auf.
Minecraft-Paper-Server erstellen
Jetzt der eigentliche Teil: ein echter Gameserver. Wechseln Sie zu Admin → Servers → Create Server.
- Server Name:
Mein Minecraft Server - Server Owner: Ihr Admin-Account
- Node:
local-seed - Allocation: die gerade angelegte 25565-Allocation
- Egg:
Paper(in der Kategorie Minecraft Java) - Ressourcen-Limits:
- Memory: 2048 MiB
- Disk: 5000 MiB
- CPU Limit: 200 (entspricht 2 Kernen)
- Variablen (die Felder, die das Paper-Egg standardmäßig anbietet, alle drei können auf den Defaults bleiben):
Minecraft Version:latestServer Jar File:server.jarBuild Number:latest
Auf Create Server klicken. Wings holt jetzt das passende Docker-Image, lädt das Paper-JAR, generiert die Welt und startet den Server. Den Fortschritt sehen Sie in der Panel-Konsole oder per:
docker compose logs -f wings
Beim ersten Start stoppt Paper mit der Aufforderung, die Minecraft-EULA zu akzeptieren. Öffnen Sie deshalb gleich nach dem Erstellen rechts oben das Konsolen-Symbol des Servers und warten Sie, bis im Console-Dialog der EULA-Prompt erscheint. Bestätigen Sie ihn dort. Danach läuft der Server bis zum Status Running durch.
Öffnen Sie Minecraft Java Edition und verbinden Sie sich mit der Seed-IP auf Port 25565. Anders als der Admin-Browser läuft die Spieler-Verbindung nicht über Caddy, sondern direkt zum Gameserver-Container. Die Domain spielt dafür keine Rolle, nur die IP und der Port zählen.

Backups einrichten
Server-Backups im Panel
Pelican hat eine Backup-Funktion an Bord. Im Panel öffnen Sie den Server, wechseln zum Reiter Backups und klicken auf Create Backup. Das Backup landet als ZIP unter /var/lib/pelican/volumes/<server-id>/.backups/ auf dem Host. Über den Reiter Schedules lassen sich Backups auch zeitgesteuert anlegen.
Datenbank-Backup
Spielwelten und Server-Dateien liegen auf dem Dateisystem, nicht in der Datenbank. Die Datenbank hält dafür Benutzer, Nodes, Server-Konfigurationen und Audit-Logs. Ein täglicher Datenbank-Dump sichert diese Metadaten:
mkdir -p /opt/backups
docker compose exec -T db sh -c 'mariadb-dump -u root -p"$MARIADB_ROOT_PASSWORD" panel' > /opt/backups/panel-$(date +%Y%m%d).sql
Der Trick mit sh -c '...' führt den Dump-Befehl im DB-Container aus, wo MARIADB_ROOT_PASSWORD über die Compose-Datei bereits als Env-Variable gesetzt ist. So muss das Passwort weder in der Shell exportiert noch aus der .env herausgegrept werden.
Als Cronjob (crontab -e):
0 4 * * * cd /opt/pelican && docker compose exec -T db sh -c 'mariadb-dump -u root -p"$MARIADB_ROOT_PASSWORD" panel' > /opt/backups/panel-$(date +\%Y\%m\%d).sql
30 4 * * * find /opt/backups -name "panel-*.sql" -mtime +7 -delete
Das erste Kommando legt täglich um 04:00 Uhr ein Dump-Backup an, das zweite löscht Backups, die älter als sieben Tage sind.
Offsite-Backups über die dataforest Cloud
Die dataforest Cloud bietet automatische tägliche Offsite-Backups als zubuchbare Option. Damit lässt sich der komplette Seed inklusive Spielwelten und Datenbank täglich sichern. Backups sind nicht standardmäßig aktiv und müssen in der Cloud-Konsole aktiviert werden.
Updates
Bevor Sie Pelican updaten, legen Sie in der dataforest Cloud-Konsole einen Snapshot des Seeds an. Snapshots sind eine zubuchbare Option und konservieren den kompletten Zustand inklusive Datenbank, Spielwelten und APP_KEY. Bricht das Update etwas, sind Sie mit einem Klick wieder auf dem alten Stand. Gerade in der Beta-Phase ist das essenziell: Pelican ändert in dieser Zeit regelmäßig Datenbank-Schemata oder Konfigurationsfelder.
Wenn der Snapshot durchgelaufen ist, ziehen Sie die neuen Images und starten den Stack neu:
cd /opt/pelican
docker compose pull
docker compose up -d
Beim Neustart des Panel-Containers laufen die Datenbank-Migrationen automatisch. Vor einem Update lohnt sich ein Blick in die Pelican-Release-Notes, damit Sie wissen, was sich geändert hat.
Fehlerbehebung
Wings zeigt im Panel „Heartbeat failed":
Prüfen Sie im Node die Felder Domain Name (wings.example.com), Communicate over SSL (HTTPS with (reverse) proxy) und Connect Port (443). Schauen Sie danach in docker compose logs wings. Typische Fehler sind ein veraltetes Token in der config.yml (Konfiguration aus dem Panel neu kopieren) oder ein TLS-Mismatch (api.ssl.enabled in config.yml muss false sein, weil Caddy das TLS terminiert).
TLS-Fehler im Panel direkt nach dem Anlegen (z. B. cURL error 35: TLS connect error … tlsv1 alert internal error):
Race-Condition direkt nach dem ersten Hochfahren: Caddy holt sein Let's-Encrypt-Zertifikat für wings.example.com (kann ein bis zwei Minuten dauern), und der Wings-Container braucht selbst noch einen Moment bis zur ersten Antwort. Das Panel pollt aber sofort. Zwei bis drei Minuten warten und die Node-Seite neu laden, der Fehler verschwindet von selbst, sobald Cert und Wings beide stehen. Bleibt es länger als fünf Minuten: docker compose logs caddy (ACME-Fehler?) und docker compose logs wings (Daemon hochgefahren?) prüfen.
Caddy bekommt kein Zertifikat:
Mit docker compose logs caddy sehen Sie die ACME-Fehler im Klartext. Häufigste Ursache: einer der DNS-A-Records zeigt nicht auf den Seed oder ist noch nicht propagiert. Prüfen mit dig +short panel.example.com und dig +short wings.example.com. Caddy versucht standardmäßig sowohl die HTTP-01- (Port 80) als auch die TLS-ALPN-01-Challenge (Port 443); mindestens einer der beiden Ports muss aus dem Internet erreichbar sein, sonst gibt Let's Encrypt kein Zertifikat aus.
Konsole im Panel verbindet sich nicht (WebSocket-Fehler):
Das deutet auf ein Proxy- oder Trusted-Proxy-Problem hin. Prüfen Sie, dass TRUSTED_PROXIES im Panel-Service der Compose-Datei gesetzt ist (mit privaten Docker-CIDRs wie 172.16.0.0/12,192.168.0.0/16,10.0.0.0/8) und dass Caddy wings.example.com korrekt auf wings:8080 proxied.
Upload-Fehler im Panel („413 Payload Too Large"):
Meist ein Trusted-Proxy-Symptom. Falls der Wert schon richtig steht, lässt sich das Limit bei Caddy explizit hochsetzen (Caddy selbst hat per Default einen Limit von 10 MB; das Pelican-Panel-Image kann eigene PHP-Upload-Limits dazulegen). In /opt/pelican/Caddyfile im Panel-Block ergänzen:
{$PANEL_DOMAIN} {
request_body {
max_size 100MB
}
reverse_proxy panel:80
}
Danach docker compose restart caddy.
Gameserver startet nicht oder ist nicht erreichbar:
Die Allocation-IP muss die öffentliche IPv4 Ihres Seeds sein (über das Tastatur-Symbol im IP-Dropdown manuell eingeben). Eine Container-interne Bridge-IP wie 172.21.0.3 aus dem vorgewählten Dropdown funktioniert für externe Spieler nicht, weil sie nur innerhalb des wings0-Netzes erreichbar ist.
„Permission denied" auf dem Docker-Socket:
Der Wings-Container braucht Zugriff auf /var/run/docker.sock. Stellen Sie sicher, dass der Mount in der Compose-Datei korrekt ist und der Socket auf dem Host existiert (ls -l /var/run/docker.sock). Bei aktivem SELinux/AppArmor sind unter Umständen zusätzliche Labels nötig. Auf einem frischen dataforest Seed mit Debian 13 ist das nicht der Fall.
Port 80 oder 443 bereits belegt:
Andere Container, die 80 oder 443 belegen, müssen gestoppt werden, bevor Caddy starten kann. Mit ss -tlnp | grep -E ':80|:443' finden Sie den belegenden Prozess.
Firewall blockiert Ports:
Wenn auf dem Seed eine Firewall läuft (ufw, nftables, eine Cloud-Firewall vor dem Seed o. Ä.), müssen alle Ports freigegeben sein, die der Stack nach außen anbietet:
80/tcpund443/tcpfür Caddy (HTTP- und HTTPS-Traffic ans Panel, ACME-Challenge)2022/tcpfür SFTP (Pelican Wings bietet SFTP-Zugriff auf die Gameserver-Dateien)25565/tcpfür den Minecraft-Server (oder welcher Port auch immer in der Allocation steht)
Wichtig: jede zusätzliche Allocation, die Sie im Panel für weitere Gameserver anlegen, braucht ihren Port ebenfalls freigegeben. Wer einen Port-Bereich wie 25565-25570 allokiert hat, gibt den ganzen Bereich frei. Symptom bei fehlender Freigabe ist, dass der Panel-Login von außen Timeouts wirft oder Spieler den Gameserver nicht erreichen, obwohl er intern läuft. Auf einem frischen dataforest Seed mit Debian 13 ist ohne ufw enable keine Firewall aktiv, die müssten Sie also bewusst eingerichtet haben.
Zusammenfassung
Nach Abschluss dieser Anleitung läuft auf Ihrem Seed:
- Pelican Panel unter
https://panel.example.commit eigener MariaDB - Pelican Wings als Daemon, erreichbar über
https://wings.example.com - Caddy als TLS-Terminator für beide Subdomains
- Ein Minecraft-Paper-Gameserver, erreichbar über die Seed-IP auf Port 25565
Weitere Gameserver legen Sie jetzt direkt im Panel an. Für andere Spiele holen Sie das passende Egg über Admin → Eggs → Import Egg aus der GitHub-Organisation pelican-eggs nach. Dort liegt pro Kategorie ein eigenes Repository: minecraft (Paper, Vanilla, Spigot, Forge, Fabric, NeoForge …), games-steamcmd (CS2, Rust, ARK, Valheim …), games-standalone (Terraria, Factorio …), voice, database und einige mehr. Jeder Gameserver bekommt seine eigene Konsole, einen eigenen SFTP-Zugang und Backups per Klick.
Für einen einzelnen, schlanken Minecraft- oder Valheim-Server ohne Panel sind die direkten Setups in den Guides Minecraft mit Docker und Valheim mit Docker einfacher. Wings lässt sich auch auf mehrere Seeds verteilen, um die Last zu trennen oder Gameserver pro Spielkategorie zu isolieren. Unser Folge-Guide Pelican mit mehreren Wings-Nodes skalieren beschreibt das Setup mit WireGuard-Tunnel (Hub-and-Spoke) und zentralem Caddy. Eine Übersicht aller Möglichkeiten bietet unsere Gameserver-Lösung.






