diff --git a/infrastructure.org b/infrastructure.org index e919aef..24fffb6 100644 --- a/infrastructure.org +++ b/infrastructure.org @@ -588,6 +588,18 @@ http: - security-headers@file - traefik-bouncer@file + tubearchivist: + rule: "Host(`tubearchivist.gharbeia.net`)" + service: tubearchivist-internal + entryPoints: + - secureweb + tls: + certResolver: letsencrypt + middlewares: + - authentik-forwardauth@file + - security-headers@file + - traefik-bouncer@file + guacamole: rule: "Host(`guacamole.gharbeia.net`)" service: guacamole-internal @@ -713,6 +725,10 @@ http: loadBalancer: servers: - url: http://audiobookshelf:13378 + tubearchivist-internal: + loadBalancer: + servers: + - url: http://tubearchivist:8000 guacamole-internal: loadBalancer: servers: @@ -860,11 +876,12 @@ include: - services/stash.yaml - services/tdarr.yaml - services/tdarr-node.yaml + - services/tubearchivist.yaml - services/audiobookshelf.yaml - services/whisparr.yaml #+END_SRC -All 43 services are organized alphabetically by category in the include list. +All 44 services are organized alphabetically by category in the include list. The order matters for startup dependencies: infrastructure services (gluetun, postgresql, valkey, authentik, traefik) come first. @@ -1183,6 +1200,88 @@ services: - /docker/appdata/unbound/unbound.conf:/opt/unbound/etc/unbound/unbound.conf:ro #+END_SRC +** Tube Archivist — YouTube Archiving + +Tube Archivist downloads and indexes YouTube channels, playlists, and +videos. It provides full-text search, metadata browsing, and automatic +subscription updates via a web UI. The stack has three containers: + +- =tubearchivist= (main app) — Django-based web UI on port 8000 +- =tubearchivist-es= — Elasticsearch 7.17 for metadata storage + search +- =tubearchivist-redis= — Redis for Celery task queue + +Tube Archivist does NOT need VPN routing (it reaches YouTube directly). + +#+BEGIN_SRC yaml :tangle /docker/compose/services/tubearchivist.yaml +services: + tubearchivist: + image: bbilly1/tubearchivist:latest + container_name: tubearchivist + restart: unless-stopped + networks: + - networking + ports: + - ${WEBUI_PORT_TUBEARCHIVIST:-8000}:8000 + environment: + - TZ=${TIMEZONE:?err} + - TA_USERNAME=${TA_USERNAME:?err} + - TA_PASSWORD=${TA_PASSWORD:?err} + - ES_URL=http://tubearchivist-es:9200 + - REDIS_HOST=tubearchivist-redis + - REDIS_PORT=6379 + - HOST_UID=${PUID:?err} + - HOST_GID=${PGID:?err} + volumes: + - ${FOLDER_FOR_DATA:?err}/tubearchivist/media:/youtube + - ${FOLDER_FOR_DATA:?err}/tubearchivist/cache:/cache + depends_on: + tubearchivist-es: + condition: service_healthy + tubearchivist-redis: + condition: service_healthy + labels: + - traefik.enable=true + - traefik.http.routers.tubearchivist.service=tubearchivist + - traefik.http.routers.tubearchivist.rule=Host(`tubearchivist.${CLOUDFLARE_DNS_ZONE:?err}`) + - traefik.http.routers.tubearchivist.entrypoints=tunnel + - traefik.http.routers.tubearchivist.middlewares=authentik-forwardauth@file,security-headers@file,traefik-bouncer@file + - traefik.http.services.tubearchivist.loadbalancer.server.scheme=http + - traefik.http.services.tubearchivist.loadbalancer.server.port=8000 + + tubearchivist-es: + image: docker.elastic.co/elasticsearch/elasticsearch:7.17.22 + container_name: tubearchivist-es + restart: unless-stopped + networks: + - networking + environment: + - discovery.type=single-node + - ES_JAVA_OPTS=-Xms512m -Xmx512m + - xpack.security.enabled=false + volumes: + - ${FOLDER_FOR_DATA:?err}/tubearchivist/es:/usr/share/elasticsearch/data + healthcheck: + test: curl -s http://localhost:9200/_cluster/health | grep -vq '"status":"red"' + interval: 30s + timeout: 10s + retries: 3 + + tubearchivist-redis: + image: redis:7-alpine + container_name: tubearchivist-redis + restart: unless-stopped + networks: + - networking + command: --save 60 1 --loglevel warning + volumes: + - ${FOLDER_FOR_DATA:?err}/tubearchivist/redis:/data + healthcheck: + test: redis-cli ping | grep PONG + interval: 30s + timeout: 10s + retries: 3 +#+END_SRC + ** Remaining Services The following services follow the same pattern as those documented above. @@ -1209,6 +1308,7 @@ definition, environment, volumes, and Traefik labels. - =qbittorrent.yaml, sabnzbd.yaml= — Torrent and usenet clients - =stash.yaml= — Adult content library manager - =tdarr.yaml, tdarr-node.yaml= — Media transcoding automation +- =tubearchivist.yaml= — YouTube archiving (Tube Archivist) - =audiobookshelf.yaml= — Audiobook and podcast server * .env Configuration @@ -1221,9 +1321,18 @@ Key variables: - =CLOUDFLARE_DNS_ZONE= (=gharbeia.net=) is used in all Traefik routes - =PUID= and =PGID= control file ownership (1000:1000) - =TUNNEL_TOKEN= is the Cloudflare tunnel auth token (managed externally) +- =TA_USERNAME= and =TA_PASSWORD= — Tube Archivist admin credentials * LOGBOOK +** [2026-05-16 Sat 21:40] Tube Archivist added to infrastructure +- Added tubearchivist.yaml service fragment (3 containers: tubearchivist + ES 7.17 + Redis) +- Added Traefik secureweb router + service entry in traefik-internal.yaml +- Added tunnel router via Docker labels for external access through Cloudflare +- Added to master compose include list (service #44) +- Added TA_USERNAME and TA_PASSWORD to .env reference +- NOTE: traefik-internal-noauth.yaml must be updated manually on production-1 + ** [2026-05-15 Thu 09:30] Jellyfin SSO fixed — KnownProxies and Two-Step Flow - Root cause: Jellyfin's empty KnownProxies caused SSO plugin to use HTTP base URL, breaking the JavaScript two-step auth flow (iframe/POST/redirect)