#!/usr/bin/env bash # Apply qBittorrent BT net fixes on koopa (flame / firewalled inbound). # # Supersedes session one-shot /tmp/koopa-bt-fix.sh (2026-09-25). # # On koopa (hernani; firewalld needs sudo): # bash /path/to/koopa-admin-log/scripts/prime/apply-qbittorrent-bt-net.sh # # or after clone: # bash ~/koopa-admin-log/scripts/prime/apply-qbittorrent-bt-net.sh # # What it does: # 1) /downloads/incomplete/ as container user abc (host uid 100999) # 2) PortForwardingEnabled + Connection\UPnP = true (edit inside container) # 3) firewalld public: 6881/tcp + 6881/udp (sudo) # 4) podman restart koopa-prime-qbittorrent + STATUS= lines # # WAN inbound: VeciGate DNAT 6881 tcp+udp → koopa:6881 (+ hairpin LAN/LAN2) # applied 2026-09-25 (comment~qBittorrent). Re-check with script footer STATUS. # # Freigabe: podman + firewalld (session Freigabe required for live apply). set -euo pipefail CTR=koopa-prime-qbittorrent CONF_IN=/config/qBittorrent/qBittorrent.conf BT_PORT="${BT_PORT:-6881}" STAMP="$(date +%Y%m%d-%H%M%S)" die() { echo "ERROR: $*" >&2; exit 1; } command -v podman >/dev/null || die "podman missing" podman container exists "$CTR" || die "container $CTR missing" echo "===1_INCOMPLETE===" podman exec -u abc "$CTR" sh -c ' set -e mkdir -p /downloads/incomplete ls -lad /downloads /downloads/incomplete touch /downloads/incomplete/.writeok && rm /downloads/incomplete/.writeok echo incomplete_write=OK ' echo "===2_CONF_UPNP_PF===" # Host hernani cannot write config (owned by mapped abc/100999). Edit as abc. podman exec -u abc "$CTR" sh -c " set -e CONF='$CONF_IN' test -f \"\$CONF\" || { echo missing_conf; exit 1; } cp -a \"\$CONF\" \"\${CONF}.bak-btfix-$STAMP\" echo bak=\${CONF}.bak-btfix-$STAMP python3 - \"\$CONF\" <<'PY' import sys from pathlib import Path p = Path(sys.argv[1]) text = p.read_text() orig = text repls = [ ('PortForwardingEnabled=false', 'PortForwardingEnabled=true'), ('Connection\\\\UPnP=false', 'Connection\\\\UPnP=true'), ] changed = False for a, b in repls: if a in text: text = text.replace(a, b) changed = True if not changed: # Already true, or unexpected keys — report and continue if already OK keys = [ln for ln in text.splitlines() if 'UPnP' in ln or 'PortForward' in ln] if any('=true' in ln for ln in keys) and not any('=false' in ln for ln in keys if 'UPnP' in ln or 'PortForward' in ln): print('already_ok') for ln in keys: print(ln) raise SystemExit(0) print('no_keys_replaced') for ln in keys: print(ln) raise SystemExit(2) p.write_text(text) print('replaced_ok') for ln in text.splitlines(): if 'UPnP' in ln or 'PortForward' in ln: print(ln) PY " echo "===3_FIREWALLD===" fw_ok=0 if command -v firewall-cmd >/dev/null 2>&1; then if sudo -n true 2>/dev/null; then SUDO=(sudo -n) elif [[ "$(id -u)" -eq 0 ]]; then SUDO=() else # Interactive sudo (Freigabe path) SUDO=(sudo) fi if "${SUDO[@]}" firewall-cmd --permanent --add-port="${BT_PORT}/tcp" \ && "${SUDO[@]}" firewall-cmd --permanent --add-port="${BT_PORT}/udp" \ && "${SUDO[@]}" firewall-cmd --reload; then echo "firewalld_ports=$("${SUDO[@]}" firewall-cmd --list-ports 2>/dev/null || true)" echo "firewalld=OK" fw_ok=1 else echo "firewalld=FAIL" fi else echo "firewalld=MISSING_CMD" fi if [[ "$fw_ok" -ne 1 ]]; then echo "HINT: sudo firewall-cmd --permanent --add-port=${BT_PORT}/tcp" echo "HINT: sudo firewall-cmd --permanent --add-port=${BT_PORT}/udp" echo "HINT: sudo firewall-cmd --reload" fi echo "===4_RESTART===" podman restart "$CTR" sleep 4 podman ps --filter "name=$CTR" --format '{{.Names}} {{.Status}} {{.Ports}}' echo "===5_POST===" podman exec -u abc "$CTR" sh -c " grep -E 'UPnP|PortForward' $CONF_IN || true ls -lad /downloads/incomplete " ss -lntup 2>/dev/null | grep -E "${BT_PORT}|9023" || true ss -lnup 2>/dev/null | grep "${BT_PORT}" || true echo "STATUS=apply_done ctr=$CTR bt_port=$BT_PORT firewalld_ok=$fw_ok stamp=$STAMP" # VeciGate DNAT live 2026-09-25: wan dstnat tcp+udp 6881 → 192.168.100.95:6881 # + hairpin LAN 192.168.100.0/24 and LAN2 192.168.88.0/24 to 212.51.151.254:6881 echo "STATUS=vecigate_dnat live wan+hairpin LAN/LAN2 → 192.168.100.95:$BT_PORT (comment~qBittorrent)" echo "STATUS=verify WAN: nc -vz 212.51.151.254 $BT_PORT ; LAN: nc -vz 192.168.100.95 $BT_PORT" echo "STATUS=verify WebUI connection icon (flame=firewalled) at bt.hacktivism.ch"