arrstack: set *arr UrlBase=/<app> for path-based proxy hosting (#378)

## Why
arrproxy forwards `arrstack.unkin.net/<app>/...` to each *arr Service **preserving** the `/<app>` prefix. Without a matching `<UrlBase>` the apps 307-redirect to `/`, breaking path-based hosting. Prerequisite for arrproxy path routing (PR #377... arrproxy service account added in #376).

## Change
Extend the existing idempotent `apikey-init` init container in sonarr/radarr/prowlarr to also enforce `<UrlBase>/<app></UrlBase>` in `/config/config.xml` (sonarr=/sonarr, radarr=/radarr, prowlarr=/prowlarr):

- Set/replace `<UrlBase>` if present, insert after `<Config>` if absent, or write both `<ApiKey>` + `<UrlBase>` when creating a fresh config. `<ApiKey>` handling is unchanged.
- Because Servarr moves all routes (including `/ping`) under the URL base, update liveness/readiness probes from `/ping` to `/<app>/ping` so they don't 404 once UrlBase is set.

nzbget is not fronted by arrproxy and is left untouched.

## Validation
- `kustomize build --enable-helm apps/overlays/au-syd1/arrstack` succeeds
- `pre-commit` (yamllint etc.) passes

---------

Co-authored-by: BenVincent <benvin@main.unkin.net>
Co-authored-by: unkin-agent <unkin-agent@git.unkin.net>
Reviewed-on: #378
Co-authored-by: Unkin Agent <unkin-agent@unkin.net>
Co-committed-by: Unkin Agent <unkin-agent@unkin.net>
This commit was merged in pull request #378.
This commit is contained in:
2026-08-17 07:59:48 +10:00
committed by BenVincent
parent cd8e2c262f
commit 76da30d2f7
3 changed files with 66 additions and 36 deletions
+20 -10
View File
@@ -21,10 +21,12 @@ spec:
fsGroup: 1000
fsGroupChangePolicy: OnRootMismatch
initContainers:
# Enforce the Vault-sourced API key in /config/config.xml before the app
# starts. Vault is source of truth (override bootstrap): the key is minted
# in Vault, synced by VSO into the prowlarr-apikey Secret, and written here.
# Runs as root to fix ownership; touches only the <ApiKey> element.
# Enforce the Vault-sourced API key and the reverse-proxy URL base in
# /config/config.xml before the app starts. Vault is source of truth
# (override bootstrap): the key is minted in Vault, synced by VSO into the
# prowlarr-apikey Secret, and written here. UrlBase=/prowlarr lets arrproxy
# forward arrstack.unkin.net/prowlarr/... with the prefix preserved (no 307).
# Runs as root to fix ownership; touches only <ApiKey> and <UrlBase>.
- name: apikey-init
image: artifactapi.k8s.syd1.au.unkin.net/dockerhub/library/busybox:1.37.0
imagePullPolicy: IfNotPresent
@@ -43,21 +45,29 @@ spec:
set -eu
case "$API_KEY" in
"" | *[!0-9a-fA-F]*)
echo "apikey-init: API_KEY missing or not hex; refusing" >&2
echo "config-init: API_KEY missing or not hex; refusing" >&2
exit 1
;;
esac
URL_BASE=/prowlarr
CFG=/config/config.xml
if [ ! -f "$CFG" ]; then
printf '<Config>\n <ApiKey>%s</ApiKey>\n</Config>\n' "$API_KEY" > "$CFG"
elif grep -q '<ApiKey>' "$CFG"; then
printf '<Config>\n <ApiKey>%s</ApiKey>\n <UrlBase>%s</UrlBase>\n</Config>\n' "$API_KEY" "$URL_BASE" > "$CFG"
else
if grep -q '<ApiKey>' "$CFG"; then
sed -i "s|<ApiKey>[^<]*</ApiKey>|<ApiKey>${API_KEY}</ApiKey>|" "$CFG"
else
sed -i "s|<Config>|<Config>\n <ApiKey>${API_KEY}</ApiKey>|" "$CFG"
fi
if grep -q '<UrlBase>' "$CFG"; then
sed -i "s|<UrlBase>[^<]*</UrlBase>|<UrlBase>${URL_BASE}</UrlBase>|" "$CFG"
else
sed -i "s|<Config>|<Config>\n <UrlBase>${URL_BASE}</UrlBase>|" "$CFG"
fi
fi
chown 1000:1000 "$CFG"
chmod 600 "$CFG"
echo "apikey-init: <ApiKey> enforced from Vault"
echo "config-init: <ApiKey> and <UrlBase>=${URL_BASE} enforced from Vault"
resources:
requests:
cpu: 50m
@@ -85,7 +95,7 @@ spec:
value: Australia/Sydney
livenessProbe:
httpGet:
path: /ping
path: /prowlarr/ping
port: http
initialDelaySeconds: 30
periodSeconds: 30
@@ -93,7 +103,7 @@ spec:
failureThreshold: 3
readinessProbe:
httpGet:
path: /ping
path: /prowlarr/ping
port: http
initialDelaySeconds: 10
periodSeconds: 10
+20 -10
View File
@@ -21,10 +21,12 @@ spec:
fsGroup: 1000
fsGroupChangePolicy: OnRootMismatch
initContainers:
# Enforce the Vault-sourced API key in /config/config.xml before the app
# starts. Vault is source of truth (override bootstrap): the key is minted
# in Vault, synced by VSO into the radarr-apikey Secret, and written here.
# Runs as root to fix ownership; touches only the <ApiKey> element.
# Enforce the Vault-sourced API key and the reverse-proxy URL base in
# /config/config.xml before the app starts. Vault is source of truth
# (override bootstrap): the key is minted in Vault, synced by VSO into the
# radarr-apikey Secret, and written here. UrlBase=/radarr lets arrproxy
# forward arrstack.unkin.net/radarr/... with the prefix preserved (no 307).
# Runs as root to fix ownership; touches only <ApiKey> and <UrlBase>.
- name: apikey-init
image: artifactapi.k8s.syd1.au.unkin.net/dockerhub/library/busybox:1.37.0
imagePullPolicy: IfNotPresent
@@ -43,21 +45,29 @@ spec:
set -eu
case "$API_KEY" in
"" | *[!0-9a-fA-F]*)
echo "apikey-init: API_KEY missing or not hex; refusing" >&2
echo "config-init: API_KEY missing or not hex; refusing" >&2
exit 1
;;
esac
URL_BASE=/radarr
CFG=/config/config.xml
if [ ! -f "$CFG" ]; then
printf '<Config>\n <ApiKey>%s</ApiKey>\n</Config>\n' "$API_KEY" > "$CFG"
elif grep -q '<ApiKey>' "$CFG"; then
printf '<Config>\n <ApiKey>%s</ApiKey>\n <UrlBase>%s</UrlBase>\n</Config>\n' "$API_KEY" "$URL_BASE" > "$CFG"
else
if grep -q '<ApiKey>' "$CFG"; then
sed -i "s|<ApiKey>[^<]*</ApiKey>|<ApiKey>${API_KEY}</ApiKey>|" "$CFG"
else
sed -i "s|<Config>|<Config>\n <ApiKey>${API_KEY}</ApiKey>|" "$CFG"
fi
if grep -q '<UrlBase>' "$CFG"; then
sed -i "s|<UrlBase>[^<]*</UrlBase>|<UrlBase>${URL_BASE}</UrlBase>|" "$CFG"
else
sed -i "s|<Config>|<Config>\n <UrlBase>${URL_BASE}</UrlBase>|" "$CFG"
fi
fi
chown 1000:1000 "$CFG"
chmod 600 "$CFG"
echo "apikey-init: <ApiKey> enforced from Vault"
echo "config-init: <ApiKey> and <UrlBase>=${URL_BASE} enforced from Vault"
resources:
requests:
cpu: 50m
@@ -85,7 +95,7 @@ spec:
value: Australia/Sydney
livenessProbe:
httpGet:
path: /ping
path: /radarr/ping
port: http
initialDelaySeconds: 30
periodSeconds: 30
@@ -93,7 +103,7 @@ spec:
failureThreshold: 3
readinessProbe:
httpGet:
path: /ping
path: /radarr/ping
port: http
initialDelaySeconds: 10
periodSeconds: 10
+20 -10
View File
@@ -24,10 +24,12 @@ spec:
fsGroup: 1000
fsGroupChangePolicy: OnRootMismatch
initContainers:
# Enforce the Vault-sourced API key in /config/config.xml before the app
# starts. Vault is source of truth (override bootstrap): the key is minted
# in Vault, synced by VSO into the sonarr-apikey Secret, and written here.
# Runs as root to fix ownership; touches only the <ApiKey> element.
# Enforce the Vault-sourced API key and the reverse-proxy URL base in
# /config/config.xml before the app starts. Vault is source of truth
# (override bootstrap): the key is minted in Vault, synced by VSO into the
# sonarr-apikey Secret, and written here. UrlBase=/sonarr lets arrproxy
# forward arrstack.unkin.net/sonarr/... with the prefix preserved (no 307).
# Runs as root to fix ownership; touches only <ApiKey> and <UrlBase>.
- name: apikey-init
image: artifactapi.k8s.syd1.au.unkin.net/dockerhub/library/busybox:1.37.0
imagePullPolicy: IfNotPresent
@@ -46,21 +48,29 @@ spec:
set -eu
case "$API_KEY" in
"" | *[!0-9a-fA-F]*)
echo "apikey-init: API_KEY missing or not hex; refusing" >&2
echo "config-init: API_KEY missing or not hex; refusing" >&2
exit 1
;;
esac
URL_BASE=/sonarr
CFG=/config/config.xml
if [ ! -f "$CFG" ]; then
printf '<Config>\n <ApiKey>%s</ApiKey>\n</Config>\n' "$API_KEY" > "$CFG"
elif grep -q '<ApiKey>' "$CFG"; then
printf '<Config>\n <ApiKey>%s</ApiKey>\n <UrlBase>%s</UrlBase>\n</Config>\n' "$API_KEY" "$URL_BASE" > "$CFG"
else
if grep -q '<ApiKey>' "$CFG"; then
sed -i "s|<ApiKey>[^<]*</ApiKey>|<ApiKey>${API_KEY}</ApiKey>|" "$CFG"
else
sed -i "s|<Config>|<Config>\n <ApiKey>${API_KEY}</ApiKey>|" "$CFG"
fi
if grep -q '<UrlBase>' "$CFG"; then
sed -i "s|<UrlBase>[^<]*</UrlBase>|<UrlBase>${URL_BASE}</UrlBase>|" "$CFG"
else
sed -i "s|<Config>|<Config>\n <UrlBase>${URL_BASE}</UrlBase>|" "$CFG"
fi
fi
chown 1000:1000 "$CFG"
chmod 600 "$CFG"
echo "apikey-init: <ApiKey> enforced from Vault"
echo "config-init: <ApiKey> and <UrlBase>=${URL_BASE} enforced from Vault"
resources:
requests:
cpu: 50m
@@ -88,7 +98,7 @@ spec:
value: Australia/Sydney
livenessProbe:
httpGet:
path: /ping
path: /sonarr/ping
port: http
initialDelaySeconds: 30
periodSeconds: 30
@@ -96,7 +106,7 @@ spec:
failureThreshold: 3
readinessProbe:
httpGet:
path: /ping
path: /sonarr/ping
port: http
initialDelaySeconds: 10
periodSeconds: 10