feat: initial project scaffold for lxs multi-tool
- add main entrypoint with interactive menu and CLI dispatcher (lxs.sh) - add shared helpers library with colors, loggers, and spinner (lib/common.sh) - add app installers for coolify, pterodactyl, uptime-kuma, cloudpanel, and proxmox (apps/) - add system tools for monitoring, benchmarking, and hardening (tools/) - add VERSION file (0.1.0) as single source of truth for releases - add MIT LICENSE - expand README with usage, project structure, and release workflow
This commit is contained in:
Executable
+330
@@ -0,0 +1,330 @@
|
||||
#!/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
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user