Gaming

Pelican mit mehreren Wings-Nodes skalieren

Pelican-Setup um weitere Wings-Seeds erweitern. WireGuard-Tunnel zwischen Panel und Wings, Caddy bleibt zentral.

AutorMarc Hülsbeck
Veröffentlicht am23. Mai 2026
Min. Lesezeit~20 min
Wörter3.400
Schwierigkeit Experte
StackPelican · Pterodactyl · Gaming · Docker · WireGuard · Multi-Node

Diese Anleitung zeigt, wie Sie eine bestehende Pelican-Installation um zusätzliche Wings-Seeds erweitern. Sie ziehen einen zweiten Seed in der dataforest Cloud, verbinden ihn per WireGuard-Tunnel mit dem Panel-Seed und richten ihn als eigenständigen Wings-Node ein. Caddy auf dem Panel-Seed bleibt der zentrale TLS-Terminator und proxiet über das verschlüsselte VPN zu jedem Wings-Seed.

Topologisch bauen wir damit eine Sterntopologie (Hub-and-Spoke): Panel-Seed = Hub, jeder Wings-Seed = Spoke. Wings-Seeds reden nicht direkt miteinander, das ist auch nicht nötig. Alle Kommunikation läuft über das Panel. Spieler-Traffic geht weiterhin direkt über das öffentliche Internet zu den jeweiligen Wings-IPs, am Tunnel vorbei. Nur Steuer-Traffic (Daemon-API, Browser-Konsole) läuft durch das private Transport-Netz.

Planen Sie 30 bis 60 Minuten pro zusätzlichem Wings-Seed ein.

Wann lohnt sich ein zweiter Wings-Node?

Im Single-Seed-Setup laufen Panel und Wings noch zusammen auf einem Seed. Für eine Handvoll Gameserver reicht das gut aus. Es gibt aber zwei Situationen, in denen sich ein zweiter Wings-Seed eher lohnt, als den bestehenden Seed immer wieder hochzurüsten.

1. Mehr Kapazität. 4 CPU und 8 GB RAM tragen ein paar Gameserver gut. Sobald ein weiterer Server den Host an die Belastungsgrenze bringt oder die Nachbarn merklich ausbremst, bringt eine größere Maschine nur kurzfristig etwas. Ein zweiter Wings-Seed verteilt die Last stattdessen auf mehrere Maschinen. Das Panel bleibt unverändert, jeder Wings-Node läuft für sich.

