feat: Complete Sablier lazy loading implementation

- Add Sablier middleware to all 32 services across stacks
- Update vaultwarden port from 80 to 8091 to avoid conflicts
- Add tdarr-server and unmanic services with lazy loading
- Optimize health checks (wget for some services, dozzle built-in)
- Update Traefik routers and service definitions
- Update port documentation

All services now support on-demand startup via Sablier middleware.
This commit is contained in:
EZ-Homelab
2026-01-24 20:20:11 -05:00
parent 602dc3d12d
commit 5e7fe08652
7 changed files with 73 additions and 39 deletions

View File

@@ -22,16 +22,16 @@ http:
- sablier-${SERVER_HOSTNAME}-bookstack@file - sablier-${SERVER_HOSTNAME}-bookstack@file
- authelia@docker - authelia@docker
bitwarden-${SERVER_HOSTNAME}: vaultwarden-${SERVER_HOSTNAME}:
rule: "Host(`bitwarden.${DOMAIN}`)" rule: "Host(`vault.${DOMAIN}`)"
entryPoints: entryPoints:
- websecure - websecure
service: bitwarden-${SERVER_HOSTNAME} service: vaultwarden-${SERVER_HOSTNAME}
tls: tls:
certResolver: letsencrypt certResolver: letsencrypt
middlewares: # SSO disabled for browser extension and mobile app compatibility
- sablier-${SERVER_HOSTNAME}-bitwarden@file # middlewares:
- authelia@docker # - sablier-${SERVER_HOSTNAME}-vaultwarden@file
calibre-web-${SERVER_HOSTNAME}: calibre-web-${SERVER_HOSTNAME}:
rule: "Host(`calibre.${DOMAIN}`)" rule: "Host(`calibre.${DOMAIN}`)"
@@ -173,6 +173,17 @@ http:
- sablier-${SERVER_HOSTNAME}-jellyfin@file - sablier-${SERVER_HOSTNAME}-jellyfin@file
# No authelia middleware for media apps # No authelia middleware for media apps
jupyter-${SERVER_HOSTNAME}:
rule: "Host(`jupyter.${DOMAIN}`)"
entryPoints:
- websecure
service: jupyter-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-jupyter@file
- authelia@docker
kopia-${SERVER_HOSTNAME}: kopia-${SERVER_HOSTNAME}:
rule: "Host(`kopia.${DOMAIN}`)" rule: "Host(`kopia.${DOMAIN}`)"
entryPoints: entryPoints:
@@ -381,10 +392,10 @@ http:
- url: "http://192.168.4.11:9898" - url: "http://192.168.4.11:9898"
passHostHeader: true passHostHeader: true
bitwarden-${SERVER_HOSTNAME}: vaultwarden-${SERVER_HOSTNAME}:
loadBalancer: loadBalancer:
servers: servers:
- url: "http://192.168.4.11:8000" - url: "http://192.168.4.11:8091"
passHostHeader: true passHostHeader: true
bookstack-${SERVER_HOSTNAME}: bookstack-${SERVER_HOSTNAME}:
@@ -471,6 +482,12 @@ http:
- url: "http://192.168.4.11:8096" - url: "http://192.168.4.11:8096"
passHostHeader: true passHostHeader: true
jupyter-${SERVER_HOSTNAME}:
loadBalancer:
servers:
- url: "http://192.168.4.11:8890"
passHostHeader: true
kopia-${SERVER_HOSTNAME}: kopia-${SERVER_HOSTNAME}:
loadBalancer: loadBalancer:
servers: servers:
@@ -516,7 +533,7 @@ http:
qbittorrent-${SERVER_HOSTNAME}: qbittorrent-${SERVER_HOSTNAME}:
loadBalancer: loadBalancer:
servers: servers:
- url: "http://192.168.4.11:8080" - url: "http://192.168.4.11:8081"
passHostHeader: true passHostHeader: true
tdarr-${SERVER_HOSTNAME}: tdarr-${SERVER_HOSTNAME}:
@@ -528,7 +545,7 @@ http:
unmanic-${SERVER_HOSTNAME}: unmanic-${SERVER_HOSTNAME}:
loadBalancer: loadBalancer:
servers: servers:
- url: "http://192.168.4.11:8888" - url: "http://192.168.4.11:8889"
passHostHeader: true passHostHeader: true
wordpress-${SERVER_HOSTNAME}: wordpress-${SERVER_HOSTNAME}:

View File

