From fe26ce4cbb29f22af863861df75d9609a3d0b75e Mon Sep 17 00:00:00 2001 From: Oliver Braasch Date: Mon, 20 Apr 2026 23:34:43 +0200 Subject: [PATCH] Dateien nach "scripts" hochladen --- scripts/proxmox-vpn-install.sh | 174 +++++++++++++++++++++++++++------ 1 file changed, 146 insertions(+), 28 deletions(-) diff --git a/scripts/proxmox-vpn-install.sh b/scripts/proxmox-vpn-install.sh index a27ee92..4b2e7be 100644 --- a/scripts/proxmox-vpn-install.sh +++ b/scripts/proxmox-vpn-install.sh @@ -182,7 +182,8 @@ collect_vpn_config() { NORD_USER="$REPLY" [[ -z "$NORD_USER" ]] && error "Username darf nicht leer sein!" - ask_secret "NordVPN Service-Passwort" + stty echo 2>/dev/null || true + ask "NordVPN Service-Passwort" NORD_PASS="$REPLY" [[ -z "$NORD_PASS" ]] && error "Passwort darf nicht leer sein!" @@ -196,8 +197,10 @@ collect_vpn_config() { VPN_PROTO="udp" # Start mit UDP, automatischer Fallback auf TCP bei TLS-Fehler 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}" + echo -e "\n ${YELLOW}Hostnamen Format: de507.nordvpn.com, de654.nordvpn.com etc.${NC}" + echo -e " ${YELLOW}Wichtig: NordVPN zeigt oft neue Server die Gluetun noch nicht kennt.${NC}" + echo -e " ${YELLOW}Falls 'Ungültiger Hostname' erscheint → die angezeigten gültigen Server nutzen.${NC}" + echo -e " ${CYAN}Tipp: Modus 1 (Serverland) ist einfacher – Gluetun wählt selbst.${NC}" ask "Hostname (z.B. de507.nordvpn.com)" VPN_HOSTNAME="$REPLY"; VPN_COUNTRY="" else @@ -205,13 +208,9 @@ collect_vpn_config() { 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" + # FreqUI Port aus bestehender docker-compose.yml lesen (ändert sich nicht) + FT_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") + info "FreqUI Port: ${FT_PORT} (aus bestehender Konfiguration)" echo -e "\n${BOLD}${BLUE}══════════ Zusammenfassung ══════════${NC}" echo -e " Container: ${CYAN}CT ${SEL_ID} | ${SEL_NAME}${NC}" @@ -227,6 +226,8 @@ collect_vpn_config() { # ── Konfiguration in Container schreiben ────────────────────────────────────── write_vpn_config() { step "VPN-Konfiguration in Container schreiben" + # Image: custom build bei Dedicated-IP, sonst offizielles Image + GLUETUN_IMAGE="${GLUETUN_IMAGE:-qmcgaw/gluetun:latest}" local FT_DIR="/opt/docker-projekte/freqtrade" local NORD_USER_B64 NORD_PASS_B64 @@ -234,9 +235,15 @@ write_vpn_config() { 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}" + local VPN_CUSTOM_LINE="" + if [[ -n "$VPN_HOSTNAME" ]]; then + # Dedicated-IP: Custom Config direkt mit IP – bypasses Gluetun Hostname-Validierung + VPN_SERVER_LINE=" - VPN_SERVICE_PROVIDER=custom" + VPN_CUSTOM_LINE=" - OPENVPN_CUSTOM_CONFIG=/gluetun/nordvpn-custom.conf" + else + VPN_SERVER_LINE=" - VPN_SERVICE_PROVIDER=nordvpn" + VPN_CUSTOM_LINE=" - SERVER_COUNTRIES=${VPN_COUNTRY}" + fi # Backup pct exec "$SEL_ID" -- bash -c \ @@ -275,7 +282,7 @@ services: # Gluetun läuft als HTTP-Proxy auf Port 8888. # Freqtrade schickt nur den Exchange-Traffic darüber. gluetun: - image: qmcgaw/gluetun:latest + image: ${GLUETUN_IMAGE:-qmcgaw/gluetun:latest} container_name: gluetun restart: unless-stopped cap_add: @@ -283,11 +290,11 @@ services: devices: - /dev/net/tun:/dev/net/tun environment: - - VPN_SERVICE_PROVIDER=nordvpn +${VPN_SERVER_LINE} - VPN_TYPE=openvpn - OPENVPN_USER=\${OPENVPN_USER} - OPENVPN_PASSWORD=\${OPENVPN_PASSWORD} -${VPN_SERVER_LINE} +${VPN_CUSTOM_LINE} # HTTP-Proxy aktivieren – darüber leitet Freqtrade den Binance-Traffic - HTTPPROXY=on - HTTPPROXY_LOG=off @@ -345,6 +352,90 @@ start_and_verify() { local vpn_ok=false VPN_IP="" + # Bei Hostname-Modus: Gluetun aus GitHub klonen, Server eintragen, neu kompilieren + # → Löst das Problem dauerhaft: de1370 wird in die Binary eingebaut + if [[ -n "${VPN_HOSTNAME:-}" ]]; then + step "Gluetun Custom Build für ${VPN_HOSTNAME}" + + # IP per DNS auflösen + local server_ip="" + server_ip=$(pct exec "$SEL_ID" -- bash -c "getent hosts ${VPN_HOSTNAME} 2>/dev/null | awk '{print \$1}' | head -1" 2>/dev/null || echo "") + [[ -z "$server_ip" ]] && server_ip=$(pct exec "$SEL_ID" -- bash -c "nslookup ${VPN_HOSTNAME} 2>/dev/null | awk '/Address:/ && !/#/{print \$2}' | head -1" 2>/dev/null || echo "") + [[ -z "$server_ip" ]] && error "IP für ${VPN_HOSTNAME} nicht auflösbar!" + info "DNS: ${VPN_HOSTNAME} → ${server_ip}" + + # Prüfen ob Image bereits existiert (kein Rebuild nötig) + local img_exists + img_exists=$(pct exec "$SEL_ID" -- bash -c "docker image inspect gluetun-custom:latest 2>/dev/null | grep -c 'Id' || echo 0" 2>/dev/null || echo "0") + + if [[ "$img_exists" -gt 0 ]]; then + # Prüfen ob der Hostname schon drin ist + local host_in_img + host_in_img=$(pct exec "$SEL_ID" -- bash -c "docker run --rm --entrypoint sh gluetun-custom:latest -c 'cat /gluetun/servers.json 2>/dev/null | grep -c ${VPN_HOSTNAME} || echo 0'" 2>/dev/null || echo "0") + if [[ "$host_in_img" -gt 0 ]]; then + success "gluetun-custom:latest bereits vorhanden und enthält ${VPN_HOSTNAME}" + GLUETUN_IMAGE="gluetun-custom:latest" + return 0 2>/dev/null || true + fi + info "Image vorhanden, aber ${VPN_HOSTNAME} fehlt – baue neu..." + fi + + # git installieren falls nötig + pct exec "$SEL_ID" -- bash -c "command -v git &>/dev/null || apt-get install -y -qq git" 2>/dev/null + + info "Klone Gluetun von GitHub (einmalig, ~3-5 Min zum Kompilieren)..." + pct exec "$SEL_ID" -- bash -c "rm -rf /tmp/gluetun-build && git clone --depth 1 https://github.com/qdm12/gluetun.git /tmp/gluetun-build 2>&1 | tail -3" + + info "Füge ${VPN_HOSTNAME} (${server_ip}) in servers.json ein..." + pct exec "$SEL_ID" -- bash -c "python3 << PYEOF +import json, copy, sys + +path = '/tmp/gluetun-build/internal/storage/servers.json' +hostname = '${VPN_HOSTNAME}' +ip = '${server_ip}' + +with open(path) as f: + db = json.load(f) + +servers = db.get('nordvpn', {}).get('servers', []) + +if any(s.get('hostname') == hostname for s in servers): + print(f'Bereits vorhanden: {hostname}') + sys.exit(0) + +# Deutschen OpenVPN-Eintrag als Template klonen +template = next( + (s for s in servers if s.get('country','').lower() == 'germany' and s.get('vpn') == 'openvpn'), + servers[0] +) +entry = copy.deepcopy(template) +entry['hostname'] = hostname +entry['ips'] = [ip] + +servers.append(entry) +db['nordvpn']['servers'] = servers + +with open(path, 'w') as f: + json.dump(db, f, indent=2) +print(f'Eingetragen: {hostname} ({ip}) – Gesamt NordVPN-Server: {len(servers)}') +PYEOF" + + info "Kompiliere Gluetun Docker Image (dauert ~3-5 Minuten)..." + echo -e " ${YELLOW}Bitte warten – Go Multi-Stage Build...${NC}" + pct exec "$SEL_ID" -- bash -c "cd /tmp/gluetun-build && docker build -t gluetun-custom:latest . 2>&1 | grep -E '^Step|Successfully|error|Error|=>|RUN|COPY' | tail -30" && success "gluetun-custom:latest erfolgreich gebaut!" || error "Docker Build fehlgeschlagen. Prüfe: pct exec ${SEL_ID} -- docker build /tmp/gluetun-build" + + GLUETUN_IMAGE="gluetun-custom:latest" + info "Aufräumen..." + pct exec "$SEL_ID" -- bash -c "rm -rf /tmp/gluetun-build" 2>/dev/null || true + else + GLUETUN_IMAGE="qmcgaw/gluetun:latest" + fi + + # docker-compose.yml mit korrektem Image aktualisieren + info "Setze Image in docker-compose.yml: ${GLUETUN_IMAGE}" + pct exec "$SEL_ID" -- bash -c "sed -i 's|image: .*gluetun.*|image: ${GLUETUN_IMAGE}|' ${FT_DIR}/docker-compose.yml" + + # Protokoll-Reihenfolge: UDP zuerst, dann automatisch TCP for proto in udp tcp; do [[ "$proto" == "tcp" ]] && info "UDP fehlgeschlagen – versuche TCP automatisch..." @@ -367,7 +458,7 @@ start_and_verify() { ${CYAN}[INFO]${NC} ${proto^^} – ${elapsed}s..." local log_snippet - log_snippet=$(pct exec "$SEL_ID" -- bash -c "docker logs --since 30s gluetun 2>&1" 2>/dev/null || echo "") + log_snippet=$(pct exec "$SEL_ID" -- bash -c "docker logs gluetun 2>&1 | tail -60" 2>/dev/null || echo "") # Auth-Fehler → sofort abbrechen, kein Retry if echo "$log_snippet" | grep -qi "AUTH_FAILED\|auth.*fail\|wrong.*password\|incorrect.*password"; then @@ -388,22 +479,49 @@ start_and_verify() { fi fi - # Hostname ungültig → sofort abbrechen + # Hostname ungültig → gültige Server aus Log parsen und zur Auswahl anbieten if echo "$log_snippet" | grep -qi "hostname.*not valid\|not one of the possible choices"; then echo - echo -e " - ${RED}✗ Ungültiger Hostname!${NC}" - echo -e " ${YELLOW}Gültige Server: de507.nordvpn.com, de654.nordvpn.com, de675.nordvpn.com ...${NC}" - pct exec "$SEL_ID" -- bash -c "cd ${FT_DIR} && docker compose down 2>/dev/null || true" + echo -e " ${RED}✗ Ungültiger Hostname: ${VPN_HOSTNAME}${NC}" + echo -e " ${YELLOW}Nicht in Gluetuns Server-Datenbank. Bitte einen der folgenden wählen:${NC} +" - if confirm "Anderen Hostname eingeben?"; then - collect_vpn_config - write_vpn_config - start_and_verify - return + # Mehr Log holen – die Server-Liste ist sehr lang + local full_log valid_servers + full_log=$(pct exec "$SEL_ID" -- bash -c "docker logs gluetun 2>&1" 2>/dev/null || echo "") + # Nur deutsche Server aus der Liste filtern (de*) + valid_servers=$(echo "$full_log" | grep -oP 'de[0-9]+\.nordvpn\.com' | sort -uV | head -20) + # Falls keine deutschen → alle zeigen + [[ -z "$valid_servers" ]] && valid_servers=$(echo "$full_log" | grep -oP '[a-z]{2}[0-9]+\.nordvpn\.com' | sort -u | head -20) + + if [[ -n "$valid_servers" ]]; then + local i=1 + while IFS= read -r srv; do + printf " ${CYAN}%2s)${NC} %s +" "$i" "$srv" + i=$((i+1)) + done <<< "$valid_servers" + echo + echo -ne "${YELLOW} ➜ ${NC}Nummer wählen oder Hostname direkt eingeben: " + read -r sel + if [[ "$sel" =~ ^[0-9]+$ ]]; then + VPN_HOSTNAME=$(echo "$valid_servers" | sed -n "${sel}p") + elif [[ -n "$sel" ]]; then + VPN_HOSTNAME="$sel" + fi + if [[ -n "$VPN_HOSTNAME" ]]; then + info "Neuer Hostname: $VPN_HOSTNAME – schreibe Config neu..." + pct exec "$SEL_ID" -- bash -c "cd ${FT_DIR} && docker compose down 2>/dev/null || true" + write_vpn_config + tries=0; tls_error=false + pct exec "$SEL_ID" -- bash -c "cd ${FT_DIR} && docker compose up -d 2>&1" || true + continue + fi else - error "Abgebrochen." + echo -e " ${YELLOW}Keine Server im Log gefunden. Modus 1 (Serverland) empfohlen.${NC}" fi + pct exec "$SEL_ID" -- bash -c "cd ${FT_DIR} && docker compose down 2>/dev/null || true" + error "Abgebrochen." fi # TLS-Fehler → nächstes Protokoll versuchen