15c42e1f24
- add `require_disk_space` function to lib/common.sh with dedup logic for shared filesystems - gate cloudpanel, coolify, pterodactyl installs behind a 2–3 GB disk check - gate uptime-kuma, proxmox update, harden, update-server, and server-benchmark behind 300–1024 MB disk checks - fail early with a clear error before apt installs or config writes can leave the system in a partial state
387 lines
14 KiB
Bash
Executable File
387 lines
14 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# LXS - Proxmox VE Management Script
|
|
# Description: Tools for managing and troubleshooting Proxmox VE
|
|
# 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_proxmox.log"
|
|
|
|
require_root "$0" "$@"
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Configuration
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
LOCKFILE="/var/lib/pve-cluster/.pmxcfs.lockfile"
|
|
SERVICE_NAME="pve-cluster"
|
|
PANEL_PORT=8006
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Helper Functions
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
is_proxmox() {
|
|
[ -f /etc/pve/.version ] || command -v pveversion &> /dev/null
|
|
}
|
|
|
|
get_service_status() {
|
|
if systemctl is-active --quiet $SERVICE_NAME; then
|
|
echo -e "${GREEN}running${NC}"
|
|
else
|
|
echo -e "${RED}stopped${NC}"
|
|
fi
|
|
}
|
|
|
|
check_proxmox() {
|
|
if ! is_proxmox; then
|
|
echo -e "${RED}[!] This is not a Proxmox VE system!${NC}"
|
|
echo -e "${YELLOW} This script is designed for Proxmox VE only.${NC}"
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Login Fix Functions
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
fix_login_issue() {
|
|
local start_time=$(date +%s)
|
|
|
|
echo -e "${WHITE}${BOLD}PROXMOX LOGIN FIX${NC}\n"
|
|
|
|
check_proxmox || return 1
|
|
|
|
echo -e "${CYAN}This will reset the pve-cluster lockfile to fix login issues.${NC}"
|
|
echo ""
|
|
|
|
echo "[1/3] Stopping pve-cluster service..."
|
|
run_spinner "Stopping $SERVICE_NAME..." "systemctl stop $SERVICE_NAME"
|
|
|
|
if [ $? -ne 0 ]; then
|
|
echo -e "${RED}[!] Failed to stop pve-cluster service${NC}"
|
|
return 1
|
|
fi
|
|
echo ""
|
|
|
|
echo "[2/3] Removing lockfile..."
|
|
if [ -f "$LOCKFILE" ]; then
|
|
run_spinner "Removing lockfile..." "rm -f '$LOCKFILE'"
|
|
echo -e "${GRAY} Lockfile was present and has been removed${NC}"
|
|
else
|
|
echo -e "${YELLOW}[!] Lockfile not found (may already be removed)${NC}"
|
|
fi
|
|
echo ""
|
|
|
|
echo "[3/3] Starting pve-cluster service..."
|
|
run_spinner "Starting $SERVICE_NAME..." "systemctl start $SERVICE_NAME"
|
|
|
|
if [ $? -ne 0 ]; then
|
|
echo -e "${RED}[!] Failed to start pve-cluster service${NC}"
|
|
echo -e "${YELLOW} Check logs with: journalctl -xe${NC}"
|
|
return 1
|
|
fi
|
|
|
|
sleep 2
|
|
|
|
local duration=$(( $(date +%s) - start_time ))
|
|
local server_ip=$(hostname -I | awk '{print $1}')
|
|
|
|
echo ""
|
|
show_separator
|
|
echo -e "${GREEN}${BOLD}Fix Completed!${NC}"
|
|
echo -e "${GRAY}Time: ${duration}s${NC}"
|
|
echo ""
|
|
echo -e "${WHITE}Service Status:${NC} $(get_service_status)"
|
|
echo ""
|
|
echo -e "${CYAN}You should now be able to login to the Proxmox web interface.${NC}"
|
|
echo -e "${WHITE}Panel URL: ${GREEN}${BOLD}https://$server_ip:$PANEL_PORT${NC}"
|
|
show_separator
|
|
}
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Service Management Functions
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
restart_pve_cluster() {
|
|
echo -e "${WHITE}${BOLD}RESTART PVE-CLUSTER${NC}\n"
|
|
|
|
check_proxmox || return 1
|
|
|
|
run_spinner "Restarting $SERVICE_NAME..." "systemctl restart $SERVICE_NAME"
|
|
|
|
sleep 2
|
|
|
|
echo ""
|
|
echo -e "${WHITE}Service Status:${NC} $(get_service_status)"
|
|
}
|
|
|
|
restart_all_services() {
|
|
echo -e "${WHITE}${BOLD}RESTART ALL PROXMOX SERVICES${NC}\n"
|
|
|
|
check_proxmox || return 1
|
|
|
|
local services=("pve-cluster" "pvedaemon" "pveproxy" "pvestatd")
|
|
|
|
for service in "${services[@]}"; do
|
|
if systemctl list-unit-files | grep -q "^$service.service"; then
|
|
run_spinner "Restarting $service..." "systemctl restart $service"
|
|
fi
|
|
done
|
|
|
|
sleep 2
|
|
|
|
echo ""
|
|
echo -e "${GREEN}[✓] All services restarted${NC}"
|
|
echo ""
|
|
echo -e "${WHITE}Panel URL: ${GREEN}${BOLD}https://$(hostname -I | awk '{print $1}'):$PANEL_PORT${NC}"
|
|
}
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Status Functions
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
show_status() {
|
|
echo -e "${WHITE}${BOLD}PROXMOX VE STATUS${NC}\n"
|
|
|
|
check_proxmox || return 1
|
|
|
|
# Proxmox version
|
|
echo -e "${WHITE}Proxmox Version:${NC}"
|
|
pveversion 2>/dev/null || echo -e "${GRAY}Unable to determine version${NC}"
|
|
echo ""
|
|
|
|
# Service statuses
|
|
echo -e "${WHITE}Service Status:${NC}"
|
|
local services=("pve-cluster" "pvedaemon" "pveproxy" "pvestatd")
|
|
|
|
for service in "${services[@]}"; do
|
|
if systemctl list-unit-files | grep -q "^$service.service"; then
|
|
if systemctl is-active --quiet $service; then
|
|
echo -e " ${GREEN}[✓]${NC} $service"
|
|
else
|
|
echo -e " ${RED}[✗]${NC} $service"
|
|
fi
|
|
fi
|
|
done
|
|
echo ""
|
|
|
|
# Lockfile status
|
|
if [ -f "$LOCKFILE" ]; then
|
|
echo -e "${WHITE}Lockfile:${NC} ${YELLOW}Present${NC} ($LOCKFILE)"
|
|
else
|
|
echo -e "${WHITE}Lockfile:${NC} ${GREEN}Not present${NC}"
|
|
fi
|
|
echo ""
|
|
|
|
# Access URL
|
|
local server_ip=$(hostname -I | awk '{print $1}')
|
|
echo -e "${WHITE}Panel URL: ${GREEN}${BOLD}https://$server_ip:$PANEL_PORT${NC}"
|
|
echo ""
|
|
|
|
# Cluster info
|
|
if command -v pvecm &> /dev/null; then
|
|
echo -e "${WHITE}Cluster Status:${NC}"
|
|
pvecm status 2>/dev/null | head -5 || echo -e "${GRAY}Not in a cluster or unable to get status${NC}"
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
show_storage_status() {
|
|
echo -e "${WHITE}${BOLD}PROXMOX STORAGE STATUS${NC}\n"
|
|
|
|
check_proxmox || return 1
|
|
|
|
# Storage list
|
|
echo -e "${WHITE}Storage Configuration:${NC}"
|
|
if command -v pvesm &> /dev/null; then
|
|
pvesm status 2>/dev/null || echo -e "${GRAY}Unable to get storage status${NC}"
|
|
else
|
|
echo -e "${GRAY}pvesm command not available${NC}"
|
|
fi
|
|
echo ""
|
|
|
|
# Disk usage
|
|
echo -e "${WHITE}Disk Usage:${NC}"
|
|
df -h / /var /tmp 2>/dev/null | head -5
|
|
|
|
return 0
|
|
}
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Maintenance Functions
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
clear_cache() {
|
|
echo -e "${WHITE}${BOLD}CLEAR PROXMOX CACHE${NC}\n"
|
|
|
|
check_proxmox || return 1
|
|
|
|
echo -e "${CYAN}This will clear various Proxmox caches and temporary files.${NC}"
|
|
echo ""
|
|
|
|
run_spinner "Clearing apt cache..." "apt clean"
|
|
run_spinner "Clearing journal logs (older than 7 days)..." "journalctl --vacuum-time=7d"
|
|
|
|
# Clear task logs older than 30 days
|
|
if [ -d "/var/log/pve/tasks" ]; then
|
|
run_spinner "Clearing old task logs..." "find /var/log/pve/tasks -type f -mtime +30 -delete"
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${GREEN}[✓] Cache cleared${NC}"
|
|
}
|
|
|
|
update_proxmox() {
|
|
echo -e "${WHITE}${BOLD}UPDATE PROXMOX VE${NC}\n"
|
|
|
|
check_proxmox || return 1
|
|
|
|
require_disk_space 1024 || return 1
|
|
|
|
# Configure non-interactive mode
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
export NEEDRESTART_MODE=a
|
|
export NEEDRESTART_SUSPEND=1
|
|
|
|
local start_time=$(date +%s)
|
|
|
|
run_spinner "Updating package lists..." "apt update"
|
|
|
|
echo ""
|
|
echo -e "${PURPLE}[*] Upgrading packages...${NC}"
|
|
show_separator
|
|
apt dist-upgrade -y
|
|
local exit_code=$?
|
|
show_separator
|
|
|
|
if [ $exit_code -eq 0 ]; then
|
|
local duration=$(( $(date +%s) - start_time ))
|
|
echo ""
|
|
echo -e "${GREEN}${BOLD}Update Completed!${NC}"
|
|
echo -e "${GRAY}Time: $((duration / 60))m $((duration % 60))s${NC}"
|
|
echo ""
|
|
echo -e "${YELLOW}[!] A reboot may be required if the kernel was updated.${NC}"
|
|
else
|
|
echo ""
|
|
echo -e "${RED}[✗] Update failed${NC}"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Network Functions
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
show_network_info() {
|
|
echo -e "${WHITE}${BOLD}PROXMOX NETWORK INFO${NC}\n"
|
|
|
|
check_proxmox || return 1
|
|
|
|
local server_ip=$(hostname -I | awk '{print $1}')
|
|
local public_ip=$(get_public_ip)
|
|
|
|
echo -e "${WHITE}Hostname:${NC} $(hostname)"
|
|
echo -e "${WHITE}Local IP:${NC} $server_ip"
|
|
echo -e "${WHITE}Public IP:${NC} $public_ip"
|
|
echo ""
|
|
|
|
echo -e "${WHITE}Network Interfaces:${NC}"
|
|
ip -br addr show 2>/dev/null || ifconfig 2>/dev/null | grep -E "^[a-z]|inet "
|
|
echo ""
|
|
|
|
echo -e "${WHITE}Bridges:${NC}"
|
|
if command -v brctl &> /dev/null; then
|
|
brctl show 2>/dev/null || echo -e "${GRAY}No bridges found${NC}"
|
|
else
|
|
ip link show type bridge 2>/dev/null || echo -e "${GRAY}No bridges found${NC}"
|
|
fi
|
|
|
|
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
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
show_menu() {
|
|
clear
|
|
echo -e "${WHITE}${BOLD}PROXMOX VE MANAGEMENT${NC}\n"
|
|
echo -e " ${GREEN}[1]${NC} Fix Login Issue (reset lockfile)"
|
|
echo -e " ${YELLOW}[2]${NC} Restart pve-cluster service"
|
|
echo -e " ${YELLOW}[3]${NC} Restart all Proxmox services"
|
|
echo -e " ${CYAN}[4]${NC} View System Status"
|
|
echo -e " ${CYAN}[5]${NC} View Storage Status"
|
|
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-9]: "
|
|
}
|
|
|
|
main() {
|
|
while true; do
|
|
show_menu
|
|
read -r choice
|
|
echo ""
|
|
|
|
case $choice in
|
|
1) fix_login_issue ;;
|
|
2) restart_pve_cluster ;;
|
|
3) restart_all_services ;;
|
|
4) show_status ;;
|
|
5) show_storage_status ;;
|
|
6) show_network_info ;;
|
|
7) update_proxmox ;;
|
|
8) clear_cache ;;
|
|
9) open_firewall_ports ;;
|
|
0) return 75 ;;
|
|
*) echo -e "${RED}Invalid option${NC}" ;;
|
|
esac
|
|
|
|
echo ""
|
|
read -p "Press Enter to continue..."
|
|
done
|
|
}
|
|
|
|
main
|
|
|