Pterodactyl is an open source control panel for game servers. It has two parts: the Panel, a PHP web application where you create servers and users, and Wings, a daemon that runs each game server in its own Docker container on a node. In this tutorial you will install both on a single Ubuntu 24.04 server with Nginx, MariaDB, Redis and a Let's Encrypt certificate, register the server as a node and create a first game server from an egg.
Prerequisites
To follow this guide you need:
- A server running Ubuntu 24.04 LTS (x86_64 or arm64), for example a CubePath VPS, with at least 2 vCPU and 4 GB of RAM plus whatever the game servers themselves need.
- A non-root user with
sudoprivileges. - A domain name such as
panel.your_domainwith a DNS A record pointing toyour_server_ip. Both the Panel and Wings use it for HTTPS. - UFW enabled with OpenSSH allowed.
Wings runs game servers in Docker containers, so the server must be a full virtual machine or bare metal, not a container such as LXC or OpenVZ.
Step 1 - Installing the Panel dependencies
Ubuntu 24.04 ships PHP 8.3, which Pterodactyl 1.11 supports, so the distribution packages are enough. Install PHP with the required extensions, MariaDB, Nginx, Redis and a few tools:
sudo apt update
sudo apt install php8.3 php8.3-cli php8.3-common php8.3-gd php8.3-mysql php8.3-mbstring php8.3-bcmath php8.3-xml php8.3-fpm php8.3-curl php8.3-zip mariadb-server nginx redis-server tar unzip git curl
Install Composer, the PHP dependency manager, with its official installer:
curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer
Check the versions:
php -v
composer --version
PHP 8.3.6 (cli) (built: ...)
Composer version 2.8.x
Make sure MariaDB and Redis are running and enabled at boot:
sudo systemctl enable --now mariadb redis-server
Step 2 - Downloading the Panel
Create the application directory and download the latest release:
sudo mkdir -p /var/www/pterodactyl
cd /var/www/pterodactyl
sudo curl -Lo panel.tar.gz https://github.com/pterodactyl/panel/releases/latest/download/panel.tar.gz
sudo tar -xzf panel.tar.gz
sudo rm panel.tar.gz
sudo chmod -R 755 storage/* bootstrap/cache/
List the directory to confirm the files are there:
ls /var/www/pterodactyl
You should see artisan, composer.json, .env.example (shown with ls -a) and directories such as app and public.
Step 3 - Creating the database
Open the MariaDB shell as root:
sudo mariadb
Create a database and a user for the Panel. Replace your_db_password with a strong, unique password:
CREATE USER 'pterodactyl'@'127.0.0.1' IDENTIFIED BY 'your_db_password';
CREATE DATABASE panel;
GRANT ALL PRIVILEGES ON panel.* TO 'pterodactyl'@'127.0.0.1' WITH GRANT OPTION;
EXIT;
Check that the user can log in over TCP, which is how the Panel connects:
mariadb -u pterodactyl -p -h 127.0.0.1 -e "SHOW DATABASES;"
The output lists the panel database.
Step 4 - Configuring the Panel
Copy the example environment file, install the PHP dependencies and generate the application encryption key:
cd /var/www/pterodactyl
sudo cp .env.example .env
sudo COMPOSER_ALLOW_SUPERUSER=1 composer install --no-dev --optimize-autoloader
sudo php artisan key:generate --force
ImportantThe
APP_KEYin/var/www/pterodactyl/.envencrypts sensitive data in the database. Back it up somewhere safe. If you lose it, encrypted data cannot be recovered even with a database backup.
Run the interactive environment setup. Use https://panel.your_domain as the application URL, choose redis for the cache, session and queue drivers, and keep 127.0.0.1 for Redis with no password:
sudo php artisan p:environment:setup
Next, enter the database settings from Step 3 (host 127.0.0.1, port 3306, database panel, user pterodactyl):
sudo php artisan p:environment:database
Optionally, configure outgoing mail so the Panel can send password reset emails:
sudo php artisan p:environment:mail
Create the database tables and load the default eggs:
sudo php artisan migrate --seed --force
The command ends without errors after running all migrations and seeders. Create your administrator account and answer yes when asked whether the user is an administrator:
sudo php artisan p:user:make
Finally, give the web server user ownership of the files:
sudo chown -R www-data:www-data /var/www/pterodactyl
Step 5 - Setting up the queue worker and scheduler
The Panel uses a scheduled task and a queue worker for background jobs such as sending emails and running server schedules. Add the scheduler to root's crontab:
sudo crontab -e
Add this line at the end of the file:
* * * * * php /var/www/pterodactyl/artisan schedule:run >> /dev/null 2>&1
Then create a systemd unit for the queue worker:
sudo nano /etc/systemd/system/pteroq.service
[Unit]
Description=Pterodactyl Queue Worker
After=redis-server.service
[Service]
User=www-data
Group=www-data
Restart=always
ExecStart=/usr/bin/php /var/www/pterodactyl/artisan queue:work --queue=high,standard,low --sleep=3 --tries=3
StartLimitInterval=180
StartLimitBurst=30
RestartSec=5s
[Install]
WantedBy=multi-user.target
Enable and start it:
sudo systemctl daemon-reload
sudo systemctl enable --now pteroq.service
systemctl is-active pteroq.service
active
Step 6 - Configuring Nginx with HTTPS
Open HTTP and HTTPS in the firewall and obtain a certificate from Let's Encrypt with Certbot:
sudo ufw allow 'Nginx Full'
sudo apt install certbot python3-certbot-nginx
sudo certbot certonly --nginx -d panel.your_domain
Certbot stores the certificate under /etc/letsencrypt/live/panel.your_domain/ and installs a timer that renews it automatically.
Remove the default site and create a site for the Panel:
sudo rm /etc/nginx/sites-enabled/default
sudo nano /etc/nginx/sites-available/pterodactyl.conf
Paste the following, replacing panel.your_domain in all four places:
server {
listen 80;
server_name panel.your_domain;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name panel.your_domain;
root /var/www/pterodactyl/public;
index index.php;
access_log /var/log/nginx/pterodactyl.app-access.log;
error_log /var/log/nginx/pterodactyl.app-error.log error;
client_max_body_size 100m;
client_body_timeout 120s;
sendfile off;
ssl_certificate /etc/letsencrypt/live/panel.your_domain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/panel.your_domain/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header Referrer-Policy same-origin;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param PHP_VALUE "upload_max_filesize = 100M \n post_max_size=100M";
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTP_PROXY "";
fastcgi_intercept_errors off;
fastcgi_buffer_size 16k;
fastcgi_buffers 4 16k;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
}
location ~ /\.ht {
deny all;
}
}
Enable the site, test the configuration and reload Nginx:
sudo ln -s /etc/nginx/sites-available/pterodactyl.conf /etc/nginx/sites-enabled/pterodactyl.conf
sudo nginx -t
sudo systemctl reload nginx
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Open https://panel.your_domain in a browser and log in with the administrator account from Step 4.
Step 7 - Installing Docker for Wings
Wings needs Docker Engine. Install it from Docker's official repository:
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io
Enable Docker and check that it works:
sudo systemctl enable --now docker
sudo docker run --rm hello-world
The output includes Hello from Docker!.
Step 8 - Installing Wings
Download the Wings binary for your architecture and create its configuration directory:
sudo mkdir -p /etc/pterodactyl
sudo curl -L -o /usr/local/bin/wings "https://github.com/pterodactyl/wings/releases/latest/download/wings_linux_$([ "$(uname -m)" = "x86_64" ] && echo amd64 || echo arm64)"
sudo chmod u+x /usr/local/bin/wings
Confirm that it runs:
sudo wings version
Creating the location and node in the Panel
In the Panel, open the admin area (the gear icon at the top right) and do the following:
- Go to Locations, click Create New and add a location, for example
eu1. - Go to Nodes, click Create New and fill in the form:
- FQDN:
panel.your_domain(Wings runs on the same server, so it can reuse the certificate). - Communicate Over SSL: Use SSL Connection.
- Total Memory and Total Disk Space: what you want to hand out to game servers, leaving room for the operating system and the Panel.
- Daemon Port
8080and Daemon SFTP Port2022(the defaults).
- FQDN:
- Open the new node, go to the Configuration tab and copy the YAML block shown there.
Paste it into the Wings configuration file:
sudo nano /etc/pterodactyl/config.yml
The file contains the node's token and the certificate paths, so do not share it.
Opening the Wings ports
Wings listens on port 8080 for the Panel and your browser, and on port 2022 for SFTP file access:
sudo ufw allow 8080/tcp
sudo ufw allow 2022/tcp
Testing Wings in the foreground
Run Wings once in debug mode to catch configuration errors:
sudo wings --debug
Wings checks Docker, creates the pterodactyl0 network and starts listening. In the Panel, the node's heart icon on the Nodes page turns green. Stop Wings with Ctrl+C.
Running Wings as a service
Create the systemd unit:
sudo nano /etc/systemd/system/wings.service
[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
Enable and start it:
sudo systemctl daemon-reload
sudo systemctl enable --now wings.service
sudo systemctl status wings.service
The service shows active (running).
Step 9 - Creating allocations and a first server
An allocation is an IP and port pair that a game server can bind to. Go to Nodes, open your node and select the Allocation tab. Enter your_server_ip as the IP address and a range of ports, for example 25565-25575, then click Submit.
Now create a server:
- Go to Servers and click Create New.
- Give it a name, choose the owner (your admin user) and select an allocation from your node.
- Set the memory, disk and CPU limits for this server.
- Under Nest Configuration, choose the Minecraft nest and the Paper egg.
- Click Create Server.
Wings pulls the egg's Docker image and runs its install script. When the installation finishes, open the server from the Panel's front page and click Start. The console shows the Minecraft startup log ending in Done.
Docker publishes container ports directly through iptables, so allocated game ports are reachable even without a UFW rule. Only allocate ports you intend to expose.
The seeded eggs cover Minecraft, Source engine games, Rust and voice servers. For other games, import an egg JSON file under Nests with Import Egg. The community-maintained pelican-eggs repositories on GitHub have eggs for many titles.
Troubleshooting
The Panel shows a 500 error: check /var/www/pterodactyl/storage/logs/ for the newest log file and sudo tail -n 50 /var/log/nginx/pterodactyl.app-error.log. Wrong database credentials in .env and files not owned by www-data are the most common causes.
The node heart stays red: make sure Wings is running (sudo systemctl status wings), port 8080 is open, and the node FQDN has a valid certificate. The browser connects to Wings directly, so a certificate error there also breaks the console.
Emails or schedules never run: the queue worker or cron entry is missing. Check systemctl status pteroq and sudo crontab -l.
The server install fails: open the node's server and read the install log, or run sudo journalctl -u wings -n 100. Not enough disk space in the node limits is a frequent cause.
Conclusion
You installed the Pterodactyl Panel with Nginx, MariaDB and Redis behind HTTPS, set up Wings with Docker on the same server, and created a game server from an egg. Users you create in the Panel can now manage their own servers through the web interface and SFTP. As next steps, schedule backups of the panel database and the .env file, add more nodes on other servers as demand grows, and restrict SSH to key-based authentication.
