#!/bin/bash set -e ###################################################################################### # Interceptor de flags del sistema for arg in "$@"; do case $arg in -v | --version) echo "pterodactyl-installer v2.3.1" exit 0 ;; -h | --help) echo "Uso: bash install.sh [opciones]" echo "" echo "Opciones:" echo " -v, --version Mostrar versión del script" echo " -h, --help Mostrar esta ayuda" echo " --debug Activar modo depuración" echo " --no-update Omitir comprobación de actualizaciones" echo " --template Cargar una plantilla de configuración (local/remota)" echo " --auto Modo automático (usa variables de entorno)" exit 0 ;; --template) TEMPLATE_PATH="${2:-}" shift ;; --auto) export AUTO_MODE=true ;; --debug) echo "* Modo depuración activado" set -x ;; esac done # # # Proyecto 'pterodactyl-installer' # # # # Copyright (C) 2026, Fabian Mendez # # # # Este programa es software libre: puedes redistribuirlo y/o modificarlo # # bajo los términos de la Licencia Pública General GNU publicada por # # la Free Software Foundation, ya sea la versión 3 de la Licencia, o # # (a tu elección) cualquier versión posterior. # # # # Este programa se distribuye con la esperanza de que sea útil, # # pero SIN NINGUNA GARANTÍA; incluso sin la garantía implícita de # # COMERCIALIZACIÓN o APTITUD PARA UN PROPÓSITO PARTICULAR. Consulta la # # Licencia Pública General GNU para más detalles. # # # # Deberías haber recibido una copia de la Licencia Pública General GNU # # junto con este programa. Si no es así, consulta . # # # # https://github.com/pterodactyl-installer/pterodactyl-installer/blob/master/LICENSE # # # # Este script NO está asociado con el Proyecto Pterodactyl oficial. # # https://github.com/FabianMendez3/script-pterodactyl-instaler # # # ###################################################################################### export GITHUB_SOURCE="" export SCRIPT_RELEASE="v2.3.1" export GITHUB_BASE_URL="https://ptero.fabianm.dev" LOG_PATH="/var/log/pterodactyl-installer.log" # --- Manejador de limpieza --- cleanup() { # Variable de código de salida para preservarlo local exit_code=$? # Solo limpiar si estamos usando archivos temporales if [[ -f "/tmp/lib.sh" ]]; then # Usamos color condicional para evitar errores si constants.sh no se cargó echo -e "\n\n ${COLOR_CYAN:-}▶${COLOR_NC:-} Limpiando archivos temporales..." rm -f /tmp/lib.sh # LIB_MODULES se define en lib.sh if [[ -n "${LIB_MODULES[*]:-}" ]]; then for module in "${LIB_MODULES[@]}"; do rm -f "/tmp/$module" done fi fi exit "$exit_code" } # Trap para salida normal, Ctrl+C (SIGINT) y SIGTERM trap cleanup EXIT SIGINT SIGTERM # Comprobar dependencias (curl, sudo, git) dependencies=("curl" "sudo" "git") missing_deps="" for dep in "${dependencies[@]}"; do if ! [ -x "$(command -v "$dep")" ]; then missing_deps="$missing_deps $dep" fi done if [ -n "$missing_deps" ] || ! type whiptail >/dev/null 2>&1; then echo "* Faltan dependencias críticas (curl, git, sudo o whiptail/newt)." echo "* Intentando instalar automáticamente..." if [ -x "$(command -v apt-get)" ]; then # shellcheck disable=SC2086 apt-get update -qq && apt-get install -y -qq $missing_deps whiptail elif [ -x "$(command -v dnf)" ]; then # shellcheck disable=SC2086 dnf install -y -q $missing_deps newt elif [ -x "$(command -v yum)" ]; then # shellcheck disable=SC2086 yum install -y -q $missing_deps newt elif [ -x "$(command -v pacman)" ]; then # shellcheck disable=SC2086 pacman -Sy --noconfirm $missing_deps libnewt elif [ -x "$(command -v apk)" ]; then # shellcheck disable=SC2086 apk add $missing_deps newt else echo "* No se pudo detectar el gestor de paquetes. Por favor instale dependencias manualmente." exit 1 fi echo "* Dependencias instaladas." fi # Cargar lib.sh localmente si se ejecuta desde entorno de desarrollo, de lo contrario descargarlo PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [ -f "$PROJECT_ROOT/lib/lib.sh" ]; then # shellcheck source=lib/lib.sh source "$PROJECT_ROOT/lib/lib.sh" elif [ -f "/vagrant/lib/lib.sh" ]; then # shellcheck source=lib/lib.sh source "/vagrant/lib/lib.sh" else [ -f /tmp/lib.sh ] && rm -f /tmp/lib.sh curl -sSL -A curl --connect-timeout 10 -o /tmp/lib.sh "$GITHUB_BASE_URL/lib/lib.sh?t=$(date +%s)" # Verificar que la descarga es un script válido (el HTML nunca empieza con #!) if ! head -1 /tmp/lib.sh 2>/dev/null | grep -q "^#!"; then echo "* ERROR: No se pudo descargar lib.sh (respuesta inválida del servidor)." echo "* Comprueba tu conexión a Internet e inténtalo de nuevo." rm -f /tmp/lib.sh exit 1 fi # shellcheck source=lib/lib.sh source /tmp/lib.sh fi manage_logs() { if [ -f "$LOG_PATH" ]; then # Obtener el tamaño del log actual en kilobytes local log_size_kb log_size_kb=$(du -k "$LOG_PATH" | cut -f1 2>/dev/null || echo 0) # 2048 KB = 2MB. Si es mayor o igual, archivar el viejo if [ "$log_size_kb" -ge 2048 ]; then mv -f "$LOG_PATH" "${LOG_PATH%.log}.old.log" 2>/dev/null || true touch "$LOG_PATH" chmod 644 "$LOG_PATH" fi fi } # --- Mecanismo de Auto-Actualización --- check_update() { # Omitir si se pasa la bandera --no-update o si estamos en modo depuración estricto [[ "$*" == *"--no-update"* ]] && return # Solo avisar si estamos en una terminal interactiva [ -t 0 ] || return # echo -e " ${COLOR_CYAN}▶${COLOR_NC} Comprobando actualizaciones..." # Timeout corto para no bloquear si no hay internet o el servidor está caído LATEST_VER=$(curl -sSL -A curl --connect-timeout 2 "$GITHUB_BASE_URL/release" 2>/dev/null || echo "") if [ -n "$LATEST_VER" ] && [[ "$LATEST_VER" == v* ]] && [ "$LATEST_VER" != "$SCRIPT_RELEASE" ]; then if tui_yesno "¡Nueva versión disponible! ($LATEST_VER)\n\nVersión actual: $SCRIPT_RELEASE\n\n¿Deseas actualizar el script ahora?" "Actualización Disponible"; then echo -e " ${COLOR_CYAN}▶${COLOR_NC} Descargando actualización..." # Intentar detectar si el script es un archivo físico SCRIPT_PATH=$(readlink -f "$0" 2>/dev/null || echo "$0") if [ -f "$SCRIPT_PATH" ] && [ -w "$SCRIPT_PATH" ]; then if curl -sSL -A curl -o "$SCRIPT_PATH.tmp" "$GITHUB_BASE_URL/install.sh"; then mv "$SCRIPT_PATH.tmp" "$SCRIPT_PATH" chmod +x "$SCRIPT_PATH" tui_msgbox "Script actualizado con éxito. El instalador se reiniciará ahora." "Éxito" exec bash "$SCRIPT_PATH" "$@" --no-update fi else # Si se ejecuta vía curl directo (bash <(curl ...)) exec bash <(curl -sSL -A curl "$GITHUB_BASE_URL/install.sh") "$@" --no-update fi fi fi } execute() { manage_logs echo -e "\n\n* pterodactyl-installer $(date) \n\n" >>$LOG_PATH # Nota: usamos > >(tee -a) en lugar de |& tee para preservar stdin (fd 0) # conectado a la terminal. Con |& tee, bash <(curl...) pierde su stdin. if [ -f "$(dirname "${BASH_SOURCE[0]}")/ui/${1}.sh" ]; then bash "$(dirname "${BASH_SOURCE[0]}")/ui/${1}.sh" > >(tee -a "$LOG_PATH") 2>&1 elif [ -f "/vagrant/ui/${1}.sh" ]; then bash "/vagrant/ui/${1}.sh" > >(tee -a "$LOG_PATH") 2>&1 else run_ui "${1}" > >(tee -a "$LOG_PATH") 2>&1 fi if [[ -n ${2:-} ]]; then if tui_yesno "Instalación de $(basename "$1") completada.\n\n¿Deseas continuar con la instalación de $(basename "$2")?" "Continuar Instalación"; then execute "$2" else tui_msgbox "Instalación de $(basename "$2") cancelada." "Cancelado" exit 1 fi fi } # Inicializar modo desatendido si es necesario if [[ -n "${TEMPLATE_PATH:-}" ]]; then load_template "$TEMPLATE_PATH" elif [[ "${AUTO_MODE:-}" == "true" ]]; then enable_auto_mode fi welcome "" check_update "$@" pre_flight_checks done=false while [ "$done" == false ]; do options=() actions=() idx=0 add_option() { options+=("$1") actions+=("$2") echo -e " ${COLOR_CYAN}[$idx]${COLOR_NC} $1" idx=$((idx + 1)) } echo -e "\n ${COLOR_BOLD}${COLOR_BCYAN}❓ ¿Qué deseas hacer?${COLOR_NC}\n" # 🦅 PTERODACTYL echo -e " ${COLOR_BOLD}${COLOR_BBLUE}🦅 PTERODACTYL & WINGS${COLOR_NC}" add_option "Instalar Panel Pterodactyl" "panel/pterodactyl/panel" add_option "Instalar Wings" "wings/wings" add_option "Instalar Pterodactyl Panel + Wings" "panel/pterodactyl/panel;wings/wings" echo "" # 🐉 REVIACTYL echo -e " ${COLOR_BOLD}${COLOR_BGREEN}🐉 REVIACTYL${COLOR_NC}" add_option "Instalar Reviactyl" "panel/reviactyl/panel_reviactyl" add_option "Instalar Reviactyl + Wings" "panel/reviactyl/panel_reviactyl;wings/wings" add_option "Migrar Pterodactyl ➔ Reviactyl" "panel/reviactyl/reviactyl" add_option "Migrar Reviactyl ➔ Pterodactyl" "panel/reviactyl/reviactyl_to_pterodactyl" echo "" # 🔥 PYRODACTYL echo -e " ${COLOR_BOLD}${COLOR_BRED}🔥 PYRODACTYL & ELYTRA${COLOR_NC}" add_option "Instalar Pyrodactyl" "panel/pyrodactyl/panel_pyrodactyl" add_option "Instalar Elytra (Daemon)" "wings/elytra" add_option "Instalar Pyrodactyl Panel + Elytra" "panel/pyrodactyl/panel_pyrodactyl;wings/elytra" add_option "Migrar a Pyrodactyl" "panel/pyrodactyl/pyrodactyl" echo "" # 🐦 PELICAN echo -e " ${COLOR_BOLD}${COLOR_BCYAN}🐦 PELICAN${COLOR_NC}" add_option "Instalar Pelican Panel" "panel/pterodactyl/pelican" add_option "Instalar Pelican Wings" "wings/pelican_wings" add_option "Instalar Pelican Panel + Wings" "panel/pterodactyl/pelican;wings/pelican_wings" echo "" # 🛠️ MANTENIMIENTO echo -e " ${COLOR_BOLD}${COLOR_MAGENTA}🛠️ MANTENIMIENTO${COLOR_NC}" add_option "Limpiar Basura de Docker" "maintenance/docker_clean" add_option "Reparar Permisos (Fix 500 Error)" "maintenance/fix_permissions" add_option "Limpiar Caché del Sistema" "maintenance/clear_cache" add_option "Crear/Renovar Certificados SSL" "maintenance/ssl_cert" add_option "Configurar Backups (Base de Datos)" "maintenance/backup_db" add_option "Migrar Panel: IP → Dominio" "maintenance/ip_to_domain" add_option "Migrar phpMyAdmin: IP → Dominio" "maintenance/pma_ip_to_domain" add_option "Migración de Panel a otra VPS" "maintenance/hot_migration" add_option "Bypass IP-HTTPS" "maintenance/ip_https_bypass" echo "" # 📦 EXTRAS & GESTIÓN echo -e " ${COLOR_BOLD}${COLOR_BYELLOW}📦 EXTRAS & GESTIÓN${COLOR_NC}" add_option "Instalar phpMyAdmin" "extras/phpmyadmin/phpmyadmin" add_option "Desinstalar phpMyAdmin" "extras/phpmyadmin/uninstall_phpmyadmin" add_option "Actualizar phpMyAdmin" "updaters/phpmyadmin/update_phpmyadmin" add_option "Instalar NookTheme" "extras/nooktheme" add_option "Instalar Blueprint" "extras/blueprint" add_option "Actualizar Blueprint" "updaters/blueprint/blueprint_upgrade" add_option "Actualizar Panel" "updaters/panel/update_panel" add_option "Configurar Proxies" "extras/proxy" add_option "Crear Usuario en Panel" "extras/create_user" add_option "Gestor de Firewall" "extras/firewall" add_option "Restablecer 2FA (Usuario)" "maintenance/reset_2fa" add_option "Desinstalar Panel o Wings" "maintenance/uninstall" add_option "Generar Plantilla (Desatendida)" "extras/generate_template" echo "" echo -n "* Elige una opción 0-$((idx - 1)): " read -r action [ -z "$action" ] && error "Se requiere una opción" && continue if [[ "$action" =~ ^[0-9]+$ ]] && [ "$action" -ge 0 ] && [ "$action" -lt "$idx" ]; then done=true IFS=";" read -r i1 i2 <<<"${actions[$action]}" execute "$i1" "$i2" else error "Opción inválida" fi done # Eliminar lib.sh para que la próxima vez que se ejecute el script se descargue la versión más reciente. rm -rf /tmp/lib.sh