@@ -32,15 +32,15 @@ http:
theme: ghost theme: ghost
show-details-by-default: true show-details-by-default: true
sablier-${SERVER_HOSTNAME}-bitwarden: sablier-${SERVER_HOSTNAME}-vaultwarden:
plugin: plugin:
sablier: sablier:
sablierUrl: http://sablier-service:10000 sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-bitwarden group: ${SERVER_HOSTNAME}-vaultwarden
sessionDuration: 5m sessionDuration: 5m
ignoreUserAgent: curl ignoreUserAgent: curl
dynamic: dynamic:
displayName: bitwarden displayName: Vaultwarden
theme: ghost theme: ghost
show-details-by-default: true show-details-by-default: true
@@ -176,6 +176,18 @@ http:
theme: ghost theme: ghost
show-details-by-default: true show-details-by-default: true
sablier-${SERVER_HOSTNAME}-jupyter:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-jupyter
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Jupyter
theme: ghost
show-details-by-default: true
sablier-${SERVER_HOSTNAME}-komodo: sablier-${SERVER_HOSTNAME}-komodo:
plugin: plugin:
sablier: sablier:
@@ -220,7 +232,7 @@ http:
sessionDuration: 5m sessionDuration: 5m
ignoreUserAgent: curl ignoreUserAgent: curl
dynamic: dynamic:
displayName: mediawiki displayName: MediaWiki
theme: ghost theme: ghost
show-details-by-default: true show-details-by-default: true

View File

@@ -149,7 +149,7 @@ services:
- DOZZLE_TAILSIZE=300 - DOZZLE_TAILSIZE=300
- DOZZLE_FILTER=status=running - DOZZLE_FILTER=status=running
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/"] test: ["CMD", "/dozzle", "healthcheck"]
interval: 30s interval: 30s
timeout: 10s timeout: 10s
retries: 3 retries: 3

View File

