#!/bin/bash # DockMon LXC Container Auto-Creation Script for Proxmox # Run this script on your Proxmox host to automatically create and configure DockMon # Usage: bash dockmon-lxc.sh set -e # Ensure /usr/sbin is in PATH for Proxmox commands export PATH="/usr/sbin:/usr/bin:/sbin:/bin:$PATH" # Color codes for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' # No Color # Default Configuration (modify as needed) CONTAINER_ID="" # Leave empty for next available ID CONTAINER_NAME="dockmon" DEBIAN_VERSION="" # Will be selected by user TEMPLATE="" # Will be set based on Debian version STORAGE="local-lvm" DISK_SIZE="4" MEMORY="512" SWAP="512" CORES="1" BRIDGE="vmbr0" IP_CONFIG="dhcp" # Set to "dhcp" or specify like "192.168.1.100/24" GATEWAY="" # Set if using static IP, e.g., "192.168.1.1" DNS="" # Leave empty for host settings or set like "8.8.8.8" ROOT_PASSWORD="" # Will be set by user SSH_KEY="" # Optional: path to SSH public key file START_ON_BOOT="1" # 1 for yes, 0 for no PROXMOX_NODE=$(hostname) # Template options DEBIAN_12_TEMPLATE="debian-12-standard_12.2-1_amd64.tar.zst" DEBIAN_13_TEMPLATE="debian-13-standard_13.0-1_amd64.tar.zst" # GitHub repository GITHUB_REPO="https://github.com/darthnorse/dockmon.git" # Function to print colored output print_info() { echo -e "${BLUE}[INFO]${NC} $1" } print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } print_error() { echo -e "${RED}[ERROR]${NC} $1" } print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } print_cyan() { echo -e "${CYAN}$1${NC}" } # Detect if running in non-interactive mode (curl | bash) INTERACTIVE=true if [[ ! -t 0 ]]; then INTERACTIVE=false fi # Helper function for interactive prompts with defaults prompt_or_default() { local prompt="$1" local default="$2" local result if [[ "$INTERACTIVE" == "true" ]]; then read -p "$prompt" result echo "${result:-$default}" else echo "$default" fi } # Header clear echo -e "${GREEN}════════════════════════════════════════════════════════${NC}" echo -e "${GREEN} DockMon LXC Container Auto-Creation for Proxmox ${NC}" echo -e "${GREEN}════════════════════════════════════════════════════════${NC}" echo "" # Non-interactive mode notification if [[ "$INTERACTIVE" == "false" ]]; then print_info "Non-interactive mode detected - using default settings" print_info "For customization, download and run the script directly" echo "" fi # Check if running on Proxmox VE (community-scripts approach) check_root() { if [[ $EUID -ne 0 ]]; then print_error "This script must be run as root" exit 1 fi } check_proxmox() { if [ "$1" = "--bypass-proxmox-check" ]; then print_info "Bypassing Proxmox check for testing" return 0 fi if ! command -v pveversion >/dev/null 2>&1; then print_error "No PVE Detected!" print_error "This script must be run on a Proxmox VE host" exit 1 fi # Get Proxmox version and validate local pve=$(pveversion | grep "pve-manager" | awk '{print substr($2, 1, 3)}') if [[ ! "$pve" =~ ^(8\.[0-9]|9\.[0-9])$ ]]; then print_error "This version of Proxmox VE is not supported" print_info "Requires PVE Version 8.0 or higher" print_info "Detected: $(pveversion | grep pve-manager)" exit 1 fi print_info "Detected Proxmox VE: $(pveversion | grep pve-manager | awk '{print $2}')" } # Perform checks check_root check_proxmox "$1" # Function to get next available container ID get_next_ctid() { local max_id=100 for ctid in $(pct list 2>/dev/null | tail -n +2 | awk '{print $1}'); do if [ "$ctid" -ge "$max_id" ]; then max_id=$((ctid + 1)) fi done echo $max_id } # Function to check if container ID exists check_ctid_exists() { pct status $1 &>/dev/null return $? } # Function to validate IP address format validate_ip() { if [[ $1 =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then return 0 fi return 1 } # Function to validate IP with CIDR validate_ip_cidr() { if [[ $1 =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$ ]]; then return 0 fi return 1 } # Select Debian version echo -e "${CYAN}Step 1: Select Debian Version${NC}" echo "══════════════════════════════════════" echo "1) Debian 12 (Bookworm) - Stable, Recommended" echo "2) Debian 13 (Trixie) - Testing" echo "" # Interactive vs non-interactive selection if [[ "$INTERACTIVE" == "true" ]]; then # Interactive mode while true; do read -p "Select Debian version (1 or 2): " debian_choice case $debian_choice in 1) DEBIAN_VERSION="12" TEMPLATE=$DEBIAN_12_TEMPLATE print_success "Selected Debian 12 (Bookworm)" break ;; 2) DEBIAN_VERSION="13" TEMPLATE=$DEBIAN_13_TEMPLATE print_success "Selected Debian 13 (Trixie)" break ;; *) print_error "Invalid selection. Please enter 1 or 2" ;; esac done else # Non-interactive mode - use defaults DEBIAN_VERSION="12" TEMPLATE=$DEBIAN_12_TEMPLATE print_success "Using Debian 12 (Bookworm) - default" fi echo "" # Set root password echo -e "${CYAN}Step 2: Set Root Password${NC}" echo "══════════════════════════════════════" echo "Enter the root password for the container" echo "(Password will not be visible while typing)" echo "" if [[ "$INTERACTIVE" == "true" ]]; then while true; do read -s -p "Enter root password: " ROOT_PASSWORD echo read -s -p "Confirm root password: " ROOT_PASSWORD_CONFIRM echo if [ "$ROOT_PASSWORD" != "$ROOT_PASSWORD_CONFIRM" ]; then print_error "Passwords do not match! Please try again." echo "" elif [ -z "$ROOT_PASSWORD" ]; then print_error "Password cannot be empty! Please try again." echo "" else print_success "Root password set successfully" break fi done else # Non-interactive mode - generate random password ROOT_PASSWORD=$(openssl rand -base64 12 2>/dev/null || echo "dockmon123") print_success "Generated random root password: $ROOT_PASSWORD" print_warning "Save this password! It will be displayed again at the end." fi echo "" # Select storage echo -e "${CYAN}Step 3: Select Storage${NC}" echo "══════════════════════════════════════" print_info "Available storage pools:" echo "" pvesm status | grep -E "^[[:alnum:]]" | awk '{printf " %-20s %s\n", $1, "(" $2 ")"}' echo "" while true; do read -p "Select storage pool [$STORAGE]: " input STORAGE=${input:-$STORAGE} # Verify storage exists if pvesm status | grep -q "^$STORAGE "; then print_success "Selected storage: $STORAGE" break else print_error "Storage pool '$STORAGE' not found. Please select from the list above." fi done echo "" # Configuration options echo -e "${CYAN}Step 4: Container Configuration${NC}" echo "══════════════════════════════════════" echo -e "${BLUE}Default Configuration:${NC}" echo " Node: $PROXMOX_NODE" echo " Storage: $STORAGE (selected)" echo " Disk Size: ${DISK_SIZE}GB" echo " Memory: ${MEMORY}MB" echo " CPU Cores: $CORES" echo " Network Bridge: $BRIDGE" echo " IP Configuration: $IP_CONFIG" echo " Start on Boot: $([ $START_ON_BOOT -eq 1 ] && echo 'Yes' || echo 'No')" echo "" read -p "Do you want to customize these settings? (y/n): " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then echo "" print_info "Enter custom configuration (press Enter to keep defaults):" echo "" # Disk size read -p "Disk Size in GB [$DISK_SIZE]: " input DISK_SIZE=${input:-$DISK_SIZE} # Memory read -p "Memory in MB [$MEMORY]: " input MEMORY=${input:-$MEMORY} # CPU cores read -p "CPU Cores [$CORES]: " input CORES=${input:-$CORES} # Network bridge print_cyan "Available bridges:" ip link show type bridge | grep -E "^[0-9]+" | awk -F': ' '{print " - " $2}' read -p "Network Bridge [$BRIDGE]: " input BRIDGE=${input:-$BRIDGE} # IP configuration echo "" print_cyan "IP Configuration:" echo " 1) DHCP (automatic)" echo " 2) Static IP" read -p "Select IP configuration (1 or 2) [1]: " ip_choice if [ "$ip_choice" == "2" ]; then while true; do read -p "Enter IP address with CIDR (e.g., 192.168.1.100/24): " IP_CONFIG if validate_ip_cidr "$IP_CONFIG"; then break else print_error "Invalid IP format. Please use format: 192.168.1.100/24" fi done while true; do read -p "Enter Gateway IP: " GATEWAY if validate_ip "$GATEWAY"; then break else print_error "Invalid gateway IP format" fi done read -p "DNS Server [8.8.8.8]: " input DNS=${input:-"8.8.8.8"} else IP_CONFIG="dhcp" fi # Start on boot read -p "Start container on boot? (y/n) [y]: " -n 1 -r echo if [[ $REPLY =~ ^[Nn]$ ]]; then START_ON_BOOT="0" fi fi echo "" # SSH key option read -p "Do you want to add an SSH public key for root access? (y/n): " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then read -p "Enter path to SSH public key file: " SSH_KEY if [ ! -f "$SSH_KEY" ]; then print_warning "SSH key file not found, skipping SSH key configuration" SSH_KEY="" fi fi echo "" # Get or assign container ID echo -e "${CYAN}Step 5: Container ID Assignment${NC}" echo "══════════════════════════════════════" # Show existing containers for reference print_info "Existing containers:" pct list | head -10 echo "" # Ask user if they want to specify their own ID read -p "Do you want to specify a custom container ID? (y/n) [n]: " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then while true; do read -p "Enter desired container ID (e.g., 200): " CUSTOM_ID # Validate input is a number if ! [[ "$CUSTOM_ID" =~ ^[0-9]+$ ]]; then print_error "Container ID must be a number" continue fi # Check if ID is in valid range (typically 100-999999) if [ "$CUSTOM_ID" -lt 100 ] || [ "$CUSTOM_ID" -gt 999999 ]; then print_error "Container ID should be between 100 and 999999" continue fi # Check if ID already exists if check_ctid_exists $CUSTOM_ID; then print_error "Container ID $CUSTOM_ID already exists!" read -p "Try a different ID? (y/n): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then break fi else CONTAINER_ID=$CUSTOM_ID print_success "Will use Container ID: $CONTAINER_ID" break fi done fi # If no custom ID was set or user cancelled, use next available if [ -z "$CONTAINER_ID" ]; then CONTAINER_ID=$(get_next_ctid) print_info "Using next available Container ID: $CONTAINER_ID" fi echo "" # Download and prepare template dynamically echo -e "${CYAN}Step 6: Template Preparation${NC}" echo "══════════════════════════════════════" # Function to get latest Debian template get_latest_debian_template() { local version=$1 print_info "Fetching latest Debian $version templates from Proxmox..." # Update template list pveam update >/dev/null 2>&1 # Find the latest Debian template for the specified version local available_template=$(pveam available | grep "debian-$version" | grep "standard" | head -1 | awk '{print $2}') if [ -n "$available_template" ]; then echo "$available_template" return 0 else return 1 fi } # Function to download template download_template() { local template_name=$1 local template_path="/var/lib/vz/template/cache/$template_name" print_info "Checking if template exists locally..." if [ -f "$template_path" ]; then print_success "Template already available: $template_name" return 0 fi print_info "Downloading template: $template_name" print_info "This may take several minutes depending on your connection..." # Download the template if pveam download local "$template_name"; then print_success "Template downloaded successfully: $template_name" return 0 else print_error "Failed to download template: $template_name" return 1 fi } # Get the latest template for selected Debian version print_info "Determining latest Debian $DEBIAN_VERSION template..." LATEST_TEMPLATE=$(get_latest_debian_template $DEBIAN_VERSION) if [ -n "$LATEST_TEMPLATE" ]; then print_info "Latest available: $LATEST_TEMPLATE" TEMPLATE=$LATEST_TEMPLATE else print_warning "Could not find latest template, using fallback..." if [ "$DEBIAN_VERSION" == "12" ]; then TEMPLATE=$DEBIAN_12_TEMPLATE else TEMPLATE=$DEBIAN_13_TEMPLATE fi # Check if fallback template exists in available list if ! pveam available | grep -q "$TEMPLATE"; then print_error "Fallback template $TEMPLATE not available!" print_info "Available Debian $DEBIAN_VERSION templates:" pveam available | grep "debian-$DEBIAN_VERSION" | awk '{print " - " $2}' exit 1 fi fi # Download the template if ! download_template "$TEMPLATE"; then # If download fails, try to find any available Debian template for this version print_warning "Primary download failed, searching for alternative templates..." available_templates=$(pveam available | grep "debian-$DEBIAN_VERSION" | awk '{print $2}') if [ -n "$available_templates" ]; then print_info "Available Debian $DEBIAN_VERSION templates:" echo "$available_templates" | nl -w2 -s'. ' echo "" while true; do read -p "Select template number (or 0 to exit): " template_num if [ "$template_num" == "0" ]; then print_error "Template selection cancelled" exit 1 fi selected_template=$(echo "$available_templates" | sed -n "${template_num}p") if [ -n "$selected_template" ]; then TEMPLATE=$selected_template if download_template "$TEMPLATE"; then break else print_error "Failed to download selected template" fi else print_error "Invalid selection. Please try again." fi done else print_error "No Debian $DEBIAN_VERSION templates available!" exit 1 fi fi TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE" print_success "Template ready: $TEMPLATE" echo "" # Build network configuration if [ "$IP_CONFIG" == "dhcp" ]; then NET_CONFIG="name=eth0,bridge=$BRIDGE,ip=dhcp" else NET_CONFIG="name=eth0,bridge=$BRIDGE,ip=$IP_CONFIG" if [ -n "$GATEWAY" ]; then NET_CONFIG="$NET_CONFIG,gw=$GATEWAY" fi fi # Create the container echo -e "${CYAN}Step 7: Creating LXC Container${NC}" echo "══════════════════════════════════════" print_info "Creating container with ID $CONTAINER_ID..." print_info "Using template: $TEMPLATE" # Create temporary file for password PASS_FILE=$(mktemp) echo -e "$ROOT_PASSWORD\n$ROOT_PASSWORD" > "$PASS_FILE" # Create container with password from file print_info "Executing container creation..." pct create $CONTAINER_ID "$TEMPLATE_PATH" \ --hostname $CONTAINER_NAME \ --storage $STORAGE \ --rootfs $STORAGE:$DISK_SIZE \ --memory $MEMORY \ --swap $SWAP \ --cores $CORES \ --net0 $NET_CONFIG \ --features nesting=1 \ --unprivileged 1 \ --onboot $START_ON_BOOT \ --password < "$PASS_FILE" # Remove temporary password file rm -f "$PASS_FILE" if [ $? -ne 0 ]; then print_error "Failed to create container!" exit 1 fi print_success "Container $CONTAINER_ID created successfully!" # Set DNS if specified if [ -n "$DNS" ]; then pct set $CONTAINER_ID --nameserver "$DNS" fi # Add SSH key if provided if [ -n "$SSH_KEY" ] && [ -f "$SSH_KEY" ]; then print_info "Adding SSH key..." pct set $CONTAINER_ID --ssh-public-keys "$SSH_KEY" fi echo "" # Start the container echo -e "${CYAN}Step 8: Starting Container${NC}" echo "══════════════════════════════════════" print_info "Starting container..." pct start $CONTAINER_ID # Wait for container to be ready print_info "Waiting for container to be ready..." sleep 10 # Get container IP print_info "Getting container IP address..." for i in {1..30}; do CONTAINER_IP=$(pct exec $CONTAINER_ID -- ip -4 addr show eth0 2>/dev/null | grep inet | awk '{print $2}' | cut -d/ -f1) if [ -n "$CONTAINER_IP" ]; then break fi sleep 2 done if [ -z "$CONTAINER_IP" ]; then print_warning "Could not determine container IP address" CONTAINER_IP="" fi echo "" # Install DockMon inside the container echo -e "${CYAN}Step 9: Installing DockMon${NC}" echo "══════════════════════════════════════" print_info "Installing DockMon in the container..." # Create installation script cat << 'INSTALL_SCRIPT' > /tmp/install-dockmon.sh #!/bin/bash set -e # Update system echo "Updating system packages..." apt-get update DEBIAN_FRONTEND=noninteractive apt-get upgrade -y # Install required packages echo "Installing nginx, git, Python 3, and required dependencies..." DEBIAN_FRONTEND=noninteractive apt-get install -y nginx git curl python3 python3-pip python3-venv supervisor # Clone DockMon repository echo "Cloning DockMon repository..." cd /opt git clone https://github.com/darthnorse/dockmon.git # Set up Python backend echo "Setting up DockMon backend..." cd /opt/dockmon/backend # Create virtual environment python3 -m venv venv source venv/bin/activate # Install Python dependencies pip install --no-cache-dir -r requirements.txt # Create data directory mkdir -p /opt/dockmon/backend/data chown -R www-data:www-data /opt/dockmon/backend/data # Copy application to web root echo "Setting up DockMon frontend..." cp /opt/dockmon/src/index.html /var/www/html/index.html cp -r /opt/dockmon/images /var/www/html/ # Update frontend to point to backend API (if needed) sed -i 's|http://localhost:8080|http://localhost:8080|g' /var/www/html/index.html # Configure nginx to serve on port 8001 echo "Configuring nginx for port 8001..." cat << 'NGINX_CONF' > /etc/nginx/sites-available/dockmon server { listen 8001 default_server; listen [::]:8001 default_server; root /var/www/html; index index.html; server_name _; location / { try_files \$uri \$uri/ =404; } # Optional: Add some basic security headers add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; } NGINX_CONF # Enable the new site and disable default ln -sf /etc/nginx/sites-available/dockmon /etc/nginx/sites-enabled/ rm -f /etc/nginx/sites-enabled/default # Configure nginx to start on boot systemctl enable nginx systemctl restart nginx # Create systemd service for DockMon backend cat << 'BACKEND_SERVICE' > /etc/systemd/system/dockmon-backend.service [Unit] Description=DockMon Backend API After=network.target Wants=network.target [Service] Type=simple User=www-data Group=www-data WorkingDirectory=/opt/dockmon/backend Environment=PYTHONPATH=/opt/dockmon/backend ExecStart=/opt/dockmon/backend/venv/bin/python main.py Restart=always RestartSec=10 [Install] WantedBy=multi-user.target BACKEND_SERVICE # Create supervisor configuration as backup process manager cat << 'SUPERVISOR_CONF' > /etc/supervisor/conf.d/dockmon-backend.conf [program:dockmon-backend] command=/opt/dockmon/backend/venv/bin/python main.py directory=/opt/dockmon/backend user=www-data autostart=true autorestart=true stderr_logfile=/var/log/dockmon-backend.err.log stdout_logfile=/var/log/dockmon-backend.out.log environment=PYTHONPATH="/opt/dockmon/backend" SUPERVISOR_CONF # Create a simple frontend systemd service cat << 'FRONTEND_SERVICE' > /etc/systemd/system/dockmon-frontend.service [Unit] Description=DockMon Web Interface After=network.target nginx.service dockmon-backend.service Requires=nginx.service Wants=dockmon-backend.service [Service] Type=oneshot ExecStart=/bin/true RemainAfterExit=yes [Install] WantedBy=multi-user.target FRONTEND_SERVICE systemctl daemon-reload systemctl enable dockmon-backend.service systemctl enable dockmon-frontend.service systemctl start dockmon-backend.service # Start supervisor as backup systemctl enable supervisor systemctl start supervisor # Create update script echo "Creating update script..." cat << 'UPDATE_SCRIPT' > /usr/local/bin/update #!/bin/bash # DockMon Update Script # Updates both the system and DockMon to latest versions set -e # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Functions for colored output print_info() { echo -e "\${BLUE}[INFO]\${NC} \$1" } print_success() { echo -e "\${GREEN}[SUCCESS]\${NC} \$1" } print_error() { echo -e "\${RED}[ERROR]\${NC} \$1" } print_warning() { echo -e "\${YELLOW}[WARNING]\${NC} \$1" } # Header echo -e "\${GREEN}════════════════════════════════════════\${NC}" echo -e "\${GREEN} DockMon System Update Tool \${NC}" echo -e "\${GREEN}════════════════════════════════════════\${NC}" echo "" # Check if running as root if [ "\$EUID" -ne 0 ]; then print_error "This script must be run as root!" print_info "Try: sudo update" exit 1 fi # Step 1: Update Debian packages echo -e "\${BLUE}Step 1: Updating Debian System\${NC}" echo "════════════════════════════════════" print_info "Updating package lists..." apt-get update print_info "Upgrading installed packages..." DEBIAN_FRONTEND=noninteractive apt-get upgrade -y print_info "Performing distribution upgrade..." DEBIAN_FRONTEND=noninteractive apt-get dist-upgrade -y print_info "Removing unnecessary packages..." apt-get autoremove -y print_info "Cleaning package cache..." apt-get autoclean print_success "System update completed!" echo "" # Step 2: Update DockMon echo -e "\${BLUE}Step 2: Updating DockMon\${NC}" echo "════════════════════════════════════" # Check if DockMon directory exists if [ ! -d "/opt/dockmon" ]; then print_error "DockMon directory not found at /opt/dockmon" print_info "Attempting to clone repository..." cd /opt git clone https://github.com/darthnorse/dockmon.git if [ \$? -ne 0 ]; then print_error "Failed to clone DockMon repository" exit 1 fi fi # Navigate to DockMon directory cd /opt/dockmon # Store current version (if exists) if [ -f "src/index.html" ]; then OLD_VERSION=\$(grep -oP 'DockMon v\K[0-9.]+' src/index.html | head -1 || echo "unknown") else OLD_VERSION="not installed" fi print_info "Current version: \$OLD_VERSION" # Fetch latest changes print_info "Fetching latest updates from GitHub..." git fetch origin # Check if there are updates LOCAL=\$(git rev-parse HEAD) REMOTE=\$(git rev-parse origin/main) if [ "\$LOCAL" = "\$REMOTE" ]; then print_info "DockMon is already up to date" else print_info "Updates available, pulling latest version..." # Pull latest changes git pull origin main if [ \$? -ne 0 ]; then print_warning "Git pull failed, attempting to reset..." git reset --hard origin/main fi # Get new version NEW_VERSION=\$(grep -oP 'DockMon v\K[0-9.]+' src/index.html | head -1 || echo "unknown") print_success "Updated DockMon from v\$OLD_VERSION to v\$NEW_VERSION" fi # Update the web application print_info "Deploying updated application..." cp -f /opt/dockmon/src/index.html /var/www/html/index.html cp -rf /opt/dockmon/images /var/www/html/ if [ \$? -eq 0 ]; then print_success "Application deployed successfully!" else print_error "Failed to deploy application" exit 1 fi # Restart nginx to ensure everything is fresh print_info "Restarting web server..." systemctl restart nginx if systemctl is-active --quiet nginx; then print_success "Web server restarted successfully!" else print_error "Web server failed to restart" exit 1 fi echo "" # Step 3: Check for script updates echo -e "\${BLUE}Step 3: Checking for Script Updates\${NC}" echo "════════════════════════════════════" # Check if this update script itself needs updating if [ -f "/opt/dockmon/scripts/update.sh" ]; then if ! cmp -s "/opt/dockmon/scripts/update.sh" "/usr/local/bin/update"; then print_info "Update script has a newer version, updating..." cp -f /opt/dockmon/scripts/update.sh /usr/local/bin/update chmod +x /usr/local/bin/update print_success "Update script updated! Please run 'update' again if needed." else print_info "Update script is current" fi fi echo "" # Summary echo -e "\${GREEN}════════════════════════════════════════\${NC}" echo -e "\${GREEN} Update Complete! ✅ \${NC}" echo -e "\${GREEN}════════════════════════════════════════\${NC}" echo "" echo -e "\${BLUE}Summary:\${NC}" echo "• System packages: Updated" echo "• DockMon application: \$([ "\$LOCAL" = "\$REMOTE" ] && echo "Already current" || echo "Updated")" echo "• Web server: Running" echo "" echo -e "\${BLUE}DockMon Access:\${NC}" echo "• Web Interface: http://\$(hostname -I | awk '{print \$1}')" echo "" # Check if reboot is required if [ -f /var/run/reboot-required ]; then echo -e "\${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\${NC}" echo -e "\${YELLOW}⚠️ REBOOT REQUIRED\${NC}" echo -e "\${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\${NC}" echo "A system reboot is required to complete updates." echo "Please run: reboot" echo "" fi exit 0 UPDATE_SCRIPT # Make update script executable and accessible chmod +x /usr/local/bin/update # Create shorter alias ln -sf /usr/local/bin/update /usr/local/bin/dockmon-update # Also create the update script in the repository for future updates mkdir -p /opt/dockmon/scripts cp /usr/local/bin/update /opt/dockmon/scripts/update.sh chmod +x /opt/dockmon/scripts/update.sh echo "DockMon installation completed!" INSTALL_SCRIPT # Copy and execute installation script in container pct push $CONTAINER_ID /tmp/install-dockmon.sh /tmp/install-dockmon.sh pct exec $CONTAINER_ID -- chmod +x /tmp/install-dockmon.sh pct exec $CONTAINER_ID -- /tmp/install-dockmon.sh # Clean up rm /tmp/install-dockmon.sh # Final status check print_info "Verifying installation..." if pct exec $CONTAINER_ID -- systemctl is-active nginx >/dev/null 2>&1; then print_success "Nginx is running" else print_warning "Nginx might not be running properly" fi echo "" # Summary echo -e "${GREEN}════════════════════════════════════════════════════════${NC}" echo -e "${GREEN} DockMon Installation Complete! 🎉 ${NC}" echo -e "${GREEN}════════════════════════════════════════════════════════${NC}" echo "" echo -e "${BLUE}Container Details:${NC}" echo "══════════════════════════════════════" echo "Container ID: $CONTAINER_ID" echo "Container Name: $CONTAINER_NAME" echo "Debian Version: $DEBIAN_VERSION" echo "IP Address: $CONTAINER_IP" echo "Memory: ${MEMORY}MB" echo "Disk Size: ${DISK_SIZE}GB" echo "CPU Cores: $CORES" echo "Start on Boot: $([ $START_ON_BOOT -eq 1 ] && echo 'Yes' || echo 'No')" echo "" echo -e "${BLUE}Access DockMon:${NC}" echo "══════════════════════════════════════" echo -e "Web Interface: ${GREEN}http://$CONTAINER_IP:8001${NC}" echo -e "SSH Access: ${GREEN}ssh root@$CONTAINER_IP${NC}" echo "" echo -e "${BLUE}Container Management:${NC}" echo "══════════════════════════════════════" echo "Start: pct start $CONTAINER_ID" echo "Stop: pct stop $CONTAINER_ID" echo "Restart: pct restart $CONTAINER_ID" echo "Console: pct console $CONTAINER_ID" echo "Remove: pct destroy $CONTAINER_ID" echo "" echo -e "${YELLOW}Notes:${NC}" echo "• Template used: $TEMPLATE (downloaded automatically)" echo "• Frontend (nginx) serves on port 8001" echo "• Backend API runs on port 8080" echo "• Root password: (the password you set)" echo "• Services: dockmon-backend, dockmon-frontend, nginx, supervisor" echo "• To update DockMon, run inside container: update" echo "• Backend logs: journalctl -u dockmon-backend -f" echo "• Supervisor logs: tail -f /var/log/dockmon-backend.out.log" echo "" echo -e "${GREEN}Enjoy DockMon!${NC} 🐳"