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
Manual Solution
Have customers use playit.gg individually
Requires manual port management
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:
Default egg author email: [Enter to skip]
Application URL:
https://panel.domain.com
Timezone: [Enter for UTC]
[Enter] x5
Cache driver: Type 'no'
[Enter] for remaining prompts
Database configuration:
php artisan p:environment:database
Database prompts:
[Enter] x4
Enter database password
[Enter] to continue
6. Database Migration
php artisan migrate --seed --force
7. Admin Account Creation
php artisan p:user:make
Follow prompts:
Type 'yes'
Email address
Username
First name
Last name
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
Access Cloudflare Zero Trust Dashboard
Navigate to Networks → Create a Tunnel
Name your tunnel
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
Settings → Locations
Create new location
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?