dda32051ac
- cloudpanel: allow ftp, smtp, dns, http, https, smtps, imaps, pop3s, and admin panel ports - coolify: allow http, https, and dashboard port after install - pterodactyl: allow http, https, wings daemon (8080), and sftp (2022) ports - uptime-kuma: allow app port on install - proxmox: add open_firewall_ports() with ufw guard checks and new menu option [9]
336 lines
12 KiB
Bash
Executable File
336 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# LXS - Pterodactyl Installation Script
|
|
# Description: Install Pterodactyl Panel + Wings
|
|
# Author: LXS
|
|
# Date: 2025
|
|
|
|
# Load LXS common library (colors, separator, run_spinner, loggers, helpers)
|
|
LXS_RAW_BASE="${LXS_RAW_BASE:-https://git.hyko.cx/hykocx/lxs/raw/branch/main}"
|
|
_lib=$(curl -fsSL "${LXS_RAW_BASE}/lib/common.sh") || { echo "Failed to fetch lib/common.sh" >&2; exit 1; }
|
|
eval "$_lib"
|
|
unset _lib
|
|
export LXS_LOG_FILE="/tmp/lxs_pterodactyl.log"
|
|
|
|
require_root "$0" "$@"
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Configuration
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
PANEL_DIR="/var/www/pterodactyl"
|
|
WINGS_DIR="/etc/pterodactyl"
|
|
DB_NAME="panel"
|
|
DB_USER="pterodactyl"
|
|
DB_HOST="127.0.0.1"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Helper Functions
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
is_installed() {
|
|
[ -d "$PANEL_DIR" ] && systemctl list-unit-files | grep -q "pteroq.service"
|
|
}
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Installation Functions
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
install_dependencies() {
|
|
apt_noninteractive
|
|
|
|
run_spinner "Updating system..." "apt update -qq"
|
|
run_spinner "Installing dependencies..." "apt install -y -qq software-properties-common curl -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold'"
|
|
run_spinner "Adding PHP repository..." "LC_ALL=C.UTF-8 add-apt-repository -y ppa:ondrej/php && apt update -qq"
|
|
run_spinner "Installing PHP and services..." "apt install -y -qq php8.3 php8.3-{cli,gd,mysql,mbstring,bcmath,xml,fpm,curl,zip} mariadb-server nginx tar unzip git redis-server -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold'"
|
|
}
|
|
|
|
install_composer() {
|
|
run_spinner "Installing Composer..." "curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer --quiet"
|
|
}
|
|
|
|
setup_database() {
|
|
DB_PASS=$(generate_password)
|
|
|
|
echo -e "${PURPLE}[*] Configuring database...${NC}"
|
|
systemctl start mariadb && systemctl enable mariadb
|
|
|
|
mysql -u root <<MYSQL_SCRIPT
|
|
CREATE DATABASE IF NOT EXISTS ${DB_NAME};
|
|
CREATE USER IF NOT EXISTS '${DB_USER}'@'${DB_HOST}' IDENTIFIED BY '${DB_PASS}';
|
|
GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'${DB_HOST}';
|
|
FLUSH PRIVILEGES;
|
|
MYSQL_SCRIPT
|
|
|
|
[ $? -eq 0 ] && echo -e "${GREEN}[✓] Database configured${NC}" || { echo -e "${RED}[✗] Database failed${NC}"; return 1; }
|
|
}
|
|
|
|
install_panel() {
|
|
mkdir -p $PANEL_DIR && cd $PANEL_DIR
|
|
run_spinner "Downloading Panel..." "curl -Lo panel.tar.gz https://github.com/pterodactyl/panel/releases/latest/download/panel.tar.gz"
|
|
run_spinner "Extracting..." "tar -xzf panel.tar.gz"
|
|
run_spinner "Setting permissions..." "chmod -R 755 storage/* bootstrap/cache/"
|
|
}
|
|
|
|
configure_panel() {
|
|
cd $PANEL_DIR
|
|
|
|
echo -e "${PURPLE}[*] Installing dependencies (this may take a few minutes)...${NC}"
|
|
export COMPOSER_ALLOW_SUPERUSER=1
|
|
COMPOSER_ALLOW_SUPERUSER=1 composer install --no-dev --optimize-autoloader --no-interaction > /tmp/lxs_composer.log 2>&1
|
|
|
|
cp .env.example .env
|
|
php artisan key:generate --force
|
|
|
|
sed -i "s/DB_DATABASE=.*/DB_DATABASE=${DB_NAME}/" .env
|
|
sed -i "s/DB_USERNAME=.*/DB_USERNAME=${DB_USER}/" .env
|
|
sed -i "s/DB_PASSWORD=.*/DB_PASSWORD=${DB_PASS}/" .env
|
|
|
|
run_spinner "Running migrations..." "php artisan migrate --seed --force"
|
|
|
|
echo ""
|
|
echo -e "${WHITE}${BOLD}Admin Account Setup${NC}"
|
|
read -p "Email: " ADMIN_EMAIL
|
|
read -p "Username: " ADMIN_USERNAME
|
|
read -p "First Name: " ADMIN_FIRSTNAME
|
|
read -p "Last Name: " ADMIN_LASTNAME
|
|
read -sp "Password: " ADMIN_PASSWORD
|
|
echo ""
|
|
|
|
php artisan p:user:make --email="$ADMIN_EMAIL" --username="$ADMIN_USERNAME" --name-first="$ADMIN_FIRSTNAME" --name-last="$ADMIN_LASTNAME" --password="$ADMIN_PASSWORD" --admin=1 --no-interaction
|
|
|
|
chown -R www-data:www-data $PANEL_DIR
|
|
}
|
|
|
|
configure_nginx() {
|
|
local domain=$1
|
|
|
|
cat > /etc/nginx/sites-available/pterodactyl.conf <<'EOF'
|
|
server {
|
|
listen 80;
|
|
server_name DOMAIN_PLACEHOLDER;
|
|
root /var/www/pterodactyl/public;
|
|
index index.php;
|
|
|
|
location / {
|
|
try_files $uri $uri/ /index.php?$query_string;
|
|
}
|
|
|
|
location ~ \.php$ {
|
|
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
|
|
fastcgi_index index.php;
|
|
include fastcgi_params;
|
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
|
}
|
|
}
|
|
EOF
|
|
|
|
sed -i "s/DOMAIN_PLACEHOLDER/$domain/g" /etc/nginx/sites-available/pterodactyl.conf
|
|
ln -sf /etc/nginx/sites-available/pterodactyl.conf /etc/nginx/sites-enabled/
|
|
rm -f /etc/nginx/sites-enabled/default
|
|
|
|
nginx -t && systemctl restart nginx php8.3-fpm
|
|
}
|
|
|
|
configure_ssl() {
|
|
local domain=$1
|
|
local email=$2
|
|
|
|
run_spinner "Installing Certbot..." "apt install -y -qq certbot python3-certbot-nginx -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold'"
|
|
certbot --nginx -d $domain --non-interactive --agree-tos --email $email --redirect 2>/dev/null
|
|
|
|
[ $? -eq 0 ] && cd $PANEL_DIR && sed -i "s|APP_URL=.*|APP_URL=https://${domain}|" .env
|
|
}
|
|
|
|
setup_services() {
|
|
cat > /etc/systemd/system/pteroq.service <<'EOF'
|
|
[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
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
systemctl enable --now redis-server pteroq.service
|
|
(crontab -l 2>/dev/null; echo "* * * * * php /var/www/pterodactyl/artisan schedule:run >> /dev/null 2>&1") | crontab -
|
|
}
|
|
|
|
install_docker() {
|
|
run_spinner "Installing Docker..." "curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && \
|
|
echo \"deb [arch=\$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \$(lsb_release -cs) stable\" | tee /etc/apt/sources.list.d/docker.list > /dev/null && \
|
|
apt update -qq && apt install -y -qq docker-ce docker-ce-cli containerd.io -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold'"
|
|
systemctl enable --now docker
|
|
}
|
|
|
|
install_wings() {
|
|
mkdir -p $WINGS_DIR
|
|
run_spinner "Installing Wings..." "curl -L -o /usr/local/bin/wings https://github.com/pterodactyl/wings/releases/latest/download/wings_linux_amd64 && chmod +x /usr/local/bin/wings"
|
|
|
|
cat > /etc/systemd/system/wings.service <<'EOF'
|
|
[Unit]
|
|
Description=Pterodactyl Wings
|
|
After=docker.service
|
|
Requires=docker.service
|
|
|
|
[Service]
|
|
User=root
|
|
WorkingDirectory=/etc/pterodactyl
|
|
ExecStart=/usr/local/bin/wings
|
|
Restart=on-failure
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
systemctl daemon-reload
|
|
}
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Main Installation
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
install_pterodactyl() {
|
|
local start_time=$(date +%s)
|
|
|
|
# Configure non-interactive mode globally
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
export NEEDRESTART_MODE=a
|
|
export NEEDRESTART_SUSPEND=1
|
|
|
|
echo -e "${WHITE}${BOLD}PTERODACTYL INSTALLATION${NC}\n"
|
|
|
|
if is_installed; then
|
|
echo -e "${YELLOW}Pterodactyl is already installed!${NC}"
|
|
return 0
|
|
fi
|
|
|
|
echo "[1/10] Installing dependencies..."
|
|
install_dependencies && install_composer
|
|
echo ""
|
|
|
|
echo "[2/10] Setting up database..."
|
|
setup_database
|
|
echo ""
|
|
|
|
echo "[3/10] Installing Panel..."
|
|
install_panel
|
|
echo ""
|
|
|
|
echo "[4/10] Configuring Panel..."
|
|
configure_panel
|
|
echo ""
|
|
|
|
echo "[5/10] Domain configuration..."
|
|
read -p "Panel domain (e.g., panel.example.com): " PANEL_DOMAIN
|
|
read -p "Wings domain (e.g., wings.example.com): " WINGS_DOMAIN
|
|
read -p "Email for SSL: " SSL_EMAIL
|
|
echo ""
|
|
|
|
echo "[6/10] Configuring Nginx..."
|
|
configure_nginx "$PANEL_DOMAIN"
|
|
echo ""
|
|
|
|
echo "[7/10] Configuring SSL..."
|
|
configure_ssl "$PANEL_DOMAIN" "$SSL_EMAIL"
|
|
echo ""
|
|
|
|
echo "[8/10] Setting up services..."
|
|
setup_services
|
|
echo ""
|
|
|
|
echo "[9/10] Installing Wings..."
|
|
install_docker && install_wings
|
|
echo ""
|
|
|
|
echo "[10/10] Wings configuration..."
|
|
echo -e "${YELLOW}Configure Wings from Panel: Admin -> Nodes -> Create Node${NC}"
|
|
echo -e "${GRAY}Node settings:${NC}"
|
|
echo -e " FQDN: ${CYAN}$WINGS_DOMAIN${NC}"
|
|
echo -e " SSL: ${CYAN}Yes${NC}"
|
|
echo -e " Port: ${CYAN}8080${NC}"
|
|
echo ""
|
|
|
|
read -p "Press Enter when ready to paste Wings config..."
|
|
echo -e "${CYAN}Paste config and press Ctrl+D:${NC}"
|
|
cat > /etc/pterodactyl/config.yml
|
|
|
|
[ -s /etc/pterodactyl/config.yml ] && systemctl enable --now wings
|
|
|
|
ufw_allow 80/tcp "Pterodactyl HTTP"
|
|
ufw_allow 443/tcp "Pterodactyl HTTPS"
|
|
ufw_allow 8080/tcp "Pterodactyl Wings daemon"
|
|
ufw_allow 2022/tcp "Pterodactyl Wings SFTP"
|
|
|
|
local duration=$(( $(date +%s) - start_time ))
|
|
|
|
echo ""
|
|
echo -e "${GREEN}${BOLD}Installation Completed!${NC}"
|
|
echo -e "${GRAY}Time: $((duration / 60))m $((duration % 60))s${NC}"
|
|
echo ""
|
|
echo -e "${CYAN}Panel: ${BOLD}https://$PANEL_DOMAIN${NC}"
|
|
echo -e "${CYAN}Wings: ${BOLD}$WINGS_DOMAIN:8080${NC}"
|
|
echo ""
|
|
echo -e "${WHITE}Database Credentials:${NC}"
|
|
echo -e " Host: $DB_HOST"
|
|
echo -e " Database: $DB_NAME"
|
|
echo -e " User: $DB_USER"
|
|
echo -e " Password: $DB_PASS"
|
|
}
|
|
|
|
show_status() {
|
|
echo -e "${WHITE}${BOLD}PTERODACTYL STATUS${NC}\n"
|
|
|
|
if ! is_installed; then
|
|
echo -e "${RED}Pterodactyl is not installed!${NC}"
|
|
return 1
|
|
fi
|
|
|
|
systemctl is-active --quiet pteroq && echo -e "${GREEN}[✓] Panel Queue${NC}" || echo -e "${RED}[✗] Panel Queue${NC}"
|
|
systemctl is-active --quiet nginx && echo -e "${GREEN}[✓] Web Server${NC}" || echo -e "${RED}[✗] Web Server${NC}"
|
|
systemctl is-active --quiet wings && echo -e "${GREEN}[✓] Wings${NC}" || echo -e "${YELLOW}[!] Wings (needs config)${NC}"
|
|
|
|
return 0
|
|
}
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Main Menu
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
show_menu() {
|
|
clear
|
|
echo -e "${WHITE}${BOLD}PTERODACTYL MANAGEMENT${NC}\n"
|
|
echo -e " ${GREEN}[1]${NC} Install Pterodactyl"
|
|
echo -e " ${CYAN}[2]${NC} View Status"
|
|
echo -e " ${RED}[0]${NC} Back to main menu"
|
|
echo ""
|
|
echo -n "Choice [0-2]: "
|
|
}
|
|
|
|
main() {
|
|
while true; do
|
|
show_menu
|
|
read -r choice
|
|
echo ""
|
|
|
|
case $choice in
|
|
1) install_pterodactyl ;;
|
|
2) show_status ;;
|
|
0) return 0 ;;
|
|
*) echo -e "${RED}Invalid option${NC}" ;;
|
|
esac
|
|
|
|
echo ""
|
|
read -p "Press Enter to continue..."
|
|
done
|
|
}
|
|
|
|
main
|