Skip to content

Instantly share code, notes, and snippets.

@socketbox
Forked from trevordavies095/update_qbit_port.sh
Last active February 24, 2024 11:31
Show Gist options
  • Save socketbox/12be539ba0e26b76529e082c97bff53c to your computer and use it in GitHub Desktop.
Save socketbox/12be539ba0e26b76529e082c97bff53c to your computer and use it in GitHub Desktop.
Determine protonvpn port via gluetun and update qbittorrent
#!/bin/sh
# Determine protonvpn port via gluetun and update qbittorrent
#
# Add the following to sudo crontab -e to run every 5 minutes
# */5 * * * * /bin/sh /path/to/update_qbit_port.sh
# For synology users, run the script as root via the task scheduler every 5 minutes.
QBITTORRENT_USER= # qbittorrent username
QBITTORRENT_PASS= # qbittorrent password
QBITTORRENT_PORT=
QBITTORRENT_SERVER=localhost # usually localhost if running all containers on the same machine
GLUETUN_SERVER=localhost # usually localhost if running all containers on the same machine
GLUETUN_PORT=
VPN_CT_NAME=gluetun
timestamp() {
date '+%Y-%m-%d %H:%M:%S'
}
findconfiguredport() {
curl -s --header "Referer: http://${QBITTORRENT_SERVER}:${QBITTORRENT_PORT}" --cookie "$1" "http://${QBITTORRENT_SERVER}:${QBITTORRENT_PORT}/api/v2/app/preferences" | jq -r '.listen_port'
}
findactiveport() {
curl -s "http://${GLUETUN_SERVER}:${GLUETUN_PORT}/v1/openvpn/portforwarded" | jq -r '.port'
}
getpublicip() {
curl -s "http://${GLUETUN_SERVER}:${GLUETUN_PORT}/v1/publicip/ip" | jq -r '.public_ip'
}
qbt_login() {
qbt_sid=$(curl -s -i --header "Referer: http://${QBITTORRENT_SERVER}:${QBITTORRENT_PORT}" --data "username=${QBITTORRENT_USER}" --data-urlencode "password=${QBITTORRENT_PASS}" "http://${QBITTORRENT_SERVER}:${QBITTORRENT_PORT}/api/v2/auth/login" | awk -F'SID=|;' '/set-cookie: SID/{print $2}')
return $?
}
qbt_changeport() {
curl -s -i --header "Referer: http://${QBITTORRENT_SERVER}:${QBITTORRENT_PORT}" --cookie "$1" --data-urlencode "json={\"listen_port\":$2,\"random_port\":false,\"upnp\":false}" "http://${QBITTORRENT_SERVER}:${QBITTORRENT_PORT}/api/v2/app/setPreferences" >/dev/null 2>&1
return $?
}
qbt_checksid() {
if curl -s --header "Referer: http://${QBITTORRENT_SERVER}:${QBITTORRENT_PORT}" --cookie "${qbt_sid}" "http://${QBITTORRENT_SERVER}:${QBITTORRENT_PORT}/api/v2/app/version" | grep -qi forbidden; then
return 1
else
return 0
fi
}
qbt_isreachable() {
nc -vw 5 ${QBITTORRENT_SERVER} ${QBITTORRENT_PORT} &>/dev/null 2>&1
}
check_vpn_ct_health() {
while true;
do
response_code=$(curl -s -X GET -w "%{http_code}\n" "http://${GLUETUN_SERVER}:${GLUETUN_PORT}/v1/openvpn/portforwarded" -o /dev/null)
if [ $response_code -ne 200 ]; then
echo "$(timestamp) | VPN container ${VPN_CT_NAME} not answering..."
sleep 10
else
echo "$(timestamp) | VPN container ${VPN_CT_NAME} in healthy state!"
break
fi
done
}
get_portmap() {
res=0
public_ip=$(getpublicip)
echo "Debug--this is public_ip: $public_ip"
qbt_login
echo "Debug--this is qbt_sid: $qbt_sid"
if ! qbt_checksid; then
echo "$(timestamp) | qBittorrent Cookie invalid, getting new SessionID"
if ! qbt_login; then
echo "$(timestamp) | Failed getting new SessionID from qBittorrent"
return 1
fi
else
echo "$(timestamp) | qBittorrent SessionID Ok!"
fi
configured_port=$(findconfiguredport "${qbt_sid}")
active_port=$(findactiveport)
echo "$(timestamp) | Public IP: ${public_ip}"
echo "$(timestamp) | Configured Port: ${configured_port}"
echo "$(timestamp) | Active Port: ${active_port}"
if [ "${configured_port}" != "${active_port}" ]; then
if qbt_changeport "${qbt_sid}" ${active_port}; then
echo "$(timestamp) | Port Changed to: $(findconfiguredport ${qbt_sid})"
else
echo "$(timestamp) | Port Change failed."
res=1
fi
else
echo "$(timestamp) | Port OK (Act: ${active_port} Cfg: ${configured_port})"
fi
return $res
}
public_ip=
configured_port=
active_port=
qbt_sid=
# Wait for a healthy state on the VPN container
sleep 20
check_vpn_ct_health
# check and possibly update the port
get_portmap
exit $?
@socketbox
Copy link
Author

Re-written for use in an Alpine-based container. A suitable service block/stanza in a docker compose file would look like the following:

port-updater:
    container_name: port-updater
    depends_on:
      - gluetun
      - qbittorrent-nox
    build:
      dockerfile_inline: |
        FROM alpine:latest
        RUN apk add --no-cache curl jq
        COPY --chmod=755 update_qbit_port.sh /bin/update_qbit_port.sh
        CMD update_qbit_port.sh
    network_mode: service:gluetun

Note the network_mode. It allows us to use localhost as the host in requests to both the gluetun and qbittorrent-nox only if the qbittorrent-nox container is also using service:gluetun for its network.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment