diff --git a/scripts/freqtrade-lxc-install.sh b/scripts/freqtrade-lxc-install.sh index 3e87285..27a3cad 100644 --- a/scripts/freqtrade-lxc-install.sh +++ b/scripts/freqtrade-lxc-install.sh @@ -190,15 +190,6 @@ create_lxc() { success "LXC erstellt" - # TUN-Device für NordVPN/Gluetun vorbereiten - # (muss VOR dem Start in die Config, danach braucht install-vpn.sh keinen manuellen Eingriff) - cat >> "/etc/pve/lxc/${CT_ID}.conf" << 'TUNCFG' -# TUN-Device fuer NordVPN/Gluetun (eingetragen von freqtrade-lxc-install.sh) -lxc.cgroup2.devices.allow: c 10:200 rwm -lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file -TUNCFG - success "TUN-Device in LXC-Config eingetragen" - # Container mit Tag "freqtrade" versehen (für proxmox-vpn-install.sh nutzbar) pct set "$CT_ID" --tags "freqtrade" 2>/dev/null || true @@ -515,11 +506,11 @@ show_result() { echo -e " ${YELLOW}1. Binance API-Keys in config.json eintragen${NC}" echo -e " ${YELLOW}2. dry_run: false setzen wenn bereit${NC}" echo -e " ${YELLOW}3. Strategie anpassen${NC}" - echo -e " ${YELLOW}4. NordVPN optional: install-vpn.sh im LXC ausführen${NC}" + echo -e " ${YELLOW}4. NordVPN optional: proxmox-vpn-install.sh auf dem Proxmox Host ausführen${NC}" echo echo -e " ${BOLD}LXC-Konsole öffnen:${NC} ${CYAN}pct enter ${CT_ID}${NC}" echo -e " ${BOLD}NordVPN Addon:${NC}" - echo -e " ${CYAN}bash -c \"\$(curl -fsSL https://git.obraasch.de/olli1986/freqtrade-proxmox-deploy/raw/branch/main/scripts/install-vpn.sh)\"${NC}" + echo -e " ${CYAN}bash -c \"\$(curl -fsSL https://git.obraasch.de/olli1986/freqtrade-proxmox-deploy/raw/branch/main/scripts/proxmox-vpn-install.sh)\"${NC}" echo } diff --git a/scripts/proxmox-vpn-install.sh b/scripts/proxmox-vpn-install.sh index 40142b2..9163bc7 100644 --- a/scripts/proxmox-vpn-install.sh +++ b/scripts/proxmox-vpn-install.sh @@ -1,10 +1,13 @@ #!/usr/bin/env bash # ============================================================================= # Freqtrade NordVPN Addon – Proxmox Host Installer -# Erkennt Freqtrade-Container automatisch per Tag, richtet TUN-Device ein -# und startet install-vpn.sh im Container. +# Läuft komplett auf dem PROXMOX HOST. +# - Zeigt Freqtrade-Container zur Auswahl (gefiltert nach Tag/Hostname) +# - Richtet TUN-Device ein (Container-Neustart) +# - Fragt NordVPN-Credentials ab +# - Schreibt .env + docker-compose.yml mit Gluetun im Container +# - Startet Stack und prüft VPN-IP # -# Läuft auf dem PROXMOX HOST. # Quelle: https://git.obraasch.de/olli1986/freqtrade-proxmox-deploy # ============================================================================= set -euo pipefail @@ -18,7 +21,23 @@ warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } error() { echo -e "${RED}[FAIL]${NC} $*"; exit 1; } step() { echo -e "\n${BOLD}${BLUE}▶ $*${NC}"; } -VPN_SCRIPT_URL="https://git.obraasch.de/olli1986/freqtrade-proxmox-deploy/raw/branch/main/scripts/install-vpn.sh" +ask() { + local prompt="$1" default="${2:-}" + [[ -n "$default" ]] \ + && echo -ne "${YELLOW} ➜ ${NC}${prompt} [${CYAN}${default}${NC}]: " \ + || echo -ne "${YELLOW} ➜ ${NC}${prompt}: " + read -r REPLY; REPLY="${REPLY:-$default}" +} + +ask_secret() { + echo -ne "${YELLOW} ➜ ${NC}${1}: " + read -rs REPLY; echo +} + +confirm() { + echo -ne "${YELLOW} ➜ ${NC}${1} [${CYAN}j${NC}/N]: " + read -r ans; [[ "$ans" =~ ^[jJyY]$ ]] +} # ── Banner ───────────────────────────────────────────────────────────────────── print_banner() { @@ -32,160 +51,373 @@ print_banner() { NordVPN Addon – Proxmox Host Installer BANNER echo -e "${NC}" - echo -e " ${CYAN}Richtet TUN-Device ein und startet NordVPN-Setup im LXC${NC}\n" + echo -e " ${CYAN}Richtet TUN + Gluetun/NordVPN vollautomatisch ein${NC}" + echo -e " ${CYAN}Quelle: git.obraasch.de/olli1986/freqtrade-proxmox-deploy${NC}\n" } # ── Proxmox-Check ────────────────────────────────────────────────────────────── check_host() { + step "Proxmox Host prüfen" [[ $EUID -ne 0 ]] && error "Bitte als root ausführen!" command -v pct &>/dev/null || error "pct nicht gefunden – läuft das auf Proxmox?" + command -v pvesh &>/dev/null || error "pvesh nicht gefunden." success "Proxmox Host erkannt" } # ── Container-Auswahl ───────────────────────────────────────────────────────── select_container() { - step "Freqtrade Container suchen" + step "Freqtrade Container auswählen" - # Alle laufenden Container mit Tag "freqtrade" finden - mapfile -t TAGGED_IDS < <( - pct list 2>/dev/null | awk 'NR>1{print $1}' | while read -r id; do - tags=$(pct config "$id" 2>/dev/null | grep '^tags:' | sed 's/tags: *//' || true) - if echo "$tags" | grep -qi "freqtrade"; then - name=$(pct config "$id" 2>/dev/null | grep '^hostname:' | awk '{print $2}' || echo "?") - status=$(pct list 2>/dev/null | awk -v id="$id" '$1==id{print $2}') - echo "${id}|${name}|${status}" - fi - done - ) + # Alle Container auflisten mit Tag-Info + local -a ct_list=() + while IFS= read -r line; do + local ct_id status + ct_id=$(echo "$line" | awk '{print $1}') + status=$(echo "$line" | awk '{print $2}') + [[ "$ct_id" =~ ^[0-9]+$ ]] || continue - # Auch ungetaggte Container mit Hostname "freqtrade" als Fallback - mapfile -t HOSTNAME_IDS < <( - pct list 2>/dev/null | awk 'NR>1{print $1}' | while read -r id; do - hostname=$(pct config "$id" 2>/dev/null | grep '^hostname:' | awk '{print $2}' || true) - tags=$(pct config "$id" 2>/dev/null | grep '^tags:' | sed 's/tags: *//' || true) - if echo "$hostname" | grep -qi "freqtrade" && ! echo "$tags" | grep -qi "freqtrade"; then - status=$(pct list 2>/dev/null | awk -v id="$id" '$1==id{print $2}') - echo "${id}|${hostname}|${status} (kein Tag)" - fi - done - ) + local hostname tags marker="" + hostname=$(pct config "$ct_id" 2>/dev/null | awk '/^hostname:/{print $2}' || echo "?") + tags=$(pct config "$ct_id" 2>/dev/null | awk '/^tags:/{print $2}' || echo "") - ALL_IDS=("${TAGGED_IDS[@]}" "${HOSTNAME_IDS[@]}") - - if [[ ${#ALL_IDS[@]} -eq 0 ]]; then - warn "Keine Freqtrade-Container gefunden (Tag 'freqtrade' oder Hostname 'freqtrade*')" - echo - echo -e " Alle verfügbaren Container:" - pct list 2>/dev/null | awk 'NR==1{printf " %-8s %-12s %s\n",$1,$2,$3} NR>1{printf " %-8s %-12s %s\n",$1,$2,$3}' - echo - echo -ne "${YELLOW} ➜ ${NC}Container-ID manuell eingeben: " - read -r SEL_ID - SEL_NAME=$(pct config "$SEL_ID" 2>/dev/null | grep '^hostname:' | awk '{print $2}' || echo "unbekannt") - SEL_STATUS=$(pct list 2>/dev/null | awk -v id="$SEL_ID" '$1==id{print $2}') - elif [[ ${#ALL_IDS[@]} -eq 1 ]]; then - # Genau einer gefunden → direkt nehmen - IFS='|' read -r SEL_ID SEL_NAME SEL_STATUS <<< "${ALL_IDS[0]}" - echo -e " ${GREEN}Gefunden:${NC} CT ${CYAN}${SEL_ID}${NC} | ${CYAN}${SEL_NAME}${NC} | ${SEL_STATUS}" - else - # Mehrere → Auswahl anzeigen - echo -e " ${CYAN}Gefundene Freqtrade-Container:${NC}\n" - echo -e " ${BOLD}Nr ID Hostname Status${NC}" - echo -e " ${BLUE}────────────────────────────────────${NC}" - local i=1 - for entry in "${ALL_IDS[@]}"; do - IFS='|' read -r cid cname cstatus <<< "$entry" - printf " ${CYAN}%-4s${NC} %-8s %-16s %s\n" "$i" "$cid" "$cname" "$cstatus" - ((i++)) - done - echo - echo -ne "${YELLOW} ➜ ${NC}Nummer auswählen [1]: " - read -r sel_nr - sel_nr="${sel_nr:-1}" - IFS='|' read -r SEL_ID SEL_NAME SEL_STATUS <<< "${ALL_IDS[$((sel_nr-1))]}" - fi - - [[ -z "${SEL_ID:-}" ]] && error "Keine Container-ID gewählt!" - - # Status-Check - local cur_status - cur_status=$(pct list 2>/dev/null | awk -v id="$SEL_ID" '$1==id{print $2}' || echo "unknown") - if [[ "$cur_status" != "running" ]]; then - warn "Container $SEL_ID ist nicht running (Status: $cur_status)" - echo -ne "${YELLOW} ➜ ${NC}Container starten? [j/N]: " - read -r ans - if [[ "$ans" =~ ^[jJyY]$ ]]; then - pct start "$SEL_ID" - sleep 5 - success "Container gestartet" + # Freqtrade-Container markieren + if echo "$tags" | grep -qi "freqtrade"; then + marker="${GREEN}★${NC}" else - error "Container muss laufen für die Installation!" + marker=" " fi + ct_list+=("${ct_id}|${hostname}|${status}|${marker}") + done < <(pct list 2>/dev/null | tail -n +2) + + if [[ ${#ct_list[@]} -eq 0 ]]; then + error "Keine Container gefunden!" fi - success "Gewählt: CT ${SEL_ID} | ${SEL_NAME}" + # Nur Container mit Tag "freqtrade" anzeigen + local -a display_list=() + for entry in "${ct_list[@]}"; do + if echo "$entry" | grep -q "★"; then + display_list+=("$entry") + fi + done + + if [[ ${#display_list[@]} -eq 0 ]]; then + error "Keine Container mit Tag 'freqtrade' gefunden!\n Bitte zuerst freqtrade-lxc-install.sh ausführen oder manuell setzen:\n pct set --tags freqtrade" + fi + + echo + echo -e " ${BOLD}Nr ID Hostname Status ${GREEN}★${NC}${BOLD} = Freqtrade${NC}" + echo -e " ${BLUE}─────────────────────────────────────────${NC}" + local i=1 + for entry in "${display_list[@]}"; do + IFS='|' read -r cid cname cstatus cmark <<< "$entry" + printf " ${CYAN}%-4s${NC} %-8s %-18s %-10s %b\n" "$i" "$cid" "$cname" "$cstatus" "$cmark" + ((i++)) + done + echo + + local sel_nr=1 + if [[ ${#display_list[@]} -gt 1 ]]; then + ask "Container Nummer wählen" "1" + sel_nr="$REPLY" + else + info "Nur ein Container vorhanden – wird automatisch gewählt." + fi + + 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} | ${SEL_NAME} | ${SEL_STATUS}" + + # Starten falls nötig + if [[ "$SEL_STATUS" != "running" ]]; then + warn "Container ist nicht running. Starte..." + pct start "$SEL_ID" + sleep 5 + success "Container gestartet" + fi } # ── TUN-Device einrichten ────────────────────────────────────────────────────── setup_tun() { step "TUN-Device für CT ${SEL_ID} prüfen" - local conf="/etc/pve/lxc/${SEL_ID}.conf" [[ ! -f "$conf" ]] && error "LXC-Config nicht gefunden: $conf" - local tun_ok=true - grep -q "lxc.cgroup2.devices.allow: c 10:200 rwm" "$conf" || tun_ok=false - grep -q "lxc.mount.entry: /dev/net/tun" "$conf" || tun_ok=false - - if [[ "$tun_ok" == "true" ]]; then + if grep -q "lxc.cgroup2.devices.allow: c 10:200 rwm" "$conf" && \ + grep -q "lxc.mount.entry: /dev/net/tun" "$conf"; then success "TUN-Device bereits konfiguriert" return fi - info "TUN-Device Zeilen fehlen – trage ein..." + info "Trage TUN-Device in Config ein und starte Container neu..." cat >> "$conf" << 'TUNCFG' # TUN-Device fuer NordVPN/Gluetun (eingetragen von proxmox-vpn-install.sh) lxc.cgroup2.devices.allow: c 10:200 rwm lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file TUNCFG - success "TUN-Device in $conf eingetragen" - # Container neu starten damit die Config greift - info "Container neu starten damit TUN-Device aktiv wird..." - pct stop "$SEL_ID" + pct stop "$SEL_ID" sleep 3 pct start "$SEL_ID" - sleep 5 - # Warten auf Netzwerk local tries=0 + info "Warte auf Netzwerk..." until pct exec "$SEL_ID" -- bash -c "ip route | grep -q default" 2>/dev/null; do sleep 3; tries=$((tries+1)); echo -n "." [[ $tries -ge 15 ]] && error "Netzwerk nach Neustart nicht erreichbar!" done echo - success "Container läuft wieder mit TUN-Device" + success "Container neu gestartet mit TUN-Device" } -# ── install-vpn.sh im Container ausführen ───────────────────────────────────── -run_vpn_install() { - step "NordVPN-Setup im Container starten" - echo -e "\n ${YELLOW}Das install-vpn.sh Script läuft jetzt interaktiv im Container.${NC}" - echo -e " ${YELLOW}Du wirst nach deinen NordVPN Service-Credentials gefragt.${NC}\n" - echo -e " Service-Credentials: ${CYAN}https://my.nordaccount.com${NC}" - echo -e " ${CYAN}→ NordVPN → 'Set up NordVPN manually'${NC}\n" +# ── NordVPN Konfiguration abfragen ───────────────────────────────────────────── +collect_vpn_config() { + step "NordVPN Konfiguration" + echo -e "\n ${BOLD}Service-Credentials${NC} findest du unter:" + echo -e " ${CYAN}https://my.nordaccount.com → NordVPN → 'Set up NordVPN manually'${NC}" + echo -e " ${RED} Nicht deine E-Mail/Passwort – die Service-Credentials!${NC}\n" - echo -ne "${YELLOW} ➜ ${NC}Jetzt starten? [j/N]: " - read -r ans - [[ ! "$ans" =~ ^[jJyY]$ ]] && { info "Abgebrochen. Manuell starten mit:\n pct enter ${SEL_ID} dann: bash -c \"\$(curl -fsSL ${VPN_SCRIPT_URL})\""; exit 0; } + ask "NordVPN Service-Username" + NORD_USER="$REPLY" + [[ -z "$NORD_USER" ]] && error "Username darf nicht leer sein!" + + ask_secret "NordVPN Service-Passwort" + NORD_PASS="$REPLY" + [[ -z "$NORD_PASS" ]] && error "Passwort darf nicht leer sein!" - # Script in Container laden und interaktiv ausführen - info "Lade install-vpn.sh in Container..." - pct exec "$SEL_ID" -- bash -c "curl -fsSL '${VPN_SCRIPT_URL}' -o /root/install-vpn.sh && chmod +x /root/install-vpn.sh" - success "Script geladen – starte interaktive Session im Container..." echo - echo -e "${BOLD}${BLUE}──── Container ${SEL_ID} – NordVPN Setup ────${NC}" - # pct enter öffnet eine echte interaktive Shell → Script direkt übergeben - pct exec "$SEL_ID" -- bash /root/install-vpn.sh + echo -e " ${BOLD}VPN-Server Modus:${NC}" + echo -e " ${CYAN}1)${NC} Serverland – normaler Server (IP kann wechseln)" + echo -e " ${CYAN}2)${NC} Hostname – Dedicated-IP oder spez. Server pinnen" + ask "Auswahl [1/2]" "1" + VPN_MODE="$REPLY" + + if [[ "$VPN_MODE" == "2" ]]; then + echo -e "\n ${YELLOW}Gültige Hostnamen haben das Format: de507.nordvpn.com, de654.nordvpn.com etc.${NC}" + echo -e " ${YELLOW}Beispiele für Deutschland: de507, de654, de675 ... de1118${NC}" + ask "Hostname (z.B. de507.nordvpn.com)" + VPN_HOSTNAME="$REPLY"; VPN_COUNTRY="" + else + ask "Serverland" "Germany" + VPN_COUNTRY="$REPLY"; VPN_HOSTNAME="" + fi + + # FreqUI Port aus bestehender config ermitteln + local current_port + current_port=$(pct exec "$SEL_ID" -- bash -c \ + "grep -oP '0\.0\.0\.0:\K[0-9]+(?=:[0-9]+)' /opt/docker-projekte/freqtrade/docker-compose.yml 2>/dev/null | head -1 || echo 8080" \ + 2>/dev/null || echo "8080") + ask "FreqUI Port" "$current_port" + FT_PORT="$REPLY" + + echo -e "\n${BOLD}${BLUE}══════════ Zusammenfassung ══════════${NC}" + echo -e " Container: ${CYAN}CT ${SEL_ID} | ${SEL_NAME}${NC}" + echo -e " NordVPN User: ${CYAN}${NORD_USER}${NC}" + [[ -n "$VPN_HOSTNAME" ]] \ + && echo -e " VPN Server: ${CYAN}${VPN_HOSTNAME}${NC}" \ + || echo -e " VPN Land: ${CYAN}${VPN_COUNTRY}${NC}" + echo -e " FreqUI Port: ${CYAN}${FT_PORT}${NC}" + echo -e "${BOLD}${BLUE}=====================================\n${NC}" + confirm "Einrichten?" || { info "Abgebrochen."; exit 0; } +} + +# ── Konfiguration in Container schreiben ────────────────────────────────────── +write_vpn_config() { + step "VPN-Konfiguration in Container schreiben" + + local FT_DIR="/opt/docker-projekte/freqtrade" + local NORD_USER_B64 NORD_PASS_B64 + NORD_USER_B64=$(printf '%s' "$NORD_USER" | base64 -w0) + NORD_PASS_B64=$(printf '%s' "$NORD_PASS" | base64 -w0) + + local VPN_SERVER_LINE="" + [[ -n "$VPN_HOSTNAME" ]] \ + && VPN_SERVER_LINE=" - SERVER_HOSTNAMES=${VPN_HOSTNAME}" \ + || VPN_SERVER_LINE=" - SERVER_COUNTRIES=${VPN_COUNTRY}" + + # Backup + pct exec "$SEL_ID" -- bash -c \ + "cp ${FT_DIR}/docker-compose.yml ${FT_DIR}/docker-compose.yml.bak-\$(date +%Y%m%d_%H%M%S) 2>/dev/null || true" + success "Backup erstellt" + + # Stack stoppen + pct exec "$SEL_ID" -- bash -c \ + "cd ${FT_DIR} && docker compose down 2>/dev/null || true" + success "Stack gestoppt" + + # .env schreiben + pct exec "$SEL_ID" -- bash -c " + echo \"OPENVPN_USER=\$(echo ${NORD_USER_B64} | base64 -d)\" > ${FT_DIR}/.env + echo \"OPENVPN_PASSWORD=\$(echo ${NORD_PASS_B64} | base64 -d)\" >> ${FT_DIR}/.env + chmod 600 ${FT_DIR}/.env + " + success ".env geschrieben (chmod 600)" + + # docker-compose.yml schreiben + pct exec "$SEL_ID" -- bash -c "cat > ${FT_DIR}/docker-compose.yml << 'COMPOSEEOF' +# Freqtrade + NordVPN/Gluetun | generiert von proxmox-vpn-install.sh +# Netzwerk: [Freqtrade] -> [Gluetun] -> NordVPN -> Internet +# WebUI: http://LXC-IP:${FT_PORT} + +services: + + gluetun: + image: qmcgaw/gluetun:latest + container_name: gluetun + restart: unless-stopped + cap_add: + - NET_ADMIN + devices: + - /dev/net/tun:/dev/net/tun + environment: + - VPN_SERVICE_PROVIDER=nordvpn + - VPN_TYPE=openvpn + - OPENVPN_USER=\${OPENVPN_USER} + - OPENVPN_PASSWORD=\${OPENVPN_PASSWORD} +${VPN_SERVER_LINE} + ports: + - \"0.0.0.0:${FT_PORT}:8080\" + volumes: + - gluetun_data:/gluetun + healthcheck: + test: [\"CMD-SHELL\", \"wget -qO- https://ipinfo.io/ip || exit 1\"] + interval: 30s + timeout: 15s + retries: 5 + start_period: 45s + + freqtrade: + image: freqtradeorg/freqtrade:stable + restart: unless-stopped + container_name: freqtrade + network_mode: \"container:gluetun\" + depends_on: + gluetun: + condition: service_healthy + volumes: + - \"./user_data:/freqtrade/user_data\" + command: > + trade + --logfile /freqtrade/user_data/logs/freqtrade.log + --db-url sqlite:////freqtrade/user_data/tradesv3.sqlite + --config /freqtrade/user_data/config.json + --strategy SampleStrategy + +volumes: + gluetun_data: +COMPOSEEOF" + success "docker-compose.yml geschrieben" +} + +# ── Stack starten mit Fehlerbehandlung ───────────────────────────────────────── +start_and_verify() { + step "VPN-Stack starten" + + local FT_DIR="/opt/docker-projekte/freqtrade" + local MAX_ATTEMPTS=3 + local attempt=1 + + while [[ $attempt -le $MAX_ATTEMPTS ]]; do + echo -e "\n ${CYAN}Versuch ${attempt}/${MAX_ATTEMPTS}...${NC}" + + # Stack starten + pct exec "$SEL_ID" -- bash -c "cd ${FT_DIR} && docker compose up -d 2>&1" || true + + # Auf Gluetun warten (bis zu 60s) + info "Warte auf VPN-Verbindung (bis zu 60s)..." + local tries=0 + local vpn_ok=false + while [[ $tries -lt 12 ]]; do + sleep 5; echo -n "."; tries=$((tries+1)) + if pct exec "$SEL_ID" -- bash -c \ + "docker exec gluetun wget -qO- https://ipinfo.io/ip 2>/dev/null" &>/dev/null; then + vpn_ok=true + break + fi + done + echo + + if [[ "$vpn_ok" == "true" ]]; then + VPN_IP=$(pct exec "$SEL_ID" -- bash -c \ + "docker exec gluetun wget -qO- https://ipinfo.io/ip 2>/dev/null" || echo "unbekannt") + success "VPN verbunden! Ausgehende IP: ${BOLD}${GREEN}${VPN_IP}${NC}" + break + fi + + # Fehleranalyse + echo + warn "VPN-Verbindung fehlgeschlagen. Gluetun-Log:" + echo -e "${YELLOW}─────────────────────────────────────────${NC}" + pct exec "$SEL_ID" -- bash -c \ + "docker logs gluetun 2>&1 | grep -E 'ERROR|WARN|hostname|credentials|password|Invalid' | tail -20" \ + 2>/dev/null || true + echo -e "${YELLOW}─────────────────────────────────────────${NC}" + + # Häufige Fehler erkennen und erklären + local gluetun_errors + gluetun_errors=$(pct exec "$SEL_ID" -- bash -c \ + "docker logs gluetun 2>&1 | tail -30" 2>/dev/null || echo "") + + if echo "$gluetun_errors" | grep -qi "hostname.*not valid\|not one of the possible choices"; then + echo -e "\n ${RED}FEHLER: Ungültiger Hostname!${NC}" + echo -e " ${YELLOW}Gültige deutsche Server haben das Format: de507.nordvpn.com${NC}" + echo -e " ${YELLOW}Sieh die Fehlermeldung für eine Liste gültiger Hostnamen.${NC}" + elif echo "$gluetun_errors" | grep -qi "auth\|credential\|password\|unauthorized\|401"; then + echo -e "\n ${RED}FEHLER: Ungültige Credentials!${NC}" + echo -e " ${YELLOW}Bitte Service-Credentials prüfen unter:${NC}" + echo -e " ${CYAN}https://my.nordaccount.com → NordVPN → Set up NordVPN manually${NC}" + fi + + pct exec "$SEL_ID" -- bash -c "cd ${FT_DIR} && docker compose down 2>/dev/null || true" + + if [[ $attempt -lt $MAX_ATTEMPTS ]]; then + echo + if confirm "Andere Konfiguration versuchen?"; then + collect_vpn_config + write_vpn_config + else + error "Abgebrochen. Stack wurde gestoppt." + fi + fi + attempt=$((attempt+1)) + done + + [[ "$vpn_ok" != "true" ]] && error "VPN konnte nach ${MAX_ATTEMPTS} Versuchen nicht verbunden werden." + + # Freqtrade prüfen + sleep 6 + if pct exec "$SEL_ID" -- bash -c \ + "docker ps --filter name=freqtrade --filter status=running | grep -q freqtrade" 2>/dev/null; then + success "Freqtrade läuft" + else + warn "Freqtrade prüfen: pct exec ${SEL_ID} -- docker logs freqtrade" + fi +} + +# ── Ergebnis anzeigen ────────────────────────────────────────────────────────── +show_result() { + local LXC_IP + LXC_IP=$(pct exec "$SEL_ID" -- hostname -I 2>/dev/null | awk '{print $1}' || echo "unbekannt") + + echo + echo -e "${BOLD}${GREEN}╔══════════════════════════════════════════╗${NC}" + echo -e "${BOLD}${GREEN}║ ✅ NordVPN erfolgreich eingerichtet! ║${NC}" + echo -e "${BOLD}${GREEN}╚══════════════════════════════════════════╝${NC}" + echo + echo -e " ${BOLD}FreqUI:${NC} ${CYAN}http://${LXC_IP}:${FT_PORT}${NC}" + echo -e " ${BOLD}NordVPN IP:${NC} ${BOLD}${GREEN}${VPN_IP}${NC}" + echo + echo -e " ${BOLD}${YELLOW}⚠ Binance API-Key anpassen:${NC}" + echo -e " ${YELLOW}Binance → API Management → IP-Beschränkung${NC}" + echo -e " ${YELLOW}Die NordVPN-IP eintragen: ${BOLD}${VPN_IP}${NC}" + echo + echo -e " ${BOLD}Nützliche Befehle (im LXC: pct enter ${SEL_ID}):${NC}" + echo -e " ${CYAN}docker exec gluetun wget -qO- https://ipinfo.io/ip${NC} # VPN-IP prüfen" + echo -e " ${CYAN}docker logs gluetun${NC} # VPN-Logs" + echo -e " ${CYAN}docker logs freqtrade${NC} # Freqtrade-Logs" + echo -e " ${CYAN}cd /opt/docker-projekte/freqtrade && docker compose restart${NC}" + echo } # ── Hauptprogramm ────────────────────────────────────────────────────────────── @@ -194,7 +426,10 @@ main() { check_host select_container setup_tun - run_vpn_install + collect_vpn_config + write_vpn_config + start_and_verify + show_result } main "$@"