Files
freqtrade-proxmox-deploy/scripts/proxmox-vpn-install-dev.sh
T

273 lines
10 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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
# =============================================================================
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]$ ]]
}
# ── 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"
}
# ── 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?"
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
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
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}"
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"
((i++))
done
echo
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
}
# ── TUN-Device & Ordner einrichten ─────────────────────────────────────────────
setup_system() {
step "System & VPN-Ordner vorbereiten"
# 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 "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 3 && pct start "$SEL_ID"
sleep 5
success "TUN-Device eingerichtet & Container neu gestartet"
else
success "TUN-Device war bereits konfiguriert"
fi
# 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 und custom.conf erstellt (/opt/docker-projekte/VPN)"
}
# ── 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
}
# ── Konfiguration abfragen & Datei befüllen lassen ─────────────────────────────
collect_and_wait() {
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}=== 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 "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)
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
}
# ── Docker Compose schreiben & anwenden ────────────────────────────────────────
deploy_stack() {
step "Docker Stack anwenden"
local FT_DIR="/opt/docker-projekte/freqtrade"
# 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}"
# 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
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}
# Automatisch ermitteltes lokales Netz für Erreichbarkeit
- 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"
# Stack starten
info "Starte Stack neu..."
pct exec "$SEL_ID" -- bash -c "cd ${FT_DIR} && docker compose up -d"
sleep 5
success "Deployment abgeschlossen!"
}
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 "$@"