Commit Graph

182 Commits

Author SHA1 Message Date
Will Anderson 3f33a76ed2 media: natpmpc-helper sleep before apk install (VPN must be up first) 2026-04-11 08:29:54 -05:00
Will Anderson ca5f9e90da media: fix natpmpc-helper package name (libnatpmp not natpmpc) 2026-04-11 08:27:53 -05:00
Will Anderson f99965da0a media: fix natpmpc-helper OOM and API call format
Increase memory limit 32→64Mi (apk install was hitting the 32Mi ceiling).
Fix qBittorrent setPreferences call: use form-encoded json=<string> not
json body nesting.
2026-04-11 08:24:19 -05:00
Will Anderson fd08987e12 media: add natpmpc-helper sidecar for ProtonVPN port forwarding
Adds a lightweight Alpine sidecar that runs natpmpc against the ProtonVPN
NAT-PMP gateway (10.2.0.1) every 45s to maintain a forwarded port, then
updates qBittorrent's listen port via API. Without inbound port forwarding
peers can only be dialed out to, which severely limits download speeds on
a gigabit connection.
2026-04-11 08:21:37 -05:00
Will Anderson 615f455eff fix(bazarr): merge duplicate metadata blocks in pod template 2026-04-11 04:40:21 -05:00
Will Anderson 0f15063260 fix(bazarr): patch ffprobe refiner to handle BoxList audio language
Audio tracks in some video files return language as a BoxList (list of
Language objects) from the video metadata parser. The existing code
tries to add this directly to a Python set, which fails because BoxList
is not hashable — crashing subtitle search for every movie.

Fix: check if lang has __iter__ and iterate over it, or call .alpha3
directly if it's a single Language object.

Delivered via ConfigMap volumeMount so it survives pod restarts.
2026-04-11 04:39:33 -05:00
Will Anderson 7c17b8a93e fix(gluetun): remove shell wrapper, use default entrypoint
The /gluetun binary has restrictive permissions and cannot be exec'd
from a shell wrapper. The OOM fix (512Mi limit) prevents the crashes
that caused stale ip rules, so the wrapper is not needed.
2026-04-11 04:31:01 -05:00
Will Anderson 203233beca fix(gluetun): prevent OOM crash and stale ip rule on container restart
- Increase memory limit 128Mi → 512Mi (DNS block list download needs ~200MB)
- Add command wrapper that cleans stale ip rules before exec'ing gluetun
  so container restarts within the same pod don't fail with "file exists"
- Fix deprecated VPN_ENDPOINT_IP/PORT → WIREGUARD_ENDPOINT_IP/PORT
2026-04-11 04:28:32 -05:00
Will Anderson 28a108a1d8 fix(gluetun): pin to US-TX#457 server to restore downloads
The protonvpn named provider rotates through P2P servers and DNS
health checks were failing on every server it tried. Switching back
to custom provider pinned to the specific US-TX#457 server/key combo
from the ProtonVPN conf file, which is confirmed to work.

