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
Was wo läuft:
| Komponente | Wo | Rolle |
|---|---|---|
| Panel + MariaDB + Caddy | Panel-Seed | Web-UI, Datenbank, TLS-Terminator |
| Wings (optional lokal) | Panel-Seed | erster Wings aus der Single-Seed-Anleitung, kann auch entfernt sein |
| Wings (remote) | je ein Wings-Seed pro Spielkategorie/Kapazitätsbedarf | führt Gameserver-Container aus |
| WireGuard-Verbund | alle Seeds | privates 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.comzeigt auf die Panel-Seed-IP (für die Daemon-API über Caddy)sftp-<name>.example.comzeigt 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:
apt update && apt install -y wireguard
Schlüssel erzeugen
Auf jedem Seed separat:
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 eigenenwg0.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:
nano /etc/wireguard/wg0.conf
Mit folgendem Inhalt:
[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:
systemctl enable --now wg-quick@wg0
Wings-Seed konfigurieren
Auf dem Wings-Seed dieselbe Datei anlegen:
nano /etc/wireguard/wg0.conf
Mit folgendem Inhalt:
[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:
systemctl enable --now wg-quick@wg0
Tunnel verifizieren
Vom Wings-Seed aus den Panel-Seed über die WG-IP anpingen:
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
curl -fsSL https://get.docker.com | sh
Verzeichnisse anlegen
Genau wie auf dem Panel-Seed:
mkdir -p /opt/pelican && cd /opt/pelican
mkdir -p /etc/pelican /var/lib/pelican /var/log/pelican /tmp/pelican
docker-compose.yml anlegen
nano /opt/pelican/docker-compose.yml
Mit folgendem Inhalt:
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:8080bindet 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:2022bleibt 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
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):
nano /opt/pelican/docker-compose.yml
Im caddy-Block den environment-Abschnitt ergänzen:
caddy:
...
environment:
PANEL_DOMAIN: "${PANEL_DOMAIN}"
WINGS_DOMAIN: "${WINGS_DOMAIN}"
WINGS_MC_DOMAIN: "${WINGS_MC_DOMAIN}"
ACME_EMAIL: "${ACME_EMAIL}"
Caddyfile erweitern
nano /opt/pelican/Caddyfile
Den dritten reverse_proxy-Block am Ende ergänzen, die ersten beiden bleiben unverändert:
{
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
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-Port8080, Connect-Port443und das Behind-Proxy-Flag. - Im zweiten Wizard-Schritt „Advanced" das Feld SFTP Alias:
sftp-mc.example.com. Ohne diesen Eintrag fällt Pelican auf denFQDN/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
6144MiB · Überbelegung0% - Disk: Begrenzt · Speicherplatz Limit
51200MiB (≈ 50 GB, anpassen) · Überbelegung0% - CPU: Begrenzt · CPU Limit
400% (= 4 Kerne) · Überbelegung0%
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:
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:
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
- Minecraft-Node:
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):
cd /opt/pelican && docker compose pull panel && docker compose up -d panel
Auf jedem Wings-Seed:
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/udpeingehend vom Wings-Seed. Der Wings-Seed initiiert die WireGuard-Verbindung, weil bei ihm dasEndpoint-Feld gesetzt ist; auf dem Panel-Seed muss UDP 51820 aus dem Internet annehmbar sein.
Wings-Seed:
2022/tcpeingehend aus dem Internet für SFTP- die Allocation-Ports laut Spielkategorie, also z. B.
25565/tcpund25565/udpfür Minecraft oder27015/tcpund27015/udpfür Source-Engine - kein eingehender
51820/udpnö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:
| Was | 1. Node (Beispiel) | 2. Node (Beispiel) |
|---|---|---|
| WG-IP | 10.99.0.2 | 10.99.0.3 |
| Daemon-API-Domain | wings-mc.example.com | wings-source.example.com |
| SFTP-Domain | sftp-mc.example.com | sftp-source.example.com |
.env-Variable | WINGS_MC_DOMAIN | WINGS_SOURCE_DOMAIN |
| Allocation-Ports | 25565-25600 | 27015-27050 |
Auf dem Panel-Seed (bestehende Konfiguration erweitern, nicht ersetzen)
- In
/etc/wireguard/wg0.confeinen weiteren[Peer]-Block für den neuen Wings-Seed anhängen (Public Key des neuen Seeds +AllowedIPs = 10.99.0.3/32):bashnano /etc/wireguard/wg0.conf systemctl restart wg-quick@wg0 - Zwei neue A-Records anlegen (siehe Tabelle).
.envergänzen:bashecho "WINGS_SOURCE_DOMAIN=wings-source.example.com" >> /opt/pelican/.env tail -1 /opt/pelican/.env- Im
caddy-Block derdocker-compose.ymldas neue Env-Var anhängen (WINGS_SOURCE_DOMAIN: "${WINGS_SOURCE_DOMAIN}"). - Im
Caddyfileeinen weiterenreverse_proxy-Block ergänzen, diesmal auf10.99.0.3:8080. - 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.