Instalar o Pterodactyl Panel para gameservers
O Panel e o Wings são dois programas distintos, com duas tarefas distintas. Quem percebeu isso instala o Pterodactyl em meia hora. Quem não percebeu passa dias à procura do erro.
O Pterodactyl é a interface livre mais utilizada para gameservers. A fama de ser complicado quase nunca vem da instalação em si, mas de um único mal-entendido: o Pterodactyl não é um programa, são dois. Este guia separa os dois com clareza, mostra as diferenças entre Debian e Ubuntu e percorre depois as mensagens de erro que levam qualquer pessoa a copiá-las tal e qual para o motor de busca.
Panel e Wings: dois programas, dois papéis
O Panel é uma aplicação PHP assente em Laravel. Fornece a interface web, gere utilizadores, permissões, bases de dados e agendamentos, e guarda tudo numa base de dados MySQL ou MariaDB própria. O Panel nunca arranca um gameserver por si. Nem sequer conhece o Docker.
O Wings é um único programa escrito em Go. Corre em cada máquina onde os gameservers devem efetivamente correr, fala com o daemon do Docker, arranca containers, transmite a consola e disponibiliza o acesso SFTP. O Wings não tem interface web nem base de dados. Escuta numa porta HTTP e espera instruções do Panel.
Os dois comunicam exclusivamente através de HTTP, nos dois sentidos, com tokens assinados. Daí resultam três consequências que convém aceitar desde o início:
- O Panel tem de alcançar o node através de um nome de domínio, e não de um IP. O certificado está preso ao nome.
- O Panel e o Wings têm de falar o mesmo protocolo. Panel em HTTPS com Wings em HTTP não funciona, porque o browser bloqueia a ligação da consola.
- Os dois relógios têm de estar certos. Os tokens têm um tempo de vida de poucos minutos.
Quem interiorizar estas três frases já evitou metade dos problemas típicos do Pterodactyl.
Requisitos e a escolha do sistema
O Pterodactyl 1.11 e mais recente exige PHP 8.2 ou 8.3. É neste ponto que a maioria dos guias fica imprecisa, porque as distribuições fornecem versões muito diferentes. Em julho de 2026, a situação nas fontes padrão é a seguinte:
| Sistema | PHP | Base de dados | nginx |
| Debian 12 | 8.2 (serve) | MariaDB 10.11 | 1.22 |
| Debian 13 | 8.4 (demasiado recente) | MariaDB 11.8 | 1.26 |
| Ubuntu 24.04 | 8.3 (serve) | MySQL 8.0 ou MariaDB 10.11 | 1.24 |
| Ubuntu 22.04 | 8.1 (demasiado antiga) | MySQL 8.0 ou MariaDB 10.6 | 1.18 |
| Debian 11 | 7.4 (demasiado antiga) | MariaDB 10.5 | 1.18 |
Este guia é feito à medida de Debian e Ubuntu. Em AlmaLinux, Rocky Linux e Oracle Linux não existe apt, pelo que nenhum dos comandos de pacotes seguintes se aplica.
Consequência prática: o Debian 12 e o Ubuntu 24.04 são os dois sistemas em que o Panel corre sem fontes externas. No Ubuntu 22.04 precisa do PPA do Ondřej Surý, no Debian 13 do respetivo equivalente para Debian, porque ali é o PHP 8.4 que fornece o metapacote e a composer.json do Panel exige expressamente ^8.2 || ^8.3. Na prática, a execução do Composer até passa com PHP 8.4, mas isso é terreno por confirmar e não é um estado em que se queira operar um servidor produtivo. Quem quiser poupar-se à fonte adicional escolhe Debian 12 ou Ubuntu 24.04.
Já os dois sistemas demasiado antigos não falham no comando de pacotes, mas apenas dois passos mais à frente, e é isso que os torna traiçoeiros. O apt install php corre no Ubuntu 22.04 (PHP 8.1.2) e no Debian 11 (PHP 7.4.33) com código de saída 0, e só depois a execução do Composer aborta, no Ubuntu 22.04 com brick/math requires php (^8.2) failed e no Debian 11 com aws/aws-sdk-php requires php (>=8.1) failed. Se tiver mesmo de ficar num destes sistemas, instale a partir da fonte externa pacotes com versão explícita (php8.3, php8.3-cli, php8.3-fpm e assim por diante) em vez do metapacote php, caso contrário volta a entrar a versão da distribuição.
Segunda diferença que surpreende com regularidade: a Debian não fornece qualquer pacote mysql-server. Ali o MariaDB é a escolha assente, e isso é perfeitamente aceitável, porque o Pterodactyl exige MariaDB 10.2 ou mais recente. Quem escrever apt install mysql-server em Debian recebe E: Unable to locate package mysql-server e passa a procurar no sítio errado.
Para o node com o Wings, estas regras de PHP não se aplicam de todo. O Wings é um programa em Go com ligação estática e precisa apenas de Docker e de um kernel minimamente atual. O node pode perfeitamente ser Debian 13 enquanto o Panel corre em Debian 12.
Instalar o Panel
Todos os comandos seguintes são executados como root. Primeiro os pacotes de base. Tenha o cuidado de incluir as extensões de PHP na totalidade, porque um php-bcmath em falta só dá nas vistas na execução do Composer.
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
Verifique de imediato se a versão serve, antes de avançar:
php -v
php -m | grep -E "bcmath|mbstring|curl|zip|gd|xml"
A seguir, o Composer e os ficheiros do Panel:
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
A base de dados. Crie o utilizador em 127.0.0.1 e não em localhost, caso contrário entra o acesso por socket e o Laravel acaba por receber uma recusa de acesso apesar de a palavra-passe estar correta. Como destrinçar esse caso está explicado no nosso artigo sobre Access denied for user.
mariadb -u root -e "CREATE DATABASE panel;"
mariadb -u root -e "CREATE USER 'pterodactyl'@'127.0.0.1' IDENTIFIED BY 'AquiUmaPalavraPasseLonga';"
mariadb -u root -e "GRANT ALL PRIVILEGES ON panel.* TO 'pterodactyl'@'127.0.0.1' WITH GRANT OPTION;"
mariadb -u root -e "FLUSH PRIVILEGES;"
A base de dados deve ser protegida logo a seguir, e para isso temos um artigo próprio sobre como proteger o MariaDB e o MySQL.
Agora a configuração propriamente dita. Os comandos p:environment são interativos e perguntam pelo URL do Panel, fuso horário, driver de cache e acesso à base de dados:
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/*
Em p:environment:setup, escolha Redis como driver de sessão e de cache, para que a fila descrita mais abaixo funcione como deve ser. E introduza o URL do Panel com https://. Um http:// neste ponto gera mais tarde conteúdos mistos e uma consola que fica eternamente à espera de ligação.
O nginx e a armadilha das versões
As bases da configuração do servidor web estão no nosso artigo sobre como instalar o nginx. Para o Pterodactyl há dois pormenores importantes, e é neles que os modelos prontos que circulam pela internet falham com regularidade.
Primeiro, o socket do PHP-FPM. O nome do ficheiro contém a versão de PHP e difere consoante o sistema. Verifique em vez de adivinhar:
systemctl status php8.2-fpm
ls /run/php/
No Debian 12 o socket chama-se php8.2-fpm.sock, no Ubuntu 24.04 php8.3-fpm.sock. Um caminho errado aqui produz exatamente a página 502 Bad Gateway que tanta gente procura. A consulta do estado vem propositadamente antes: o ficheiro do socket só nasce quando o serviço FPM está a correr. Se ele não estiver arrancado, /run/php/ está vazio e conclui-se erradamente que o caminho está errado. Se o serviço ainda não estiver a correr, resolve-se com systemctl enable --now php8.2-fpm, com o número de versão que corresponder à sua instalação.
Segundo, a forma de escrever o HTTP/2. A diretiva nova http2 on; só existe a partir do nginx 1.25.1. Em Debian 12 (1.22), Ubuntu 22.04 (1.18) e também em Ubuntu 24.04 (1.24) tem de usar a forma antiga listen 443 ssl http2;, caso contrário o arranque aborta com nginx: [emerg] unknown directive "http2". Só o Debian 13, com o nginx 1.26, entende as duas formas.
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 "";
}
}
Fila de tarefas e agendamento
Sem estas duas peças, o Panel parece funcional, mas não envia mensagens de correio nem executa tarefas agendadas. A estrutura do ficheiro de unit está explicada em detalhe no nosso artigo sobre como criar um serviço systemd; aqui fica a versão final:
[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
A isto junta-se uma entrada na crontab do root; os pormenores da sintaxe encontram-se no artigo Configurar um cronjob em Linux:
* * * * * php /var/www/pterodactyl/artisan schedule:run >> /dev/null 2>&1
Instalar o Wings no node
A partir daqui trabalha na máquina que vai executar os gameservers. Pode ser o mesmo servidor, mas não tem de ser. O requisito é o Docker, cuja instalação descrevemos no artigo Instalar o Docker em Debian e 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
Em servidores ARM o nome do ficheiro é wings_linux_arm64. Se descarregar o pacote errado, a shell limita-se a responder cannot execute binary file: Exec format error. Não estranhe o resultado da última linha: o wings version responde com um v duplicado, ou seja, algo como wings vv1.13.1. Vem assim de origem e não é sinal de uma instalação estragada.
O ficheiro /etc/pterodactyl/config.yml não é escrito por si. É criado automaticamente daqui a pouco. Para já, crie apenas o serviço:
[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
Ainda não arranque nada. Sem configuração, o Wings aborta de imediato, com uma mensagem que aponta, no essencial, para um ficheiro de configuração em falta em /etc/pterodactyl/config.yml. Neste ponto isso é perfeitamente normal e não é um erro.
Uma palavra sobre o swap: muitos guias antigos exigem swapaccount=1 em /etc/default/grub. Isso diz respeito exclusivamente a sistemas com cgroup v1. O Debian 12 e 13, bem como o Ubuntu 22.04 e 24.04, usam cgroup v2 por predefinição, e aí a entrada é supérflua. Pode verificá-lo com docker info. Se aí aparecer WARNING: No swap limit support, o limite de memória não abrange a área de swap. Como dimensionar o swap de forma sensata está no artigo Configurar swap.
Certificado para o node, não apenas para o Panel
O erro de raciocínio mais frequente: arranja-se um certificado para panel.example.com e depois estranha-se que o node não funcione. O Wings precisa de um certificado próprio para o seu próprio nome de domínio, por exemplo node1.example.com. Os dois nomes podem apontar para o mesmo IP, mas são dois nomes.
Num node puro não corre nenhum servidor web, e por isso o modo autónomo do Certbot é o caminho mais simples. Para isso, a porta 80 tem de estar acessível a partir do exterior durante esse curto período:
apt -y install certbot
certbot certonly --standalone -d node1.example.com
Quem gere muitos nodes fica mais bem servido com um certificado wildcard, que descrevemos no artigo Certificado wildcard da Let's Encrypt.
Dois obstáculos que custam muito tempo:
- O Wings lê os ficheiros do certificado no arranque. Depois de uma renovação, o serviço tem de ser recarregado. Coloque em
/etc/letsencrypt/renewal-hooks/deploy/um pequeno script comsystemctl restart wings. Sem isso, o node corre 90 dias de forma impecável e falha depois aparentemente sem motivo. - Desligue o proxy da Cloudflare para o nome do node. A nuvem laranja abre a ligação TLS e substitui o certificado. O Panel passa então a receber um certificado que não corresponde ao emissor esperado, e a ligação da consola por WebSocket comporta-se de forma imprevisível. O registo A do node pertence ao cinzento.
Criar e ligar o node
No Panel, em Admin, Locations, crie primeiro uma localização e, a seguir, o node em Nodes. Os campos que realmente contam:
- FQDN:
node1.example.com, exatamente o nome que consta do certificado. - Communicate over SSL: ativado, se o Panel correr sobre HTTPS. Caso contrário, mais vale nem começar.
- Behind Proxy: ativar apenas se existir mesmo um reverse proxy à frente do Wings e for esse a terminar o TLS.
- Daemon Port: 8080. Daemon SFTP Port: 2022.
- Memory e Disk: os limites que o Panel respeita ao distribuir servidores.
Depois de guardar, abra o separador Configuration do node. Aí o Panel gera um comando com um token de utilização única. Execute-o no node:
cd /etc/pterodactyl
wings configure --panel-url https://panel.example.com --token TOKEN --node 1
Com isso, o Wings vai buscar a sua configuração completa e escreve /etc/pterodactyl/config.yml. Verifique o conteúdo: se no endereço do Panel estiver http:// em vez de https://, copiou o comando de um ambiente em que o URL do Panel está mal registado. Corrija-o na origem com php artisan p:environment:setup, e não à mão no ficheiro YAML.
A seguir, no separador Allocations, introduza o IP do node e os intervalos de portas pretendidos, por exemplo 25565 a 25600 para Minecraft. Sem pelo menos uma atribuição livre não é possível criar nenhum servidor.
Só agora deve arrancar o serviço:
systemctl enable --now wings
systemctl status wings
As portas têm de estar abertas na firewall. Com o ufw, cujas bases abordamos no artigo Configurar a firewall ufw:
ufw allow 8080/tcp
ufw allow 2022/tcp
ufw allow 25565:25600/tcp
ufw allow 25565:25600/udp
Quando o Wings não se liga
O Panel mostra um símbolo vermelho no node ou devolve um erro ao criar um servidor. Trate as mensagens pela ordem em que surgem, porque são surpreendentemente claras.
cURL error 7: Failed to connect ... Connection refused
O servidor do Panel não alcança a porta. Ou o Wings não está a correr, ou a firewall bloqueia, ou o serviço está à escuta no endereço errado. Verifique por esta ordem:
systemctl status wings
ss -tlnp | grep 8080
journalctl -u wings -n 50 --no-pager
E a partir do servidor do Panel, que é o teste decisivo:
curl -v https://node1.example.com:8080
Uma resposta HTTP, mesmo um 404 com conteúdo JSON, é neste ponto um sucesso. Prova que DNS, firewall, porta e TLS funcionam em conjunto.
cURL error 60: SSL certificate problem
O certificado do node não está a ser aceite. Com self signed certificate está a usar um certificado criado por si, e o Panel não lida com isso porque a biblioteca subjacente não conhece exceções. Com unable to get local issuer certificate falta normalmente a cadeia intermédia, ou seja, a sua configuração do Wings aponta para cert.pem em vez de fullchain.pem. Com certificate has expired a renovação até correu, mas o Wings ainda tem o ficheiro antigo em memória, veja o ponto do reinício mais acima.
cURL error 28: Operation timed out
Nenhuma resposta e nenhum reset. Isto cheira a uma firewall que descarta pacotes em vez de os rejeitar, ou a um node atrás de NAT. Um caso particular: Panel e Wings no mesmo servidor, com o Panel a contactar o próprio IP público. Algumas redes não devolvem esse trajeto. A solução passa por uma entrada em /etc/hosts no servidor do Panel, que aponte o nome do node para o endereço interno.
Cannot connect to the Docker daemon at unix:///var/run/docker.sock
O Wings está a correr, o Docker não. O systemctl status docker esclarece isso numa linha. Ainda assim, o node aparece muitas vezes como acessível no Panel, porque a consulta de estado funciona, mas qualquer arranque de servidor falha.
O node responde, mas todas as ações são recusadas
Há um token errado. Isso acontece depois de um novo wings configure com um token antigo, ou depois de o node ter sido apagado e criado de novo no Panel. Solução: gerar um token novo no separador Configuration do Panel, executar outra vez o comando e reiniciar o Wings. Não vale a pena andar a adivinhar no ficheiro YAML.
Para todos os casos em que a mensagem continua pouco clara, pare o serviço e arranque o Wings em primeiro plano. A saída é bastante mais conversadora do que o journal:
systemctl stop wings
wings --debug
Também ajuda o modo de relatório integrado, que recolhe a configuração, o estado do Docker e os dados do sistema:
wings diagnostics
Desfasamento horário entre o Panel e o node
Este erro é traiçoeiro porque se parece com um problema de rede. Sintomas: o node é apresentado no Panel como acessível, os servidores podem ser criados, mas a consola fica presa a estabelecer ligação e o acesso SFTP recusa credenciais corretas.
A razão está na própria arquitetura. O Panel assina tokens de vida curta, cuja validade se conta em minutos. O Wings verifica o momento de emissão e o prazo de validade contra o seu próprio relógio. Se os dois sistemas divergirem mais do que alguns minutos, o Wings descarta todos os tokens por expirados ou por ainda não válidos, mesmo que tenham acabado de ser gerados.
Importante para perceber: não se trata do fuso horário. O Panel e o node podem ter fusos horários diferentes configurados, isso é irrelevante. Trata-se do instante absoluto. Verifique nas duas máquinas:
date -u
timedatectl status
Na saída do timedatectl tem de constar System clock synchronized: yes e NTP service: active. Caso contrário:
timedatectl set-ntp true
Em sistemas sem systemd-timesyncd, por exemplo depois de uma instalação mínima, instale o chrony e verifique a sincronização:
apt -y install chrony
chronyc tracking
O valor em System time deve situar-se na ordem dos milissegundos. As máquinas virtuais clonadas a partir de uma imagem ou repostas a partir de um snapshot são a origem mais frequente de desvios maiores.
Como perceber que está mesmo a funcionar
Um símbolo verde no Panel é apenas a primeira de cinco provas. Percorra a lista e passa a ter a certeza:
- O
systemctl is-active wingsdevolveactive, e umjournalctl -u wings -n 20não mostra erros recorrentes. - O node, na vista geral, comunica a capacidade real de memória e de armazenamento do servidor de destino, e não apenas os limites registados no Panel. Estes números chegam do node em direto e são uma prova de que a comunicação funciona.
- Crie um servidor de teste. Na vista geral, ele passa pelo estado Installing e depois é apresentado normalmente. No node, o
docker ps -amostra o container correspondente. - Arranque o servidor e observe no browser saída de consola em curso. É essa a prova da ligação WebSocket e, com ela, do certificado e da hora ao mesmo tempo.
- Ligue-se por SFTP na porta 2022 com as suas credenciais do Panel e veja os ficheiros do servidor. Fica assim confirmada também a segunda porta do Wings.
A instalação só está completa quando os cinco pontos batem certo. Os pontos quatro e cinco são, por experiência, os que falham com mais frequência, apesar de até aí o Panel parecer perfeitamente normal.
Operar o Panel e o Wings juntos ou separados
As duas coisas são possíveis. Num servidor único basta ter dois cuidados: use dois nomes de domínio diferentes no mesmo IP, um para o Panel na porta 443 e outro para o node na porta 8080. E conte com o facto de a fome de memória dos gameservers travar também o Panel quando as coisas apertarem.
A partir do segundo node, separar as duas partes é de qualquer forma o caso normal e tem um efeito secundário agradável: um gameserver sobrecarregado ou sob ataque não arrasta consigo a interface de administração. Para a proteção de base das duas máquinas vale a pena consultar a nossa checklist para servidores root novos, bem como os artigos sobre proteção do SSH e fail2ban.
Para terminar, uma nota prática para a operação: as imagens Docker dos gameservers trazem consigo o seu próprio ambiente Java. Não precisa de instalar Java no node. Quem, ainda assim, quiser testar alguma coisa fora do Pterodactyl encontra os caminhos adequados nos nossos artigos sobre Java 21 em Debian e sobre o servidor de Minecraft em Debian. E mantenha o espaço em disco debaixo de olho, porque as imagens e os backups crescem depressa; a esse tema assenta bem o artigo Disco cheio em Linux.
Perguntas frequentes
Qual é a diferença entre o Pterodactyl Panel e o Wings?
De que versão de PHP preciso para o Pterodactyl?
Porque é que o Wings não se liga ao Panel?
Que portas tenho de abrir para o Pterodactyl?
Preciso de um certificado SSL próprio para cada node?
Porque é que a consola do servidor fica presa no browser a estabelecer ligação?
Tenho de instalar Java no node?
2026 KernelHost GmbH. Todos os direitos reservados. Este guia está protegido por direitos de autor. A sua republicação noutros sites, na íntegra, em parte ou de forma editada, não é permitida sem o nosso consentimento por escrito. Citações com indicação da fonte e ligação são expressamente bem-vindas.

