urocibg ha revisionato questo gist . Vai alla revisione
1 file changed, 229 insertions
lxc.sh(file creato)
| @@ -0,0 +1,229 @@ | |||
| 1 | + | #!/bin/bash | |
| 2 | + | # | |
| 3 | + | # Proxmox LXC Container Creator v2.1 | |
| 4 | + | # Автоматично създаване и конфигуриране на LXC контейнери | |
| 5 | + | # Автор: Федя Серафиев / urocibg.eu | |
| 6 | + | ||
| 7 | + | set -euo pipefail | |
| 8 | + | ||
| 9 | + | # 🌈 Цветове и Функции | |
| 10 | + | RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'; BOLD='\033[1m' | |
| 11 | + | ||
| 12 | + | print_header() { | |
| 13 | + | clear | |
| 14 | + | echo -e "${CYAN}${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n $1\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" | |
| 15 | + | } | |
| 16 | + | ||
| 17 | + | print_success() { | |
| 18 | + | echo -e "${GREEN}✅ $1${NC}" | |
| 19 | + | } | |
| 20 | + | ||
| 21 | + | print_error() { | |
| 22 | + | echo -e "${RED}❌ ГРЕШКА: $1${NC}" | |
| 23 | + | } | |
| 24 | + | ||
| 25 | + | # ---------------------------------------------------------------------------------- | |
| 26 | + | # 🌐 Избор на ОС Шаблон (ДИНАМИЧЕН ИЗБОР - С HTTP ЛИНК) | |
| 27 | + | # ---------------------------------------------------------------------------------- | |
| 28 | + | BASE_URL="http://download.proxmox.com/images/system/" | |
| 29 | + | print_header "PROXMOX LXC СЪЗДАТЕЛ – ДИНАМИЧЕН ИЗБОР НА ШАБЛОН" | |
| 30 | + | ||
| 31 | + | print_success "Свалям списък с най-новите LXC шаблони от $BASE_URL..." | |
| 32 | + | ||
| 33 | + | # Сваляне, филтриране и сортиране на последните 10 шаблона, като изключваме almalinux | |
| 34 | + | mapfile -t ALL_TEMPLATES < <(wget -q -O - "$BASE_URL" | \ | |
| 35 | + | grep -o 'href="[^"]*\(tar\.zst\|tar\.xz\)"' | \ | |
| 36 | + | grep -v 'almalinux' | \ | |
| 37 | + | awk -F'"' '{print $2}' | \ | |
| 38 | + | sort -r | \ | |
| 39 | + | head -n 10) | |
| 40 | + | ||
| 41 | + | if [ ${#ALL_TEMPLATES[@]} -eq 0 ]; then | |
| 42 | + | print_error "Неуспешно изтегляне на списъка с шаблони. Използвам резервен (статичен) списък." | |
| 43 | + | # Резервен (статичен) списък | |
| 44 | + | ALL_TEMPLATES=( | |
| 45 | + | "debian-12-standard_12.7-1_amd64.tar.xz" | |
| 46 | + | "ubuntu-24.04-standard_24.04-2_amd64.tar.zst" | |
| 47 | + | "debian-11-standard_11.9-1_amd64.tar.zst" | |
| 48 | + | "ubuntu-22.04-standard_22.04-1_amd64.tar.zst" | |
| 49 | + | ) | |
| 50 | + | fi | |
| 51 | + | ||
| 52 | + | echo -e "\n${BOLD}Избери ОС (най-новите налични шаблони):${NC}" | |
| 53 | + | ||
| 54 | + | # Показваме списъка | |
| 55 | + | i=1 | |
| 56 | + | for tmpl in "${ALL_TEMPLATES[@]}"; do | |
| 57 | + | # Форматиране на името за по-кратък и ясен изглед | |
| 58 | + | 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') | |
| 59 | + | ||
| 60 | + | RECOMMENDATION="" | |
| 61 | + | if [[ "$tmpl" =~ ^debian-12 ]]; then | |
| 62 | + | RECOMMENDATION="← Препоръчителен" | |
| 63 | + | fi | |
| 64 | + | ||
| 65 | + | echo -e " $i) $DISPLAY_NAME $RECOMMENDATION" | |
| 66 | + | ((i++)) | |
| 67 | + | done | |
| 68 | + | ||
| 69 | + | # Избор на шаблон | |
| 70 | + | while :; do | |
| 71 | + | read -p "Въведи 1–$((i-1)) [1]: " os_choice | |
| 72 | + | os_choice=${os_choice:-1} | |
| 73 | + | if [[ "$os_choice" =~ ^[0-9]+$ ]] && (( os_choice >= 1 && os_choice < i )); then | |
| 74 | + | TEMPLATE="${ALL_TEMPLATES[os_choice-1]}" | |
| 75 | + | # URL за сваляне на избрания шаблон | |
| 76 | + | URL="$BASE_URL$TEMPLATE" | |
| 77 | + | break | |
| 78 | + | else | |
| 79 | + | print_error "Невалиден избор." | |
| 80 | + | fi | |
| 81 | + | done | |
| 82 | + | ||
| 83 | + | # ---------------------------------------------------------------------------------- | |
| 84 | + | # 💡 Настройки на Контейнера | |
| 85 | + | # ---------------------------------------------------------------------------------- | |
| 86 | + | while :; do | |
| 87 | + | read -p "CT ID (напр. 100): " CTID | |
| 88 | + | if [[ $CTID =~ ^[0-9]+$ ]] && (( CTID >= 100 )); then | |
| 89 | + | if ! pct status "$CTID" &>/dev/null; then | |
| 90 | + | break | |
| 91 | + | else | |
| 92 | + | print_error "Контейнер с ID $CTID вече съществува или е зает." | |
| 93 | + | fi | |
| 94 | + | else | |
| 95 | + | print_error "Невалидно CT ID. Трябва да е число >= 100." | |
| 96 | + | fi | |
| 97 | + | done | |
| 98 | + | ||
| 99 | + | read -p "Hostname [lxc-$CTID]: " HOSTNAME; HOSTNAME=${HOSTNAME:-lxc-$CTID} | |
| 100 | + | read -p "Storage [local-lvm]: " STORAGE; STORAGE=${STORAGE:-local-lvm} | |
| 101 | + | read -p "Disk GB [20]: " DISK; DISK=${DISK:-20} | |
| 102 | + | read -p "RAM MB [4096]: " RAM; RAM=${RAM:-4096} | |
| 103 | + | read -p "CPU ядра [2]: " CORES; CORES=${CORES:-2} | |
| 104 | + | read -p "Bridge [vmbr0]: " BRIDGE; BRIDGE=${BRIDGE:-vmbr0} | |
| 105 | + | ||
| 106 | + | # 🌐 Мрежови Настройки | |
| 107 | + | IP=""; GW=""; DNS="" | |
| 108 | + | read -p "Статично IP? (y/N): " yn | |
| 109 | + | if [[ $yn =~ ^[Yy]$ ]]; then | |
| 110 | + | read -p "IP/MASK (напр. 10.0.0.178/24): " IP | |
| 111 | + | read -p "Gateway (Enter = без): " GW | |
| 112 | + | DNS="1.1.1.1 8.8.8.8" | |
| 113 | + | fi | |
| 114 | + | ||
| 115 | + | # 🔑 SSH Ключ / Парола | |
| 116 | + | SSH_KEY_ARG="" | |
| 117 | + | PASSWORD_ARG="" | |
| 118 | + | KEY_TEMP_FILE="" | |
| 119 | + | ||
| 120 | + | echo -e "\n${BOLD}Избери метод за достъп (SSH ключ или парола):${NC}" | |
| 121 | + | echo " 1) Добавяне на SSH публичен ключ" | |
| 122 | + | echo " 2) Използване на root парола" | |
| 123 | + | read -p "Въведи 1 или 2 [1]: " auth_choice | |
| 124 | + | ||
| 125 | + | if [[ "${auth_choice:-1}" == "1" ]]; then | |
| 126 | + | read -p "Път до SSH публичен ключ (Enter за директно поставяне): " keyfile | |
| 127 | + | ||
| 128 | + | SSH_KEY_CONTENT="" | |
| 129 | + | if [[ -f "$keyfile" ]]; then | |
| 130 | + | SSH_KEY_CONTENT=$(cat "$keyfile") | |
| 131 | + | print_success "Прочетен ключ от файл: $keyfile" | |
| 132 | + | elif [[ -z "$keyfile" ]]; then | |
| 133 | + | echo -e "${YELLOW}Моля, поставете целия си публичен SSH ключ и натиснете Enter:${NC}" | |
| 134 | + | read SSH_KEY_CONTENT | |
| 135 | + | if [[ -z "$SSH_KEY_CONTENT" ]]; then | |
| 136 | + | print_error "Не е въведен SSH ключ." | |
| 137 | + | auth_choice=2 | |
| 138 | + | fi | |
| 139 | + | else | |
| 140 | + | print_error "Файлът с ключ не е намерен ($keyfile)." | |
| 141 | + | auth_choice=2 | |
| 142 | + | fi | |
| 143 | + | ||
| 144 | + | if [[ -n "${SSH_KEY_CONTENT:-}" ]]; then | |
| 145 | + | KEY_TEMP_FILE=$(mktemp) | |
| 146 | + | echo "$SSH_KEY_CONTENT" > "$KEY_TEMP_FILE" | |
| 147 | + | SSH_KEY_ARG="--ssh-public-keys $KEY_TEMP_FILE" | |
| 148 | + | fi | |
| 149 | + | fi | |
| 150 | + | ||
| 151 | + | if [[ "${auth_choice:-1}" == "2" ]]; then | |
| 152 | + | while :; do | |
| 153 | + | read -s -p "Root парола: " PASSWORD; echo | |
| 154 | + | read -s -p "Повтори парола: " p2; echo | |
| 155 | + | if [[ "$PASSWORD" == "$p2" ]]; then | |
| 156 | + | PASSWORD_ARG="--password \"$PASSWORD\"" | |
| 157 | + | break | |
| 158 | + | else | |
| 159 | + | print_error "Паролите не съвпадат. Опитай пак." | |
| 160 | + | fi | |
| 161 | + | done | |
| 162 | + | fi | |
| 163 | + | ||
| 164 | + | # 🔒 Привилегирован/Непривилегирован | |
| 165 | + | read -p "Непривилегирован контейнер (препоръчва се)? (Y/n): " u | |
| 166 | + | [[ $u =~ ^[Nn]$ ]] && UNPRIVILEGED=0 || UNPRIVILEGED=1 | |
| 167 | + | ||
| 168 | + | # 📝 Резюме | |
| 169 | + | print_header "ПРЕГЛЕД НА НАСТРОЙКИТЕ" | |
| 170 | + | echo -e "ОС: $TEMPLATE" | |
| 171 | + | echo -e "CTID: $CTID | Hostname: $HOSTNAME" | |
| 172 | + | echo -e "Спецификации: $DISK GB / $RAM MB RAM / $CORES ядра (Swap: 0)" | |
| 173 | + | echo -e "Мрежа: $BRIDGE | IP: ${IP:-DHCP}" | |
| 174 | + | echo -e "Достъп: $([[ -n "$SSH_KEY_ARG" ]] && echo "SSH Key" || echo "Root Парола")" | |
| 175 | + | echo -e "Тип: $([[ "$UNPRIVILEGED" == "1" ]] && echo "Непривилегирован" || echo "Привилегирован")" | |
| 176 | + | ||
| 177 | + | read -p "ГОТОВО? (y/N): " ok | |
| 178 | + | [[ $ok =~ ^[Yy]$ ]] || { [[ -n "${KEY_TEMP_FILE:-}" ]] && rm "$KEY_TEMP_FILE"; exit 0; } | |
| 179 | + | ||
| 180 | + | # ⬇️ Сваляне на Шаблона | |
| 181 | + | tmpl="/var/lib/vz/template/cache/$TEMPLATE" | |
| 182 | + | if [[ ! -f "$tmpl" ]]; then | |
| 183 | + | print_success "Свалям $TEMPLATE ..." | |
| 184 | + | wget -q --show-progress -O "$tmpl" "$URL" | |
| 185 | + | else | |
| 186 | + | print_success "Шаблонът $TEMPLATE вече съществува, пропускам свалянето." | |
| 187 | + | fi | |
| 188 | + | ||
| 189 | + | # ⚙️ Подготовка на Мрежата | |
| 190 | + | net="name=eth0,bridge=$BRIDGE,firewall=1" | |
| 191 | + | [[ -n "${IP:-}" ]] && net+=",ip=$IP" | |
| 192 | + | [[ -n "${GW:-}" ]] && net+=",gw=$GW" | |
| 193 | + | ||
| 194 | + | # 🏗️ Създаване на Контейнера | |
| 195 | + | print_success "Създавам контейнер $CTID ..." | |
| 196 | + | ||
| 197 | + | # Аргументи: --swap 0 и настройки за сигурност | |
| 198 | + | COMMAND="pct create \"$CTID\" \"$tmpl\" \ | |
| 199 | + | --hostname \"$HOSTNAME\" --storage \"$STORAGE\" --rootfs \"$STORAGE:$DISK\" \ | |
| 200 | + | --memory \"$RAM\" --cores \"$CORES\" --net0 \"$net\" --swap 0 \ | |
| 201 | + | --features nesting=1,keyctl=1 --onboot 1 --unprivileged \"$UNPRIVILEGED\" \ | |
| 202 | + | $SSH_KEY_ARG \ | |
| 203 | + | $PASSWORD_ARG" | |
| 204 | + | ||
| 205 | + | if ! eval "$COMMAND"; then | |
| 206 | + | print_error "Неуспешно създаване на контейнера. Проверете настройките и логовете на Proxmox." | |
| 207 | + | [[ -n "${KEY_TEMP_FILE:-}" ]] && rm "$KEY_TEMP_FILE" | |
| 208 | + | exit 1 | |
| 209 | + | fi | |
| 210 | + | ||
| 211 | + | # 📝 Добавяне на DNS | |
| 212 | + | [[ -n "${IP:-}" ]] && pct set "$CTID" --nameserver "$DNS" | |
| 213 | + | ||
| 214 | + | # 🚀 Стартиране и Първоначална Настройка | |
| 215 | + | print_success "Стартирам контейнер $CTID..." | |
| 216 | + | pct start "$CTID" | |
| 217 | + | ||
| 218 | + | print_success "Изчаквам и инсталирам основни пакети (около 30-50 секунди)..." | |
| 219 | + | sleep 8 | |
| 220 | + | 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 | |
| 221 | + | ||
| 222 | + | # 🥳 Край | |
| 223 | + | print_header "ГОТОВО!" | |
| 224 | + | echo -e "${GREEN}Контейнер $CTID ($HOSTNAME) е готов и работи!${NC}" | |
| 225 | + | echo -e "Влез с: ${CYAN}pct enter $CTID${NC}" | |
| 226 | + | [[ -n "$IP" ]] && echo -e "или с: ${CYAN}ssh root@$(echo $IP | cut -d/ -f1)${NC}" | |
| 227 | + | ||
| 228 | + | # 🧹 Почистване на временен файл, ако е създаден | |
| 229 | + | [[ -n "${KEY_TEMP_FILE:-}" ]] && rm "$KEY_TEMP_FILE" | |
Più nuovi
Più vecchi