This sacrifices automatic port forwarding but restores stable downloads.
2026-04-11 04:24:35 -05:00
Will Anderson e5785f3359 gluetun: fix ip rule cleanup in init container for VPN restart stability
Delete ip rule by priority 101 before table 51820 to prevent 'file exists'
errors when gluetun internally restarts the WireGuard connection.
2026-04-11 04:18:56 -05:00
Will Anderson 9cd3dd0134 gluetun: switch to protonvpn provider with port forwarding enabled
Custom WireGuard mode doesn't support NAT-PMP port forwarding — peers
can't connect inbound so most torrents stall. Switching to protonvpn
provider with SERVER_FEATURES=p2p picks a port-forwarding-capable server
and VPN_PORT_FORWARDING=on handles the NAT-PMP handshake. Up command
updates qBittorrent listen port automatically when gluetun gets the port.
2026-04-11 04:09:29 -05:00
Will Anderson d59af5b6aa seerr: fix mediaServerType to numeric 2 (JELLYFIN enum value)
Seerr's scheduler compares mediaServerType against numeric enum values
(PLEX=1, JELLYFIN=2, EMBY=3). restore.js was setting the string 'JELLYFIN'
which never matched, so Jellyfin scan jobs were never registered in the
scheduler — causing 'Watch on Jellyfin' buttons to never appear.
2026-04-11 02:52:15 -05:00
Will Anderson ba339ee5c9 bazarr: increase liveness probe delay to 120s — startup takes 90+s
Bazarr initializes scheduler, DB, and Radarr/Sonarr connections before
serving HTTP. 30s initialDelay was too short, causing restart loops.
Also add readinessProbe and failureThreshold for resilience.
2026-04-11 02:33:41 -05:00
Will Anderson c8d240e131 fix(seerr): persist applicationUrl so Jellyfin OAuth callback works 2026-04-11 02:16:57 -05:00
Will Anderson 7225f56fbc fix(seerr): set public.initialized=true to skip setup wizard on every start 2026-04-11 02:01:54 -05:00
Will Anderson c1d4390393 fix(seerr): persist library config in ConfigMap, restore libraries on pod restart 2026-04-11 01:58:06 -05:00
Will Anderson 280924b1b3 chore(seerr): force pod restart to pick up fix for main.mediaServerType 2026-04-11 01:47:15 -05:00
Will Anderson 4031628f4b fix(seerr): add main.mediaServerType to settings.json to prevent crash
Seerr's checkOverseerrMerge calls Settings.load with raw=true, which
replaces this.data entirely with file contents. If settings.main is
absent (as in our jellyfin-only restore), it crashes at line 418:
'Cannot read properties of undefined (reading apiKey)'.

