#!/bin/bash # # Proxmox LXC Container Creator v2.1 # Автоматично създаване и конфигуриране на LXC контейнери # Автор: Федя Серафиев / urocibg.eu set -euo pipefail # 🌈 Цветове и Функции RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'; BOLD='\033[1m' print_header() { clear echo -e "${CYAN}${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n $1\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" } print_success() { echo -e "${GREEN}✅ $1${NC}" } print_error() { echo -e "${RED}❌ ГРЕШКА: $1${NC}" } # ---------------------------------------------------------------------------------- # 🌐 Избор на ОС Шаблон (ДИНАМИЧЕН ИЗБОР - С HTTP ЛИНК) # ---------------------------------------------------------------------------------- BASE_URL="http://download.proxmox.com/images/system/" print_header "PROXMOX LXC СЪЗДАТЕЛ – ДИНАМИЧЕН ИЗБОР НА ШАБЛОН" print_success "Свалям списък с най-новите LXC шаблони от $BASE_URL..." # Сваляне, филтриране и сортиране на последните 10 шаблона, като изключваме almalinux mapfile -t ALL_TEMPLATES < <(wget -q -O - "$BASE_URL" | \ grep -o 'href="[^"]*\(tar\.zst\|tar\.xz\)"' | \ grep -v 'almalinux' | \ awk -F'"' '{print $2}' | \ sort -r | \ head -n 10) if [ ${#ALL_TEMPLATES[@]} -eq 0 ]; then print_error "Неуспешно изтегляне на списъка с шаблони. Използвам резервен (статичен) списък." # Резервен (статичен) списък ALL_TEMPLATES=( "debian-12-standard_12.7-1_amd64.tar.xz" "ubuntu-24.04-standard_24.04-2_amd64.tar.zst" "debian-11-standard_11.9-1_amd64.tar.zst" "ubuntu-22.04-standard_22.04-1_amd64.tar.zst" ) fi echo -e "\n${BOLD}Избери ОС (най-новите налични шаблони):${NC}" # Показваме списъка i=1 for tmpl in "${ALL_TEMPLATES[@]}"; do # Форматиране на името за по-кратък и ясен изглед DISPLAY_NAME=$(echo "$tmpl" | sed -E 's/(-standard|_default|(_[0-9]+\.?[0-9]*)+_amd64\.tar\.(zst|xz))//g' | tr '-' ' ' | awk '{$1=toupper(substr($1,1,1)) substr($1,2)}1') RECOMMENDATION="" if [[ "$tmpl" =~ ^debian-12 ]]; then RECOMMENDATION="← Препоръчителен" fi echo -e " $i) $DISPLAY_NAME $RECOMMENDATION" ((i++)) done # Избор на шаблон while :; do read -p "Въведи 1–$((i-1)) [1]: " os_choice os_choice=${os_choice:-1} if [[ "$os_choice" =~ ^[0-9]+$ ]] && (( os_choice >= 1 && os_choice < i )); then TEMPLATE="${ALL_TEMPLATES[os_choice-1]}" # URL за сваляне на избрания шаблон URL="$BASE_URL$TEMPLATE" break else print_error "Невалиден избор." fi done # ---------------------------------------------------------------------------------- # 💡 Настройки на Контейнера # ---------------------------------------------------------------------------------- while :; do read -p "CT ID (напр. 100): " CTID if [[ $CTID =~ ^[0-9]+$ ]] && (( CTID >= 100 )); then if ! pct status "$CTID" &>/dev/null; then break else print_error "Контейнер с ID $CTID вече съществува или е зает." fi else print_error "Невалидно CT ID. Трябва да е число >= 100." fi done read -p "Hostname [lxc-$CTID]: " HOSTNAME; HOSTNAME=${HOSTNAME:-lxc-$CTID} read -p "Storage [local-lvm]: " STORAGE; STORAGE=${STORAGE:-local-lvm} read -p "Disk GB [20]: " DISK; DISK=${DISK:-20} read -p "RAM MB [4096]: " RAM; RAM=${RAM:-4096} read -p "CPU ядра [2]: " CORES; CORES=${CORES:-2} read -p "Bridge [vmbr0]: " BRIDGE; BRIDGE=${BRIDGE:-vmbr0} # 🌐 Мрежови Настройки IP=""; GW=""; DNS="" read -p "Статично IP? (y/N): " yn if [[ $yn =~ ^[Yy]$ ]]; then read -p "IP/MASK (напр. 10.0.0.178/24): " IP read -p "Gateway (Enter = без): " GW DNS="1.1.1.1 8.8.8.8" fi # 🔑 SSH Ключ / Парола SSH_KEY_ARG="" PASSWORD_ARG="" KEY_TEMP_FILE="" echo -e "\n${BOLD}Избери метод за достъп (SSH ключ или парола):${NC}" echo " 1) Добавяне на SSH публичен ключ" echo " 2) Използване на root парола" read -p "Въведи 1 или 2 [1]: " auth_choice if [[ "${auth_choice:-1}" == "1" ]]; then read -p "Път до SSH публичен ключ (Enter за директно поставяне): " keyfile SSH_KEY_CONTENT="" if [[ -f "$keyfile" ]]; then SSH_KEY_CONTENT=$(cat "$keyfile") print_success "Прочетен ключ от файл: $keyfile" elif [[ -z "$keyfile" ]]; then echo -e "${YELLOW}Моля, поставете целия си публичен SSH ключ и натиснете Enter:${NC}" read SSH_KEY_CONTENT if [[ -z "$SSH_KEY_CONTENT" ]]; then print_error "Не е въведен SSH ключ." auth_choice=2 fi else print_error "Файлът с ключ не е намерен ($keyfile)." auth_choice=2 fi if [[ -n "${SSH_KEY_CONTENT:-}" ]]; then KEY_TEMP_FILE=$(mktemp) echo "$SSH_KEY_CONTENT" > "$KEY_TEMP_FILE" SSH_KEY_ARG="--ssh-public-keys $KEY_TEMP_FILE" fi fi if [[ "${auth_choice:-1}" == "2" ]]; then while :; do read -s -p "Root парола: " PASSWORD; echo read -s -p "Повтори парола: " p2; echo if [[ "$PASSWORD" == "$p2" ]]; then PASSWORD_ARG="--password \"$PASSWORD\"" break else print_error "Паролите не съвпадат. Опитай пак." fi done fi # 🔒 Привилегирован/Непривилегирован read -p "Непривилегирован контейнер (препоръчва се)? (Y/n): " u [[ $u =~ ^[Nn]$ ]] && UNPRIVILEGED=0 || UNPRIVILEGED=1 # 📝 Резюме print_header "ПРЕГЛЕД НА НАСТРОЙКИТЕ" echo -e "ОС: $TEMPLATE" echo -e "CTID: $CTID | Hostname: $HOSTNAME" echo -e "Спецификации: $DISK GB / $RAM MB RAM / $CORES ядра (Swap: 0)" echo -e "Мрежа: $BRIDGE | IP: ${IP:-DHCP}" echo -e "Достъп: $([[ -n "$SSH_KEY_ARG" ]] && echo "SSH Key" || echo "Root Парола")" echo -e "Тип: $([[ "$UNPRIVILEGED" == "1" ]] && echo "Непривилегирован" || echo "Привилегирован")" read -p "ГОТОВО? (y/N): " ok [[ $ok =~ ^[Yy]$ ]] || { [[ -n "${KEY_TEMP_FILE:-}" ]] && rm "$KEY_TEMP_FILE"; exit 0; } # ⬇️ Сваляне на Шаблона tmpl="/var/lib/vz/template/cache/$TEMPLATE" if [[ ! -f "$tmpl" ]]; then print_success "Свалям $TEMPLATE ..." wget -q --show-progress -O "$tmpl" "$URL" else print_success "Шаблонът $TEMPLATE вече съществува, пропускам свалянето." fi # ⚙️ Подготовка на Мрежата net="name=eth0,bridge=$BRIDGE,firewall=1" [[ -n "${IP:-}" ]] && net+=",ip=$IP" [[ -n "${GW:-}" ]] && net+=",gw=$GW" # 🏗️ Създаване на Контейнера print_success "Създавам контейнер $CTID ..." # Аргументи: --swap 0 и настройки за сигурност COMMAND="pct create \"$CTID\" \"$tmpl\" \ --hostname \"$HOSTNAME\" --storage \"$STORAGE\" --rootfs \"$STORAGE:$DISK\" \ --memory \"$RAM\" --cores \"$CORES\" --net0 \"$net\" --swap 0 \ --features nesting=1,keyctl=1 --onboot 1 --unprivileged \"$UNPRIVILEGED\" \ $SSH_KEY_ARG \ $PASSWORD_ARG" if ! eval "$COMMAND"; then print_error "Неуспешно създаване на контейнера. Проверете настройките и логовете на Proxmox." [[ -n "${KEY_TEMP_FILE:-}" ]] && rm "$KEY_TEMP_FILE" exit 1 fi # 📝 Добавяне на DNS [[ -n "${IP:-}" ]] && pct set "$CTID" --nameserver "$DNS" # 🚀 Стартиране и Първоначална Настройка print_success "Стартирам контейнер $CTID..." pct start "$CTID" print_success "Изчаквам и инсталирам основни пакети (около 30-50 секунди)..." sleep 8 pct exec "$CTID" -- bash -c "apt update && apt upgrade -y && apt install -y sudo curl wget git nano htop net-tools qemu-guest-agent" >/dev/null 2>&1 # 🥳 Край print_header "ГОТОВО!" echo -e "${GREEN}Контейнер $CTID ($HOSTNAME) е готов и работи!${NC}" echo -e "Влез с: ${CYAN}pct enter $CTID${NC}" [[ -n "$IP" ]] && echo -e "или с: ${CYAN}ssh root@$(echo $IP | cut -d/ -f1)${NC}" # 🧹 Почистване на временен файл, ако е създаден [[ -n "${KEY_TEMP_FILE:-}" ]] && rm "$KEY_TEMP_FILE"