docker-compose-nas/docker-compose.yml

627 lines
27 KiB
YAML

services:
traefik:
image: ghcr.io/traefik/traefik:3.3
container_name: traefik
restart: always
command:
- --ping=true
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
- --entrypoints.web-secure.address=:443
- --experimental.plugins.rewrite-body.modulename=github.com/packruler/rewrite-body
- --experimental.plugins.rewrite-body.version=v1.2.0
- --experimental.plugins.rewriteHeaders.modulename=github.com/XciD/traefik-plugin-rewrite-headers
- --experimental.plugins.rewriteHeaders.version=v0.0.3
network_mode: service:tailscale # Add this line
# ports: # Remove this section
# - "80:80"
# - "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
# extra_hosts: # Remove this section
# - host.docker.internal:172.17.0.1
healthcheck:
test: ["CMD", "traefik", "healthcheck", "--ping"]
interval: 30s
retries: 10
redis:
image: redis:alpine
container_name: redis
restart: always
environment:
- REDIS_PASSWORD=${AUTHELIA_REDIS_PASSWORD}
command: ["redis-server", "--requirepass", "${AUTHELIA_REDIS_PASSWORD}"] # Use actual password variable
volumes:
- ${CONFIG_ROOT:-.}/redis:/data:Z
healthcheck:
test: ["CMD", "redis-cli", "-a", "${AUTHELIA_REDIS_PASSWORD}", "ping"] # Use actual password variable
interval: 5s
timeout: 3s
retries: 5
authelia:
image: authelia/authelia:latest
container_name: authelia
restart: always
user: ${USER_ID}:${GROUP_ID}
volumes:
- ${CONFIG_ROOT:-.}/authelia:/config:Z
environment:
# Core secrets
- AUTHELIA_JWT_SECRET=${AUTHELIA_JWT_SECRET}
- AUTHELIA_SESSION_SECRET=${AUTHELIA_SESSION_SECRET}
- AUTHELIA_STORAGE_ENCRYPTION_KEY=${AUTHELIA_STORAGE_ENCRYPTION_KEY}
- AUTHELIA_SESSION_REDIS_PASSWORD=${AUTHELIA_REDIS_PASSWORD}
# Only environment variable needed for identity validation
- AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET=${AUTHELIA_JWT_SECRET}
# Timezone
- TZ=${TIMEZONE}
labels:
- traefik.enable=true
# Rule for Authelia portal itself (handles internal paths like /api, /logout etc.)
- traefik.http.routers.authelia.rule=PathPrefix(`/`)
- traefik.http.routers.authelia.entrypoints=web
- traefik.http.routers.authelia.priority=100 # High priority to catch root path
- traefik.http.services.authelia.loadbalancer.server.port=9091
# Define the forwardAuth middleware
- traefik.http.middlewares.authelia-auth.forwardAuth.address=http://authelia:9091/api/verify?rd=https://${APP_HOSTNAME}/
- traefik.http.middlewares.authelia-auth.forwardAuth.trustForwardHeader=true
- traefik.http.middlewares.authelia-auth.forwardAuth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email
# Homepage labels for Authelia itself
- homepage.group=Security
- homepage.name=Authelia
- homepage.icon=authelia.png
- homepage.href=https://${APP_HOSTNAME}/
- homepage.description=Authentication Portal
sonarr:
image: lscr.io/linuxserver/sonarr
container_name: sonarr
environment:
- PUID=${USER_ID}
- PGID=${GROUP_ID}
- TZ=${TIMEZONE}
volumes:
- ${CONFIG_ROOT:-.}/sonarr:/config:Z
- ${DATA_ROOT}:/data:Z
restart: always
healthcheck:
test: ["CMD", "curl", "--fail", "http://127.0.0.1:8989/sonarr/ping"]
interval: 30s
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.sonarr.rule=PathPrefix(`/sonarr`)
- traefik.http.routers.sonarr.entrypoints=web
- traefik.http.routers.sonarr.middlewares=authelia-auth@docker
- traefik.http.services.sonarr.loadbalancer.server.port=8989
- homepage.group=Media
- homepage.name=Sonarr
- homepage.icon=sonarr.png
- homepage.href=/sonarr
- homepage.description=Series management
- homepage.weight=0
- homepage.widget.type=sonarr
- homepage.widget.url=http://sonarr:8989/sonarr
- homepage.widget.key=${SONARR_API_KEY}
radarr:
image: lscr.io/linuxserver/radarr
container_name: radarr
environment:
- PUID=${USER_ID}
- PGID=${GROUP_ID}
- TZ=${TIMEZONE}
volumes:
- ${CONFIG_ROOT:-.}/radarr:/config:Z
- ${DATA_ROOT}:/data:Z
restart: always
healthcheck:
test: ["CMD", "curl", "--fail", "http://127.0.0.1:7878/radarr/ping"]
interval: 30s
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.radarr.rule=PathPrefix(`/radarr`)
- traefik.http.routers.radarr.entrypoints=web
- traefik.http.routers.radarr.middlewares=authelia-auth@docker
- traefik.http.services.radarr.loadbalancer.server.port=7878
- homepage.group=Media
- homepage.name=Radarr
- homepage.icon=radarr.png
- homepage.href=/radarr
- homepage.description=Movies management
- homepage.weight=1
- homepage.widget.type=radarr
- homepage.widget.url=http://radarr:7878/radarr
- homepage.widget.key=${RADARR_API_KEY}
lidarr:
image: lscr.io/linuxserver/lidarr
container_name: lidarr
environment:
- PUID=${USER_ID}
- PGID=${GROUP_ID}
- TZ=${TIMEZONE}
volumes:
- ${CONFIG_ROOT:-.}/lidarr:/config:Z
- ${DATA_ROOT}:/data:Z
restart: always
healthcheck:
test: ["CMD", "curl", "--fail", "http://127.0.0.1:8686/lidarr/ping"]
interval: 30s
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.lidarr.rule=PathPrefix(`/lidarr`)
- traefik.http.routers.lidarr.entrypoints=web
- traefik.http.routers.lidarr.middlewares=authelia-auth@docker
- traefik.http.services.lidarr.loadbalancer.server.port=8686
- homepage.group=Media
- homepage.name=Lidarr
- homepage.icon=lidarr.png
- homepage.href=/lidarr
- homepage.description=Music management
- homepage.weight=2
- homepage.widget.type=lidarr
- homepage.widget.url=http://lidarr:8686/lidarr
- homepage.widget.key=${LIDARR_API_KEY}
profiles:
- lidarr
bazarr:
image: lscr.io/linuxserver/bazarr
container_name: bazarr
environment:
- PUID=${USER_ID}
- PGID=${GROUP_ID}
- TZ=${TIMEZONE}
volumes:
- ${CONFIG_ROOT:-.}/bazarr/config:/config:Z
- ${DATA_ROOT}:/data:Z
restart: always
healthcheck:
test: ["CMD", "curl", "--fail", "http://127.0.0.1:6767/bazarr/ping"]
interval: 5s
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.bazarr.rule=PathPrefix(`/bazarr`)
- traefik.http.routers.bazarr.entrypoints=web
- traefik.http.routers.bazarr.middlewares=authelia-auth@docker
- traefik.http.services.bazarr.loadbalancer.server.port=6767
- homepage.group=Download
- homepage.name=Bazarr
- homepage.icon=bazarr.png
- homepage.href=/bazarr
- homepage.description=Subtitles management
- homepage.weight=4
- homepage.widget.type=bazarr
- homepage.widget.url=http://bazarr:6767/bazarr
- homepage.widget.key=${BAZARR_API_KEY}
jellyseerr:
image: ghcr.io/fallenbagel/jellyseerr:latest
container_name: jellyseerr
environment:
- LOG_LEVEL=debug
- TZ=${TIMEZONE}
volumes:
- ${CONFIG_ROOT:-.}/jellyseerr:/app/config:Z
restart: always
healthcheck:
test:
[
"CMD",
"wget",
"http://127.0.0.1:5055/api/v1/status",
"-qO",
"/dev/null",
]
interval: 30s
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.jellyseerr.rule=PathPrefix(`/jellyseerr`)
- traefik.http.routers.jellyseerr.entrypoints=web
- traefik.http.services.jellyseerr.loadbalancer.server.port=5055
- traefik.http.routers.jellyseerr.middlewares=jellyseerr-stripprefix,jellyseerr-rewrite,jellyseerr-rewriteHeaders,authelia-auth@docker
- traefik.http.middlewares.jellyseerr-stripprefix.stripPrefix.prefixes=/jellyseerr
- traefik.http.middlewares.jellyseerr-rewriteHeaders.plugin.rewriteHeaders.rewrites[0].header=location
- traefik.http.middlewares.jellyseerr-rewriteHeaders.plugin.rewriteHeaders.rewrites[0].regex=^/(.+)$
- traefik.http.middlewares.jellyseerr-rewriteHeaders.plugin.rewriteHeaders.rewrites[0].replacement=/jellyseerr/$1
- traefik.http.middlewares.jellyseerr-rewriteHeaders.plugin.rewriteHeaders.rewrites[1].header=location
- traefik.http.middlewares.jellyseerr-rewriteHeaders.plugin.rewriteHeaders.rewrites[1].regex=^/$
- traefik.http.middlewares.jellyseerr-rewriteHeaders.plugin.rewriteHeaders.rewrites[1].replacement=/jellyseerr
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.monitoring.types[0]=text/html
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.monitoring.types[1]=application/javascript
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.monitoring.types[2]=*/*
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.monitoring.types[3]=application/json
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[1].regex=/_next
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[1].replacement=/jellyseerr/_next
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[2].regex=/_next/data/
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[2].replacement=/jellyseerr/_next/data/
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[3].regex=/api/v1
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[3].replacement=/jellyseerr/api/v1
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[4].regex=/login/plex/loading
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[4].replacement=/jellyseerr/login/plex/loading
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[5].regex=/images/
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[5].replacement=/jellyseerr/images/
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[6].regex=/favicon
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[6].replacement=/jellyseerr/favicon
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[7].regex=/logo_
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[7].replacement=/jellyseerr/logo_
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[8].regex=/site.webmanifest
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[8].replacement=/jellyseerr/site.webmanifest
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[9].regex=/sw.js
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[9].replacement=/jellyseerr/sw.js
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[10].regex=/offline.html
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[10].replacement=/jellyseerr/offline.html
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[11].regex=src="/os_logo_square.png"
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[11].replacement=src="/jellyseerr/os_logo_square.png"
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[12].regex=href([=:])"/([/a-zA-Z?=]*)"
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[12].replacement=href$1"/jellyseerr/$2"
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[13].regex=linkUrl:"/([/a-zA-Z?=]*)"
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[13].replacement=linkUrl:"/jellyseerr/$1"
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[14].regex="/([a-z]+)/".concat
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[14].replacement="/jellyseerr/$1/".concat
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[15].regex=url:"/([/a-zA-Z?=]*)"
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[15].replacement=url:"/jellyseerr/$1"
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[16].regex=/imageproxy/
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[16].replacement=/jellyseerr/imageproxy/
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[17].regex=/avatarproxy/
- traefik.http.middlewares.jellyseerr-rewrite.plugin.rewrite-body.rewrites[17].replacement=/jellyseerr/avatarproxy/
- homepage.group=Media
- homepage.name=JellySeerr
- homepage.icon=jellyseerr.png
- homepage.href=/jellyseerr
- homepage.description=Content Recommendations and Request Management
- homepage.weight=3
- homepage.widget.type=jellyseerr
- homepage.widget.url=http://jellyseerr:5055
- homepage.widget.key=${JELLYSEERR_API_KEY}
prowlarr:
image: lscr.io/linuxserver/prowlarr:latest
container_name: prowlarr
environment:
- PUID=${USER_ID}
- PGID=${GROUP_ID}
- TZ=${TIMEZONE}
volumes:
- ${CONFIG_ROOT:-.}/prowlarr:/config:Z
restart: always
healthcheck:
test: ["CMD", "curl", "--fail", "http://127.0.0.1:9696/prowlarr/ping"]
interval: 30s
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.prowlarr.rule=PathPrefix(`/prowlarr`)
- traefik.http.routers.prowlarr.entrypoints=web
- traefik.http.routers.prowlarr.middlewares=authelia-auth@docker
- traefik.http.services.prowlarr.loadbalancer.server.port=9696
- homepage.group=Download
- homepage.name=Prowlarr
- homepage.icon=prowlarr.png
- homepage.href=/prowlarr
- homepage.description=Indexers management
- homepage.weight=1
- homepage.widget.type=prowlarr
- homepage.widget.url=http://prowlarr:9696/prowlarr
- homepage.widget.key=${PROWLARR_API_KEY}
flaresolverr:
image: 21hsmw/flaresolverr:nodriver
container_name: flaresolverr
restart: always
environment:
- LOG_LEVEL=${LOG_LEVEL:-info}
- LOG_HTML=${LOG_HTML:-false}
- CAPTCHA_SOLVER=${CAPTCHA_SOLVER:-none}
- TZ=${TIMEZONE}
labels:
- traefik.enable=true
- traefik.http.routers.flaresolverr.rule=PathPrefix(`/flaresolverr`)
- traefik.http.routers.flaresolverr.entrypoints=web
- traefik.http.routers.flaresolverr.middlewares=authelia-auth@docker
- traefik.http.services.flaresolverr.loadbalancer.server.port=8191
profiles:
- flaresolverr
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:libtorrentv1
container_name: qbittorrent
environment:
- PUID=${USER_ID}
- PGID=${GROUP_ID}
- TZ=${TIMEZONE}
- WEBUI_PORT=8080
- DOCKER_MODS=ghcr.io/gabe565/linuxserver-mod-vuetorrent
volumes:
- ${CONFIG_ROOT:-.}/qbittorrent:/config:Z
- ${DOWNLOAD_ROOT}:/data/torrents:Z
restart: always
healthcheck:
# Container may fail if the PIA's token expired, so mark as unhealthy when there is no internet connection
# see: https://github.com/qdm12/gluetun/issues/641#issuecomment-933856220
test:
["CMD", "curl", "--fail", "http://127.0.0.1:8080", "https://google.com"]
interval: 30s
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.qbittorrent.rule=PathPrefix(`/qbittorrent`)
- traefik.http.routers.qbittorrent.entrypoints=web
- traefik.http.services.qbittorrent.loadbalancer.server.port=8080
- traefik.http.routers.qbittorrent.middlewares=qbittorrent-strip-slash,qbittorrent-stripprefix,authelia-auth@docker
# https://github.com/qbittorrent/qBittorrent/issues/5693#issuecomment-552146296
- traefik.http.middlewares.qbittorrent-stripprefix.stripPrefix.prefixes=/qbittorrent
# https://community.traefik.io/t/middleware-to-add-the-if-needed/1895/19
- traefik.http.middlewares.qbittorrent-strip-slash.redirectregex.regex=(^.*\/qbittorrent$$)
- traefik.http.middlewares.qbittorrent-strip-slash.redirectregex.replacement=$$1/
- traefik.http.middlewares.qbittorrent-strip-slash.redirectregex.permanent=false
#- com.centurylinklabs.watchtower.depends-on=/vpn
- homepage.group=Download
- homepage.name=qBittorrent
- homepage.icon=qbittorrent.png
- homepage.href=/qbittorrent
- homepage.description=Bittorrent client
- homepage.weight=2
- homepage.widget.type=qbittorrent
- homepage.widget.url=http://qbittorrent:8080
- homepage.widget.username=${QBITTORRENT_USERNAME}
- homepage.widget.password=${QBITTORRENT_PASSWORD}
unpackerr:
image: ghcr.io/unpackerr/unpackerr:latest
container_name: unpackerr
volumes:
- ${DOWNLOAD_ROOT}:/data/torrents:Z
restart: always
user: ${USER_ID}:${GROUP_ID}
environment:
- TZ=${TIMEZONE}
- UN_SONARR_0_URL=http://sonarr:8989/sonarr
- UN_SONARR_0_API_KEY=${SONARR_API_KEY}
- UN_RADARR_0_URL=http://radarr:7878/radarr
- UN_RADARR_0_API_KEY=${RADARR_API_KEY}
security_opt:
- no-new-privileges:true
sabnzbd:
image: lscr.io/linuxserver/sabnzbd:latest
container_name: sabnzbd
environment:
- PUID=${USER_ID}
- PGID=${GROUP_ID}
- TZ=${TIMEZONE}
volumes:
- ${CONFIG_ROOT:-.}/sabnzbd:/config:Z
- ${DATA_ROOT}:/data:Z
restart: always
labels:
- traefik.enable=true
- traefik.http.routers.sabnzbd.rule=PathPrefix(`/sabnzbd`) # Simplified rule
- traefik.http.routers.sabnzbd.entrypoints=web
- traefik.http.routers.sabnzbd.middlewares=authelia-auth@docker
- traefik.http.services.sabnzbd.loadbalancer.server.port=8080
- homepage.group=Download
- homepage.name=Sabnzbd
- homepage.icon=sabnzbd.png
- homepage.href=/sabnzbd
- homepage.description=Usenet
- homepage.weight=3
- homepage.widget.type=sabnzbd
- homepage.widget.url=http://sabnzbd:8080/sabnzbd
- homepage.widget.key=${SABNZBD_API_KEY}
profiles:
- sabnzbd
jellyfin:
image: lscr.io/linuxserver/jellyfin:latest
container_name: jellyfin
environment:
- PUID=${USER_ID}
- PGID=${GROUP_ID}
- TZ=${TIMEZONE}
- JELLYFIN_PublishedServerUrl=${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}/jellyfin
volumes:
- ${CONFIG_ROOT:-.}/jellyfin:/config:Z
- ${DATA_ROOT}:/data:Z
ports:
- "7359:7359/udp"
- "1900:1900/udp"
restart: always
healthcheck:
test: ["CMD", "curl", "--fail", "http://127.0.0.1:8096/jellyfin/health"]
interval: 30s
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.jellyfin.rule=PathPrefix(`/jellyfin`)
- traefik.http.routers.jellyfin.entrypoints=web
- traefik.http.routers.jellyfin.middlewares=authelia-auth@docker
- traefik.http.services.jellyfin.loadbalancer.server.port=8096
- homepage.group=Media
- homepage.name=Jellyfin
- homepage.icon=jellyfin.png
- homepage.href=/jellyfin
- homepage.description=Media server
- homepage.weight=4
- homepage.widget.type=jellyfin
- homepage.widget.url=http://jellyfin:8096/jellyfin
- homepage.widget.key=${JELLYFIN_API_KEY}
calibre-web:
image: lscr.io/linuxserver/calibre-web:latest
container_name: calibre-web
environment:
- PUID=${USER_ID}
- PGID=${GROUP_ID}
- TZ=${TIMEZONE}
- DOCKER_MODS=linuxserver/mods:universal-calibre
- OAUTHLIB_RELAX_TOKEN_SCOPE=1
volumes:
- ${CONFIG_ROOT:-.}/calibre-web:/config:Z
- ${DATA_ROOT}/books:/books:Z
restart: unless-stopped
labels:
- traefik.enable=true
- traefik.http.middlewares.calibre-headers.headers.customRequestHeaders.X-Scheme=https
- traefik.http.middlewares.calibre-headers.headers.customRequestHeaders.X-Script-Name=/calibre
- traefik.http.middlewares.calibre-stripprefixregex.stripPrefixRegex.regex=/calibre
- traefik.http.routers.calibre.middlewares=calibre-headers,calibre-stripprefixregex,authelia-auth@docker
- traefik.http.routers.calibre.rule=PathPrefix(`/calibre`)
- traefik.http.routers.calibre.entrypoints=web
- traefik.http.services.calibre.loadbalancer.server.port=8083
- homepage.group=Media
- homepage.name=Calibre-Web
- homepage.icon=calibre-web.png
- homepage.href=/calibre
- homepage.description=Books management
- homepage.weight=5
- homepage.widget.type=calibreweb
- homepage.widget.url=http://calibre-web:8083
- homepage.widget.username=${CALIBRE_USERNAME}
- homepage.widget.password=${CALIBRE_PASSWORD}
profiles:
- calibre-web
decluttarr:
image: ghcr.io/manimatter/decluttarr:latest
container_name: decluttarr
restart: always
environment:
- PUID=${USER_ID}
- PGID=${GROUP_ID}
- TZ=${TIMEZONE}
- RADARR_URL=http://radarr:7878/radarr
- RADARR_KEY=${RADARR_API_KEY}
- SONARR_URL=http://sonarr:8989/sonarr
- SONARR_KEY=${SONARR_API_KEY}
- LIDARR_URL=http://lidarr:8686/lidarr
- LIDARR_KEY=${LIDARR_API_KEY}
- QBITTORRENT_URL=http://qbittorrent:8080
- QBITTORRENT_USERNAME=${QBITTORRENT_USERNAME}
- QBITTORRENT_PASSWORD=${QBITTORRENT_PASSWORD}
- LOG_LEVEL=${DECLUTTARR_LOG_LEVEL:-INFO}
- TEST_RUN=${DECLUTTARR_TEST_RUN:-False}
- REMOVE_TIMER=${DECLUTTARR_REMOVE_TIMER:-10}
- REMOVE_FAILED=${DECLUTTARR_REMOVE_FAILED:-True}
- REMOVE_FAILED_IMPORTS=${DECLUTTARR_REMOVE_FAILED_IMPORTS:-True}
- REMOVE_METADATA_MISSING=${DECLUTTARR_REMOVE_METADATA_MISSING:-True}
- REMOVE_MISSING_FILES=${DECLUTTARR_REMOVE_MISSING_FILES:-True}
- REMOVE_ORPHANS=${DECLUTTARR_REMOVE_ORPHANS:-True}
- REMOVE_SLOW=${DECLUTTARR_REMOVE_SLOW:-True}
- REMOVE_STALLED=${DECLUTTARR_REMOVE_STALLED:-True}
- REMOVE_UNMONITORED=${DECLUTTARR_REMOVE_UNMONITORED:-True}
- RUN_PERIODIC_RESCANS=${DECLUTTARR_RUN_PERIODIC_RESCANS:-}
- PERMITTED_ATTEMPTS=${DECLUTTARR_PERMITTED_ATTEMPTS:-3}
- NO_STALLED_REMOVAL_QBIT_TAG=${DECLUTTARR_REMOVAL_QBIT_TAG:-"stalled"}
- MIN_DOWNLOAD_SPEED=${DECLUTTARR_MIN_DOWNLOAD_SPEED:-100}
- FAILED_IMPORT_MESSAGE_PATTERNS=${DECLUTTARR_FAILED_IMPORT_MESSAGE_PATTERNS:-}
- IGNORED_DOWNLOAD_CLIENTS=${DECLUTTARR_IGNORED_DOWNLOAD_CLIENTS:-}
profiles:
- decluttarr
homepage:
image: ghcr.io/gethomepage/homepage:latest
container_name: homepage
environment:
- HOMEPAGE_VAR_TITLE=${HOMEPAGE_VAR_TITLE}
- HOMEPAGE_VAR_SEARCH_PROVIDER=${HOMEPAGE_VAR_SEARCH_PROVIDER}
- HOMEPAGE_VAR_HEADER_STYLE=${HOMEPAGE_VAR_HEADER_STYLE}
- HOMEPAGE_VAR_WEATHER_CITY=${HOMEPAGE_VAR_WEATHER_CITY}
- HOMEPAGE_VAR_WEATHER_LAT=${HOMEPAGE_VAR_WEATHER_LAT}
- HOMEPAGE_VAR_WEATHER_LONG=${HOMEPAGE_VAR_WEATHER_LONG}
- HOMEPAGE_VAR_WEATHER_TIME=${TIMEZONE}
- HOMEPAGE_VAR_WEATHER_UNIT=${HOMEPAGE_VAR_WEATHER_UNIT}
# Explicitly allow the hostname constructed from Tailscale variables
- HOMEPAGE_ALLOWED_HOSTS=${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}
volumes:
- ${CONFIG_ROOT:-.}/homepage:/app/config:Z
- /var/run/docker.sock:/var/run/docker.sock:ro
- ${DATA_ROOT}:/data:Z
restart: always
command:
[sh, -c, "cp -n /app/config/tpl/*.yaml /app/config && node server.js"]
labels:
- traefik.enable=true
# Rule for homepage, now at /home, needs auth
- traefik.http.routers.homepage.rule=PathPrefix(`/home`)
- traefik.http.routers.homepage.entrypoints=web
- traefik.http.routers.homepage.priority=10 # Lower priority than Authelia's root rule
- traefik.http.middlewares.homepage-stripprefix.stripPrefix.prefixes=/home
- traefik.http.routers.homepage.middlewares=homepage-stripprefix,authelia-auth@docker
# Homepage's own labels for discovery (unchanged)
- homepage.group=Dashboard
- homepage.name=Homepage
- homepage.icon=homepage.png
- homepage.href=/home # Update link to new path
- homepage.description=Service Dashboard
watchtower:
image: ghcr.io/containrrr/watchtower:latest
container_name: watchtower
restart: always
environment:
- WATCHTOWER_CLEANUP=true
volumes:
- /var/run/docker.sock:/var/run/docker.sock
autoheal:
image: willfarrell/autoheal:latest
container_name: autoheal
restart: always
environment:
- AUTOHEAL_CONTAINER_LABEL=all
volumes:
- /var/run/docker.sock:/var/run/docker.sock
tailscale:
image: tailscale/tailscale:latest
container_name: tailscale
hostname: ${TAILSCALE_HOSTNAME:-tailscale-nas} # Hostname for Tailscale access
environment:
TS_AUTHKEY: ${TAILSCALE_AUTHKEY} # Needs to be set in .env
TS_EXTRA_ARGS: "--advertise-tags=${TAILSCALE_TAGS:-tag:nas}" # Keep tags if desired
TS_STATE_DIR: "/var/lib/tailscale"
TS_USERSPACE: "false"
# Switch to enable Funnel (public access) or Serve (Tailnet only)
ENABLE_FUNNEL_HTTPS: ${ENABLE_FUNNEL_HTTPS:-false}
volumes:
- ${CONFIG_ROOT:-.}/tailscale/state:/var/lib/tailscale:Z # Persist state
- /var/run/docker.sock:/var/run/docker.sock # Optional, keep if needed
devices:
- /dev/net/tun:/dev/net/tun
cap_add:
- NET_ADMIN
- NET_RAW
extra_hosts: # Add this section
- host.docker.internal:172.17.0.1
restart: always
command:
- /bin/sh
- -c
- |
set -e
echo "Starting containerboot (tailscaled)..."
/usr/local/bin/containerboot &
echo "Waiting for tailscaled to achieve running state..."
retries=60
count=0
until tailscale status --json | grep -q '"BackendState": "Running"'; do
count=$$(($$count+1))
if [ $$count -gt $$retries ]; then
echo "Error: tailscaled did not reach running state after $$retries seconds."
exit 1
fi
echo -n "."
sleep 1
done
echo " Tailscaled is running."
# --- Start Tailscale Funnel/Serve ---
# Check the ENABLE_FUNNEL_HTTPS variable
if [ "${ENABLE_FUNNEL_HTTPS}" = "true" ]; then
echo "ENABLE_FUNNEL_HTTPS is true. Setting up Funnel -> http://localhost:80..."
tailscale funnel --bg http://localhost:80
echo "Tailscale Funnel configured."
else
echo "ENABLE_FUNNEL_HTTPS is false. Setting up Serve -> http://localhost:80..."
tailscale serve --bg http://localhost:80
echo "Tailscale Serve configured."
fi
# --- End Tailscale Funnel/Serve ---
echo "Tailscale forwarding configured. Container will remain running."
wait # Wait indefinitely for background processes
networks:
default:
name: docker-compose-nas