restore.js now ensures settings.main exists and mediaServerType=JELLYFIN,
which both prevents the crash and causes checkOverseerrMerge to return
early (migration already done).
2026-04-11 01:44:41 -05:00
Will Anderson 71f335c153 seerr: fix init container — use script file instead of inline shell 2026-04-11 01:36:13 -05:00
Will Anderson 32a9f92467 seerr: restore Jellyfin config from ConfigMap on pod start
Init container detects if Jellyfin apiKey is missing and restores
it from the seerr-defaults ConfigMap. Prevents config loss on pod
restarts or when the Jellyfin API key fails validation.
2026-04-11 01:34:02 -05:00
Will Anderson 409274ff54 media: add nightly config backup to Cloudflare R2 via restic
Backs up all service config PVCs (Jellyfin, Radarr, Sonarr, Prowlarr,
qBittorrent, Bazarr, Seerr) at 3am daily to legion-media-backup R2 bucket.
Media files are excluded — they are re-downloadable.
2026-04-11 01:22:24 -05:00
Will Anderson d3289895e5 media: add full library folder structure, store all secrets in Vault
- external-secrets: add qbittorrent, jellyfin, seerr keys from Vault
- pvc: document all media folder paths (movies, tv, anime, docs, standup, concerts, kids, music)
- jellyfin: init container creates all media subdirs on startup
2026-04-11 01:19:48 -05:00
Will Anderson 4ab5cf1e06 fix gluetun: flush stale IPv4 routing rules on pod start 2026-04-11 00:58:10 -05:00
Will Anderson 07fff8804b Remove all Plex references — Jellyfin only 2026-04-11 00:15:28 -05:00
Will Anderson cf5da8dfa1 Add jellyfin.nook.family ingress 2026-04-11 00:13:22 -05:00
Will Anderson a1c1c7b0f6 Switch Plex → Jellyfin, fix gluetun IPv6 VPN issue 2026-04-11 00:11:41 -05:00
Will Anderson e08d7eaa03 Switch Overseerr to Seerr 2026-04-11 00:10:09 -05:00
Will Anderson abbc0e2c08 Add LAN-only Traefik ingresses for media admin services 2026-04-10 23:39:56 -05:00
Will Anderson f1def110de Revert to Overseerr — Seerr permission issue on existing config volume 2026-04-10 23:38:04 -05:00
Will Anderson cdf801b380 Switch to Seerr image, add media stack README 2026-04-10 23:28:51 -05:00
Will Anderson e616f7298a Add FlareSolverr for Cloudflare-protected indexers (1337x, EZTV) 2026-04-10 23:19:38 -05:00
Will Anderson 6a9da6d900 Fix media app: use internal Gitea URL for Argo CD 2026-04-10 22:50:51 -05:00
Will Anderson ba99111753 Add media stack: Plex, Radarr, Sonarr, Prowlarr, qBittorrent, Bazarr, Overseerr
- Namespace: media (created via Terraform)
- Storage: hostPath PV at /media on Legion (movies, tv/shows, tv/anime, downloads)
- VPN: gluetun sidecar with ProtonVPN WireGuard (US-TX#253), all torrent traffic tunneled
- Radarr: movie automation with /media/movies root
- Sonarr: TV/anime automation with /media/tv/{shows,anime} roots
- Prowlarr: indexer aggregator (YTS, 1337x, Nyaa for anime)
- qBittorrent: torrent client, network namespaced behind gluetun VPN
- Bazarr: automatic subtitle downloads (connects to Radarr + Sonarr)
- Overseerr: family request portal at watch.nook.family
- Plex: media server at plex.nook.family
2026-04-10 22:50:13 -05:00
Will Anderson 8c40075b81 fix: use custom WordPress image with wp-cli pre-installed
Adds a Dockerfile extending wordpress:latest to include wp-cli at
/usr/local/bin/wp. Required for sync-whitepapers.py to manage content
via kubectl exec without manual installation after each pod restart.
2026-04-09 00:09:00 -05:00
Will Anderson a283f1148f Fix Memos port: set MEMOS_PORT=5230 explicitly 2026-04-08 15:57:12 -05:00
Will Anderson 78c1c9750f Add Memos journaling app at journal.neuralplatform.ai 2026-04-08 15:46:10 -05:00
Gitea CI 54b2abf767 chore(neuron): deploy d97b23808e953dccf35d784c47ca003d74bcda61 2026-04-06 14:01:48 +00:00
Gitea CI 937e138f7d chore(neuron): deploy d3d72a5adbdddfd6c18ae674c921469d410dc7da 2026-04-06 13:44:50 +00:00
Gitea CI 55f4eab6ae chore(neuron): deploy bf185a6b19bfce25a3c67d4d13fa4e39b6fc6685 2026-04-06 13:38:05 +00:00
Will Anderson 3ba1bf5c08 fix: neuron probes — use tcpSocket, /mcp returns 406 on plain GET 2026-04-06 04:17:11 -05:00
Will Anderson c138982fcf fix: neuron health probes — /health 404, use /mcp endpoint 2026-04-06 04:14:51 -05:00
Gitea CI 49b5604860 chore(neuron): deploy 2476e1167826cf320375143c09e94852b4330114 2026-04-06 07:54:36 +00:00
Will Anderson 92d3f8adea rename: newsletter.harmonic-framework.com → campaigns.harmonic-framework.com 2026-04-04 19:10:42 -05:00
Will Anderson bd7c906c05 fix: remove legacy admin_username/password env vars from listmonk config 2026-04-04 19:01:35 -05:00
Will Anderson 58eea3b686 fix: remove destructive initContainer, use one-time Argo CD hook Job for schema install 2026-04-04 18:57:36 -05:00
Will Anderson 0b8eb4264a fix: bind listmonk to 0.0.0.0:9000 so k8s service can route traffic 2026-04-04 18:49:41 -05:00
Will Anderson e788fd48fd fix: listmonk init container command — override entrypoint, drop nonexistent --idempotent flag 2026-04-04 18:46:09 -05:00
Will Anderson bf40bd7f15 feat: add Listmonk newsletter platform on Legion k3s
- Namespace, ExternalSecrets (Vault), DB init job, deployment, service, PVC, ingress
- Routes newsletter.harmonic-framework.com via existing Cloudflare tunnel
- Uses shared platform postgres with dedicated listmonk DB/user
- Credentials stored at secret/data/listmonk in Vault
2026-04-04 18:43:44 -05:00
Will Anderson eefaeafcfc fix(adguard): remove split-horizon DNS rewrites
Split-horizon breaks VPN/LAN hybrid scenarios. Let all clients use
public DNS (Cloudflare proxy IPs) and route via CF tunnel. Works
everywhere, no network-topology-dependent DNS required.
2026-04-04 11:06:38 -05:00
Will Anderson f50d14ccdc fix(adguard): use Tailscale IP for split-horizon DNS rewrites
LAN IP 192.168.68.77 unreachable over Tailscale VPN. 100.64.0.1 works
for both LAN (Tailscale installed) and remote VPN clients. Also adds
*.neuralplatform.dev which was missing from the configmap.
2026-04-04 10:59:33 -05:00