Pterodactyl Panel installeren voor gameservers
Panel en Wings zijn twee losse programma's met twee losse taken. Wie dat begrijpt, installeert Pterodactyl in een half uur; wie het niet begrijpt, zoekt dagenlang naar de fout.
Pterodactyl is het meest gebruikte gratis beheerpaneel voor gameservers. Dat het als ingewikkeld te boek staat, komt bijna nooit door de installatie zelf, maar door één misverstand: Pterodactyl is niet één programma, maar twee. Deze handleiding scheidt beide netjes, laat de verschillen tussen Debian en Ubuntu zien en loopt daarna de foutmeldingen langs die u letterlijk in een zoekmachine intypt.
Panel en Wings: twee programma's, twee rollen
Het Panel is een PHP-toepassing op basis van Laravel. Het levert de webinterface, beheert gebruikers, rechten, databases en planningen en slaat alles op in een eigen MySQL- of MariaDB-database. Het Panel start nooit zelf een gameserver. Het kent Docker niet eens.
Wings is één enkel programma, geschreven in Go. Het draait op elke machine waarop daadwerkelijk gameservers moeten draaien, praat met de Docker-daemon, start containers, streamt de console en stelt de SFTP-toegang beschikbaar. Wings heeft geen webinterface en geen database. Het luistert op een HTTP-poort en wacht op instructies van het Panel.
Beide communiceren uitsluitend via HTTP met elkaar, in beide richtingen, met ondertekende tokens. Daaruit volgen drie dingen die u vanaf het begin moet accepteren:
- Het Panel moet de node via een domeinnaam bereiken, niet via een IP-adres. Het certificaat hangt aan de naam.
- Panel en Wings moeten hetzelfde protocol spreken. Een Panel op HTTPS met Wings op HTTP werkt niet, de browser blokkeert de consoleverbinding.
- Beide klokken moeten kloppen. De tokens zijn maar een paar minuten geldig.
Wie deze drie zinnen in het achterhoofd houdt, heeft de helft van de gebruikelijke Pterodactyl-problemen al voorkomen.
Vereisten en de keuze van het systeem
Pterodactyl 1.11 en nieuwer vereist PHP 8.2 of 8.3. Precies op dat punt worden de meeste handleidingen onnauwkeurig, want de distributies leveren zeer uiteenlopende versies mee. Stand juli 2026 ziet het er in de standaardbronnen zo uit:
| Systeem | PHP | Database | nginx |
| Debian 12 | 8.2 (past) | MariaDB 10.11 | 1.22 |
| Debian 13 | 8.4 (te nieuw) | MariaDB 11.8 | 1.26 |
| Ubuntu 24.04 | 8.3 (past) | MySQL 8.0 of MariaDB 10.11 | 1.24 |
| Ubuntu 22.04 | 8.1 (te oud) | MySQL 8.0 of MariaDB 10.6 | 1.18 |
| Debian 11 | 7.4 (te oud) | MariaDB 10.5 | 1.18 |
Deze handleiding gaat puur over Debian en Ubuntu. Op AlmaLinux, Rocky Linux en Oracle Linux bestaat apt niet, daar werkt geen van de volgende pakketcommando's.
Praktisch gevolg: Debian 12 en Ubuntu 24.04 zijn de twee systemen waarop het Panel zonder externe pakketbronnen draait. Op Ubuntu 22.04 hebt u het PPA van Ondřej Surý nodig, op Debian 13 de Debian-tegenhanger daarvan, want het metapakket levert daar PHP 8.4 en de composer.json van het Panel eist uitdrukkelijk ^8.2 || ^8.3. In de praktijk loopt Composer onder PHP 8.4 weliswaar gewoon door, maar dat is onbevestigd terrein en geen situatie waarin u een productieserver wilt draaien. Wie de extra pakketbron wil vermijden, kiest Debian 12 of Ubuntu 24.04.
De twee te oude systemen stranden overigens niet op het pakketcommando, maar pas twee stappen later, en juist dat maakt ze zo verraderlijk. apt install php loopt op Ubuntu 22.04 (PHP 8.1.2) en Debian 11 (PHP 7.4.33) netjes door met exitcode 0, pas Composer breekt daarna af, op Ubuntu 22.04 met brick/math requires php (^8.2) failed, op Debian 11 met aws/aws-sdk-php requires php (>=8.1) failed. Moet u op een van deze systemen blijven, installeer dan uit de externe pakketbron uitdrukkelijk de pakketten met versienummer (php8.3, php8.3-cli, php8.3-fpm enzovoort) in plaats van het metapakket php, anders wint de distributieversie het opnieuw.
Tweede verschil dat regelmatig verrast: Debian levert helemaal geen pakket mysql-server. Daar is MariaDB de standaard, en dat is volkomen in orde, want Pterodactyl vraagt MariaDB 10.2 of nieuwer. Wie onder Debian apt install mysql-server intypt, krijgt E: Unable to locate package mysql-server te zien en gaat vervolgens op de verkeerde plek zoeken.
Voor de node met Wings gelden deze PHP-regels overigens helemaal niet. Wings is een statisch gelinkt Go-programma en heeft alleen Docker en een redelijk actuele kernelversie nodig. De node mag zonder problemen Debian 13 zijn terwijl het Panel op Debian 12 draait.
Het Panel installeren
Alle volgende commando's als root. Eerst de basispakketten. Let erop dat u de PHP-extensies volledig meeneemt, een ontbrekend php-bcmath valt pas tijdens de Composer-run op.
apt update
apt -y install curl ca-certificates gnupg lsb-release tar unzip git
apt -y install mariadb-server nginx redis-server
apt -y install php php-cli php-common php-gd php-mysql php-mbstring php-bcmath php-xml php-fpm php-curl php-zip
Controleer meteen of de versie klopt voordat u verdergaat:
php -v
php -m | grep -E "bcmath|mbstring|curl|zip|gd|xml"
Daarna Composer en de Panel-bestanden:
curl -sS https://getcomposer.org/installer -o /tmp/composer-setup.php
php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer
mkdir -p /var/www/pterodactyl
curl -Lo /var/www/pterodactyl/panel.tar.gz https://github.com/pterodactyl/panel/releases/latest/download/panel.tar.gz
tar -xzf /var/www/pterodactyl/panel.tar.gz -C /var/www/pterodactyl
Nu de database. Maak de gebruiker aan op 127.0.0.1 en niet op localhost, anders loopt de verbinding via de socket en krijgt Laravel later een toegangsweigering terwijl het wachtwoord gewoon klopt. Hoe u die twee gevallen uit elkaar houdt, leest u in ons artikel over Access denied for user.
mariadb -u root -e "CREATE DATABASE panel;"
mariadb -u root -e "CREATE USER 'pterodactyl'@'127.0.0.1' IDENTIFIED BY 'HierEenLangWachtwoord';"
mariadb -u root -e "GRANT ALL PRIVILEGES ON panel.* TO 'pterodactyl'@'127.0.0.1' WITH GRANT OPTION;"
mariadb -u root -e "FLUSH PRIVILEGES;"
Beveilig de database daarna, daarover hebben wij een apart artikel: MariaDB en MySQL beveiligen.
Nu de eigenlijke inrichting. De p:environment-commando's zijn interactief en vragen om de Panel-URL, de tijdzone, de cache-driver en de databasetoegang:
cd /var/www/pterodactyl
cp .env.example .env
COMPOSER_ALLOW_SUPERUSER=1 composer install --no-dev --optimize-autoloader
php artisan key:generate --force
php artisan p:environment:setup
php artisan p:environment:database
php artisan migrate --seed --force
php artisan p:user:make
chown -R www-data:www-data /var/www/pterodactyl/*
Kies bij p:environment:setup Redis als session- en cache-driver, dan werkt de verderop beschreven wachtrij zoals bedoeld. En voer de Panel-URL met https:// in. Een http:// op deze plek levert later gemengde inhoud op en een console die eindeloos op verbinding blijft wachten.
nginx en de versievalstrik
De basis van de webserverinrichting staat in ons artikel over nginx installeren. Voor Pterodactyl zijn twee details belangrijk waarop kant-en-klare sjablonen van internet regelmatig stuklopen.
Ten eerste de PHP-FPM-socket. De bestandsnaam bevat de PHP-versie en verschilt per systeem. Kijk het na in plaats van te gokken:
systemctl status php8.2-fpm
ls /run/php/
Op Debian 12 heet de socket php8.2-fpm.sock, op Ubuntu 24.04 php8.3-fpm.sock. Een verkeerd pad levert hier precies de 502-Bad-Gateway-pagina op waar zoveel mensen naar zoeken. De statusopvraag staat er bewust vóór: het socketbestand ontstaat pas als de FPM-service draait. Is die niet gestart, dan is /run/php/ leeg en houdt u het pad ten onrechte voor verkeerd. Draait de service nog niet, dan helpt systemctl enable --now php8.2-fpm met het versienummer dat bij uw installatie past.
Ten tweede de HTTP/2-schrijfwijze. De nieuwe directive http2 on; bestaat pas vanaf nginx 1.25.1. Op Debian 12 (1.22), Ubuntu 22.04 (1.18) en ook op Ubuntu 24.04 (1.24) moet u de oude vorm listen 443 ssl http2; gebruiken, anders breekt de start af met nginx: [emerg] unknown directive "http2". Alleen Debian 13 met nginx 1.26 begrijpt beide vormen.
server {
listen 443 ssl http2;
server_name panel.example.com;
root /var/www/pterodactyl/public;
index index.php;
client_max_body_size 100m;
ssl_certificate /etc/letsencrypt/live/panel.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/panel.example.com/privkey.pem;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTP_PROXY "";
}
}
Wachtrij en planning
Zonder deze twee bouwstenen ziet het Panel er werkend uit, maar verstuurt het geen e-mail en voert het geen geplande taken uit. De opbouw van het unit-bestand leggen wij uitgebreid uit in ons artikel over een systemd-service maken, hier de kant-en-klare versie:
[Unit]
Description=Pterodactyl Queue Worker
After=redis-server.service
[Service]
User=www-data
Group=www-data
Restart=always
RestartSec=5s
ExecStart=/usr/bin/php /var/www/pterodactyl/artisan queue:work --queue=high,standard,low --sleep=3 --tries=3
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now redis-server
systemctl enable --now pteroq.service
Daarnaast een regel in de crontab van root, details over de syntaxis vindt u in het artikel Cronjob instellen onder Linux:
* * * * * php /var/www/pterodactyl/artisan schedule:run >> /dev/null 2>&1
Wings op de node installeren
Vanaf hier werkt u op de machine die de gameservers moet draaien. Dat mag dezelfde server zijn, maar het hoeft niet. Voorwaarde is Docker, waarvan wij de installatie beschrijven in het artikel Docker installeren op Debian en Ubuntu.
mkdir -p /etc/pterodactyl
curl -L -o /usr/local/bin/wings https://github.com/pterodactyl/wings/releases/latest/download/wings_linux_amd64
chmod u+x /usr/local/bin/wings
wings version
Op ARM-servers heet het bestand wings_linux_arm64. Haalt u het verkeerde bestand binnen, dan meldt de shell simpelweg cannot execute binary file: Exec format error. Verbaas u niet over de uitvoer van de laatste regel: wings version antwoordt met een dubbele v, dus bijvoorbeeld wings vv1.13.1. Dat komt zo van de maker en is geen teken van een kapotte installatie.
Het bestand /etc/pterodactyl/config.yml schrijft u niet zelf. Dat ontstaat zo meteen automatisch. Maak eerst alleen de service aan:
[Unit]
Description=Pterodactyl Wings Daemon
After=docker.service
Requires=docker.service
PartOf=docker.service
[Service]
User=root
WorkingDirectory=/etc/pterodactyl
LimitNOFILE=4096
PIDFile=/var/run/wings/daemon.pid
ExecStart=/usr/local/bin/wings
Restart=on-failure
StartLimitInterval=180
StartLimitBurst=30
RestartSec=5s
[Install]
WantedBy=multi-user.target
Nog niet starten. Zonder configuratie breekt Wings meteen af, met een melding die er in de kern op neerkomt dat het configuratiebestand onder /etc/pterodactyl/config.yml ontbreekt. Dat is op dit punt volkomen normaal en geen fout.
Nog een woord over swap: veel oudere handleidingen eisen swapaccount=1 in /etc/default/grub. Dat geldt uitsluitend voor systemen met cgroup v1. Debian 12 en 13 en ook Ubuntu 22.04 en 24.04 gebruiken standaard cgroup v2, daar is die regel overbodig. Controleren kan met docker info. Verschijnt daar WARNING: No swap limit support, dan werkt de geheugenbegrenzing voor swap niet. Hoe u swapruimte in het algemeen verstandig dimensioneert, staat in het artikel Swap inrichten.
Certificaat voor de node, niet alleen voor het Panel
De meest gemaakte denkfout: men regelt een certificaat voor panel.example.com en verbaast zich erover dat de node niet werkt. Wings heeft een eigen certificaat voor zijn eigen domeinnaam nodig, bijvoorbeeld node1.example.com. Beide namen mogen naar hetzelfde IP-adres wijzen, maar het zijn twee namen.
Op een kale node draait geen webserver, daarom is de standalone-modus van Certbot de eenvoudigste weg. Poort 80 moet daarvoor kortstondig van buitenaf bereikbaar zijn:
apt -y install certbot
certbot certonly --standalone -d node1.example.com
Wie veel nodes beheert, is beter af met een wildcardcertificaat, dat beschrijven wij in het artikel Wildcard-certificaat met Let's Encrypt.
Twee valkuilen die veel tijd kosten:
- Wings leest de certificaatbestanden bij de start. Na een verlenging moet de service opnieuw worden geladen. Zet in
/etc/letsencrypt/renewal-hooks/deploy/een klein script neer metsystemctl restart wings. Zonder dat draait de node 90 dagen vlekkeloos en valt daarna ogenschijnlijk zonder reden uit. - Zet de Cloudflare-proxy voor de nodenaam uit. De oranje wolk breekt de TLS-verbinding open en vervangt het certificaat. Het Panel krijgt dan een certificaat dat niet bij de verwachte uitgever past en de consoleverbinding via WebSocket gedraagt zich onvoorspelbaar. Het A-record voor de node hoort op grijs te staan.
Node aanmaken en verbinden
Maak in het Panel onder Admin, Locations eerst een locatie aan en daarna onder Nodes de node. De velden die werkelijk tellen:
- FQDN:
node1.example.com, exact de naam uit het certificaat. - Communicate over SSL: aan, als het Panel via HTTPS draait. Anders begint u er beter niet aan.
- Behind Proxy: alleen inschakelen als er werkelijk een reverse proxy vóór Wings staat die het TLS afhandelt.
- Daemon Port: 8080. Daemon SFTP Port: 2022.
- Memory en Disk: de grenzen waar het Panel bij het verdelen van servers rekening mee houdt.
Open na het opslaan het tabblad Configuration van de node. Daar genereert het Panel een commando met een eenmalig token. Voer dat uit op de node:
cd /etc/pterodactyl
wings configure --panel-url https://panel.example.com --token TOKEN --node 1
Wings haalt daarmee zijn volledige configuratie op en schrijft /etc/pterodactyl/config.yml. Controleer de inhoud: staat er bij het Panel-adres http:// in plaats van https://, dan hebt u het commando gekopieerd uit een omgeving waarin de Panel-URL verkeerd is opgeslagen. Herstel dat bij de bron met php artisan p:environment:setup, niet met de hand in het YAML-bestand.
Voer daarna in het tabblad Allocations het IP-adres van de node en de gewenste poortbereiken in, bijvoorbeeld 25565 tot 25600 voor Minecraft. Zonder minstens één vrije allocatie kunt u geen server aanmaken.
Nu pas starten:
systemctl enable --now wings
systemctl status wings
De poorten moeten in de firewall openstaan. Met ufw, waarvan wij de basis behandelen in het artikel ufw-firewall instellen:
ufw allow 8080/tcp
ufw allow 2022/tcp
ufw allow 25565:25600/tcp
ufw allow 25565:25600/udp
Als Wings geen verbinding maakt
Het Panel toont bij de node een rood pictogram of geeft een fout bij het aanmaken van een server. Werk de meldingen op volgorde af, ze zijn verrassend duidelijk.
cURL error 7: Failed to connect ... Connection refused
De Panel-server bereikt de poort niet. Of Wings draait niet, of de firewall blokkeert, of de service luistert op het verkeerde adres. Controleer in deze volgorde:
systemctl status wings
ss -tlnp | grep 8080
journalctl -u wings -n 50 --no-pager
En vanaf de Panel-server, dat is de doorslaggevende test:
curl -v https://node1.example.com:8080
Een HTTP-antwoord, ook een 404 met JSON-inhoud, is op dit punt een succes. Het bewijst dat DNS, firewall, poort en TLS samenwerken.
cURL error 60: SSL certificate problem
Het certificaat van de node wordt niet geaccepteerd. Bij self signed certificate gebruikt u een zelfondertekend certificaat, daar kan het Panel niet mee overweg omdat de onderliggende bibliotheek geen uitzondering kent. Bij unable to get local issuer certificate ontbreekt meestal de tussenketen, dan verwijst uw Wings-configuratie naar cert.pem in plaats van naar fullchain.pem. Bij certificate has expired is de verlenging wel doorgelopen, maar heeft Wings nog het oude bestand in het geheugen, zie het punt over de herstart hierboven.
cURL error 28: Operation timed out
Geen antwoord, geen reset. Dat wijst op een firewall die pakketten laat vallen in plaats van ze te weigeren, of op een node achter NAT. Een bijzonder geval: Panel en Wings op dezelfde server, waarbij het Panel het eigen publieke IP-adres aanspreekt. Sommige netwerken sturen die lus niet terug. Een regel in /etc/hosts op de Panel-server die de nodenaam naar het interne adres laat wijzen, lost dat op.
Cannot connect to the Docker daemon at unix:///var/run/docker.sock
Wings draait, Docker niet. systemctl status docker maakt dat in één regel duidelijk. De node verschijnt in het Panel dan vaak toch als bereikbaar, want het opvragen van de status werkt, maar elke serverstart mislukt.
De node antwoordt, maar elke actie wordt geweigerd
Er klopt een token niet. Dat gebeurt na een nieuwe wings configure met een oud token, of nadat de node in het Panel is verwijderd en opnieuw aangemaakt. Oplossing: genereer in het Panel op het tabblad Configuration een vers token, voer het commando opnieuw uit en herstart Wings. Ga niet gokken in het YAML-bestand.
Blijft de melding onduidelijk, stop dan de service en start Wings op de voorgrond. De uitvoer is een stuk spraakzamer dan het journal:
systemctl stop wings
wings --debug
Ook nuttig is de ingebouwde rapportagemodus, die de configuratie, de Docker-status en systeemgegevens verzamelt:
wings diagnostics
Tijdverschil tussen Panel en node
Deze fout is verraderlijk, want hij ziet eruit als een netwerkprobleem. De symptomen: de node wordt in het Panel als bereikbaar weergegeven, servers laten zich aanmaken, maar de console blijft hangen bij het opbouwen van de verbinding en de SFTP-toegang weigert correcte inloggegevens.
De oorzaak zit in de opzet. Het Panel ondertekent kortlevende tokens die maar enkele minuten geldig zijn. Wings toetst het tijdstip van uitgifte en het verlooptijdstip aan de eigen klok. Lopen de twee systemen meer dan een paar minuten uiteen, dan verwerpt Wings elk token als verlopen of als nog niet geldig, hoewel het zojuist is aangemaakt.
Belangrijk om te begrijpen: het gaat niet om de tijdzone. Panel en node mogen verschillende tijdzones ingesteld hebben, dat maakt niets uit. Het gaat om het absolute tijdstip. Controleer op beide machines:
date -u
timedatectl status
In de uitvoer van timedatectl moet System clock synchronized: yes en NTP service: active staan. Zo niet:
timedatectl set-ntp true
Op systemen zonder systemd-timesyncd, bijvoorbeeld na een minimale installatie, installeert u chrony en controleert u de synchronisatie:
apt -y install chrony
chronyc tracking
De waarde bij System time hoort in de orde van milliseconden te liggen. Virtuele machines die uit een image zijn gekloond of uit een snapshot zijn teruggezet, zijn de meest voorkomende bron van grotere afwijkingen.
Waaraan u ziet dat het werkelijk draait
Een groen pictogram in het Panel is slechts het eerste van vijf bewijzen. Loop de lijst door, dan weet u het zeker:
systemctl is-active wingsgeeftactive, enjournalctl -u wings -n 20toont geen terugkerende fouten.- De node meldt in het overzicht de werkelijke geheugen- en schijfcapaciteit van de doelserver, niet alleen de in het Panel ingevoerde grenzen. Die cijfers komen live van de node en bewijzen dat de communicatie werkt.
- U maakt een testserver aan. In het overzicht doorloopt die de status Installing en wordt daarna normaal weergegeven. Op de node toont
docker ps -ade bijbehorende container. - U start de server en ziet in de browser lopende console-uitvoer. Dat is het bewijs voor de WebSocket-verbinding en daarmee tegelijk voor het certificaat en de tijd.
- U verbindt via SFTP op poort 2022 met uw Panel-inloggegevens en ziet de serverbestanden. Daarmee is ook de tweede Wings-poort bevestigd.
Pas als alle vijf punten kloppen, is de installatie compleet. Punt vier en vijf mislukken in de praktijk het vaakst, terwijl het Panel tot dat moment volstrekt normaal oogt.
Panel en Wings samen of gescheiden draaien
Beide varianten zijn mogelijk. Op één enkele server hoeft u slechts op twee dingen te letten: gebruik twee verschillende domeinnamen op hetzelfde IP-adres, één voor het Panel op poort 443 en één voor de node op poort 8080. En houd er rekening mee dat de geheugenhonger van de gameservers ook het Panel afremt zodra het krap wordt.
Gescheiden draaien is vanaf de tweede node sowieso het normale geval en heeft een prettig neveneffect: een overbelaste of aangevallen gameserver sleurt de beheeromgeving niet mee. Voor de basisbeveiliging van beide machines is een blik in onze checklist voor nieuwe rootservers de moeite waard, net als in de artikelen over SSH beveiligen en fail2ban.
Tot slot een praktische tip voor het dagelijks gebruik: de Docker-images voor de gameservers brengen hun Java-omgeving zelf mee. U hoeft op de node geen Java te installeren. Wilt u toch een keer buiten Pterodactyl om testen, dan vindt u de juiste aanpak in onze artikelen over Java 21 onder Debian en over de Minecraft-server onder Debian. En houd de schijfruimte in de gaten, images en back-ups groeien snel, daar past het artikel Schijf vol onder Linux bij.
Veelgestelde vragen
Wat is het verschil tussen Pterodactyl Panel en Wings?
Welke PHP-versie heb ik nodig voor Pterodactyl?
Waarom maakt Wings geen verbinding met het Panel?
Welke poorten moet ik voor Pterodactyl openzetten?
Heb ik voor elke node een eigen SSL-certificaat nodig?
Waarom blijft de serverconsole in de browser hangen bij het opbouwen van de verbinding?
Moet ik op de node Java installeren?
2026 KernelHost GmbH. Alle rechten voorbehouden. Deze handleiding is auteursrechtelijk beschermd. Publicatie op andere websites, geheel, gedeeltelijk of in bewerkte vorm, is zonder onze schriftelijke toestemming niet toegestaan. Citeren met bronvermelding en link is uitdrukkelijk welkom.

