Install Pterodactyl Game Panel on a VPS: Step-by-Step Guide

Published on | Updated

Install Pterodactyl Panel 1.15 and Wings on an Ubuntu VPS with PHP 8.3, MariaDB, Redis, Nginx and Docker, then add a node and create your first game server.

A technician with a tablet in a data center aisle between server racks

Pterodactyl is a free, open-source game server panel (MIT licence). The Panel is the PHP web app where you and your users manage servers; Wings is the daemon that runs each game server in its own Docker container on a node. This guide installs both on a VPS, step by step, following the official 1.x documentation as it stood on 31 October 2026.

Versions: on 31 October 2026 the latest stable releases are Panel 1.15.2 (21 October 2026) and Wings 1.13.4 (14 October 2026). Panel 2.0 is an open beta (2.0.0-beta.2) with its own install guide, so this guide sticks to 1.x, which the docs mark as stable. Panel 1.15.2 requires PHP 8.2 or 8.3. Earlier versions of this guide installed PHP 8.1, which the current panel no longer accepts.

What You Need

  • A VPS with root access running Ubuntu 24.04 or 22.04. Debian 11, 12 and 13 work too, with the extra repositories from the docs' Debian dependencies guide.
  • Virtualization that can run Docker, for Wings. The docs say KVM is guaranteed to work, while on OpenVZ, Virtuozzo or LXC you will most likely be unable to run Wings unless your provider has enabled Docker support. systemd-detect-virt tells you which one you have. Our VPS plans run on KVM with full root access, which is what Wings needs.
  • Room for the game servers. The Panel and Wings can share one VPS, or Wings runs on separate nodes; either way every game server needs its own RAM, CPU and disk on its node.
  • A domain with DNS records for the panel (for example panel.example.com) and for each node (node1.example.com), because each one gets its own SSL certificate.
  • A root shell (sudo -i). Some commands below keep the sudo from the docs; as root it changes nothing.

Panel Installation

Step 1: Install PHP 8.3, MariaDB, Nginx and Redis

The docs list PHP 8.2 or 8.3 (8.3 recommended), MySQL 5.7.22 or newer or MariaDB 10.2 or newer, Redis, a web server, curl, tar, unzip, git and Composer 2. Ubuntu 24.04 ships PHP 8.3 itself. Ubuntu 22.04 ships PHP 8.1, so there you add the ondrej/php PPA first.

apt update && apt upgrade -y

# Add "add-apt-repository" command
apt -y install software-properties-common curl apt-transport-https ca-certificates gnupg

# Ubuntu 22.04 only: PHP 8.3 comes from this PPA
LC_ALL=C.UTF-8 add-apt-repository -y ppa:ondrej/php

# Add Redis official APT repository
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list

# Update repositories list
apt update

# Install Dependencies
apt -y install php8.3 php8.3-{common,cli,gd,mysql,mbstring,bcmath,xml,fpm,curl,zip} mariadb-server nginx tar unzip git redis-server

Step 2: Install Composer

curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer

Step 3: Download the Panel

