diff --git a/scripts/proxmox-vpn-install-dev.sh b/scripts/proxmox-vpn-install-dev.sh index e186c72..c2e11e5 100644 --- a/scripts/proxmox-vpn-install-dev.sh +++ b/scripts/proxmox-vpn-install-dev.sh @@ -1,13 +1,7 @@ #!/usr/bin/env bash # ============================================================================= # Freqtrade NordVPN Addon – Proxmox Host Installer (Custom Config Edition) -# 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 +# Ablauf: System -> Ordner -> Filebrowser -> User-Input -> VPN-Start # ============================================================================= set -euo pipefail @@ -33,22 +27,11 @@ confirm() { read -r ans; [[ "$ans" =~ ^[jJyY]$ ]] } -# ── Banner ───────────────────────────────────────────────────────────────────── print_banner() { clear - 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" + echo -e "${BOLD}${BLUE} NordVPN Custom Config Installer (Filebrowser-First)${NC}\n" } -# ── Proxmox-Check ────────────────────────────────────────────────────────────── check_host() { step "Proxmox Host prüfen" [[ $EUID -ne 0 ]] && error "Bitte als root ausführen!" @@ -56,130 +39,112 @@ 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 tags + local ct_id status hostname 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 "?") - 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 + display_list+=("${ct_id}|${hostname}|${status}") done < <(pct list 2>/dev/null | tail -n +2) - [[ ${#display_list[@]} -eq 0 ]] && error "Keine Container mit Tag 'freqtrade' gefunden!" - - echo -e " ${BOLD}Nr ID Hostname Status${NC}" - echo -e " ${BLUE}─────────────────────────────────────────${NC}" + echo -e " ${BOLD}Nr ID Hostname${NC}" local i=1 for entry in "${display_list[@]}"; do IFS='|' read -r cid cname cstatus <<< "$entry" - printf " ${CYAN}%-4s${NC} %-8s %-18s %-10s\n" "$i" "$cid" "$cname" "$cstatus" + printf " ${CYAN}%-4s${NC} %-8s %-18s\n" "$i" "$cid" "$cname" ((i++)) done echo - - local sel_nr=1 - [[ ${#display_list[@]} -gt 1 ]] && { ask "Container Nummer wählen" "1"; sel_nr="$REPLY"; } - + ask "Container Nummer wählen" "1"; local 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 } -# ── TUN-Device & Ordner einrichten ───────────────────────────────────────────── -setup_system() { - step "System & VPN-Ordner vorbereiten" +setup_base_system() { + step "Grundsystem & VPN-Ordner vorbereiten" - # 1. TUN-Device in LXC Config schreiben + # TUN-Device in LXC Config local conf="/etc/pve/lxc/${SEL_ID}.conf" if ! grep -q "lxc.mount.entry: /dev/net/tun" "$conf"; then - info "Trage TUN-Device in Config ein..." + info "Konfiguriere TUN-Device..." 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 3 && pct start "$SEL_ID" - sleep 5 - success "TUN-Device eingerichtet & Container neu gestartet" - else - success "TUN-Device war bereits konfiguriert" + pct stop "$SEL_ID" && sleep 2 && pct start "$SEL_ID" && sleep 5 fi - # 2. Ordner und Datei erstellen & Rechte setzen + # VPN Ordner erstellen (BEVOR Filebrowser ihn braucht) 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 und custom.conf erstellt (/opt/docker-projekte/VPN)" + success "VPN Ordner ist bereit." +} + +update_filebrowser() { + step "Filebrowser Anbindung (Vorbereitung)" + local FB_DIR="/opt/docker-projekte/filebrowser" + local FB_YML="${FB_DIR}/docker-compose.yml" + + 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!" + else + success "Filebrowser bereits konfiguriert." + fi + else + warn "Filebrowser nicht gefunden. Du musst die custom.conf manuell bearbeiten." + fi } -# ── Konfiguration abfragen & Datei befüllen lassen ───────────────────────────── collect_and_wait() { - step "NordVPN Credentials & Config" + step "Konfiguration & User-Input" - 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}=== 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" + 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." while true; do echo - if confirm "Hast du die custom.conf befüllt und gespeichert?"; then - # Kurzer Check, ob die Datei nicht mehr leer ist + if confirm "Ist die custom.conf im Filebrowser gespeichert?"; then local size size=$(pct exec "$SEL_ID" -- stat -c%s /opt/docker-projekte/VPN/custom.conf 2>/dev/null || echo 0) - 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 + [[ "$size" -gt 10 ]] && { success "Inhalt erkannt!"; break; } + warn "Die Datei ist noch leer oder zu klein. Bitte nochmal prüfen." fi done } -# ── Docker Compose schreiben & anwenden ──────────────────────────────────────── -deploy_stack() { - step "Docker Stack anwenden" +deploy_vpn_stack() { + step "VPN & Freqtrade Stack starten" local FT_DIR="/opt/docker-projekte/freqtrade" - # Lokales Subnetz automatisch ermitteln (z.B. 192.168.178.0/24) + # Subnetz ermitteln 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}" - # 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..." + info "Schreibe neue docker-compose.yml für Freqtrade..." pct exec "$SEL_ID" -- bash -c "cat > ${FT_DIR}/docker-compose.yml << 'COMPOSEEOF' version: '3.8' - services: gluetun: image: qmcgaw/gluetun:latest @@ -195,7 +160,6 @@ 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 @@ -219,71 +183,26 @@ services: --config /freqtrade/user_data/config.json --strategy SampleStrategy COMPOSEEOF" - - # Stack starten - info "Starte Stack neu..." + + pct exec "$SEL_ID" -- bash -c "cd ${FT_DIR} && docker compose down 2>/dev/null || true" pct exec "$SEL_ID" -- bash -c "cd ${FT_DIR} && docker compose up -d" - sleep 5 - success "Deployment abgeschlossen!" + success "Freqtrade & VPN Stack gestartet!" } -# ── Filebrowser anpassen ─────────────────────────────────────────────────────── -update_filebrowser() { - 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 - 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 - 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 - info "Kein Filebrowser unter ${FB_DIR} gefunden. Überspringe diesen Schritt." - fi -} - -# ── Ergebnis anzeigen ────────────────────────────────────────────────────────── -show_result() { - # VPN IP Check - local VPN_IP - VPN_IP=$(pct exec "$SEL_ID" -- bash -c "docker exec gluetun wget -qO- https://ifconfig.me 2>/dev/null" || echo "FEHLER") - 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 "Lokales Netz") - - echo - echo -e "${BOLD}${GREEN}╔══════════════════════════════════════════╗${NC}" - echo -e "${BOLD}${GREEN}║ ✅ Setup erfolgreich abgeschlossen! ║${NC}" - echo -e "${BOLD}${GREEN}╚══════════════════════════════════════════╝${NC}" - echo -e " Neue externe VPN-IP des Bots: ${CYAN}${VPN_IP}${NC}" - echo -e " Dein lokales Subnetz (${SUBNET}) wurde in der Firewall freigegeben." - echo -e " Das Freqtrade-Webinterface bleibt über Port 8080 erreichbar." - echo -e " Der Ordner 'VPN' steht dir jetzt in deinem Filebrowser zur Verfügung!" -} - -# ── Hauptprogramm ────────────────────────────────────────────────────────────── main() { print_banner check_host select_container - setup_system - collect_and_wait - deploy_stack + setup_base_system update_filebrowser - show_result + collect_and_wait + deploy_vpn_stack + + # Finaler IP Check + local IP + IP=$(pct exec "$SEL_ID" -- bash -c "docker exec gluetun wget -qO- https://ifconfig.me 2>/dev/null" || echo "Check fehlgeschlagen") + echo -e "\n${GREEN}FERTIG! Externe VPN-IP: ${BOLD}${IP}${NC}" } main "$@" \ No newline at end of file