Gaming

Pelican Gameserver-Panel mit Docker einrichten

Eigenes Gameserver-Panel mit Pelican aufsetzen. Panel, Wings, MariaDB und Caddy via Docker Compose auf einem dataforest Seed.

AutorMarc Hülsbeck
Veröffentlicht am22. Mai 2026
Min. Lesezeit~22 min
Wörter3.800
Schwierigkeit Fortgeschritten
StackPelican · Pterodactyl · Gaming · Docker · Caddy · MariaDB · Minecraft

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.

Pelican-Stack-Architektur
Pelican-Stack-Architektur

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 --show prü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.com und wings.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:

bash
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:

bash
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 landen docker-compose.yml, .env und Caddyfile.
  • /etc/pelican: Wings-Konfiguration, kommt später als config.yml aus 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:

bash
nano /opt/pelican/.env

Mit folgendem Inhalt (Domains und E-Mail durch Ihre eigenen Werte ersetzen):

bash
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:

bash
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:

bash
nano /opt/pelican/docker-compose.yml

Mit folgendem Inhalt (kann unverändert übernommen werden):

yaml
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 (default und wings0), weil es als Reverse Proxy sowohl das Panel (im Standardnetz) als auch Wings (im wings0-Netz) erreichen muss.
  • PANEL_DOMAIN, WINGS_DOMAIN und ACME_EMAIL werden 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 mit unrecognized global option: reverse_proxy ab.
  • BEHIND_PROXY: "true" ist entscheidend. Das Pelican-Panel-Image bringt einen internen Caddy mit. Ohne dieses Flag aktiviert er bei einer https://-APP_URL automatisch HTTPS und versucht selbst, ein Let's-Encrypt-Zertifikat zu holen. Hinter einem zweiten Reverse Proxy funktioniert das nicht. Mit BEHIND_PROXY=true setzt der Entrypoint intern auto_https off und bindet den Server an Port 80 (plain HTTP). Externes Caddy übernimmt dann die TLS-Terminierung.
  • TRUSTED_PROXIES listet die privaten IP-Bereiche der Docker-Bridges, denen das Panel X-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 unter wings.example.com.
  • Wie spricht das Panel mit Wings? Pelican konfiguriert pro Node einen Connect-Port 443 und ruft die Daemon-API als https://wings.example.com auf. Der Request geht also vom Panel-Container raus auf die öffentliche Seed-IP, kommt bei Caddy wieder rein und wird über das wings0-Netz zu wings:8080 weitergeleitet. 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_data sorgt dafür, dass die Panel-Konfiguration (samt APP_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:

bash
nano /opt/pelican/Caddyfile

Mit folgendem Inhalt:

caddy
{
    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.

bash
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:

bash
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:

  1. Umgebungs-Check: Pelican prüft, ob alle Abhängigkeiten verfügbar sind.
  2. 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
  3. Datenbank: als Treiber MariaDB auswählen und eintragen:
    • Host: db
    • Port: 3306
    • Datenbank: panel
    • Benutzer: pelican
    • Passwort: der Wert von DB_PASSWORD aus Ihrer .env. Heraussuchen mit grep DB_PASSWORD /opt/pelican/.env.
  4. 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.
  5. Cache: Default (Filesystem) stehen lassen.
  6. Queue: Default (Database) stehen lassen.
  7. Session: Default (Filesystem) stehen lassen.

Nach dem letzten Schritt landen Sie im Login. Melden Sie sich mit den Admin-Daten an.

Pelican Installer: App-Konfiguration und Admin-Benutzer

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):

bash
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:

bash
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-Port 8080 (interner Port, auf den Wings bindet), Connect-Port 443 (den das Panel über Caddy nutzt), Scheme https und 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 Limit 6144 MiB · Überbelegung 0 %
  • Disk: Begrenzt · Speicherplatz Limit 51200 MiB (≈ 50 GB, an Ihren Seed anpassen) · Überbelegung 0 %
  • CPU: Begrenzt · CPU Limit 400 % (entspricht 4 Kernen à 100 %) · Überbelegung 0 %

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.

Pelican Panel: Node anlegen, Domain und SSL-Modus

Kopieren Sie diese YAML auf den Seed:

bash
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:

bash
docker compose up -d wings

Den Start verfolgen:

bash
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: 25565 für Minecraft, oder ein Port-Bereich wie 25565-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: latest
    • Server Jar File: server.jar
    • Build 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:

bash
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.

Pelican Panel: Server-Erstellung mit Node, Allocation und Egg

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:

bash
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):

text
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:

bash
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:

caddy
{$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/tcp und 443/tcp für Caddy (HTTP- und HTTPS-Traffic ans Panel, ACME-Challenge)
  • 2022/tcp für SFTP (Pelican Wings bietet SFTP-Zugriff auf die Gameserver-Dateien)
  • 25565/tcp fü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.com mit 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.

Bereit loszulegen?

Erstellen Sie Ihren ersten Seed und starten Sie in wenigen Minuten.