201 lines
8.5 KiB
Bash
201 lines
8.5 KiB
Bash
#!/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 auf dem PROXMOX HOST.
|
||
# Quelle: https://git.obraasch.de/olli1986/freqtrade-proxmox-deploy
|
||
# =============================================================================
|
||
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}"; }
|
||
|
||
VPN_SCRIPT_URL="https://git.obraasch.de/olli1986/freqtrade-proxmox-deploy/raw/branch/main/scripts/install-vpn.sh"
|
||
|
||
# ── Banner ─────────────────────────────────────────────────────────────────────
|
||
print_banner() {
|
||
clear
|
||
echo -e "${BOLD}${BLUE}"
|
||
cat << 'BANNER'
|
||
_ _ _ _ ___ _ _
|
||
| \| |___ _ _ __| \ \ / / | \| |
|
||
| .` / _ \ '_/ _` \ V /| | .` |
|
||
|_|\_\___/_| \__,_|\_/ |_|_|\_|
|
||
NordVPN Addon – Proxmox Host Installer
|
||
BANNER
|
||
echo -e "${NC}"
|
||
echo -e " ${CYAN}Richtet TUN-Device ein und startet NordVPN-Setup im LXC${NC}\n"
|
||
}
|
||
|
||
# ── Proxmox-Check ──────────────────────────────────────────────────────────────
|
||
check_host() {
|
||
[[ $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 suchen"
|
||
|
||
# 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
|
||
)
|
||
|
||
# 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
|
||
)
|
||
|
||
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"
|
||
else
|
||
error "Container muss laufen für die Installation!"
|
||
fi
|
||
fi
|
||
|
||
success "Gewählt: CT ${SEL_ID} | ${SEL_NAME}"
|
||
}
|
||
|
||
# ── 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
|
||
success "TUN-Device bereits konfiguriert"
|
||
return
|
||
fi
|
||
|
||
info "TUN-Device Zeilen fehlen – trage ein..."
|
||
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"
|
||
sleep 3
|
||
pct start "$SEL_ID"
|
||
sleep 5
|
||
|
||
# Warten auf Netzwerk
|
||
local tries=0
|
||
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"
|
||
}
|
||
|
||
# ── 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"
|
||
|
||
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; }
|
||
|
||
# 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
|
||
}
|
||
|
||
# ── Hauptprogramm ──────────────────────────────────────────────────────────────
|
||
main() {
|
||
print_banner
|
||
check_host
|
||
select_container
|
||
setup_tun
|
||
run_vpn_install
|
||
}
|
||
|
||
main "$@"
|