Installing Pterodactyl Panel with Cloudflare Tunnel

This guide will walk you through installing Pterodactyl Panel and Wings behind a Cloudflared, including SFTP configuration. This setup eliminates the need to open ports for the panel, wings, or SFTP.

Table of Contents

  • Prerequisites

  • Port Forwarding Alternatives

  • Panel Installation

  • Wings Installation

  • Cloudflare Tunnel Configuration

  • SMTP Setup

  • SFTP Configuration

  • Troubleshooting

Prerequisites

Supported Operating Systems

  • Ubuntu 20.04, 22.04, 24.04

  • RHEL / Rocky Linux / Alma Linux 8, 9

  • Debian 11, 12

Requirements

  • Domain name (any registrar)

  • Domain configured with Cloudflare DNS

Port Forwarding Alternatives

While some game servers may require port forwarding, there are alternatives:

Playit.gg Integration

  1. Manual Solution

    • Have customers use playit.gg individually

    • Requires manual port management

  2. Automated Solution (In Development)

    • Automatic IP generation via playit.gg

    • Currently limited by lack of API

    • Requirements:

      • Manual IP creation or Playit team collaboration

      • Pterodactyl feature integration

      • Firewall implementation

      • Manual port forwarding for each customer

    • Potential for firewall feature with manual review

Panel Installation

1. Dependencies Installation

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

# Add PHP repository
LC_ALL=C.UTF-8 add-apt-repository -y ppa:ondrej/php

# Add Redis 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

For Ubuntu 20.04 only:

curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash

Update and install packages:

apt update
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

2. Composer Installation

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

3. Panel Setup

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/

4. Database Configuration

Access MySQL/MariaDB:

mysql -u root -p
# Or for MariaDB:
mariadb -u root -p

Create database and user:

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

5. Environment Setup

cp .env.example .env
COMPOSER_ALLOW_SUPERUSER=1 composer install --no-dev --optimize-autoloader
php artisan key:generate --force

Configure environment:

php artisan p:environment:setup

Setup prompts:

  1. Default egg author email: [Enter to skip]

  2. Application URL: https://panel.domain.com

  3. Timezone: [Enter for UTC]

  4. [Enter] x5

  5. Cache driver: Type 'no'

  6. [Enter] for remaining prompts

Database configuration:

php artisan p:environment:database

Database prompts:

  1. [Enter] x4

  2. Enter database password

  3. [Enter] to continue

6. Database Migration

php artisan migrate --seed --force

7. Admin Account Creation

php artisan p:user:make

Follow prompts:

  1. Type 'yes'

  2. Email address

  3. Username

  4. First name

  5. Last name

  6. Password

8. Directory Permissions

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

9. Crontab Configuration

Add to crontab:

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

10. Queue Worker Setup

Create service file:

sudo nano /etc/systemd/system/pteroq.service

Add content:

[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 services:

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

11. Nginx Configuration

Remove default config:

rm /etc/nginx/sites-enabled/default

Create SSL certificates:

mkdir -p /etc/certs
cd /etc/certs
openssl req -new -newkey rsa:4096 -days 3650 -nodes -x509 -subj "/C=NA/ST=NA/L=NA/O=NA/CN=Generic SSL Certificate" -keyout privkey.pem -out fullchain.pem

Create Nginx configuration:

nano /etc/nginx/sites-available/pterodactyl.conf

Add configuration:

server {
    listen 80;
    server_name your_domain;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name 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/certs/fullchain.pem;
    ssl_certificate_key /etc/certs/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;

    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;
    }

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

Replace your_domain with server's local IP (use ip a).

For non-RHEL systems:

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

Restart Nginx:

sudo systemctl restart nginx

Wings Installation

1. Docker Installation

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

2. Swap Configuration (Skip for WSL)

Edit GRUB configuration:

nano /etc/default/grub

Add swapaccount=1 to GRUB_CMDLINE_LINUX_DEFAULT, then:

sudo update-grub
sudo reboot

3. Wings Setup

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

Cloudflare Tunnel Configuration

1. Create Tunnel

  1. Access Cloudflare Zero Trust Dashboard

  2. Navigate to Networks → Create a Tunnel

  3. Name your tunnel

  4. Choose Docker deployment

2. Deploy Tunnel

Modify the provided Docker command:

docker run -d --restart unless-stopped [cloudflare-provided-command]

3. Configure Public Hostnames

Panel Configuration

  • Subdomain: panel

  • Type: HTTPS

  • URL: [local-IP]

  • Enable "No TLS Verify"

Wings Configuration

  • Subdomain: node

  • Type: HTTPS

  • URL: [local-IP]:8080

  • Enable "No TLS Verify"

4. Panel Node Configuration

  1. Settings → Locations

    • Create new location

  2. Nodes → Create New

    • Name: [your choice]

    • FQDN: node.domain.com

    • Memory: [set limit]

    • Disk: [set limit]

    • Update daemon port to 443

SMTP Setup

[In Progress - Email configuration documentation]

SFTP Configuration

Troubleshooting

Database Connection Issues

  • Verify credentials in .env

  • Check database service status

  • Confirm proper permissions

Cloudflare Tunnel Problems

  • Verify tunnel token

  • Check Docker logs

  • Confirm hostname configuration

Permission Issues

  • Verify directory ownership

  • Check service user settings

  • Confirm SSL certificate permissions

SSL Certificate Errors

  • Verify certificate paths

  • Check certificate validity

  • Confirm permissions

Additional Resources

Last updated

Was this helpful?