So I’m learning python (by doing, reading, and doing some more), and I’ve been wanting to automate updating the listening port in my qbittorrent docker container when the gluetun vpn container changes the forwarded port.
This is what I came up with, which I combined with an hourly cronjob to keep it the listen port updated.
(Code under the spoiler tag to make this more readable).
Tap for spoiler
import re
import os
import logging
from datetime import datetime
from dotenv import load_dotenv
import docker
from qbittorrent import Client
# FUNCTION DECLARATION #
def log(code, message):
logFilePath = "/opt/pyprojects/linux-iso-torrents/pf.log"
logDateTime = datetime.today().strftime("%Y-%m-%d %H:%M:%S")
message = f"[{logDateTime}] {message}"
logger = logging.getLogger(__name__)
logging.basicConfig(
filename=f"{logFilePath}", encoding="utf-8", level=logging.DEBUG
)
match code:
case "debug":
logger.debug(message)
case "info":
logger.info(message)
case "warning":
logger.warning(message)
case "error":
logger.error(message)
def get_current_forwarded_port():
client = docker.from_env()
container = client.containers.get("a40124291102d")
logs = container.logs().decode("utf-8")
allPortForwards = re.findall(r".+port forwarded is [0-9]{5}", logs)
currentForwardedPort = allPortForwards[-1].split(" ")[-1]
return currentForwardedPort
def get_current_listening_port():
qbConfigUrl = "/home/server/docker/qbit/config/qBittorrent/qBittorrent.conf"
with open(qbConfigUrl) as f:
config = f.read()
qbitListenPort = re.search(r"Session\\Port=[0-9]{5}", config)
currentListeningPort = qbitListenPort.group(0).split("=")[-1]
return currentListeningPort
def update_qbittorrent_listen_port(port):
QB_URL = os.getenv("QB_URL")
QB_USER = os.getenv("QB_USER")
QB_PASSWORD = os.getenv("QB_PASSWORD")
portJSON = {}
portJSON["listen_port"] = port
qb = Client(QB_URL)
qb.login(f"{QB_USER}", f"{QB_PASSWORD}")
qb.set_preferences(**portJSON)
# BEGIN SCRIPT #
load_dotenv()
currentForwardedPort = get_current_forwarded_port()
currentListeningPort = get_current_listening_port()
if currentForwardedPort != currentListeningPort:
update_qbittorrent_listen_port(currentPort)
log("info", f"qbittorrent listen port set to {currentForwardedPort}")
else:
log("info", "forwarded port and listen port are a match")
There’s more I want to do, the next thing being to check the status of both containers and if one or both are down, to log that and gracefully exit, but for now, I’m pretty happy with this (open to any feedback, always willing to learn).


A common pattern with executable Python scripts is to:
#!/usr/bin/env python3) to make it easier to execute__name__ == "__main__"before running any of the script so the functions can be imported into another script without running all the code at the bottomI’m glad you mentioned the shebang. I was considering doing that (with the path to my venv python), but wasn’t sure if that was a good idea.
I will also add the
if __name__ == "__main"to the main script. Thank you!