qbittorrent: bake performance settings into initContainer

Switch qbt-config-patch from busybox/sed to python:3-alpine so we can
cleanly handle INI keys with backslashes. Now seeds both password hash
and high-throughput defaults (3000 max connections, 50 active downloads,
unlimited rate) on fresh PVC deployments. Existing configs are updated
in-place; API-applied values are preserved on restart.
This commit is contained in:
Will Anderson
2026-04-11 12:24:16 -05:00
parent 259b1bdade
commit 4ef625ef3d
2 changed files with 130 additions and 41 deletions
+86 -26
View File
@@ -35,22 +35,52 @@ spec:
securityContext:
privileged: true
- name: qbt-config-patch
image: busybox:latest
image: python:3-alpine
command:
- sh
- python3
- -c
- |
CONF=/config/qBittorrent/qBittorrent.conf
HASH='@ByteArray(HqYj1eGsdXlQ4CSy597Y9A==:J9hsJIlU5FYfHb5rY5qQoIpVpTijryS/H+CE07oMtplL/ytneBVFd2tfVJtqGjhdht8tEi4wmqSSlqTgEu444w==)'
mkdir -p /config/qBittorrent
if [ -f "$CONF" ]; then
if grep -q "Password_PBKDF2" "$CONF"; then
sed -i "s|WebUI\\\\Password_PBKDF2=.*|WebUI\\\\Password_PBKDF2=\"$HASH\"|" "$CONF"
else
sed -i "/^\[Preferences\]/a WebUI\\\\Password_PBKDF2=\"$HASH\"" "$CONF"
fi
fi
echo "Password hash set."
import os, re
CONF = '/config/qBittorrent/qBittorrent.conf'
os.makedirs('/config/qBittorrent', exist_ok=True)
text = open(CONF).read() if os.path.exists(CONF) else ''
def set_key(text, section, key, value):
"""Set key=value under [section], inserting if missing."""
key_pat = re.compile(r'^' + re.escape(key) + r'=.*', re.M)
if key_pat.search(text):
return key_pat.sub(key + '=' + value, text)
sec_pat = re.compile(r'^\[' + re.escape(section) + r'\]', re.M)
if sec_pat.search(text):
return sec_pat.sub('[' + section + ']\n' + key + '=' + value, text)
return text + f'\n[{section}]\n{key}={value}\n'
HASH = '@ByteArray(HqYj1eGsdXlQ4CSy597Y9A==:J9hsJIlU5FYfHb5rY5qQoIpVpTijryS/H+CE07oMtplL/ytneBVFd2tfVJtqGjhdht8tEi4wmqSSlqTgEu444w==)'
# Preferences
text = set_key(text, 'Preferences', r'WebUI\Password_PBKDF2', f'"{HASH}"')
text = set_key(text, 'Preferences', r'WebUI\LocalhostAuthEnabled', 'false')
# BitTorrent performance defaults (only applied when key absent — API updates persist)
bt_defaults = {
r'Session\MaxActiveDownloads': '50',
r'Session\MaxActiveTorrents': '100',
r'Session\MaxActiveUploads': '20',
r'Session\MaxConnections': '3000',
r'Session\MaxConnectionsPerTorrent': '300',
r'Session\MaxUploads': '-1',
r'Session\MaxUploadsPerTorrent': '10',
r'Session\GlobalDLSpeedLimit': '0',
r'Session\GlobalUPSpeedLimit': '0',
r'Session\DHTEnabled': 'true',
}
for key, val in bt_defaults.items():
text = set_key(text, 'BitTorrent', key, val)
open(CONF, 'w').write(text)
print('qBittorrent config patched.')
volumeMounts:
- name: config
mountPath: /config
@@ -211,22 +241,52 @@ spec:
securityContext:
privileged: true
- name: qbt-config-patch
image: busybox:latest
image: python:3-alpine
command:
- sh
- python3
- -c
- |
CONF=/config/qBittorrent/qBittorrent.conf
HASH='@ByteArray(HqYj1eGsdXlQ4CSy597Y9A==:J9hsJIlU5FYfHb5rY5qQoIpVpTijryS/H+CE07oMtplL/ytneBVFd2tfVJtqGjhdht8tEi4wmqSSlqTgEu444w==)'
mkdir -p /config/qBittorrent
if [ -f "$CONF" ]; then
if grep -q "Password_PBKDF2" "$CONF"; then
sed -i "s|WebUI\\\\Password_PBKDF2=.*|WebUI\\\\Password_PBKDF2=\"$HASH\"|" "$CONF"
else
sed -i "/^\[Preferences\]/a WebUI\\\\Password_PBKDF2=\"$HASH\"" "$CONF"
fi
fi
echo "Password hash set."
import os, re
CONF = '/config/qBittorrent/qBittorrent.conf'
os.makedirs('/config/qBittorrent', exist_ok=True)
text = open(CONF).read() if os.path.exists(CONF) else ''
def set_key(text, section, key, value):
"""Set key=value under [section], inserting if missing."""
key_pat = re.compile(r'^' + re.escape(key) + r'=.*', re.M)
if key_pat.search(text):
return key_pat.sub(key + '=' + value, text)
sec_pat = re.compile(r'^\[' + re.escape(section) + r'\]', re.M)
if sec_pat.search(text):
return sec_pat.sub('[' + section + ']\n' + key + '=' + value, text)
return text + f'\n[{section}]\n{key}={value}\n'
HASH = '@ByteArray(HqYj1eGsdXlQ4CSy597Y9A==:J9hsJIlU5FYfHb5rY5qQoIpVpTijryS/H+CE07oMtplL/ytneBVFd2tfVJtqGjhdht8tEi4wmqSSlqTgEu444w==)'
# Preferences
text = set_key(text, 'Preferences', r'WebUI\Password_PBKDF2', f'"{HASH}"')
text = set_key(text, 'Preferences', r'WebUI\LocalhostAuthEnabled', 'false')
# BitTorrent performance defaults (only applied when key absent — API updates persist)
bt_defaults = {
r'Session\MaxActiveDownloads': '50',
r'Session\MaxActiveTorrents': '100',
r'Session\MaxActiveUploads': '20',
r'Session\MaxConnections': '3000',
r'Session\MaxConnectionsPerTorrent': '300',
r'Session\MaxUploads': '-1',
r'Session\MaxUploadsPerTorrent': '10',
r'Session\GlobalDLSpeedLimit': '0',
r'Session\GlobalUPSpeedLimit': '0',
r'Session\DHTEnabled': 'true',
}
for key, val in bt_defaults.items():
text = set_key(text, 'BitTorrent', key, val)
open(CONF, 'w').write(text)
print('qBittorrent config patched.')
volumeMounts:
- name: config
mountPath: /config
@@ -27,25 +27,54 @@ spec:
command: ["sh", "-c", "mkdir -p /dev/net && [ -c /dev/net/tun ] || mknod /dev/net/tun c 10 200 && chmod 666 /dev/net/tun && sysctl -w net.ipv6.conf.all.disable_ipv6=1 || true && ip route flush table 51820 2>/dev/null || true && ip rule del priority 101 2>/dev/null || true && ip rule del table 51820 2>/dev/null || true"]
securityContext:
privileged: true
# Patch qBittorrent config before it starts so localhost auth is disabled from boot
# Patch qBittorrent config before it starts: set password hash + performance defaults
- name: qbt-config-patch
image: busybox:latest
image: python:3-alpine
command:
- sh
- python3
- -c
- |
CONF=/config/qBittorrent/qBittorrent.conf
HASH='@ByteArray(HqYj1eGsdXlQ4CSy597Y9A==:J9hsJIlU5FYfHb5rY5qQoIpVpTijryS/H+CE07oMtplL/ytneBVFd2tfVJtqGjhdht8tEi4wmqSSlqTgEu444w==)'
mkdir -p /config/qBittorrent
if [ -f "$CONF" ]; then
# Set known adminadmin password hash
if grep -q "Password_PBKDF2" "$CONF"; then
sed -i "s|WebUI\\\\Password_PBKDF2=.*|WebUI\\\\Password_PBKDF2=\"$HASH\"|" "$CONF"
else
sed -i "/^\[Preferences\]/a WebUI\\\\Password_PBKDF2=\"$HASH\"" "$CONF"
fi
fi
echo "Password hash set."
import os, re
CONF = '/config/qBittorrent/qBittorrent.conf'
os.makedirs('/config/qBittorrent', exist_ok=True)
text = open(CONF).read() if os.path.exists(CONF) else ''
def set_key(text, section, key, value):
"""Set key=value under [section], inserting if missing."""
key_pat = re.compile(r'^' + re.escape(key) + r'=.*', re.M)
if key_pat.search(text):
return key_pat.sub(key + '=' + value, text)
sec_pat = re.compile(r'^\[' + re.escape(section) + r'\]', re.M)
if sec_pat.search(text):
return sec_pat.sub('[' + section + ']\n' + key + '=' + value, text)
return text + f'\n[{section}]\n{key}={value}\n'
HASH = '@ByteArray(HqYj1eGsdXlQ4CSy597Y9A==:J9hsJIlU5FYfHb5rY5qQoIpVpTijryS/H+CE07oMtplL/ytneBVFd2tfVJtqGjhdht8tEi4wmqSSlqTgEu444w==)'
# Preferences
text = set_key(text, 'Preferences', r'WebUI\Password_PBKDF2', f'"{HASH}"')
text = set_key(text, 'Preferences', r'WebUI\LocalhostAuthEnabled', 'false')
# BitTorrent performance defaults (only applied when key absent — API updates persist)
bt_defaults = {
r'Session\MaxActiveDownloads': '50',
r'Session\MaxActiveTorrents': '100',
r'Session\MaxActiveUploads': '20',
r'Session\MaxConnections': '3000',
r'Session\MaxConnectionsPerTorrent': '300',
r'Session\MaxUploads': '-1',
r'Session\MaxUploadsPerTorrent': '10',
r'Session\GlobalDLSpeedLimit': '0',
r'Session\GlobalUPSpeedLimit': '0',
r'Session\DHTEnabled': 'true',
}
for key, val in bt_defaults.items():
text = set_key(text, 'BitTorrent', key, val)
open(CONF, 'w').write(text)
print('qBittorrent config patched.')
volumeMounts:
- name: config
mountPath: /config