diff --git a/docker-lxc.sh b/docker-lxc.sh index ea49673..aaa65e5 100644 --- a/docker-lxc.sh +++ b/docker-lxc.sh @@ -30,7 +30,6 @@ echo -e "${BOLD}╚════════════════════ DEFAULT_CTID=$(pvesh get /cluster/nextid) DEFAULT_HOSTNAME="debian-docker" DEFAULT_PASSWORD="ChangeMe123!" -DEFAULT_STORAGE="local-lvm" DEFAULT_DISK=8 # GB DEFAULT_RAM=2048 # MB DEFAULT_SWAP=512 # MB @@ -54,11 +53,104 @@ ask_yn() { [[ "${yn:-$default}" =~ ^[Jj1Yy] ]] } +# ── Storage-Auswahl (dynamisch) ─────────────────────────────────────────────── +select_storage() { + echo -e "${CYAN}── Storage-Auswahl ─────────────────────────────────────────${NC}" + echo -e " Verfügbare Storages auf diesem Host:\n" + + # pvesm status liefert: Name, Type, Status, Total, Used, Available, % + # Wir filtern nur aktive Storages, die LXC-Container unterstützen + mapfile -t STORAGE_LINES < <( + pvesm status --content rootdir 2>/dev/null \ + | awk 'NR>1 && $3=="active" {print $1, $2, $5, $4}' \ + | sort + ) + + if [[ ${#STORAGE_LINES[@]} -eq 0 ]]; then + # Fallback: alle aktiven Storages anzeigen (ohne Content-Filter) + mapfile -t STORAGE_LINES < <( + pvesm status 2>/dev/null \ + | awk 'NR>1 && $3=="active" {print $1, $2, $5, $4}' \ + | sort + ) + fi + + if [[ ${#STORAGE_LINES[@]} -eq 0 ]]; then + warn "Keine aktiven Storages gefunden – bitte manuell eingeben." + ask "Storage-Name" "local-lvm" STORAGE + return + fi + + local i=1 + local -a STORAGE_NAMES=() + printf " ${BOLD}%-4s %-20s %-14s %-12s %-12s${NC}\n" "Nr." "Name" "Typ" "Frei" "Gesamt" + echo -e " ──────────────────────────────────────────────────────────" + + for line in "${STORAGE_LINES[@]}"; do + read -r sname stype sused stotal <<< "$line" + + # Freien Speicher berechnen (Werte in KB von pvesm) + local sfree=0 + if [[ "$stotal" =~ ^[0-9]+$ ]] && [[ "$sused" =~ ^[0-9]+$ ]]; then + sfree=$(( stotal - sused )) + fi + + # Lesbare Größen + human_size() { + local kb=$1 + if (( kb >= 1073741824 )); then printf "%.1f TiB" "$(echo "scale=1; $kb/1073741824" | bc)" + elif (( kb >= 1048576 )); then printf "%.1f GiB" "$(echo "scale=1; $kb/1048576" | bc)" + elif (( kb >= 1024 )); then printf "%.1f MiB" "$(echo "scale=1; $kb/1024" | bc)" + else printf "%d KiB" "$kb"; fi + } + + local free_str total_str + if [[ "$stotal" =~ ^[0-9]+$ ]] && (( stotal > 0 )); then + free_str=$(human_size "$sfree") + total_str=$(human_size "$stotal") + else + free_str="n/a" + total_str="n/a" + fi + + # Farbe je nach freiem Platz + local color="$GREEN" + if [[ "$stotal" =~ ^[0-9]+$ ]] && (( stotal > 0 )); then + local pct=$(( sfree * 100 / stotal )) + (( pct < 15 )) && color="$RED" + (( pct >= 15 && pct < 30 )) && color="$YELLOW" + fi + + printf " ${BOLD}%-4s${NC} ${color}%-20s${NC} %-14s %-12s %-12s\n" \ + "[$i]" "$sname" "$stype" "$free_str" "$total_str" + + STORAGE_NAMES+=("$sname") + (( i++ )) + done + + echo "" + local DEFAULT_NUM=1 + while true; do + echo -ne "${BOLD}Auswahl (Nummer eingeben)${NC} [${YELLOW}${DEFAULT_NUM}${NC}]: " + read -r sel + sel="${sel:-$DEFAULT_NUM}" + if [[ "$sel" =~ ^[0-9]+$ ]] && (( sel >= 1 && sel <= ${#STORAGE_NAMES[@]} )); then + STORAGE="${STORAGE_NAMES[$((sel-1))]}" + success "Storage gewählt: ${BOLD}${STORAGE}${NC}" + break + else + warn "Ungültige Eingabe. Bitte eine Zahl zwischen 1 und ${#STORAGE_NAMES[@]} eingeben." + fi + done + echo "" +} + echo -e "${CYAN}── Container-Grundkonfiguration ────────────────────────────${NC}" ask "Container-ID" "$DEFAULT_CTID" CTID ask "Hostname" "$DEFAULT_HOSTNAME" HOSTNAME ask "Root-Passwort" "$DEFAULT_PASSWORD" PASSWORD -ask "Storage" "$DEFAULT_STORAGE" STORAGE +echo "" +select_storage ask "Disk-Größe (GB)" "$DEFAULT_DISK" DISK ask "RAM (MB)" "$DEFAULT_RAM" RAM ask "Swap (MB)" "$DEFAULT_SWAP" SWAP @@ -83,10 +175,39 @@ else INSTALL_PORTAINER=false fi -if ask_yn "SSH-Zugriff für root aktivieren?" "j"; then +echo "" +echo -e "${CYAN}── SSH-Zugriff ─────────────────────────────────────────────${NC}" +if ask_yn "SSH-Root-Login von externen Terminals aktivieren?" "j"; then ENABLE_ROOT_SSH=true + ask "SSH-Port" "22" SSH_PORT + echo "" + echo -e " ${BOLD}Authentifizierungsmethode:${NC}" + echo -e " ${YELLOW}[1]${NC} Nur Passwort" + echo -e " ${YELLOW}[2]${NC} Nur SSH-Key (du gibst deinen Public Key ein)" + echo -e " ${YELLOW}[3]${NC} Passwort ${BOLD}und${NC} SSH-Key (beide erlaubt)" + echo -ne "${BOLD}Auswahl${NC} [${YELLOW}1${NC}]: " + read -r ssh_auth_sel + case "${ssh_auth_sel:-1}" in + 2) SSH_AUTH="key" ;; + 3) SSH_AUTH="both" ;; + *) SSH_AUTH="password" ;; + esac + + SSH_PUBKEY="" + if [[ "$SSH_AUTH" == "key" || "$SSH_AUTH" == "both" ]]; then + echo "" + echo -e " Gib deinen SSH-Public-Key ein (z.B. Inhalt von ${YELLOW}~/.ssh/id_rsa.pub${NC}):" + echo -ne " ${BOLD}Public Key:${NC} " + read -r SSH_PUBKEY + if [[ -z "$SSH_PUBKEY" ]]; then + warn "Kein Public Key eingegeben – falle auf Passwort-Auth zurück." + SSH_AUTH="password" + fi + fi else ENABLE_ROOT_SSH=false + SSH_PORT="22" + SSH_AUTH="password" fi if ask_yn "Unprivilegierten Container erstellen? (empfohlen)" "j"; then @@ -106,7 +227,7 @@ printf "${BOLD}║${NC} %-22s %-20s ${BOLD}║${NC}\n" "RAM / Swap:" "${RA printf "${BOLD}║${NC} %-22s %-20s ${BOLD}║${NC}\n" "CPU-Kerne:" "$CORES" printf "${BOLD}║${NC} %-22s %-20s ${BOLD}║${NC}\n" "Netzwerk:" "$IP_ADDR" printf "${BOLD}║${NC} %-22s %-20s ${BOLD}║${NC}\n" "Portainer:" "$( $INSTALL_PORTAINER && echo "Ja (:${PORTAINER_PORT})" || echo "Nein" )" -printf "${BOLD}║${NC} %-22s %-20s ${BOLD}║${NC}\n" "Root-SSH:" "$( $ENABLE_ROOT_SSH && echo "Ja" || echo "Nein" )" +printf "${BOLD}║${NC} %-22s %-20s ${BOLD}║${NC}\n" "Root-SSH:" "$( $ENABLE_ROOT_SSH && echo "Ja (Port ${SSH_PORT}, Auth: ${SSH_AUTH})" || echo "Nein" )" printf "${BOLD}║${NC} %-22s %-20s ${BOLD}║${NC}\n" "Unprivilegiert:" "$( [[ $UNPRIVILEGED -eq 1 ]] && echo "Ja" || echo "Nein" )" echo -e "${BOLD}╚══════════════════════════════════════════════╝${NC}" echo "" @@ -217,35 +338,91 @@ docker run -d \ success "Portainer CE gestartet." fi -# ── SSH konfigurieren ────────────────────────────────────────────────────────── +# ── SSH vollständig konfigurieren ───────────────────────────────────────────── if $ENABLE_ROOT_SSH; then - info "Aktiviere Root-SSH-Login …" + info "Installiere und konfiguriere SSH-Server …" + + # openssh-server sicherstellen (Debian Minimal hat es evtl. nicht) + lxc_exec "apt-get install -y -qq openssh-server" + + # sshd_config: Root-Login und Port setzen lxc_exec " sed -i 's/^#*PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config -sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config -systemctl restart ssh +grep -q '^PermitRootLogin' /etc/ssh/sshd_config || echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config +sed -i 's/^#*Port .*/Port ${SSH_PORT}/' /etc/ssh/sshd_config +grep -q '^Port ' /etc/ssh/sshd_config || echo 'Port ${SSH_PORT}' >> /etc/ssh/sshd_config " - success "Root-SSH aktiviert." + + # Authentifizierungsmethode konfigurieren + if [[ \"\$SSH_AUTH\" == \"password\" ]]; then + lxc_exec " +sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config +grep -q '^PasswordAuthentication' /etc/ssh/sshd_config || echo 'PasswordAuthentication yes' >> /etc/ssh/sshd_config +sed -i 's/^#*PubkeyAuthentication.*/PubkeyAuthentication no/' /etc/ssh/sshd_config +" + elif [[ \"\$SSH_AUTH\" == \"key\" ]]; then + lxc_exec " +sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config +sed -i 's/^#*PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config +grep -q '^PubkeyAuthentication' /etc/ssh/sshd_config || echo 'PubkeyAuthentication yes' >> /etc/ssh/sshd_config +mkdir -p /root/.ssh && chmod 700 /root/.ssh +echo '${SSH_PUBKEY}' >> /root/.ssh/authorized_keys +chmod 600 /root/.ssh/authorized_keys +" + else + # both + lxc_exec " +sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config +grep -q '^PasswordAuthentication' /etc/ssh/sshd_config || echo 'PasswordAuthentication yes' >> /etc/ssh/sshd_config +sed -i 's/^#*PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config +grep -q '^PubkeyAuthentication' /etc/ssh/sshd_config || echo 'PubkeyAuthentication yes' >> /etc/ssh/sshd_config +mkdir -p /root/.ssh && chmod 700 /root/.ssh +echo '${SSH_PUBKEY}' >> /root/.ssh/authorized_keys +chmod 600 /root/.ssh/authorized_keys +" + fi + + # SSH-Dienst aktivieren & (neu-)starten + lxc_exec "systemctl enable ssh --now && systemctl restart ssh" + + # Verbindungstest vom PVE-Host (nc prüft ob Port offen ist) + info "Prüfe SSH-Erreichbarkeit auf Port ${SSH_PORT} …" + sleep 3 + CT_TEST_IP=$(pct exec "$CTID" -- hostname -I 2>/dev/null | awk '{print $1}' || true) + if [[ -n "$CT_TEST_IP" ]] && nc -z -w5 "$CT_TEST_IP" "$SSH_PORT" 2>/dev/null; then + success "SSH erreichbar → ssh root@${CT_TEST_IP} -p ${SSH_PORT}" + else + warn "SSH-Port noch nicht erreichbar – evtl. kurz warten und erneut testen." + fi fi # ── Abschluss ────────────────────────────────────────────────────────────────── CONTAINER_IP=$(pct exec "$CTID" -- hostname -I 2>/dev/null | awk '{print $1}' || echo "unbekannt") echo "" -echo -e "${BOLD}${GREEN}╔═══════════════════════ Fertig! ═══════════════════════╗${NC}" +echo -e "${BOLD}${GREEN}╔═══════════════════════════════════════════════════════╗${NC}" +echo -e "${GREEN}║${NC} ${BOLD}Installation abgeschlossen!${NC}" +echo -e "${BOLD}${GREEN}╠═══════════════════════════════════════════════════════╣${NC}" echo -e "${GREEN}║${NC}" -echo -e "${GREEN}║${NC} Container-ID : ${BOLD}${CTID}${NC}" -echo -e "${GREEN}║${NC} Hostname : ${BOLD}${HOSTNAME}${NC}" -echo -e "${GREEN}║${NC} IP-Adresse : ${BOLD}${CONTAINER_IP}${NC}" +printf "${GREEN}║${NC} %-18s ${BOLD}%s${NC}\n" "Container-ID:" "$CTID" +printf "${GREEN}║${NC} %-18s ${BOLD}%s${NC}\n" "Hostname:" "$HOSTNAME" +printf "${GREEN}║${NC} %-18s ${BOLD}%s${NC}\n" "IP-Adresse:" "$CONTAINER_IP" echo -e "${GREEN}║${NC}" -echo -e "${GREEN}║${NC} Docker : ${BOLD}installiert & aktiv${NC}" +printf "${GREEN}║${NC} %-18s ${BOLD}%s${NC}\n" "Docker:" "installiert & aktiv" if $INSTALL_PORTAINER; then -echo -e "${GREEN}║${NC} Portainer : ${BOLD}https://${CONTAINER_IP}:${PORTAINER_PORT}${NC}" +printf "${GREEN}║${NC} %-18s ${BOLD}https://%s:%s${NC}\n" "Portainer UI:" "$CONTAINER_IP" "$PORTAINER_PORT" fi if $ENABLE_ROOT_SSH; then -echo -e "${GREEN}║${NC} SSH : ${BOLD}ssh root@${CONTAINER_IP}${NC}" +echo -e "${GREEN}║${NC}" +echo -e "${GREEN}║${NC} ${CYAN}── SSH-Verbindung ─────────────────────────────────${NC}" +if [[ "$SSH_PORT" == "22" ]]; then +printf "${GREEN}║${NC} ${BOLD}ssh root@%s${NC}\n" "$CONTAINER_IP" +else +printf "${GREEN}║${NC} ${BOLD}ssh root@%s -p %s${NC}\n" "$CONTAINER_IP" "$SSH_PORT" +fi +printf "${GREEN}║${NC} %-18s ${BOLD}%s${NC}\n" "Auth-Methode:" "$SSH_AUTH" fi echo -e "${GREEN}║${NC}" -echo -e "${GREEN}║${NC} ${YELLOW}Bitte das Root-Passwort nach dem ersten Login ändern!${NC}" +echo -e "${GREEN}║${NC} ${YELLOW}⚠ Root-Passwort nach erstem Login bitte ändern!${NC}" echo -e "${GREEN}║${NC}" -echo -e "${BOLD}${GREEN}╚═══════════════════════════════════════════════════════╝${NC}\n" \ No newline at end of file +echo -e "${BOLD}${GREEN}╚═══════════════════════════════════════════════════════╝${NC}" \ No newline at end of file