#!/usr/bin/env bash # LisiLou Portfolio - Proxmox LXC Helper Script # Run this script on your Proxmox host to create an LXC container with the portfolio 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 # Default values CTID="${CTID:-}" HOSTNAME="${HOSTNAME:-lisilou-portfolio}" MEMORY="${MEMORY:-512}" DISK="${DISK:-4}" CORES="${CORES:-1}" STORAGE="${STORAGE:-local-lvm}" TEMPLATE_STORAGE="${TEMPLATE_STORAGE:-local}" BRIDGE="${BRIDGE:-vmbr0}" REPO_URL="https://github.com/jhodgkin/lisilou-portfolio.git" header() { echo -e "\n${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo -e "${BLUE} $1${NC}" echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n" } msg() { echo -e "${GREEN}[INFO]${NC} $1" } warn() { echo -e "${YELLOW}[WARN]${NC} $1" } error() { echo -e "${RED}[ERROR]${NC} $1" exit 1 } header "LisiLou Photography Portfolio - Proxmox Installer" # Check if running on Proxmox if ! command -v pveversion &> /dev/null; then error "This script must be run on a Proxmox VE host" fi msg "Proxmox VE $(pveversion | cut -d'/' -f2) detected" # Get next available CTID if not specified if [ -z "$CTID" ]; then CTID=$(pvesh get /cluster/nextid) msg "Using next available CTID: $CTID" fi # Prompt for configuration echo "" read -p "Container ID [$CTID]: " input CTID="${input:-$CTID}" read -p "Hostname [$HOSTNAME]: " input HOSTNAME="${input:-$HOSTNAME}" read -p "Memory in MB [$MEMORY]: " input MEMORY="${input:-$MEMORY}" read -p "Disk size in GB [$DISK]: " input DISK="${input:-$DISK}" read -p "CPU cores [$CORES]: " input CORES="${input:-$CORES}" read -p "Storage [$STORAGE]: " input STORAGE="${input:-$STORAGE}" read -p "Network bridge [$BRIDGE]: " input BRIDGE="${input:-$BRIDGE}" echo "" read -p "Use DHCP for networking? [Y/n]: " use_dhcp use_dhcp="${use_dhcp:-Y}" if [[ "${use_dhcp,,}" != "y" ]]; then read -p "IP Address (e.g., 192.168.1.100/24): " IP_ADDR read -p "Gateway: " GATEWAY NET_CONFIG="name=eth0,bridge=$BRIDGE,ip=$IP_ADDR,gw=$GATEWAY" else NET_CONFIG="name=eth0,bridge=$BRIDGE,ip=dhcp" fi # Download Debian template if not exists header "Checking Container Template" msg "Updating template list..." pveam update # Check for existing local templates first msg "Checking for existing templates..." EXISTING=$(pveam list $TEMPLATE_STORAGE 2>/dev/null | grep "debian-12" | head -1 | awk '{print $1}') if [ -n "$EXISTING" ]; then TEMPLATE="$EXISTING" msg "Found existing template: $TEMPLATE" else # Find available Debian 12 template msg "Available Debian templates:" pveam available --section system | grep -i debian echo "" TEMPLATE=$(pveam available --section system | grep -i "debian-12" | head -1 | awk '{print $2}') if [ -z "$TEMPLATE" ]; then warn "Could not auto-detect Debian 12 template." echo "" echo "Available system templates:" pveam available --section system echo "" read -p "Enter template name to use: " TEMPLATE if [ -z "$TEMPLATE" ]; then error "No template specified. Exiting." fi fi msg "Downloading $TEMPLATE..." pveam download $TEMPLATE_STORAGE $TEMPLATE || error "Failed to download template" TEMPLATE="$TEMPLATE_STORAGE:vztmpl/$TEMPLATE" fi # Create container header "Creating LXC Container" msg "Creating container $CTID ($HOSTNAME)..." msg "Using template: $TEMPLATE" pct create $CTID "$TEMPLATE" \ --hostname $HOSTNAME \ --memory $MEMORY \ --cores $CORES \ --rootfs $STORAGE:$DISK \ --net0 $NET_CONFIG \ --unprivileged 1 \ --features nesting=1,keyctl=1 \ --onboot 1 \ --start 0 msg "Container created successfully" # Start container msg "Starting container..." pct start $CTID sleep 5 # Wait for network msg "Waiting for network..." for i in {1..30}; do if pct exec $CTID -- ping -c 1 google.com &> /dev/null; then break fi sleep 2 done # Install Docker and setup application header "Installing Docker & Application" pct exec $CTID -- bash -c " set -e echo '[INFO] Updating system...' apt-get update apt-get upgrade -y echo '[INFO] Installing dependencies...' apt-get install -y ca-certificates curl gnupg git echo '[INFO] Adding Docker repository...' install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg chmod a+r /etc/apt/keyrings/docker.gpg echo \"deb [arch=\$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \$(. /etc/os-release && echo \$VERSION_CODENAME) stable\" > /etc/apt/sources.list.d/docker.list echo '[INFO] Installing Docker...' apt-get update apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin echo '[INFO] Enabling Docker service...' systemctl enable docker systemctl start docker echo '[INFO] Cloning repository...' cd /opt git clone $REPO_URL cd lisilou-portfolio echo '[INFO] Creating Docker network...' docker network create web || true echo '[INFO] Starting application...' docker compose up -d echo '[INFO] Installation complete!' " # Get container IP header "Installation Complete!" CONTAINER_IP=$(pct exec $CTID -- hostname -I | awk '{print $1}') echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo -e "${GREEN} LisiLou Portfolio has been deployed successfully!${NC}" echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo "" echo -e " ${BLUE}Container ID:${NC} $CTID" echo -e " ${BLUE}Hostname:${NC} $HOSTNAME" echo -e " ${BLUE}IP Address:${NC} $CONTAINER_IP" echo -e " ${BLUE}Portfolio URL:${NC} http://$CONTAINER_IP:8080" echo "" echo -e " ${YELLOW}Configuration:${NC}" echo -e " Edit: /opt/lisilou-portfolio/config/site.json" echo "" echo -e " ${YELLOW}Useful commands (run inside container):${NC}" echo -e " pct enter $CTID" echo -e " cd /opt/lisilou-portfolio" echo -e " docker compose logs -f" echo -e " docker compose restart" echo "" echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"