Replies: 1 comment
-
|
Or even simpler, mount the /tmp/gluetun directory to a shared volumeMount, and then use this script to read from ---
apiVersion: v1
kind: ConfigMap
metadata:
name: qbittorrent-port-sync
namespace: media
data:
sync-port.sh: |
#!/bin/sh
set -e
# Configuration
GLUETUN_PORT_FILE="/tmp/gluetun/forwarded_port"
QBITTORRENT_API="http://127.0.0.1:8180"
CHECK_INTERVAL=60
MAX_RETRIES=20
RETRY_DELAY=15
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
}
# Wait for gluetun to write the forwarded port file
wait_for_gluetun() {
log "Waiting for gluetun to create forwarded port file..."
for i in $(seq 1 $MAX_RETRIES); do
if [ -f "$GLUETUN_PORT_FILE" ] && [ -s "$GLUETUN_PORT_FILE" ]; then
local port=$(cat "$GLUETUN_PORT_FILE" 2>/dev/null | tr -d '[:space:]')
if [ -n "$port" ] && [ "$port" -gt 0 ] 2>/dev/null; then
log "Gluetun port file found with port: $port"
return 0
fi
fi
log "Waiting for port file, attempt $i/$MAX_RETRIES..."
sleep $RETRY_DELAY
done
log "ERROR: Gluetun port file did not become available at $GLUETUN_PORT_FILE"
return 1
}
# Wait for qBittorrent to be ready
wait_for_qbittorrent() {
log "Waiting for qBittorrent API to be available..."
for i in $(seq 1 $MAX_RETRIES); do
if wget -q -O- --timeout=5 "$QBITTORRENT_API/api/v2/app/version" >/dev/null 2>&1; then
log "qBittorrent API is ready"
return 0
fi
log "qBittorrent not ready, attempt $i/$MAX_RETRIES..."
sleep $RETRY_DELAY
done
log "ERROR: qBittorrent API did not become available"
return 1
}
# Get the forwarded port from gluetun file
get_gluetun_port() {
if [ ! -f "$GLUETUN_PORT_FILE" ]; then
log "WARNING: Port file does not exist: $GLUETUN_PORT_FILE"
return 1
fi
local port=$(cat "$GLUETUN_PORT_FILE" 2>/dev/null | tr -d '[:space:]')
if [ -z "$port" ]; then
log "WARNING: Port file is empty: $GLUETUN_PORT_FILE"
return 1
fi
# Validate port is a number and in valid range
if ! echo "$port" | grep -qE '^[0-9]+$'; then
log "ERROR: Invalid port value in file: '$port'"
return 1
fi
if [ "$port" -lt 1024 ] || [ "$port" -gt 65535 ]; then
log "WARNING: Port out of valid range: $port"
return 1
fi
echo "$port"
return 0
}
# Get current qBittorrent listening port
get_qbittorrent_port() {
local response
response=$(wget -q -O- --timeout=10 "$QBITTORRENT_API/api/v2/app/preferences" 2>/dev/null)
if [ $? -ne 0 ]; then
log "ERROR: Failed to fetch preferences from qBittorrent"
return 1
fi
# Extract listen_port from JSON response
local port=$(echo "$response" | sed -n 's/.*"listen_port":\([0-9]*\).*/\1/p')
echo "$port"
return 0
}
# Update qBittorrent listening port
update_qbittorrent_port() {
local new_port=$1
local current_port
current_port=$(get_qbittorrent_port)
if [ $? -ne 0 ]; then
log "WARNING: Could not get current qBittorrent port, proceeding with update..."
elif [ "$current_port" = "$new_port" ]; then
log "Port is already set to $new_port, skipping update"
return 0
fi
log "Updating qBittorrent listening port from ${current_port:-unknown} to $new_port..."
local response
# Simple wget command compatible with BusyBox
response=$(wget -O- -T 10 \
--post-data "json={\"listen_port\":$new_port,\"random_port\":false,\"upnp\":false}" \
"$QBITTORRENT_API/api/v2/app/setPreferences" 2>&1)
if [ $? -eq 0 ]; then
log "Successfully updated qBittorrent listening port to $new_port"
return 0
else
log "ERROR: Failed to update qBittorrent port (response: $response)"
return 1
fi
}
# Main sync loop
main() {
log "Starting qBittorrent port sync service..."
# Wait for services to be ready
wait_for_gluetun || exit 1
wait_for_qbittorrent || exit 1
local current_synced_port=""
while true; do
# Get port from gluetun
gluetun_port=$(get_gluetun_port)
if [ $? -eq 0 ] && [ -n "$gluetun_port" ]; then
# Only update if port has changed
if [ "$gluetun_port" != "$current_synced_port" ]; then
log "Detected new port: $gluetun_port (previous: ${current_synced_port:-none})"
if update_qbittorrent_port "$gluetun_port"; then
current_synced_port="$gluetun_port"
log "Port sync completed successfully"
else
log "Port sync failed, will retry on next check"
fi
fi
else
log "Could not get port from gluetun, will retry..."
fi
sleep $CHECK_INTERVAL
done
}
# Run main function
main
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: qbittorrent
namespace: media
spec:
serviceName: qbittorrent
template:
spec:
containers:
- env:
- name: WEBUI_PORT
value: "8180"
image: linuxserver/qbittorrent:5.1.4
imagePullPolicy: IfNotPresent
name: qbittorrent
- command:
- /bin/sh
- /scripts/sync-port.sh
image: alpine:3.19
imagePullPolicy: IfNotPresent
name: port-sync
resources:
limits:
cpu: 50m
memory: 64Mi
requests:
cpu: 10m
memory: 32Mi
volumeMounts:
- mountPath: /scripts
name: port-sync-script
readOnly: true
- mountPath: /tmp/gluetun
name: gluetun-tmp
readOnly: true
initContainers:
- env:
- name: FIREWALL
value: "on"
- name: PORT_FORWARD_ONLY
value: "on"
- name: VPN_PORT_FORWARDING
value: "on"
- name: VPN_TYPE
value: wireguard
image: qmcgaw/gluetun:v3.40.3
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /tmp/gluetun
name: gluetun-tmp
volumes:
- configMap:
defaultMode: 493
name: qbittorrent-port-sync
name: port-sync-script
- emptyDir: {}
name: gluetun-tmp
|
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Throwing this out there because I found a solution that works for me running Glutetun + ProtonVPN via Wireguard and qBittorrent on kubernetes.
I'm using ProtonVPN via Wireguard with VPN Port Forwarding on which randomizes port on connection. There are docs in the wiki on how to solve for this here which works most of the time, however I found a more k8s-friendly solution that I want to share with others.
I have added a shell script into a configmap that polls gluetun's control server API periodically and writes the port to qBittorrent's API if there is a change. I am running a qbittorrent statefulset with gluetun as an initContainer. I now also run a lightweight alpine sidecar (10m vCPU and 32Mi) that executes this shell script. I've found that this is really stable, hopefully it helps others!
Note that you will need to follow the gluetun-wiki on how to access the gluetun control server. For this example, I'm assuming you have auth disabled.
Dropping some abbreviated k8s manifests below in case they help someone.
Beta Was this translation helpful? Give feedback.
All reactions