@@ -7,18 +7,6 @@
# - no: Services with Sablier lazy loading (start on-demand) # - no: Services with Sablier lazy loading (start on-demand)
# - See individual service comments for specific reasoning # - See individual service comments for specific reasoning
# Service Access URLs:
# - Sonarr: https://sonarr.${DOMAIN}
# - Radarr: https://radarr.${DOMAIN}
# - Prowlarr: https://prowlarr.${DOMAIN}
# - Readarr: https://readarr.${DOMAIN}
# - Lidarr: https://lidarr.${DOMAIN}
# - LazyLibrarian: https://lazylibrarian.${DOMAIN}
# - Mylar3: https://mylar.${DOMAIN}
# - Jellyseerr: https://jellyseerr.${DOMAIN}
# - Tdarr: https://tdarr.${DOMAIN}
# - Unmanic: https://unmanic.${DOMAIN}
services: services:
# Sonarr - TV show automation # Sonarr - TV show automation
# Access at: https://sonarr.yourdomain.duckdns.org # Access at: https://sonarr.yourdomain.duckdns.org
@@ -64,6 +52,7 @@ services:
- "sablier.enable=true" - "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr" - "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.start-on-demand=true" - "sablier.start-on-demand=true"
# Radarr - Movie automation # Radarr - Movie automation
# Access at: https://radarr.yourdomain.duckdns.org # Access at: https://radarr.yourdomain.duckdns.org
radarr: radarr:
@@ -108,6 +97,7 @@ services:
- "sablier.enable=true" - "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr" - "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.start-on-demand=true" - "sablier.start-on-demand=true"
# Prowlarr - Indexer manager # Prowlarr - Indexer manager
# Access at: https://prowlarr.yourdomain.duckdns.org # Access at: https://prowlarr.yourdomain.duckdns.org
prowlarr: prowlarr:
@@ -150,6 +140,7 @@ services:
- "sablier.enable=true" - "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr" - "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.start-on-demand=true" - "sablier.start-on-demand=true"
# Readarr - Ebook and audiobook management # Readarr - Ebook and audiobook management
# Access at: https://readarr.${DOMAIN} # Access at: https://readarr.${DOMAIN}
readarr: readarr:
@@ -188,6 +179,7 @@ services:
- "sablier.enable=true" - "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr" - "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.start-on-demand=true" - "sablier.start-on-demand=true"
# Lidarr - Music collection manager # Lidarr - Music collection manager
# Access at: https://lidarr.${DOMAIN} # Access at: https://lidarr.${DOMAIN}
lidarr: lidarr:
@@ -226,6 +218,7 @@ services:
- "sablier.enable=true" - "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr" - "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.start-on-demand=true" - "sablier.start-on-demand=true"
# Lazy Librarian - Book manager # Lazy Librarian - Book manager
# Access at: https://lazylibrarian.${DOMAIN} # Access at: https://lazylibrarian.${DOMAIN}
lazylibrarian: lazylibrarian:
@@ -265,6 +258,7 @@ services:
- "sablier.enable=true" - "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr" - "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.start-on-demand=true" - "sablier.start-on-demand=true"
# Mylar3 - Comic book manager # Mylar3 - Comic book manager
# Access at: https://mylar.${DOMAIN} # Access at: https://mylar.${DOMAIN}
mylar3: mylar3:
@@ -303,6 +297,7 @@ services:
- "sablier.enable=true" - "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr" - "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.start-on-demand=true" - "sablier.start-on-demand=true"
# Jellyseerr - Request management for Jellyfin/Plex # Jellyseerr - Request management for Jellyfin/Plex
# Access at: https://jellyseerr.${DOMAIN} # Access at: https://jellyseerr.${DOMAIN}
jellyseerr: jellyseerr:
@@ -320,7 +315,7 @@ services:
- LOG_LEVEL=info - LOG_LEVEL=info
- TZ=${TZ} - TZ=${TZ}
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5055/"] test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:5055/"]
interval: 30s interval: 30s
timeout: 10s timeout: 10s
retries: 3 retries: 3
@@ -344,6 +339,7 @@ services:
- "sablier.enable=true" - "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr" - "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.start-on-demand=true" - "sablier.start-on-demand=true"
# FlareSolverr - Cloudflare bypass for Prowlarr # FlareSolverr - Cloudflare bypass for Prowlarr
# No web UI - used by Prowlarr # No web UI - used by Prowlarr
flaresolverr: flaresolverr:
@@ -358,6 +354,10 @@ services:
labels: labels:
- homelab.category=media - homelab.category=media
- homelab.description=Cloudflare bypass for indexers - homelab.description=Cloudflare bypass for indexers
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.start-on-demand=true"
# Tdarr Server - Distributed transcoding server # Tdarr Server - Distributed transcoding server
# Access at: https://tdarr.${DOMAIN} # Access at: https://tdarr.${DOMAIN}
tdarr-server: tdarr-server:
@@ -400,8 +400,9 @@ services:
- "traefik.http.routers.tdarr.middlewares=authelia@docker" - "traefik.http.routers.tdarr.middlewares=authelia@docker"
- "traefik.http.services.tdarr.loadbalancer.server.port=8265" - "traefik.http.services.tdarr.loadbalancer.server.port=8265"
- "sablier.enable=true" - "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr" - "sablier.group=${SERVER_HOSTNAME}-tdarr"
- "sablier.start-on-demand=true" - "sablier.start-on-demand=true"
# Tdarr Node - Transcoding worker # Tdarr Node - Transcoding worker
# No web UI - controlled by server # No web UI - controlled by server
tdarr-node: tdarr-node:
@@ -427,6 +428,10 @@ services:
labels: labels:
- homelab.category=media - homelab.category=media
- homelab.description=Tdarr transcoding worker node - homelab.description=Tdarr transcoding worker node
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-tdarr"
- "sablier.start-on-demand=true"
# Unmanic - Another transcoding option # Unmanic - Another transcoding option
# Access at: https://unmanic.${DOMAIN} # Access at: https://unmanic.${DOMAIN}
unmanic: unmanic:
@@ -463,7 +468,7 @@ services:
- "traefik.http.routers.unmanic.middlewares=authelia@docker" - "traefik.http.routers.unmanic.middlewares=authelia@docker"
- "traefik.http.services.unmanic.loadbalancer.server.port=8889" - "traefik.http.services.unmanic.loadbalancer.server.port=8889"
- "sablier.enable=true" - "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr" - "sablier.group=${SERVER_HOSTNAME}-unmanic"
- "sablier.start-on-demand=true" - "sablier.start-on-demand=true"
x-dockge: x-dockge:

View File

@@ -117,9 +117,9 @@ services:
# Service configuration # Service configuration
- "traefik.http.services.calibre.loadbalancer.server.port=8083" - "traefik.http.services.calibre.loadbalancer.server.port=8083"
# Sablier configuration (disabled by default) # Sablier configuration (disabled by default)
# - "sablier.enable=true" - "sablier.enable=true"
# - "sablier.group=${SERVER_HOSTNAME}-calibre-web" - "sablier.group=${SERVER_HOSTNAME}-calibre-web"
# - "sablier.start-on-demand=true" - "sablier.start-on-demand=true"
# ========================================== # ==========================================
# DOCKGE URL CONFIGURATION # DOCKGE URL CONFIGURATION

View File

