diff --git a/scripts/proxmox-vpn-install-dev.sh b/scripts/proxmox-vpn-install-dev.sh index c2e11e5..19afe29 100644 --- a/scripts/proxmox-vpn-install-dev.sh +++ b/scripts/proxmox-vpn-install-dev.sh @@ -1,7 +1,13 @@ #!/usr/bin/env bash # ============================================================================= # Freqtrade NordVPN Addon – Proxmox Host Installer (Custom Config Edition) -# Ablauf: System -> Ordner -> Filebrowser -> User-Input -> VPN-Start +# Läuft komplett auf dem PROXMOX HOST. +# - Richtet TUN-Device ein +# - Erstellt VPN-Ordner & Berechtigungen +# - Fragt NordVPN-Credentials ab & pausiert für custom.conf +# - Ermittelt automatisch das lokale Subnetz +# - Schreibt docker-compose.yml & startet den Stack +# - NEU: Integriert den VPN-Ordner automatisch in den Filebrowser # ============================================================================= set -euo pipefail @@ -27,11 +33,22 @@ confirm() { read -r ans; [[ "$ans" =~ ^[jJyY]$ ]] } +# ── Banner ───────────────────────────────────────────────────────────────────── print_banner() { clear - echo -e "${BOLD}${BLUE} NordVPN Custom Config Installer (Filebrowser-First)${NC}\n" + echo -e "${BOLD}${BLUE}" + cat << 'BANNER' + _ _ _ _ ___ _ _ + | \| |___ _ _ __| \ \ / / | \| | + | .` / _ \ '_/ _` \ V /| | .` | + |_|\_\___/_| \__,_|\_/ |_|_|\_| + NordVPN Custom Config Installer +BANNER + echo -e "${NC}" + echo -e " ${CYAN}Automatisiertes Setup für feste IPs via custom.conf${NC}\n" } +# ── Proxmox-Check ────────────────────────────────────────────────────────────── check_host() { step "Proxmox Host prüfen" [[ $EUID -ne 0 ]] && error "Bitte als root ausführen!" @@ -39,112 +56,157 @@ check_host() { success "Proxmox Host erkannt" } +# ── Container-Auswahl ───────────────────────────────────────────────────────── select_container() { step "Freqtrade Container auswählen" local -a display_list=() + while IFS= read -r line; do - local ct_id status hostname + local ct_id status hostname tags ct_id=$(echo "$line" | awk '{print $1}') status=$(echo "$line" | awk '{print $2}') [[ "$ct_id" =~ ^[0-9]+$ ]] || continue + hostname=$(pct config "$ct_id" 2>/dev/null | awk '/^hostname:/{print $2}' || echo "?") - display_list+=("${ct_id}|${hostname}|${status}") + tags=$(pct config "$ct_id" 2>/dev/null | awk '/^tags:/{print $2}' || echo "") + + if echo "$tags" | grep -qi "freqtrade"; then + display_list+=("${ct_id}|${hostname}|${status}") + fi done < <(pct list 2>/dev/null | tail -n +2) - echo -e " ${BOLD}Nr ID Hostname${NC}" + [[ ${#display_list[@]} -eq 0 ]] && error "Keine Container mit Tag 'freqtrade' gefunden!" + + echo -e " ${BOLD}Nr ID Hostname Status${NC}" + echo -e " ${BLUE}─────────────────────────────────────────${NC}" local i=1 for entry in "${display_list[@]}"; do IFS='|' read -r cid cname cstatus <<< "$entry" - printf " ${CYAN}%-4s${NC} %-8s %-18s\n" "$i" "$cid" "$cname" + printf " ${CYAN}%-4s${NC} %-8s %-18s %-10s\n" "$i" "$cid" "$cname" "$cstatus" ((i++)) done echo - ask "Container Nummer wählen" "1"; local sel_nr="$REPLY" - IFS='|' read -r SEL_ID SEL_NAME SEL_STATUS <<< "${display_list[$((sel_nr-1))]}" + + local sel_nr=1 + [[ ${#display_list[@]} -gt 1 ]] && { ask "Container Nummer wählen" "1"; sel_nr="$REPLY"; } + IFS='|' read -r SEL_ID SEL_NAME SEL_STATUS <<< "${display_list[$((sel_nr-1))]}" + [[ -z "${SEL_ID:-}" ]] && error "Ungültige Auswahl!" + success "Gewählt: CT ${SEL_ID}" + if [[ "$SEL_STATUS" != "running" ]]; then info "Starte Container..." pct start "$SEL_ID" && sleep 5 fi } -setup_base_system() { - step "Grundsystem & VPN-Ordner vorbereiten" +# ── TUN-Device & Ordner einrichten ───────────────────────────────────────────── +setup_system() { + step "System & VPN-Ordner vorbereiten" - # TUN-Device in LXC Config + # 1. TUN-Device in LXC Config schreiben local conf="/etc/pve/lxc/${SEL_ID}.conf" if ! grep -q "lxc.mount.entry: /dev/net/tun" "$conf"; then - info "Konfiguriere TUN-Device..." + info "Trage TUN-Device in Config ein..." cat >> "$conf" << 'TUNCFG' lxc.cgroup2.devices.allow: c 10:200 rwm lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file TUNCFG - pct stop "$SEL_ID" && sleep 2 && pct start "$SEL_ID" && sleep 5 + pct stop "$SEL_ID" && sleep 3 && pct start "$SEL_ID" + sleep 5 + success "TUN-Device eingerichtet & Container neu gestartet" + else + success "TUN-Device war bereits konfiguriert" fi - # VPN Ordner erstellen (BEVOR Filebrowser ihn braucht) + # 2. Ordner und Datei erstellen & Rechte setzen pct exec "$SEL_ID" -- bash -c " mkdir -p /opt/docker-projekte/VPN touch /opt/docker-projekte/VPN/custom.conf chown 1000:1000 -R /opt/docker-projekte/VPN " - success "VPN Ordner ist bereit." + success "VPN-Ordner und custom.conf erstellt (/opt/docker-projekte/VPN)" } +# ── Filebrowser anpassen ─────────────────────────────────────────────────────── update_filebrowser() { - step "Filebrowser Anbindung (Vorbereitung)" + step "Filebrowser aktualisieren" local FB_DIR="/opt/docker-projekte/filebrowser" local FB_YML="${FB_DIR}/docker-compose.yml" + # Prüfen, ob der Filebrowser überhaupt da ist if pct exec "$SEL_ID" -- bash -c "[ -f ${FB_YML} ]"; then - if ! pct exec "$SEL_ID" -- bash -c "grep -q '/opt/docker-projekte/VPN:/srv/VPN' ${FB_YML}"; then - info "Binde VPN-Ordner in Filebrowser ein..." - pct exec "$SEL_ID" -- bash -c "sed -i '/volumes:/a \\ - /opt/docker-projekte/VPN:/srv/VPN' ${FB_YML}" - pct exec "$SEL_ID" -- bash -c "cd ${FB_DIR} && docker compose down && docker compose up -d" - success "Filebrowser neu gestartet. VPN-Ordner ist jetzt im Web-UI sichtbar!" + info "Filebrowser gefunden. Prüfe Konfiguration..." + + # Prüfen, ob der Mount schon existiert, um Doppel-Einträge zu vermeiden + if pct exec "$SEL_ID" -- bash -c "grep -q '/opt/docker-projekte/VPN:/srv/VPN' ${FB_YML}"; then + success "VPN-Ordner ist bereits im Filebrowser gemountet." else - success "Filebrowser bereits konfiguriert." + info "Füge VPN-Mountpunkt zur docker-compose.yml hinzu..." + # Fügt die Zeile exakt nach 'volumes:' ein + pct exec "$SEL_ID" -- bash -c "sed -i '/volumes:/a \\ - /opt/docker-projekte/VPN:/srv/VPN' ${FB_YML}" + success "Konfiguration ergänzt." + + info "Starte Filebrowser neu..." + pct exec "$SEL_ID" -- bash -c "cd ${FB_DIR} && docker compose down && docker compose up -d" + success "Filebrowser ist neugestartet und hat jetzt Zugriff auf den VPN-Ordner!" fi else - warn "Filebrowser nicht gefunden. Du musst die custom.conf manuell bearbeiten." + info "Kein Filebrowser unter ${FB_DIR} gefunden. Überspringe diesen Schritt." fi } - +# ── Konfiguration abfragen & Datei befüllen lassen ───────────────────────────── collect_and_wait() { - step "Konfiguration & User-Input" + step "NordVPN Credentials & Config" + echo -e " ${YELLOW}Hinweis: Bitte nutze die Service-Credentials von der NordVPN-Website!${NC}" ask "NordVPN Service-Username" NORD_USER="$REPLY" ask "NordVPN Service-Passwort" NORD_PASS="$REPLY" - echo -e "\n${BOLD}${CYAN}=== JETZT CUSTOM.CONF BEFÜLLEN ===${NC}" - echo -e "Öffne dein Filebrowser Web-Interface (${BOLD}Port 8081${NC})." - echo -e "Gehe in den Ordner ${BOLD}VPN${NC} und bearbeite die ${BOLD}custom.conf${NC}." - echo -e "Füge dort den Inhalt deiner .ovpn Datei von NordVPN ein." + echo -e "\n${BOLD}${CYAN}=== WICHTIGER SCHRITT ===${NC}" + echo -e "Bitte öffne nun auf deinem Server (oder via SFTP/Filebrowser) die Datei im Container:" + echo -e " ${BOLD}/opt/docker-projekte/VPN/custom.conf${NC}" + echo -e "Füge dort den kompletten Text deiner NordVPN-Konfigurationsdatei (.ovpn) ein und speichere." + echo -e "Tipp: Du kannst auch in einer zweiten Konsole ausführen:" + echo -e " pct enter ${SEL_ID} und dann nano /opt/docker-projekte/VPN/custom.conf" while true; do echo - if confirm "Ist die custom.conf im Filebrowser gespeichert?"; then + if confirm "Hast du die custom.conf befüllt und gespeichert?"; then + # Kurzer Check, ob die Datei nicht mehr leer ist local size size=$(pct exec "$SEL_ID" -- stat -c%s /opt/docker-projekte/VPN/custom.conf 2>/dev/null || echo 0) - [[ "$size" -gt 10 ]] && { success "Inhalt erkannt!"; break; } - warn "Die Datei ist noch leer oder zu klein. Bitte nochmal prüfen." + if [[ "$size" -gt 10 ]]; then + success "Datei ist befüllt!" + break + else + warn "Die Datei scheint noch leer zu sein. Bitte überprüfe das." + fi fi done } -deploy_vpn_stack() { - step "VPN & Freqtrade Stack starten" +# ── Docker Compose schreiben & anwenden ──────────────────────────────────────── +deploy_stack() { + step "Docker Stack anwenden" local FT_DIR="/opt/docker-projekte/freqtrade" - # Subnetz ermitteln + # Lokales Subnetz automatisch ermitteln (z.B. 192.168.178.0/24) local SUBNET SUBNET=$(pct exec "$SEL_ID" -- bash -c "ip -o -f inet addr show eth0 | awk '{print \$4}' | sed 's/\.[0-9]\{1,3\}\//.0\//'" 2>/dev/null || echo "192.168.0.0/24") + info "Ermitteltes lokales Subnetz: ${SUBNET}" - info "Schreibe neue docker-compose.yml für Freqtrade..." + # Alten Stack stoppen + info "Stoppe aktuellen Stack..." + pct exec "$SEL_ID" -- bash -c "cd ${FT_DIR} && docker compose down 2>/dev/null || true" + + # Neue docker-compose.yml generieren + info "Schreibe neue docker-compose.yml..." pct exec "$SEL_ID" -- bash -c "cat > ${FT_DIR}/docker-compose.yml << 'COMPOSEEOF' version: '3.8' + services: gluetun: image: qmcgaw/gluetun:latest @@ -160,6 +222,7 @@ services: - OPENVPN_CUSTOM_CONFIG=/gluetun/custom.conf - OPENVPN_USER=${NORD_USER} - OPENVPN_PASSWORD=${NORD_PASS} + # Automatisch ermitteltes lokales Netz für Erreichbarkeit - FIREWALL_OUTBOUND_SUBNETS=${SUBNET} volumes: - /opt/docker-projekte/VPN:/gluetun @@ -183,11 +246,13 @@ services: --config /freqtrade/user_data/config.json --strategy SampleStrategy COMPOSEEOF" - - pct exec "$SEL_ID" -- bash -c "cd ${FT_DIR} && docker compose down 2>/dev/null || true" + + # Stack starten + info "Starte Stack neu..." pct exec "$SEL_ID" -- bash -c "cd ${FT_DIR} && docker compose up -d" - success "Freqtrade & VPN Stack gestartet!" + sleep 5 + success "Deployment abgeschlossen!" } main() {