mkdir -p /var/www/pterodactyl
cd /var/www/pterodactyl
curl -Lo panel.tar.gz https://github.com/pterodactyl/panel/releases/latest/download/panel.tar.gz
tar -xzvf panel.tar.gz
chmod -R 755 storage/* bootstrap/cache/

GitHub's latest link points to the newest release that is not a prerelease, so today it downloads 1.15.2 and not the 2.0 beta. Once 2.0 is released as stable, the same link will download 2.0, which has its own install steps.

Step 4: Create the Database

mariadb -u root -p

As the system root user you can press Enter at the password prompt: MariaDB's root@localhost account uses unix_socket authentication, which lets the system root user in without a password. Then create the panel's user and database, with your own password:

CREATE USER 'pterodactyl'@'127.0.0.1' IDENTIFIED BY 'yourPassword';
CREATE DATABASE panel;
GRANT ALL PRIVILEGES ON panel.* TO 'pterodactyl'@'127.0.0.1' WITH GRANT OPTION;
exit

Step 5: Configure the Environment

cp .env.example .env
COMPOSER_ALLOW_SUPERUSER=1 composer install --no-dev --optimize-autoloader

# Only on a first install, with no Pterodactyl data in the database
php artisan key:generate --force

Back up the APP_KEY line now (grep APP_KEY /var/www/pterodactyl/.env) and store it off the server, for example in a password manager. The docs warn that if you lose it, all encrypted data is irrecoverable, even with database backups.

php artisan p:environment:setup
php artisan p:environment:database
php artisan p:environment:mail

p:environment:setup asks for the panel URL, the timezone and the cache, session and queue drivers, and marks Redis as recommended for all three. p:environment:database takes the user and password from Step 4. For mail, pick smtp with your own mail server: the docs advise against PHP's internal mail.

Step 6: Create the Tables and the First Admin

php artisan migrate --seed --force
php artisan p:user:make

Let the migration finish: it creates the tables and adds the default Nests and Eggs. The admin password needs 8 characters, mixed case and at least one number.

Step 7: Set Permissions

chown -R www-data:www-data /var/www/pterodactyl/*

Step 8: Add the Cron Job and the Queue Worker

Open root's crontab with sudo crontab -e and add this line. It runs every minute for tasks such as session cleanup and sending scheduled tasks to the daemons, so your server schedules depend on it:

* * * * * php /var/www/pterodactyl/artisan schedule:run >> /dev/null 2>&1

Then create /etc/systemd/system/pteroq.service with the docs' queue worker file:

# Pterodactyl Queue Worker File
# ----------------------------------

[Unit]
Description=Pterodactyl Queue Worker
After=redis-server.service

[Service]
# On some systems the user and group might be different.
# Some systems use `apache` or `nginx` as the user and group.
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

Start Redis and the worker now and at every boot:

sudo systemctl enable --now redis-server
sudo systemctl enable --now pteroq.service

Step 9: Nginx with SSL

Create the certificate before you add the SSL configuration: the docs warn that the web server fails to start when the certificate files do not exist yet.

sudo apt update
sudo apt install -y certbot
sudo apt install -y python3-certbot-nginx
certbot certonly --nginx -d panel.example.com

Remove the default site:

rm /etc/nginx/sites-enabled/default

Save the docs' "Nginx With SSL" file as /etc/nginx/sites-available/pterodactyl.conf and replace every <domain> with your panel domain. Its fastcgi_pass line points at the PHP 8.3 FPM socket from Step 1.

server {
    # Replace the example <domain> with your domain name or IP address
    listen 80;
    server_name <domain>;
    return 301 https://$server_name$request_uri;
}

server {
    # Replace the example <domain> with your domain name or IP address
    listen 443 ssl http2;
    server_name <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;

    # allow larger file uploads and longer script runtimes
    client_max_body_size 100m;
    client_body_timeout 120s;

    sendfile off;

    # SSL Configuration: replace the example <domain> with your domain
    ssl_certificate /etc/letsencrypt/live/<domain>/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/<domain>/privkey.pem;
    ssl_session_cache shared:SSL:10m;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
    ssl_prefer_server_ciphers on;

    # See https://hstspreload.org/ before uncommenting the line below.
    # add_header Strict-Transport-Security "max-age=15768000; preload;";
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Robots-Tag none;
    add_header Content-Security-Policy "frame-ancestors 'self'";
    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;
        include /etc/nginx/fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }
}

Enable it and restart Nginx:

sudo ln -s /etc/nginx/sites-available/pterodactyl.conf /etc/nginx/sites-enabled/pterodactyl.conf
sudo systemctl restart nginx

Open https://panel.example.com and log in with the admin from Step 6.

Wings Installation

Wings runs on the node where game servers actually execute. Which ports and DNS names the panel and each node need is explained in our Panel vs Wings guide.

Step 1: Install Docker

curl -sSL https://get.docker.com/ | CHANNEL=stable bash
sudo systemctl enable --now docker

This is the docs' quick install. Docker's own install guide says the convenience script isn't recommended for production environments and describes an install from Docker's apt repository instead; the Pterodactyl docs point to Docker's documentation if you would rather install it manually.

Swap: the docs say swap is enabled by default on Linux 6.1 and newer, so check your kernel with uname -r first. On an older kernel, docker info usually shows WARNING: No swap limit support. The docs call enabling it optional but recommend it when you host for others: add swapaccount=1 inside the quotes of the GRUB_CMDLINE_LINUX_DEFAULT line in /etc/default/grub, run sudo update-grub and reboot.

Step 2: Install the Wings Binary

sudo mkdir -p /etc/pterodactyl
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

The download picks the amd64 or arm64 build to match your CPU.

Step 3: Create a Location and a Node

  1. In the admin area, open Locations and click Create New. A short code such as eu1 is enough; a node cannot be created without a location.
  2. Open Nodes and click Create New. Fill in the name, the location, the FQDN (node1.example.com) and Communicate Over SSL: choose Use SSL Connection when the panel runs on HTTPS, because the daemon must then use SSL too.
  3. Set Total Memory and Total Disk Space. Memory Over-Allocation and Disk Over-Allocation take a percentage: 0 blocks new servers that would push the node over its totals, and -1 turns the check off.
  4. Leave the Daemon Port at 8080 and the Daemon SFTP Port at 2022 unless you need other ports.
  5. Open the node's Configuration tab and copy the Configuration File into /etc/pterodactyl/config.yml on the node. Or click Generate Token under Auto-Deploy and run the command it shows on the node.

Step 4: Give the Node an SSL Certificate

When the panel uses SSL, Wings needs a certificate for its own FQDN, and the generated config.yml looks for it in /etc/letsencrypt/live/<node FQDN>/. On a node without a web server, use certbot's standalone mode; its HTTP challenge needs port 80 reachable:

sudo apt install -y certbot
certbot certonly --standalone -d node1.example.com

If Wings runs on the panel's VPS, use certbot certonly --nginx -d node1.example.com instead.

Step 5: Start Wings

Run it in the foreground once, so you see any errors:

sudo wings --debug

When it runs without errors, stop it with Ctrl+C and create /etc/systemd/system/wings.service with the docs' unit file:

[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

Then start it now and at every boot:

sudo systemctl enable --now wings

Step 6: Add Allocations

An allocation is an IP and port you can assign to a server, and each server needs at least one. Add them under Nodes, your node, Allocation. Find the IP with hostname -I | awk '{print $1}' (behind NAT, use the internal IP), and never use 127.0.0.1.

Creating Your First Server

  1. In the admin area, open Servers and click Create New.
  2. Enter the Server Name and the Server Owner (an existing panel user).
  3. Pick the Node and the Default Allocation (IP and port).
  4. Set Memory, Disk Space and CPU Limit, plus the Database, Allocation and Backup Limits.
  5. Pick the Nest and the Egg (the game); the Docker image, startup command and variables come from the egg.
  6. Create the server. Wings runs the egg's install script before the server can start.

If it stays on Installing, our Pterodactyl stuck on Installing guide shows how to find the install container and its log on the node.

Eggs

The migration in Step 6 adds these eggs (Panel 1.15.2):

  • Minecraft: Paper, Vanilla Minecraft, Forge Minecraft, BungeeCord and Sponge (SpongeVanilla)
  • Rust
  • Source Engine: Garry's Mod, ARK: Survival Evolved, Counter-Strike: Global Offensive, Team Fortress 2, Insurgency and a custom Source Engine game
  • Voice servers: Mumble and TeamSpeak 3

Minecraft Bedrock, Fabric, FiveM, Valheim and many other games are community eggs on eggs.pterodactyl.io. Download the egg file, import it under Nests with the Import Egg button (choose the nest), then pick it when you create a server. Imported eggs do not update themselves: to update one, download the new file and import it again.

Maintenance Tips

  • Update within 1.x with the docs' Updating the Panel and Upgrading Wings steps. Do not use the panel steps for 2.0: the docs warn they leave a 2.0 panel offline, and 2.0 has its own upgrade guide. Our Pterodactyl 2.0 beta guide covers the 1.15.2 PHP security update and how to test that upgrade on a copy.
  • Monitor disk usage: game servers can grow quickly.
  • Back up the panel database, .env with APP_KEY and each node's config.yml. Our Pterodactyl backup guide covers the full list.
  • Renew certificates on time. Certbot's docs say most installations already schedule certbot renew for you (look for it with systemctl list-timers). The Pterodactyl docs add 0 23 * * * certbot renew --quiet --deploy-hook "systemctl reload nginx" to root's crontab so Nginx reloads after a renewal, and Wings may need systemctl restart wings after its certificate renews.
  • Review server resource usage weekly.

Once installed, your users manage their own servers in the browser and reach their files over SFTP, without needing SSH access to the VPS.

Sources

All opened on 31 October 2026: