#!/usr/bin/env bash # ============================================================================= # Freqtrade NordVPN Addon – Proxmox Host Installer (Custom Config Edition) # Ablauf: System -> Ordner -> Filebrowser -> User-Input -> VPN-Start # ============================================================================= set -euo pipefail RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m' BLUE='\033[0;34m'; CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m' info() { echo -e "${CYAN}[INFO]${NC} $*"; } success() { echo -e "${GREEN}[ OK ]${NC} $*"; } warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } error() { echo -e "${RED}[FAIL]${NC} $*"; exit 1; } step() { echo -e "\n${BOLD}${BLUE}▶ $*${NC}"; } 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}" } confirm() { echo -ne "${YELLOW} ➜ ${NC}${1} [${CYAN}j${NC}/N]: " read -r ans; [[ "$ans" =~ ^[jJyY]$ ]] } print_banner() { clear echo -e "${BOLD}${BLUE} NordVPN Custom Config Installer (Filebrowser-First)${NC}\n" } 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?" success "Proxmox Host erkannt" } select_container() { step "Freqtrade Container auswählen" local -a display_list=() while IFS= read -r line; do 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 "?") display_list+=("${ct_id}|${hostname}|${status}") done < <(pct list 2>/dev/null | tail -n +2) 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\n" "$i" "$cid" "$cname" ((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))]}" 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 in LXC Config local conf="/etc/pve/lxc/${SEL_ID}.conf" if ! grep -q "lxc.mount.entry: /dev/net/tun" "$conf"; then 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 2 && pct start "$SEL_ID" && sleep 5 fi # 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 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 } collect_and_wait() { step "Konfiguration & User-Input" 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." while true; do echo 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) [[ "$size" -gt 10 ]] && { success "Inhalt erkannt!"; break; } warn "Die Datei ist noch leer oder zu klein. Bitte nochmal prüfen." fi done } deploy_vpn_stack() { step "VPN & Freqtrade Stack starten" local FT_DIR="/opt/docker-projekte/freqtrade" # 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 "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 container_name: gluetun cap_add: - NET_ADMIN devices: - /dev/net/tun:/dev/net/tun environment: - TZ=Europe/Berlin - VPN_SERVICE_PROVIDER=custom - VPN_TYPE=openvpn - OPENVPN_CUSTOM_CONFIG=/gluetun/custom.conf - OPENVPN_USER=${NORD_USER} - OPENVPN_PASSWORD=${NORD_PASS} - FIREWALL_OUTBOUND_SUBNETS=${SUBNET} volumes: - /opt/docker-projekte/VPN:/gluetun ports: - \"8080:8080\" restart: unless-stopped freqtrade: image: freqtradeorg/freqtrade:stable container_name: freqtrade restart: unless-stopped network_mode: \"container:gluetun\" volumes: - \"./user_data:/freqtrade/user_data\" depends_on: - gluetun 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 COMPOSEEOF" 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" success "Freqtrade & VPN Stack gestartet!" } main() { print_banner check_host select_container setup_base_system update_filebrowser 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 "$@"