From dda32051ac43ebcbe05195e634545c2b55ce83ec Mon Sep 17 00:00:00 2001 From: Hyko Date: Tue, 12 May 2026 17:46:31 -0400 Subject: [PATCH] feat(ufw): auto-open firewall ports after app installation - 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] --- apps/cloudpanel.sh | 15 ++++++++++++- apps/coolify.sh | 6 +++++- apps/proxmox.sh | 36 ++++++++++++++++++++++++++++--- apps/pterodactyl.sh | 7 +++++- apps/uptime-kuma.sh | 12 ++++++++--- lib/common.sh | 19 ++++++++++++++++ lxs.sh | 4 ---- tools/system-tools.sh | 50 +++++++++++++++++++++++++++++++++++++++++-- 8 files changed, 134 insertions(+), 15 deletions(-) diff --git a/apps/cloudpanel.sh b/apps/cloudpanel.sh index bc2e073..c18cbd6 100755 --- a/apps/cloudpanel.sh +++ b/apps/cloudpanel.sh @@ -283,7 +283,20 @@ install_cloudpanel() { fi echo -e "${GREEN}[✓] Installation completed${NC}" - + + ufw_allow 20/tcp "CloudPanel FTP data" + ufw_allow 21/tcp "CloudPanel FTP" + ufw_allow 25/tcp "CloudPanel SMTP" + ufw_allow 53/tcp "CloudPanel DNS (TCP)" + ufw_allow 53/udp "CloudPanel DNS (UDP)" + ufw_allow 80/tcp "CloudPanel HTTP" + ufw_allow 443/tcp "CloudPanel HTTPS" + ufw_allow 465/tcp "CloudPanel SMTPS" + ufw_allow 587/tcp "CloudPanel submission" + ufw_allow 993/tcp "CloudPanel IMAPS" + ufw_allow 995/tcp "CloudPanel POP3S" + ufw_allow "${PANEL_PORT}/tcp" "CloudPanel admin" + # Configure Basic Auth configure_cloudpanel_basic_auth diff --git a/apps/coolify.sh b/apps/coolify.sh index 91a125d..a1fed20 100755 --- a/apps/coolify.sh +++ b/apps/coolify.sh @@ -93,10 +93,14 @@ install_coolify() { sleep 2 done + ufw_allow 80/tcp "Coolify HTTP" + ufw_allow 443/tcp "Coolify HTTPS" + ufw_allow "${PORT}/tcp" "Coolify dashboard" + local duration=$(( $(date +%s) - start_time )) local minutes=$((duration / 60)) local seconds=$((duration % 60)) - + echo "" echo -e "${GREEN}${BOLD}Installation Completed Successfully!${NC}" echo -e "${GRAY}Installation time: ${minutes}m ${seconds}s${NC}" diff --git a/apps/proxmox.sh b/apps/proxmox.sh index cec9a63..3cdffb8 100755 --- a/apps/proxmox.sh +++ b/apps/proxmox.sh @@ -306,6 +306,34 @@ show_network_info() { return 0 } +# ═══════════════════════════════════════════════════════════════════════════ +# Firewall +# ═══════════════════════════════════════════════════════════════════════════ + +open_firewall_ports() { + echo -e "${WHITE}${BOLD}OPEN PROXMOX FIREWALL PORTS${NC}\n" + + check_proxmox || return 1 + + if ! command -v ufw >/dev/null 2>&1; then + echo -e "${YELLOW}[!] UFW is not installed on this host. Nothing to do.${NC}" + echo -e "${GRAY} Proxmox uses its own pve-firewall; UFW is optional.${NC}" + return 0 + fi + if ! ufw status 2>/dev/null | grep -q "Status: active"; then + echo -e "${YELLOW}[!] UFW is installed but inactive. Enable it first.${NC}" + return 0 + fi + + ufw_allow "${PANEL_PORT}/tcp" "Proxmox web UI" + ufw_allow 5900:5999/tcp "Proxmox VNC console" + ufw_allow 3128/tcp "Proxmox SPICE proxy" + + echo "" + echo -e "${GRAY}[i] For clustered nodes, also open: 5404-5405/udp (corosync), 60000-60050/tcp (live migration).${NC}" + echo -e "${GRAY}[i] If using NFS storage: 111/tcp+udp and 2049/tcp.${NC}" +} + # ═══════════════════════════════════════════════════════════════════════════ # Main Menu # ═══════════════════════════════════════════════════════════════════════════ @@ -321,9 +349,10 @@ show_menu() { echo -e " ${CYAN}[6]${NC} View Network Info" echo -e " ${PURPLE}[7]${NC} Update Proxmox VE" echo -e " ${PURPLE}[8]${NC} Clear Cache" + echo -e " ${PURPLE}[9]${NC} Open Firewall Ports (UFW)" echo -e " ${RED}[0]${NC} Back to main menu" echo "" - echo -n "Choice [0-8]: " + echo -n "Choice [0-9]: " } main() { @@ -331,7 +360,7 @@ main() { show_menu read -r choice echo "" - + case $choice in 1) fix_login_issue ;; 2) restart_pve_cluster ;; @@ -341,10 +370,11 @@ main() { 6) show_network_info ;; 7) update_proxmox ;; 8) clear_cache ;; + 9) open_firewall_ports ;; 0) return 0 ;; *) echo -e "${RED}Invalid option${NC}" ;; esac - + echo "" read -p "Press Enter to continue..." done diff --git a/apps/pterodactyl.sh b/apps/pterodactyl.sh index e9aa1a5..9319c96 100755 --- a/apps/pterodactyl.sh +++ b/apps/pterodactyl.sh @@ -263,7 +263,12 @@ install_pterodactyl() { 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 "" diff --git a/apps/uptime-kuma.sh b/apps/uptime-kuma.sh index 68aed63..9e84fa4 100755 --- a/apps/uptime-kuma.sh +++ b/apps/uptime-kuma.sh @@ -137,18 +137,24 @@ EOF echo "" echo -e "${CYAN}Access URL: ${BOLD}http://$server_ip:$PORT${NC}" echo "" - + + ufw_allow "${PORT}/tcp" "Uptime Kuma" + # Optional domain configuration echo -e "${WHITE}Configure domain with SSL? (y/n)${NC}" read -n 1 -r echo "" - + if [[ $REPLY =~ ^[Yy]$ ]]; then read -p "Domain name: " DOMAIN_NAME read -p "Email for SSL: " EMAIL echo "" configure_domain_ssl "$DOMAIN_NAME" "$EMAIL" - [ $? -eq 0 ] && echo -e "${GREEN}[✓] Domain configured: ${BOLD}https://$DOMAIN_NAME${NC}" + if [ $? -eq 0 ]; then + echo -e "${GREEN}[✓] Domain configured: ${BOLD}https://$DOMAIN_NAME${NC}" + ufw_allow 80/tcp "Uptime Kuma HTTP (nginx)" + ufw_allow 443/tcp "Uptime Kuma HTTPS (nginx)" + fi fi echo "" diff --git a/lib/common.sh b/lib/common.sh index e4244e1..38b2fd1 100644 --- a/lib/common.sh +++ b/lib/common.sh @@ -122,6 +122,25 @@ apt_noninteractive() { echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections 2>/dev/null || true } +# Add a UFW allow rule, but only if UFW is installed AND active. No-op +# otherwise — so app installers can declare the ports they need without +# forcing UFW on hosts that don't use it. +# +# Usage: +# ufw_allow 8000/tcp "Coolify dashboard" +# ufw_allow 80/tcp +ufw_allow() { + command -v ufw >/dev/null 2>&1 || return 0 + ufw status 2>/dev/null | grep -q "Status: active" || return 0 + local rule=$1 comment=${2:-} + if [ -n "$comment" ]; then + ufw allow "$rule" comment "$comment" >/dev/null + else + ufw allow "$rule" >/dev/null + fi + ok "UFW: allowed ${rule}${comment:+ (${comment})}" +} + # Wait for other apt/dpkg processes to release their locks. Up to 120s. wait_for_apt() { command -v apt >/dev/null 2>&1 || return 0 diff --git a/lxs.sh b/lxs.sh index 5b846e8..46f4b70 100755 --- a/lxs.sh +++ b/lxs.sh @@ -425,8 +425,6 @@ main_menu() { echo "" echo -e " ${GREEN}[1]${NC} Applications" echo -e " ${CYAN}[2]${NC} System Tools" - echo -e " ${PURPLE}[3]${NC} Server Benchmark" - echo -e " ${YELLOW}[4]${NC} Harden Server" echo -e " ${GRAY}[u]${NC} Update lxs" echo -e " ${RED}[0]${NC} Exit" echo "" @@ -436,8 +434,6 @@ main_menu() { case $choice in 1) menu_install_apps ;; 2) download_and_run "tools/system-tools.sh" ;; - 3) download_and_run "tools/server-benchmark.sh" ;; - 4) download_and_run "tools/harden.sh" ;; u|U) cmd_update ;; 0) clear diff --git a/tools/system-tools.sh b/tools/system-tools.sh index a6114a5..2351c79 100755 --- a/tools/system-tools.sh +++ b/tools/system-tools.sh @@ -12,6 +12,44 @@ eval "$_lib" unset _lib export LXS_LOG_FILE="/tmp/lxs_system_tools.log" +# Run a sibling tool script. Prefers a file next to this script (installed +# layout); falls back to downloading from LXS_RAW_BASE. +run_sibling() { + local script_path=$1 + shift + local script_name self_dir resolved src="${BASH_SOURCE[0]}" + script_name=$(basename "$script_path") + + if [ -n "$src" ]; then + resolved=$(readlink -f "$src" 2>/dev/null) \ + || resolved=$(realpath "$src" 2>/dev/null) \ + || resolved="$src" + self_dir=$(dirname "$resolved") + fi + + if [ -n "$self_dir" ] && [ -f "${self_dir}/${script_name}" ]; then + chmod +x "${self_dir}/${script_name}" 2>/dev/null || true + "${self_dir}/${script_name}" "$@" + return $? + fi + + local temp_file exit_code + temp_file=$(mktemp "/tmp/lxs.${script_name%.*}.XXXXXX.sh") + echo -e "${PURPLE}[*] Downloading ${BOLD}${script_name}${NC}${PURPLE}...${NC}" + if curl -fsSL -H "Cache-Control: no-cache" -o "${temp_file}" "${LXS_RAW_BASE}/${script_path}"; then + echo -e "${GREEN}[✓] Downloaded${NC}" + chmod +x "${temp_file}" + "${temp_file}" "$@" + exit_code=$? + rm -f "${temp_file}" + return $exit_code + else + echo -e "${RED}[✗] Failed to download ${script_path}${NC}" + rm -f "${temp_file}" + return 1 + fi +} + # Menu: System Tools menu_system_tools() { while true; do @@ -28,9 +66,11 @@ menu_system_tools() { echo -e " ${CYAN}[6]${NC} View system logs (last 50 lines)" echo -e " ${CYAN}[7]${NC} Show top resource-consuming processes" echo -e " ${CYAN}[8]${NC} Check disk health (SMART)" + echo -e " ${PURPLE}[9]${NC} Server Benchmark" + echo -e " ${YELLOW}[10]${NC} Harden Server" echo -e " ${RED}[0]${NC} Exit" echo "" - echo -e -n "${BOLD}Choice [0-8]: ${NC}" + echo -e -n "${BOLD}Choice [0-10]: ${NC}" read -r choice echo "" @@ -266,11 +306,17 @@ menu_system_tools() { fi fi ;; + 9) + run_sibling "tools/server-benchmark.sh" + ;; + 10) + run_sibling "tools/harden.sh" + ;; 0) exit 0 ;; *) - echo -e "${RED}[✗] Invalid option. Please select 0-8.${NC}" + echo -e "${RED}[✗] Invalid option. Please select 0-10.${NC}" sleep 2 continue ;;