@@ -42,7 +42,7 @@ services:
- BACKREST_CONFIG=/config/config.json - BACKREST_CONFIG=/config/config.json
- TZ=${TZ} - TZ=${TZ}
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9898/api/v1/status"] test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:9898/"]
interval: 30s interval: 30s
timeout: 10s timeout: 10s
retries: 3 retries: 3
@@ -126,7 +126,7 @@ services:
- JWT_SECRET=${FORMIO_JWT_SECRET} - JWT_SECRET=${FORMIO_JWT_SECRET}
- DB_SECRET=${FORMIO_DB_SECRET} - DB_SECRET=${FORMIO_DB_SECRET}
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3001/health"] test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3001/"]
interval: 30s interval: 30s
timeout: 10s timeout: 10s
retries: 3 retries: 3
@@ -174,7 +174,7 @@ services:
- homelab-network - homelab-network
- traefik-network - traefik-network
ports: ports:
- "80:80" - "8091:80"
volumes: volumes:
- ./vaultwarden/data:/data - ./vaultwarden/data:/data
environment: environment:

View File

@@ -39,14 +39,14 @@ This document tracks all ports used by services in the EZ-Homelab. Update this d
| **Utilities** | [Backrest](../service-docs/backrest.md) | 9898 | 9898 | TCP | Web UI | | **Utilities** | [Backrest](../service-docs/backrest.md) | 9898 | 9898 | TCP | Web UI |
| **Utilities** | [Duplicati](../service-docs/duplicati.md) | 8200 | 8200 | TCP | Web UI | | **Utilities** | [Duplicati](../service-docs/duplicati.md) | 8200 | 8200 | TCP | Web UI |
| **Utilities** | [Form.io](../service-docs/formio.md) | 3002 | 3001 | TCP | Web UI | | **Utilities** | [Form.io](../service-docs/formio.md) | 3002 | 3001 | TCP | Web UI |
| **Utilities** | [Vaultwarden](../service-docs/vaultwarden.md) | 80 | 80 | TCP | Internal port | | **Utilities** | [Vaultwarden](../service-docs/vaultwarden.md) | 8091 | 80 | TCP | Web UI |
| **VPN** | [Gluetun](../service-docs/gluetun.md) | 8888 | 8888 | TCP | HTTP proxy | | **VPN** | [Gluetun](../service-docs/gluetun.md) | 8888 | 8888 | TCP | HTTP proxy |
| **VPN** | [Gluetun](../service-docs/gluetun.md) | 8388 | 8388 | TCP/UDP | Shadowsocks | | **VPN** | [Gluetun](../service-docs/gluetun.md) | 8388 | 8388 | TCP/UDP | Shadowsocks |
| **VPN** | [Gluetun](../service-docs/gluetun.md) | 8081 | 8080 | TCP | qBittorrent Web UI | | **VPN** | [Gluetun](../service-docs/gluetun.md) | 8081 | 8080 | TCP | qBittorrent Web UI |
| **VPN** | [Gluetun](../service-docs/gluetun.md) | 6881 | 6881 | TCP/UDP | qBittorrent | | **VPN** | [Gluetun](../service-docs/gluetun.md) | 6881 | 6881 | TCP/UDP | qBittorrent |
| **VPN** | [qBittorrent](../service-docs/qbittorrent.md) | N/A | N/A | N/A | Routed through Gluetun | | **VPN** | [qBittorrent](../service-docs/qbittorrent.md) | N/A | N/A | N/A | Routed through Gluetun |
| **Productivity** | [DokuWiki](../service-docs/dokuwiki.md) | 80 | 80 | TCP | Internal port | | **Productivity** | [DokuWiki](../service-docs/dokuwiki.md) | 8087 | 80 | TCP | Web UI |
| **Productivity** | [Nextcloud](../service-docs/nextcloud.md) | 80 | 80 | TCP | Internal port | | **Productivity** | [Nextcloud](../service-docs/nextcloud.md) | 8089 | 80 | TCP | Web UI |
| **Productivity** | [Gitea](../service-docs/gitea.md) | 3010 | 3000 | TCP | Web UI | | **Productivity** | [Gitea](../service-docs/gitea.md) | 3010 | 3000 | TCP | Web UI |
| **Productivity** | [MinIO](../service-docs/minio.md) | 9000 | 9000 | TCP | API | | **Productivity** | [MinIO](../service-docs/minio.md) | 9000 | 9000 | TCP | API |
| **Productivity** | [MinIO](../service-docs/minio.md) | 9001 | 9001 | TCP | Web UI | | **Productivity** | [MinIO](../service-docs/minio.md) | 9001 | 9001 | TCP | Web UI |