2. Saubere Trennung nach Spielkategorie. Ein Seed nur für Minecraft, ein zweiter nur für Source-Engine-Spiele (CS2, Garry's Mod, TF2), ein dritter nur für Rust und so weiter. Der Hintergedanke: Port-Bereiche bleiben pro IP für eine einzige Spielkategorie reserviert. Minecraft-Allocations liegen rund um 25565, Source-Engine um 27015, Rust um 28015. Wenn jeder Wings-Seed nur eine Kategorie hostet, bleibt die Allocation-Übersicht aufgeräumt, Firewall-Regeln pro IP sind einfacher zu lesen, und spielspezifische Traffic-Profile lassen sich pro IP anwenden, falls das später relevant wird.

Für beide Wege setzen wir in dieser Anleitung auf eine WireGuard-Sterntopologie zwischen Panel-Seed und Wings-Seeds. Der Traffic zwischen Panel und Wings läuft damit verschlüsselt über ein privates Transport-Netz. Die Wings-Seeds brauchen keine eigene Domain, kein Let's-Encrypt-Zertifikat und kein eigenes Caddy. Caddy auf dem Panel-Seed bleibt zuständig fürs TLS und bekommt pro Wings-Node einen weiteren reverse_proxy-Block. Spieler verbinden sich weiterhin direkt zur jeweiligen Wings-Seed-IP.

Architektur-Überblick

Pelican Multi-Node-Architektur
Pelican Multi-Node-Architektur

Was wo läuft:

KomponenteWoRolle
Panel + MariaDB + CaddyPanel-SeedWeb-UI, Datenbank, TLS-Terminator
Wings (optional lokal)Panel-Seederster Wings aus der Single-Seed-Anleitung, kann auch entfernt sein
Wings (remote)je ein Wings-Seed pro Spielkategorie/Kapazitätsbedarfführt Gameserver-Container aus
WireGuard-Verbundalle Seedsprivates Transport-Netz Panel↔Wings (Sterntopologie)

Welcher Traffic geht welchen Weg:

  • Admin-Browser → Panel: direkt zum Panel-Seed via HTTPS, wie schon im Single-Seed-Setup.
  • Browser → Wings-Konsole (WebSocket): über Caddy auf dem Panel-Seed, von dort über WireGuard zum Remote-Wings. TLS außen, WG innen.
  • Panel → Wings-Daemon-API: denselben Weg, Caddy → WG → Wings.
  • Spieler → Gameserver-Port: direkt zur Wings-Seed-IP. Caddy ist nicht beteiligt, das wäre für Spiel-Traffic auch überdimensioniert.
  • Admin-SFTP → Wings: direkt zur Wings-Seed-IP auf Port 2022.

Die Aufteilung ist bewusst: Steuer-Traffic (Daemon-API, Browser-Konsole) geht klein, häufig und verschlüsselt über WG. Bandbreitenintensiver Spiel-Traffic geht direkt zum Endpunkt und belastet den Panel-Seed nicht.

Warum dieses Setup?

Drei Designentscheidungen sind beim ersten Lesen nicht offensichtlich, tragen aber das ganze Setup:

Warum WireGuard statt eigenes Caddy pro Wings-Seed? Theoretisch könnte jeder Wings-Seed sein eigenes Caddy mit eigenem Let's-Encrypt-Zertifikat fahren und die Wings-Daemon-API selbst über HTTPS exposen. Funktioniert, hat aber zwei Nachteile: jeder Wings-Seed bekommt eine eigene öffentliche TLS-Surface, und jeder Seed braucht eigenes Cert-Management. Mit dem WireGuard-Tunnel bleibt der Steuer-Traffic zwischen Panel und Wings komplett intern, kein Cert pro Wings-Seed nötig.

Warum zeigt wings-<name>.example.com auf den Panel-Seed? Pelican lässt die Browser-Live-Konsole direkt vom Browser zum Wings sprechen, nicht über das Panel als Proxy. Der Browser baut eine WebSocket-Verbindung zur Wings-Domain auf, also muss die einen TLS-Endpoint haben. Mit der Domain auf dem Panel-Seed terminiert Caddy das TLS und reicht die WebSocket-Verbindung über WireGuard zum Wings weiter. Würde die Domain stattdessen auf den Wings-Seed zeigen, wären wir wieder beim eigenen Cert pro Wings-Seed.

Was heißt das für DDoS? Die einzige öffentliche Web-Surface bleibt der Panel-Seed. Die wings-<name>.example.com-Subdomains sind zusätzliche SNIs auf demselben Panel-Seed, keine separaten öffentlichen Endpoints. Anti-DDoS-Schutz für den Panel-Seed deckt sie damit automatisch ab. Die Wings-Seed-IPs tragen ausschließlich Spiel-Traffic und SFTP. Genau das ist die Achse, an der spielspezifische Traffic-Profile pro IP greifen.

Voraussetzungen

  • Ein bestehendes Pelican-Setup laut Single-Seed-Anleitung. Panel, MariaDB und Caddy laufen auf dem Panel-Seed.
  • Ein zweiter Seed in der dataforest Cloud für den neuen Wings-Node. Die nötige Größe hängt stark vom Egg ab. Faustregel als Einstieg: 2 CPU und 4 GB RAM tragen zwei bis drei leichte Server (Vanilla Minecraft, kleine Source-Engine-Server). 4 CPU und 8 GB RAM bringen Reserve für eine halbe Hand voll Server. Speicherhungrige Spiele (modifizierte Minecraft-Server, ARK, Rust) wollen real eher 4 bis 8 GB RAM pro Server, in dem Fall lohnt sich ein direkt größerer Seed. Die Seed-Größe lässt sich später jederzeit hoch- oder runterskalieren. Fangen Sie eher klein an und wachsen Sie mit.
  • Zwei A-Records pro Wings-Seed:
    • wings-<name>.example.com zeigt auf die Panel-Seed-IP (für die Daemon-API über Caddy)
    • sftp-<name>.example.com zeigt auf die Wings-Seed-IP (für SFTP)
  • WireGuard-Grundkenntnisse. Den Einstieg zeigt unser VPN-Guide, hier kümmern wir uns nur um die Pelican-spezifischen Teile.

Im Folgenden nennen wir den neuen Wings-Seed beispielhaft wings-mc (für eine Minecraft-Kategorie). Die DNS-Einträge wären entsprechend wings-mc.example.com und sftp-mc.example.com. Wer einfach horizontal aufstockt, nimmt eher etwas wie wings2.example.com und sftp2.example.com.

WireGuard zwischen Panel- und Wings-Seed

Wir bauen eine Sterntopologie: der Panel-Seed ist der zentrale Hub, jeder Wings-Seed klinkt sich als Spoke ein. Subnetz 10.99.0.0/24:

  • Panel-Seed: 10.99.0.1
  • Erster Wings-Seed: 10.99.0.2
  • Zweiter Wings-Seed: 10.99.0.3
  • weitere fortlaufend

WireGuard installieren

Auf beiden Seeds:

bash
apt update && apt install -y wireguard

Schlüssel erzeugen

Auf jedem Seed separat:

bash
cd /etc/wireguard
umask 077
wg genkey | tee privatekey | wg pubkey > publickey
echo "private: $(cat privatekey)"
echo "public:  $(cat publickey)"

Die Pipe schreibt beide Schlüssel in die Dateien privatekey und publickey (in /etc/wireguard), die beiden echo-Zeilen geben sie zusätzlich im Terminal aus. Notieren Sie sich beide Werte pro Seed. Welcher Key wo hingehört:

  • Der private Schlüssel bleibt auf dem Seed, auf dem er erzeugt wurde, und kommt im nächsten Schritt in den [Interface]-Block der eigenen wg0.conf (Platzhalter <PRIVATEKEY-…>).
  • Der public Schlüssel wandert zum anderen Seed in den [Peer]-Block (Platzhalter <PUBLICKEY-…>).

Panel-Seed konfigurieren

Auf dem Panel-Seed /etc/wireguard/wg0.conf anlegen:

bash
nano /etc/wireguard/wg0.conf

Mit folgendem Inhalt:

ini
[Interface]
PrivateKey = <PRIVATEKEY-PANEL-SEED>
Address = 10.99.0.1/24
ListenPort = 51820

[Peer]
# Wings-Seed wings-mc
PublicKey = <PUBLICKEY-WINGS-SEED>
AllowedIPs = 10.99.0.2/32

Aktivieren und Autostart einrichten:

bash
systemctl enable --now wg-quick@wg0

Wings-Seed konfigurieren

Auf dem Wings-Seed dieselbe Datei anlegen:

bash
nano /etc/wireguard/wg0.conf

Mit folgendem Inhalt:

ini
[Interface]
PrivateKey = <PRIVATEKEY-WINGS-SEED>
Address = 10.99.0.2/24

[Peer]
# Panel-Seed
PublicKey = <PUBLICKEY-PANEL-SEED>
Endpoint = <PANEL-SEED-PUBLIC-IP>:51820
AllowedIPs = 10.99.0.0/24
PersistentKeepalive = 25

Wichtig: Endpoint ist die öffentliche IPv4 des Panel-Seeds (z. B. die IP, mit der Sie sich per SSH einloggen), nicht die WG-IP 10.99.0.1. Die WG-IP existiert erst, wenn der Tunnel steht. Setzt man sie als Endpoint, sendet WireGuard Pakete brav los, sie laufen aber ins Leere (Symptom: wg show zeigt nur sent, nie received).

PersistentKeepalive sorgt dafür, dass der Wings-Seed den Tunnel auch hinter NAT offen hält und der Panel-Seed jederzeit Pakete zustellen kann.

Aktivieren:

bash
systemctl enable --now wg-quick@wg0

Tunnel verifizieren

Vom Wings-Seed aus den Panel-Seed über die WG-IP anpingen:

bash
ping -c 3 10.99.0.1

Drei Antworten heißt: der Tunnel steht. Falls nicht, prüfen Sie, ob UDP-Port 51820 auf dem Panel-Seed erreichbar ist und ob beide Seiten dieselben Keys verwenden. wg show zeigt auf beiden Seiten den aktuellen Status.

Wings-only Setup auf dem neuen Seed

Auf dem Wings-Seed läuft nur Wings. Kein Panel, keine Datenbank, kein Caddy. Das hält den Seed schlank und macht die Update-Wege unabhängig vom Panel.

Docker installieren

bash
curl -fsSL https://get.docker.com | sh

Verzeichnisse anlegen

Genau wie auf dem Panel-Seed:

bash
mkdir -p /opt/pelican && cd /opt/pelican
mkdir -p /etc/pelican /var/lib/pelican /var/log/pelican /tmp/pelican

docker-compose.yml anlegen

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

Mit folgendem Inhalt:

yaml
services:
  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:
      - "10.99.0.2:8080:8080"
      - "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

networks:
  wings0:
    name: wings0
    driver: bridge
    ipam:
      config:
        - subnet: "172.21.0.0/16"
    driver_opts:
      com.docker.network.bridge.name: wings0

Zur Port-Konfiguration zwei Sachen, die wichtig sind:

  • 10.99.0.2:8080:8080 bindet die Daemon-API ausschließlich an die WireGuard-IP. Aus dem öffentlichen Internet ist Port 8080 damit unerreichbar, nur Peers im WG-Verbund kommen rein.
  • 2022:2022 bleibt auf allen Interfaces offen, damit Admins per SFTP direkt verbinden können.

Wichtig: Das WireGuard-Interface wg0 muss laufen, bevor der Wings-Container startet. Sonst meldet Docker bind: cannot assign requested address, weil die Adresse 10.99.0.2 zu dem Zeitpunkt schlicht noch nicht existiert. Mit systemctl enable wg-quick@wg0 auf dem Host und restart: always im Compose-File läuft das nach einem Reboot von selbst wieder hoch.

Caddy auf dem Panel-Seed erweitern

Zurück auf dem Panel-Seed. Wir ergänzen den bestehenden Stack um Variablen, Caddy-Service und Caddyfile für den neuen Wings-Node.

.env ergänzen

bash
echo "WINGS_MC_DOMAIN=wings-mc.example.com" >> /opt/pelican/.env
tail -1 /opt/pelican/.env

tail -1 zeigt die eben angehängte Zeile zur Kontrolle.

docker-compose.yml für Caddy anpassen

Datei öffnen und den Caddy-Service um die neue Variable erweitern (existierende Werte beibehalten):

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

Im caddy-Block den environment-Abschnitt ergänzen:

yaml
caddy:
  ...
  environment:
    PANEL_DOMAIN: "${PANEL_DOMAIN}"
    WINGS_DOMAIN: "${WINGS_DOMAIN}"
    WINGS_MC_DOMAIN: "${WINGS_MC_DOMAIN}"
    ACME_EMAIL: "${ACME_EMAIL}"

Caddyfile erweitern

bash
nano /opt/pelican/Caddyfile

Den dritten reverse_proxy-Block am Ende ergänzen, die ersten beiden bleiben unverändert:

caddy
{
    email {$ACME_EMAIL}
}

{$PANEL_DOMAIN} {
    reverse_proxy panel:80
}

{$WINGS_DOMAIN} {
    reverse_proxy wings:8080
}

{$WINGS_MC_DOMAIN} {
    reverse_proxy 10.99.0.2:8080
}

Der entscheidende Block ist {$WINGS_MC_DOMAIN}. Caddy nimmt eingehende Requests an https://wings-mc.example.com an und schickt sie über den WG-Tunnel an 10.99.0.2:8080. Dass der Caddy-Container überhaupt eine Host-WG-IP erreicht, übernimmt Docker im Hintergrund: alles, was nicht in einem seiner angeschlossenen Netzwerke liegt, geht über den Default-Gateway zum Host, und der Host kennt die Strecke zu 10.99.0.2 über wg0. Voraussetzung dafür ist net.ipv4.ip_forward=1 auf dem Host. Docker setzt das beim Start automatisch, ein explizites sysctl net.ipv4.ip_forward zur Bestätigung schadet nicht.

Caddy neu starten

bash
cd /opt/pelican
docker compose up -d caddy

Caddy holt automatisch ein Let's-Encrypt-Zertifikat für wings-mc.example.com. Mit docker compose logs -f caddy lässt sich das mitverfolgen.

Wings-Node im Panel anlegen

Im Pelican-Panel Admin → Nodes → + drücken eintragen:

  • Domain Name: wings-mc.example.com
  • Display Name: wings-mc
  • Communicate over SSL: HTTPS with (reverse) proxy. Pelican setzt damit automatisch Listen-Port 8080, Connect-Port 443 und das Behind-Proxy-Flag.
  • Im zweiten Wizard-Schritt „Advanced" das Feld SFTP Alias: sftp-mc.example.com. Ohne diesen Eintrag fällt Pelican auf den FQDN/Domain Name als SFTP-Hostnamen zurück, und der zeigt bei uns auf den Panel-Seed (wo kein Wings auf 2022 lauscht). Mit dem expliziten Alias landen SFTP-Clients direkt auf dem Wings-Seed. Der Helper-Text im Panel sagt das so: „Display alias for the SFTP address. Leave empty to use the Node FQDN."

Ressourcen-Limits passend zur tatsächlichen Seed-Größe wählen. Als Beispiel für einen 4-CPU/8-GB-Seed:

  • Memory: Begrenzt · RAM Limit 6144 MiB · Überbelegung 0 %
  • Disk: Begrenzt · Speicherplatz Limit 51200 MiB (≈ 50 GB, anpassen) · Überbelegung 0 %
  • CPU: Begrenzt · CPU Limit 400 % (= 4 Kerne) · Überbelegung 0 %

Für einen kleineren 2-CPU/4-GB-Einstieg entsprechend halbieren (RAM Limit 3072, CPU Limit 200). Bei größeren Seeds nach oben skalieren. Die 0%-Überbelegung sorgt dafür, dass Pelican nur das verteilt, was physisch da ist.

Speichern. Pelican legt den Node an und generiert die Wings-Konfiguration.

Konfiguration auf den Wings-Seed übertragen

Im Panel den neuen Node öffnen und in den Reiter Konfigurationsdatei wechseln. Inhalt kopieren. Auf dem Wings-Seed:

bash
nano /etc/pelican/config.yml

Inhalt einfügen, speichern. Anpassungen an der generierten Datei sind nicht nötig: api.host: 0.0.0.0 und api.ssl.enabled: false sind genau das, was wir hier wollen. Wings hört container-intern auf allen Interfaces (0.0.0.0), die Beschränkung auf die WG-IP erledigt das Docker-Port-Binding "10.99.0.2:8080:8080" aus der Compose-Datei: Host-seitig wird Port 8080 nur an die WG-IP gehängt, im Container selbst gibt es diese Adresse gar nicht. Würde Wings versuchen, sich direkt an 10.99.0.2 zu binden, käme bind: cannot assign requested address, weil die WG-Adresse nur auf dem Host existiert.

api.ssl.enabled: false stimmt ebenfalls: für TLS sorgt Caddy auf dem Panel-Seed, Wings selbst spricht innerhalb des WG-Tunnels nur plain HTTP.

Wings starten und Heartbeat verifizieren

Auf dem Wings-Seed:

bash
cd /opt/pelican
docker compose up -d wings
docker compose logs -f wings

Wings meldet sich beim Panel an und schickt Heartbeats. Im Panel unter Admin → Nodes sollte am neuen Node nach wenigen Sekunden ein grüner Punkt erscheinen.

Bleibt der Punkt rot, lohnt sich erst ein Blick auf den WG-Tunnel (ping 10.99.0.1 vom Wings-Seed) und dann auf die Wings-Logs.

Allocation hinzufügen

Im Panel zum neuen Node wechseln, Reiter Allocations:

  • IP Address: die öffentliche IPv4 des Wings-Seeds, nicht die des Panel-Seeds. Spieler-Traffic geht direkt dorthin, der WG-Tunnel ist nur für Steuer-Traffic da. Über das Tastatur-Symbol im IP-Dropdown manuell setzen, weil Wings im Container nur Container-interne IPs vorschlägt.
  • Ports: Port-Range passend zur Spielkategorie. Vorschläge:
    • Minecraft-Node: 25565-25600
    • Source-Engine-Node: 27015-27050
    • Rust-Node: 28015-28030

Auf Absenden klicken. Die Allocations tauchen in der Liste auf und stehen dem neuen Node zur Verfügung. Bei der nächsten Server-Erstellung im Panel steht der neue Node zur Auswahl.

Operationelle Hinweise

Backups pro Wings-Seed

Jeder Wings-Seed hat sein eigenes /var/lib/pelican mit den Gameserver-Volumes. Das Backup-Setup aus der Single-Seed-Anleitung müssen Sie pro Seed einmal einrichten:

  • Snapshots in der dataforest Cloud-Konsole pro Wings-Seed einzeln aktivieren. Vor jedem Pelican-Update einen Snapshot anlegen.
  • Server-Backups im Panel funktionieren node-übergreifend. Das ZIP landet jeweils unter /var/lib/pelican/volumes/<server-id>/.backups/ auf dem Wings-Seed, auf dem der Server läuft.

Update-Reihenfolge

Beim Update zuerst das Panel ziehen, danach die Wings-Nodes. Der Grund: das Panel zieht beim Container-Start die nötigen Datenbank-Migrationen, und Pelican verträgt typischerweise „Panel neuer als Wings" besser als umgekehrt. Ein älteres Panel kann mit neueren Wings-API-Calls eher kollidieren als ein neueres Panel mit etwas hinterherhinkenden Wings.

Auf dem Panel-Seed (docker compose up -d triggert auch die DB-Migrationen beim Neustart des Panel-Containers):

bash
cd /opt/pelican && docker compose pull panel && docker compose up -d panel

Auf jedem Wings-Seed:

bash
cd /opt/pelican && docker compose pull wings && docker compose up -d wings

Vor jedem Update einen Cloud-Snapshot pro betroffenem Seed anlegen. In der Beta-Phase ändern sich Konfigurationsfelder regelmäßig, ein Rollback ist mit Snapshots eine Klick-Aktion.

Firewall: Panel-Seed und Wings-Seed

Eingehender Traffic muss in den meisten Standard-Setups (ufw, nftables, Cloud-Firewall) auf beiden Seiten passen:

Panel-Seed (zusätzlich zu den Regeln aus Artikel 1):

  • 51820/udp eingehend vom Wings-Seed. Der Wings-Seed initiiert die WireGuard-Verbindung, weil bei ihm das Endpoint-Feld gesetzt ist; auf dem Panel-Seed muss UDP 51820 aus dem Internet annehmbar sein.

Wings-Seed:

  • 2022/tcp eingehend aus dem Internet für SFTP
  • die Allocation-Ports laut Spielkategorie, also z. B. 25565/tcp und 25565/udp für Minecraft oder 27015/tcp und 27015/udp für Source-Engine
  • kein eingehender 51820/udp nötig, weil die WG-Verbindung hier ausgeht (stateful Firewalls lassen die Antworten automatisch durch).

Port 8080 (Wings-Daemon-API) ist von außen nicht erreichbar. Das Compose-Binding 10.99.0.2:8080:8080 legt ihn ausschließlich auf die WG-IP, eine separate Firewall-Regel dafür ist nicht nötig.

Fehlerbehebung

Heartbeat failed nur für den neuen Node, lokaler Wings ist grün: WG-Tunnel prüfen: vom Wings-Seed ping 10.99.0.1, vom Panel-Seed ping 10.99.0.2. Wenn der Ping nicht durchgeht, wg show auf beiden Seiten anschauen und prüfen, ob UDP 51820 zum Panel-Seed offen ist.

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 (kann ein bis zwei Minuten dauern), und der Wings-Container braucht ebenfalls einen Moment, bis er antwortet. 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 auf dem Wings-Seed docker compose logs wings (Daemon hochgefahren?) prüfen.

wg show zeigt 0 B received auf dem Wings-Seed: Klassischer Fall: im [Peer]-Block der Wings-Seed-wg0.conf steht als Endpoint die WG-IP 10.99.0.1 statt der öffentlichen IPv4 des Panel-Seeds. WireGuard sendet Pakete in den eigenen Tunnel, der noch gar nicht steht, also kommt nichts zurück. Endpoint auf die echte Panel-Seed-Public-IP setzen und systemctl restart wg-quick@wg0.

Konsole im Panel öffnet nicht (WebSocket-Fehler) nur für Remote-Server: Caddy-Block für wings-mc.example.com prüfen. In docker compose logs caddy taucht das Problem meist auf. Häufig fehlt der Eintrag in .env, oder Caddy wurde nach der Caddyfile-Änderung nicht neu geladen.

Wings-Logs: listen tcp 10.99.0.2:8080: bind: cannot assign requested address: Zwei mögliche Ursachen. Erstens: das WG-Interface ist nicht aktiv und der Docker-Port-Bind hängt am Host fest. systemctl status wg-quick@wg0 prüfen, gegebenenfalls neu starten, danach den Wings-Container ebenfalls neu starten. Zweitens: jemand hat in der config.yml api.host auf die WG-IP umgestellt. Das gehört nicht dahin, Wings versucht dann innerhalb des Containers an die WG-IP zu binden, die es dort gar nicht gibt. api.host: 0.0.0.0 zurücksetzen.

SFTP-Verbindung schlägt fehl: SFTP Alias im Pelican-Node prüfen (Advanced-Tab). Wenn das Feld leer ist, leitet Pelican den SFTP-Hostnamen vom FQDN ab. Der zeigt bei uns auf den Panel-Seed, wo kein Wings auf Port 2022 läuft. SFTP Alias auf sftp-mc.example.com setzen, mit A-Record auf den Wings-Seed, dann landet SFTP am richtigen Endpunkt.

Spieler kommen nicht durch: Die Allocation-IP muss die öffentliche IP des Wings-Seeds sein, auf dem der Gameserver läuft. Der Custom-IP-Trick aus der Single-Seed-Anleitung (Tastatur-Symbol im IP-Dropdown) gilt hier genauso, nur mit der Wings-Seed-IP statt der Panel-Seed-IP.

Weiteren Wings-Node hinzufügen

Die meisten Schritte oben wiederholen sich pro zusätzlichem Wings-Seed, mit einer Handvoll Werten, die jedes Mal hochgezählt oder umbenannt werden. Beispiel: parallel zum bestehenden wings-mc kommt ein zweiter Wings-Seed wings-source für Source-Engine-Games dazu.

Werte, die pro neuem Node anders sind:

Was1. Node (Beispiel)2. Node (Beispiel)
WG-IP10.99.0.210.99.0.3
Daemon-API-Domainwings-mc.example.comwings-source.example.com
SFTP-Domainsftp-mc.example.comsftp-source.example.com
.env-VariableWINGS_MC_DOMAINWINGS_SOURCE_DOMAIN
Allocation-Ports25565-2560027015-27050

Auf dem Panel-Seed (bestehende Konfiguration erweitern, nicht ersetzen)

  1. In /etc/wireguard/wg0.conf einen weiteren [Peer]-Block für den neuen Wings-Seed anhängen (Public Key des neuen Seeds + AllowedIPs = 10.99.0.3/32):
    bash
    nano /etc/wireguard/wg0.conf
    systemctl restart wg-quick@wg0
    
  2. Zwei neue A-Records anlegen (siehe Tabelle).
  3. .env ergänzen:
    bash
    echo "WINGS_SOURCE_DOMAIN=wings-source.example.com" >> /opt/pelican/.env
    tail -1 /opt/pelican/.env
    
  4. Im caddy-Block der docker-compose.yml das neue Env-Var anhängen (WINGS_SOURCE_DOMAIN: "${WINGS_SOURCE_DOMAIN}").
  5. Im Caddyfile einen weiteren reverse_proxy-Block ergänzen, diesmal auf 10.99.0.3:8080.
  6. Caddy neu laden: docker compose up -d caddy.

Auf dem neuen Wings-Seed (kompletter Wings-only-Pfad)

Die Abschnitte oben einmal durchgehen, mit den Werten aus der Tabelle: „WireGuard installieren" → „Schlüssel erzeugen" → „Wings-Seed konfigurieren" (Adresse 10.99.0.3/24, Endpoint auf öffentliche IPv4 des Panel-Seeds) → „Wings-only Setup auf dem neuen Seed". Im Port-Binding der Compose-Datei 10.99.0.3:8080:8080 statt .2 setzen.

Im Pelican-Panel

Den Abschnitt „Wings-Node im Panel anlegen" wiederholen, mit:

  • Domain Name wings-source.example.com
  • SFTP Alias sftp-source.example.com (Advanced-Tab)
  • Ressourcen-Limits passend zur tatsächlichen Seed-Größe

Dann wie zuvor: Konfiguration kopieren, Wings starten, Allocations für die neue Port-Range mit der öffentlichen IPv4 des neuen Wings-Seeds anlegen.

Was sich pro Node nicht wiederholt

  • WireGuard auf dem Panel-Seed installieren (einmalig)
  • WG-Schlüssel auf dem Panel-Seed erzeugen (einmalig)
  • .env-Basis-Werte (PANEL_DOMAIN, WINGS_DOMAIN, ACME_EMAIL, DB_*)
  • Caddyfile-Basis (globaler Block, Panel-Block, ggf. lokaler Wings-Block)
  • Panel-Initialisierung und Datenbank-Setup

Zusammenfassung

Nach diesem Setup läuft auf der dataforest Cloud:

  • Panel-Seed: Pelican Panel, MariaDB und Caddy. Caddy bekommt pro Wings-Node einen reverse_proxy-Block.
  • Wings-Seeds: pro Spielkategorie oder Kapazitätsbedarf ein eigener Seed mit nur Wings und Docker. Wings hört nur auf der WG-IP, SFTP und Spiel-Ports bleiben öffentlich.
  • WireGuard-Verbund (Sterntopologie): verbindet Panel und alle Wings-Seeds privat. Steuer-Traffic geht verschlüsselt durch.
  • Spieler-Traffic: direkt zur jeweiligen Wings-Seed-IP, kein Umweg über den Panel-Seed.

Skalierung in Schritten, nicht in Sprüngen: pro neuem Wings-Node die Checkliste oben abarbeiten.

Wer von hier aus tiefer ins Pelican-Ökosystem will, findet in der GitHub-Organisation pelican-eggs Egg-Vorlagen für deutlich mehr Spiele, sortiert nach Repository pro Kategorie. Eine Übersicht der dataforest-Lösungen rund um Gameserver-Hosting liegt unter Gameserver-Lösung.

Bereit loszulegen?

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