Compare commits
14 Commits
a0fb667642
...
feature/tr
| Author | SHA1 | Date | |
|---|---|---|---|
| 79a7a0d4c6 | |||
| 93e709841b | |||
| 78338661b0 | |||
| 9f8ff41bf4 | |||
| 67ff6d585c | |||
| cf78372b71 | |||
| 8c5cdb111d | |||
| 42ee02d8e7 | |||
| 83016e268c | |||
| 3539cc3d3e | |||
| 4db5c27755 | |||
| 8051ea33e3 | |||
| cc51dd386c | |||
| 3ce7262e38 |
99
.env.example
99
.env.example
@@ -1,21 +1,81 @@
|
||||
# --- Docker Compose Settings ---
|
||||
# Comma-separated list of optional service profiles to enable (e.g., lidarr,sabnzbd,adguardhome)
|
||||
COMPOSE_PROFILES=
|
||||
# Path separator for COMPOSE_FILE (use ';' for Windows)
|
||||
COMPOSE_PATH_SEPARATOR=:
|
||||
# Colon-separated list of compose files to use. Allows extending the base configuration.
|
||||
COMPOSE_FILE=docker-compose.yml:adguardhome/docker-compose.yml:tandoor/docker-compose.yml:joplin/docker-compose.yml:homeassistant/docker-compose.yml:immich/docker-compose.yml
|
||||
|
||||
# --- Core System Settings ---
|
||||
# Linux User ID. Find yours with `id -u`. Crucial for file permissions.
|
||||
USER_ID=1000
|
||||
# Linux Group ID. Find yours with `id -g`. Crucial for file permissions.
|
||||
GROUP_ID=1000
|
||||
# Your local timezone (e.g., America/New_York, Europe/London, Asia/Manila). See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||
TIMEZONE="America/New_York"
|
||||
|
||||
# --- Host Paths ---
|
||||
# Base directory on host for storing service configuration files. '.' stores them in subdirectories within the project folder.
|
||||
CONFIG_ROOT="."
|
||||
# Main directory on host containing media libraries (movies, TV, music, books).
|
||||
DATA_ROOT="/mnt/data"
|
||||
# Directory on host for download clients (qBittorrent/SABnzbd). Should be on the same filesystem as DATA_ROOT for hardlinks.
|
||||
DOWNLOAD_ROOT="/mnt/data/torrents"
|
||||
# Upload location for Immich (if profile enabled)
|
||||
IMMICH_UPLOAD_LOCATION="/mnt/data/photos"
|
||||
HOSTNAME=localhost
|
||||
HOMEASSISTANT_HOSTNAME=
|
||||
IMMICH_HOSTNAME=
|
||||
ADGUARD_HOSTNAME=
|
||||
ADGUARD_USERNAME=
|
||||
ADGUARD_PASSWORD=
|
||||
|
||||
# --- Tailscale Settings ---
|
||||
# Required. Auth key from Tailscale Admin Console (Settings > Keys). Use a reusable or ephemeral key.
|
||||
TAILSCALE_AUTHKEY=
|
||||
# Desired hostname for this NAS within your Tailscale network.
|
||||
TAILSCALE_HOSTNAME=tailscale-nas
|
||||
# Required. Your Tailnet domain (e.g., your-tailnet-name.ts.net).
|
||||
TAILSCALE_TAILNET_DOMAIN=your-tailnet.ts.net
|
||||
# Optional tags to apply to the Tailscale node (e.g., tag:nas).
|
||||
TAILSCALE_TAGS=tag:nas
|
||||
# Enable Tailscale Funnel (public access) for HTTPS? Set to 'true' or 'false'. 'false' uses Serve (Tailnet only, recommended).
|
||||
ENABLE_FUNNEL_HTTPS=false
|
||||
|
||||
# --- Primary Application Hostname ---
|
||||
# Primary hostname used by Traefik/Authelia. Derived from Tailscale settings by default.
|
||||
# Renamed from HOSTNAME to avoid collision with host system environment variable.
|
||||
APP_HOSTNAME=${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}
|
||||
|
||||
# --- Application Credentials ---
|
||||
# qBittorrent Web UI Credentials (change default!)
|
||||
QBITTORRENT_USERNAME=admin
|
||||
QBITTORRENT_PASSWORD=adminadmin
|
||||
# Calibre-Web Credentials (if profile enabled)
|
||||
CALIBRE_USERNAME=admin
|
||||
CALIBRE_PASSWORD=admin123
|
||||
# Immich Database Password (if profile enabled)
|
||||
IMMICH_DB_PASSWORD=postgres
|
||||
|
||||
# --- Homepage Settings ---
|
||||
HOMEPAGE_VAR_TITLE="Docker-Compose NAS"
|
||||
HOMEPAGE_VAR_SEARCH_PROVIDER=google
|
||||
HOMEPAGE_VAR_HEADER_STYLE=boxed
|
||||
# Weather Widget (Optional)
|
||||
HOMEPAGE_VAR_WEATHER_CITY=
|
||||
HOMEPAGE_VAR_WEATHER_LAT=
|
||||
HOMEPAGE_VAR_WEATHER_LONG=
|
||||
HOMEPAGE_VAR_WEATHER_UNIT=metric
|
||||
|
||||
# --- Authelia Settings ---
|
||||
# Generate strong random secrets for these using tools like `openssl rand -hex 32`
|
||||
# These are all REQUIRED for Authelia to function properly
|
||||
AUTHELIA_JWT_SECRET= # Secret used for JWT tokens (password reset, etc)
|
||||
AUTHELIA_SESSION_SECRET= # Secret for encrypting session cookies
|
||||
AUTHELIA_STORAGE_ENCRYPTION_KEY= # Secret for encrypting stored data
|
||||
AUTHELIA_REDIS_PASSWORD= # Password for Redis session storage
|
||||
|
||||
# Note: The following variables are no longer needed with Authelia 4.38+ and the updated configuration
|
||||
# They are preserved for backward compatibility but will be automatically mapped to the new structure
|
||||
# AUTHELIA_SESSION_DOMAIN=${APP_HOSTNAME}
|
||||
# AUTHELIA_DEFAULT_REDIRECT_URL=https://${APP_HOSTNAME}/home
|
||||
|
||||
# --- API Keys & Integration Tokens (Optional - Mainly for Homepage Widgets) ---
|
||||
# Find API keys within each application's settings (usually Settings > General or Security)
|
||||
SONARR_API_KEY=
|
||||
RADARR_API_KEY=
|
||||
LIDARR_API_KEY=
|
||||
@@ -26,16 +86,12 @@ JELLYSEERR_API_KEY=
|
||||
SABNZBD_API_KEY=
|
||||
IMMICH_API_KEY=
|
||||
HOMEASSISTANT_ACCESS_TOKEN=
|
||||
HOMEPAGE_VAR_TITLE="Docker-Compose NAS"
|
||||
HOMEPAGE_VAR_SEARCH_PROVIDER=google
|
||||
HOMEPAGE_VAR_HEADER_STYLE=boxed
|
||||
HOMEPAGE_VAR_WEATHER_CITY=
|
||||
HOMEPAGE_VAR_WEATHER_LAT=
|
||||
HOMEPAGE_VAR_WEATHER_LONG=
|
||||
HOMEPAGE_VAR_WEATHER_UNIT=metric
|
||||
IMMICH_DB_PASSWORD=postgres
|
||||
CALIBRE_USERNAME=admin
|
||||
CALIBRE_PASSWORD=admin123
|
||||
# AdGuard Home Credentials (if profile enabled)
|
||||
ADGUARD_USERNAME=
|
||||
ADGUARD_PASSWORD=
|
||||
|
||||
# --- Optional Service Settings ---
|
||||
# Decluttarr Settings (if profile enabled)
|
||||
DECLUTTARR_TEST_RUN=True
|
||||
DECLUTTARR_REMOVE_TIMER=60
|
||||
DECLUTTARR_REMOVE_FAILED=True
|
||||
@@ -44,9 +100,8 @@ DECLUTTARR_REMOVE_METADATA_MISSING=True
|
||||
DECLUTTARR_REMOVE_MISSING_FILES=True
|
||||
DECLUTTARR_REMOVE_ORPHANS=True
|
||||
|
||||
# --- Tailscale Settings ---
|
||||
TAILSCALE_AUTHKEY=
|
||||
TAILSCALE_HOSTNAME=tailscale-nas
|
||||
TAILSCALE_TAGS=tag:nas
|
||||
# Enable Tailscale Funnel (public access) for HTTPS? Set to 'true' or 'false'.
|
||||
ENABLE_FUNNEL_HTTPS=false
|
||||
# --- Other Hostnames (Optional Services) ---
|
||||
# Set these if you need specific hostnames for these services (e.g., for Home Assistant integrations)
|
||||
HOMEASSISTANT_HOSTNAME=
|
||||
IMMICH_HOSTNAME=
|
||||
ADGUARD_HOSTNAME=
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,6 +1,9 @@
|
||||
*.env
|
||||
*.bak
|
||||
.idea
|
||||
docker-compose.override.yml
|
||||
/authelia/*.yml
|
||||
!/authelia/*.example.yml
|
||||
/homepage/logs
|
||||
/homepage/*.yaml
|
||||
/homepage/*.css
|
||||
|
||||
140
authelia/configuration.example.yml
Normal file
140
authelia/configuration.example.yml
Normal file
@@ -0,0 +1,140 @@
|
||||
# Authelia Configuration File v4.38+
|
||||
# Documentation: https://www.authelia.com/configuration/
|
||||
|
||||
# Server settings
|
||||
server:
|
||||
address: 'tcp://0.0.0.0:9091'
|
||||
|
||||
# Logging configuration
|
||||
log:
|
||||
level: info
|
||||
format: text
|
||||
|
||||
# Session configuration for v4.38+
|
||||
session:
|
||||
name: authelia_session
|
||||
secret: ${AUTHELIA_SESSION_SECRET}
|
||||
expiration: 1h
|
||||
inactivity: 5m
|
||||
redis:
|
||||
host: redis
|
||||
port: 6379
|
||||
password: ${AUTHELIA_SESSION_REDIS_PASSWORD}
|
||||
database_index: 0
|
||||
cookies:
|
||||
# Using your specific Tailscale domain (e.g. example.ts.net) not just ts.net
|
||||
- domain: 'your-tailnet.ts.net'
|
||||
authelia_url: 'https://tailscale-nas.your-tailnet.ts.net'
|
||||
default_redirection_url: 'https://tailscale-nas.your-tailnet.ts.net/home'
|
||||
same_site: lax
|
||||
|
||||
# Regulation (brute force protection)
|
||||
regulation:
|
||||
max_retries: 3
|
||||
find_time: 2m
|
||||
ban_time: 5m
|
||||
|
||||
# Storage (for user preferences, etc. - encrypted using storage key)
|
||||
storage:
|
||||
encryption_key: ${AUTHELIA_STORAGE_ENCRYPTION_KEY}
|
||||
local:
|
||||
path: /config/db.sqlite3
|
||||
|
||||
# Authentication backend (using file-based user database)
|
||||
authentication_backend:
|
||||
file:
|
||||
path: /config/users_database.yml
|
||||
password:
|
||||
algorithm: argon2id
|
||||
iterations: 1
|
||||
memory: 1024
|
||||
parallelism: 8
|
||||
salt_length: 16
|
||||
key_length: 32
|
||||
|
||||
# Access control rules
|
||||
access_control:
|
||||
default_policy: deny # Deny access by default
|
||||
rules:
|
||||
# Rules are processed in order. First match wins.
|
||||
# It's recommended to put more specific rules first.
|
||||
|
||||
# 1. Bypass rules (No authentication required)
|
||||
# Allow access to Authelia's own endpoints
|
||||
- domain: '*.your-tailnet.ts.net'
|
||||
path_regex: '^/auth.*' # Match /auth and anything after it
|
||||
policy: bypass
|
||||
# Allow access to the root path (will be redirected by Traefik later)
|
||||
- domain: '*.your-tailnet.ts.net'
|
||||
path: '/'
|
||||
policy: bypass
|
||||
# Allow access to API endpoints (as requested, review security implications)
|
||||
- domain: '*.your-tailnet.ts.net'
|
||||
path_regex: '^/api.*' # Match /api and anything after it
|
||||
policy: bypass
|
||||
|
||||
# 2. One-Factor Authentication Rules (Requires login)
|
||||
# Add rules for each service you want to protect.
|
||||
# The domain should match your Tailscale domain.
|
||||
# The path should match the Traefik PathPrefix for the service.
|
||||
- domain: '*.your-tailnet.ts.net'
|
||||
path_regex: '^/sonarr.*'
|
||||
policy: one_factor
|
||||
- domain: '*.your-tailnet.ts.net'
|
||||
path_regex: '^/radarr.*'
|
||||
policy: one_factor
|
||||
- domain: '*.your-tailnet.ts.net'
|
||||
path_regex: '^/lidarr.*'
|
||||
policy: one_factor
|
||||
- domain: '*.your-tailnet.ts.net'
|
||||
path_regex: '^/bazarr.*'
|
||||
policy: one_factor
|
||||
- domain: '*.your-tailnet.ts.net'
|
||||
path_regex: '^/qbittorrent.*'
|
||||
policy: one_factor
|
||||
- domain: '*.your-tailnet.ts.net'
|
||||
path_regex: '^/sabnzbd.*'
|
||||
policy: one_factor
|
||||
- domain: '*.your-tailnet.ts.net'
|
||||
path_regex: '^/calibre.*'
|
||||
policy: one_factor
|
||||
- domain: '*.your-tailnet.ts.net'
|
||||
path_regex: '^/home.*' # Protect the homepage
|
||||
policy: one_factor
|
||||
- domain: '*.your-tailnet.ts.net'
|
||||
path_regex: '^/jellyseerr.*'
|
||||
policy: one_factor
|
||||
- domain: '*.your-tailnet.ts.net'
|
||||
path_regex: '^/prowlarr.*'
|
||||
policy: one_factor
|
||||
- domain: '*.your-tailnet.ts.net'
|
||||
path_regex: '^/flaresolverr.*'
|
||||
policy: one_factor
|
||||
# Add other services here following the pattern:
|
||||
# - domain: '*.your-tailnet.ts.net'
|
||||
# path_regex: '^/<service_path>.*'
|
||||
# policy: one_factor
|
||||
|
||||
# 3. Default rule for the domain (optional, if you want a catch-all)
|
||||
# This rule will apply if no path-specific rule above matches.
|
||||
# You might want to deny or require one_factor for unmatched paths.
|
||||
# Example: Deny any other path on the domain
|
||||
# - domain: '*.your-tailnet.ts.net'
|
||||
# policy: deny
|
||||
# Example: Require login for any other path
|
||||
# - domain: '*.your-tailnet.ts.net'
|
||||
# policy: one_factor
|
||||
|
||||
# Notifier configuration
|
||||
notifier:
|
||||
filesystem:
|
||||
filename: /config/notification.txt
|
||||
|
||||
# Identity Validation (includes JWT secret for password reset)
|
||||
identity_validation:
|
||||
reset_password:
|
||||
jwt_secret: ${AUTHELIA_JWT_SECRET}
|
||||
|
||||
# Identity Providers
|
||||
identity_providers:
|
||||
oidc: null
|
||||
39
authelia/users_database.example.yml
Normal file
39
authelia/users_database.example.yml
Normal file
@@ -0,0 +1,39 @@
|
||||
# Authelia User Database
|
||||
# Documentation: https://www.authelia.com/configuration/security/authentication/file/
|
||||
|
||||
# To add users:
|
||||
# 1. Generate a password hash:
|
||||
# docker run authelia/authelia:latest authelia hash-password 'your_strong_password'
|
||||
# 2. Add the user entry below.
|
||||
#
|
||||
# To approve registered users (if registration is enabled in configuration.yml):
|
||||
# 1. New users will appear here, possibly commented out or with 'disabled: true'.
|
||||
# 2. Uncomment the user or set 'disabled: false' to grant access.
|
||||
|
||||
users:
|
||||
# First user is typically considered the admin in access rules
|
||||
admin:
|
||||
displayname: "Admin User"
|
||||
# Replace this hash with one generated for your desired password!
|
||||
password: "$argon2id$v=19$m=102400,t=1,p=8$PBf/L9l3s7LwN6jX/B3tVg$9+q3kL8VAbpWj9Gv9Z6uA5bA4zT1fB2fH3aD5c6b7e8" # Example hash for 'password'
|
||||
email: admin@example.com
|
||||
groups:
|
||||
- admins
|
||||
- users
|
||||
|
||||
# Example of a regular user
|
||||
# user1:
|
||||
# displayname: "Regular User"
|
||||
# password: "..." # Generate hash
|
||||
# email: user1@example.com
|
||||
# groups:
|
||||
# - users
|
||||
|
||||
# Example of a registered user waiting for approval (if registration enabled)
|
||||
# newuser:
|
||||
# disabled: true
|
||||
# displayname: "New User"
|
||||
# password: "..." # Hash generated during registration
|
||||
# email: newuser@example.com
|
||||
# groups:
|
||||
# - users
|
||||
@@ -13,17 +13,57 @@ services:
|
||||
- --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
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- --providers.docker.network=docker-compose-nas
|
||||
- --providers.docker.endpoint=unix:///var/run/docker.sock
|
||||
network_mode: service:tailscale
|
||||
volumes:
|
||||
- /var/run/podman/podman.sock:/var/run/docker.sock:ro
|
||||
extra_hosts:
|
||||
- host.docker.internal:172.17.0.1
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
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}"]
|
||||
volumes:
|
||||
- ${CONFIG_ROOT:-.}/redis:/data:Z
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "-a", "${AUTHELIA_REDIS_PASSWORD}", "ping"]
|
||||
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:
|
||||
- AUTHELIA_SESSION_SECRET=${AUTHELIA_SESSION_SECRET}
|
||||
- AUTHELIA_STORAGE_ENCRYPTION_KEY=${AUTHELIA_STORAGE_ENCRYPTION_KEY}
|
||||
- AUTHELIA_SESSION_REDIS_PASSWORD=${AUTHELIA_REDIS_PASSWORD}
|
||||
- AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET=${AUTHELIA_JWT_SECRET}
|
||||
- TZ=${TIMEZONE}
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.authelia.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/auth`) # Changed rule
|
||||
- traefik.http.routers.authelia.entrypoints=web
|
||||
# - traefik.http.routers.authelia.priority=100 # Removed priority
|
||||
- traefik.http.services.authelia.loadbalancer.server.port=9091
|
||||
- traefik.http.middlewares.authelia-auth.forwardAuth.address=http://authelia:9091/api/verify # Simplified forwardAuth address
|
||||
- traefik.http.routers.authelia.middlewares=https-proto@docker
|
||||
- traefik.http.middlewares.authelia-auth.forwardAuth.trustForwardHeader=true
|
||||
- traefik.http.middlewares.authelia-auth.forwardAuth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email
|
||||
- homepage.group=Security
|
||||
- homepage.name=Authelia
|
||||
- homepage.icon=authelia.png
|
||||
- homepage.href=/auth # Updated href
|
||||
- homepage.description=Authentication Portal
|
||||
sonarr:
|
||||
image: lscr.io/linuxserver/sonarr
|
||||
container_name: sonarr
|
||||
@@ -41,8 +81,9 @@ services:
|
||||
retries: 10
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.sonarr.rule=(Host(`${HOSTNAME}`) && PathPrefix(`/sonarr`))
|
||||
- traefik.http.routers.sonarr.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/sonarr`) # Added Host check
|
||||
- traefik.http.routers.sonarr.entrypoints=web
|
||||
- traefik.http.routers.sonarr.middlewares=https-proto@docker,authelia-auth@docker
|
||||
- traefik.http.services.sonarr.loadbalancer.server.port=8989
|
||||
- homepage.group=Media
|
||||
- homepage.name=Sonarr
|
||||
@@ -70,8 +111,9 @@ services:
|
||||
retries: 10
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.radarr.rule=(Host(`${HOSTNAME}`) && PathPrefix(`/radarr`))
|
||||
- traefik.http.routers.radarr.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/radarr`) # Added Host check
|
||||
- traefik.http.routers.radarr.entrypoints=web
|
||||
- traefik.http.routers.radarr.middlewares=https-proto@docker,authelia-auth@docker
|
||||
- traefik.http.services.radarr.loadbalancer.server.port=7878
|
||||
- homepage.group=Media
|
||||
- homepage.name=Radarr
|
||||
@@ -99,8 +141,9 @@ services:
|
||||
retries: 10
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.lidarr.rule=(Host(`${HOSTNAME}`) && PathPrefix(`/lidarr`))
|
||||
- traefik.http.routers.lidarr.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/lidarr`) # Added Host check
|
||||
- traefik.http.routers.lidarr.entrypoints=web
|
||||
- traefik.http.routers.lidarr.middlewares=https-proto@docker,authelia-auth@docker
|
||||
- traefik.http.services.lidarr.loadbalancer.server.port=8686
|
||||
- homepage.group=Media
|
||||
- homepage.name=Lidarr
|
||||
@@ -130,8 +173,9 @@ services:
|
||||
retries: 10
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.bazarr.rule=(Host(`${HOSTNAME}`) && PathPrefix(`/bazarr`))
|
||||
- traefik.http.routers.bazarr.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/bazarr`) # Added Host check
|
||||
- traefik.http.routers.bazarr.entrypoints=web
|
||||
- traefik.http.routers.bazarr.middlewares=https-proto@docker,authelia-auth@docker
|
||||
- traefik.http.services.bazarr.loadbalancer.server.port=6767
|
||||
- homepage.group=Download
|
||||
- homepage.name=Bazarr
|
||||
@@ -164,10 +208,10 @@ services:
|
||||
retries: 10
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.jellyseerr.rule=(Host(`${HOSTNAME}`) && PathPrefix(`/jellyseerr`))
|
||||
- traefik.http.routers.jellyseerr.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/jellyseerr`) # Added Host check
|
||||
- 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
|
||||
- traefik.http.routers.jellyseerr.middlewares=https-proto@docker,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=^/(.+)$
|
||||
@@ -238,8 +282,9 @@ services:
|
||||
retries: 10
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.prowlarr.rule=(Host(`${HOSTNAME}`) && PathPrefix(`/prowlarr`))
|
||||
- traefik.http.routers.prowlarr.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/prowlarr`) # Added Host check
|
||||
- traefik.http.routers.prowlarr.entrypoints=web
|
||||
- traefik.http.routers.prowlarr.middlewares=https-proto@docker,authelia-auth@docker
|
||||
- traefik.http.services.prowlarr.loadbalancer.server.port=9696
|
||||
- homepage.group=Download
|
||||
- homepage.name=Prowlarr
|
||||
@@ -261,8 +306,9 @@ services:
|
||||
- TZ=${TIMEZONE}
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.flaresolverr.rule=PathPrefix(`/flaresolverr`)
|
||||
- traefik.http.routers.flaresolverr.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/flaresolverr`) # Added Host check
|
||||
- traefik.http.routers.flaresolverr.entrypoints=web
|
||||
- traefik.http.routers.flaresolverr.middlewares=https-proto@docker,authelia-auth@docker
|
||||
- traefik.http.services.flaresolverr.loadbalancer.server.port=8191
|
||||
profiles:
|
||||
- flaresolverr
|
||||
@@ -280,25 +326,20 @@ services:
|
||||
- ${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=(Host(`${HOSTNAME}`) && PathPrefix(`/qbittorrent`))
|
||||
- traefik.http.routers.qbittorrent.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/qbittorrent`) # Added Host check
|
||||
- traefik.http.routers.qbittorrent.entrypoints=web
|
||||
- traefik.http.services.qbittorrent.loadbalancer.server.port=8080
|
||||
- traefik.http.routers.qbittorrent.middlewares=qbittorrent-strip-slash,qbittorrent-stripprefix
|
||||
# https://github.com/qbittorrent/qBittorrent/issues/5693#issuecomment-552146296
|
||||
- traefik.http.routers.qbittorrent.middlewares=https-proto@docker,qbittorrent-strip-slash,qbittorrent-stripprefix,authelia-auth@docker
|
||||
- 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
|
||||
@@ -337,8 +378,9 @@ services:
|
||||
restart: always
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.sabnzbd.rule=(Host(`${HOSTNAME}`) && PathPrefix(`/sabnzbd`) || PathPrefix(`/sabnzbd`))
|
||||
- traefik.http.routers.sabnzbd.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/sabnzbd`) # Added Host check
|
||||
- traefik.http.routers.sabnzbd.entrypoints=web
|
||||
- traefik.http.routers.sabnzbd.middlewares=https-proto@docker,authelia-auth@docker
|
||||
- traefik.http.services.sabnzbd.loadbalancer.server.port=8080
|
||||
- homepage.group=Download
|
||||
- homepage.name=Sabnzbd
|
||||
@@ -358,7 +400,7 @@ services:
|
||||
- PUID=${USER_ID}
|
||||
- PGID=${GROUP_ID}
|
||||
- TZ=${TIMEZONE}
|
||||
- JELLYFIN_PublishedServerUrl=${HOSTNAME}/jellyfin
|
||||
- JELLYFIN_PublishedServerUrl=https://${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}/jellyfin
|
||||
volumes:
|
||||
- ${CONFIG_ROOT:-.}/jellyfin:/config:Z
|
||||
- ${DATA_ROOT}:/data:Z
|
||||
@@ -372,8 +414,9 @@ services:
|
||||
retries: 10
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.jellyfin.rule=(Host(`${HOSTNAME}`) && PathPrefix(`/jellyfin`))
|
||||
- traefik.http.routers.jellyfin.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/jellyfin`) # Added Host check
|
||||
- traefik.http.routers.jellyfin.entrypoints=web
|
||||
- traefik.http.routers.jellyfin.middlewares=https-proto@docker # Only HTTPS, no auth
|
||||
- traefik.http.services.jellyfin.loadbalancer.server.port=8096
|
||||
- homepage.group=Media
|
||||
- homepage.name=Jellyfin
|
||||
@@ -402,8 +445,8 @@ services:
|
||||
- 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
|
||||
- traefik.http.routers.calibre.rule=(Host(`${HOSTNAME}`) && PathPrefix(`/calibre`))
|
||||
- traefik.http.routers.calibre.middlewares=https-proto@docker,calibre-headers,calibre-stripprefixregex,authelia-auth@docker
|
||||
- traefik.http.routers.calibre.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/calibre`) # Added Host check
|
||||
- traefik.http.routers.calibre.entrypoints=web
|
||||
- traefik.http.services.calibre.loadbalancer.server.port=8083
|
||||
- homepage.group=Media
|
||||
@@ -466,19 +509,27 @@ services:
|
||||
- HOMEPAGE_VAR_WEATHER_LONG=${HOMEPAGE_VAR_WEATHER_LONG}
|
||||
- HOMEPAGE_VAR_WEATHER_TIME=${TIMEZONE}
|
||||
- HOMEPAGE_VAR_WEATHER_UNIT=${HOMEPAGE_VAR_WEATHER_UNIT}
|
||||
- HOMEPAGE_ALLOWED_HOSTS=${HOSTNAME}
|
||||
- HOMEPAGE_ALLOWED_HOSTS=${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}
|
||||
volumes:
|
||||
- ${CONFIG_ROOT:-.}/homepage:/app/config:Z
|
||||
- /var/run/podman/podman.sock:/var/run/docker.sock:ro
|
||||
- /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
|
||||
- traefik.http.routers.homepage.rule=(Host(`${HOSTNAME}`) && PathPrefix(`/`))
|
||||
- traefik.http.routers.homepage.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/home`) # Changed rule to root
|
||||
- traefik.http.routers.homepage.entrypoints=web
|
||||
- traefik.http.services.homepage.loadbalancer.server.port=3000
|
||||
# - traefik.http.routers.homepage.priority=10 # Removed priority
|
||||
# Global middleware for setting HTTPS header
|
||||
- traefik.http.middlewares.https-proto.headers.customrequestheaders.X-Forwarded-Proto=https
|
||||
- traefik.http.routers.homepage.middlewares=https-proto@docker,authelia-auth@docker
|
||||
- homepage.group=Dashboard
|
||||
- homepage.name=Homepage
|
||||
- homepage.icon=homepage.png
|
||||
- homepage.href=/ # Updated href
|
||||
- homepage.description=Service Dashboard
|
||||
watchtower:
|
||||
image: ghcr.io/containrrr/watchtower:latest
|
||||
container_name: watchtower
|
||||
@@ -486,7 +537,7 @@ services:
|
||||
environment:
|
||||
- WATCHTOWER_CLEANUP=true
|
||||
volumes:
|
||||
- /var/run/podman/podman.sock:/var/run/docker.sock
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
autoheal:
|
||||
image: willfarrell/autoheal:latest
|
||||
container_name: autoheal
|
||||
@@ -494,27 +545,27 @@ services:
|
||||
environment:
|
||||
- AUTOHEAL_CONTAINER_LABEL=all
|
||||
volumes:
|
||||
- /var/run/podman/podman.sock:/var/run/docker.sock
|
||||
- /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
|
||||
hostname: ${TAILSCALE_HOSTNAME:-tailscale-nas}
|
||||
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_AUTHKEY: ${TAILSCALE_AUTHKEY}
|
||||
TS_EXTRA_ARGS: "--advertise-tags=${TAILSCALE_TAGS:-tag:nas}"
|
||||
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/podman/podman.sock:/var/run/docker.sock # Optional, keep if needed
|
||||
- ${CONFIG_ROOT:-.}/tailscale/state:/var/lib/tailscale:Z
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
devices:
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- NET_RAW
|
||||
privileged: true # As requested
|
||||
extra_hosts:
|
||||
- host.docker.internal:172.17.0.1
|
||||
restart: always
|
||||
command:
|
||||
- /bin/sh
|
||||
@@ -537,21 +588,18 @@ services:
|
||||
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://traefik:80..."
|
||||
tailscale funnel --bg http://traefik:80
|
||||
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://traefik:80..."
|
||||
tailscale serve --bg http://traefik:80
|
||||
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
|
||||
wait
|
||||
|
||||
networks:
|
||||
default:
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# See https://stackoverflow.com/a/44864004 for the sed GNU/BSD compatible hack
|
||||
|
||||
function update_arr_config {
|
||||
echo "Updating ${container} configuration..."
|
||||
until [ -f "${CONFIG_ROOT:-.}"/"$container"/config.xml ]; do sleep 1; done
|
||||
sed -i.bak "s/<UrlBase><\/UrlBase>/<UrlBase>\/$1<\/UrlBase>/" "${CONFIG_ROOT:-.}"/"$container"/config.xml && rm "${CONFIG_ROOT:-.}"/"$container"/config.xml.bak
|
||||
CONTAINER_NAME_UPPER=$(echo "$container" | tr '[:lower:]' '[:upper:]')
|
||||
sed -i.bak 's/^'"${CONTAINER_NAME_UPPER}"'_API_KEY=.*/'"${CONTAINER_NAME_UPPER}"'_API_KEY='"$(sed -n 's/.*<ApiKey>\(.*\)<\/ApiKey>.*/\1/p' "${CONFIG_ROOT:-.}"/"$container"/config.xml)"'/' .env && rm .env.bak
|
||||
echo "Update of ${container} configuration complete, restarting..."
|
||||
docker compose restart "$container"
|
||||
}
|
||||
|
||||
function update_qbittorrent_config {
|
||||
echo "Updating ${container} configuration..."
|
||||
docker compose stop "$container"
|
||||
until [ -f "${CONFIG_ROOT:-.}"/"$container"/qBittorrent/qBittorrent.conf ]; do sleep 1; done
|
||||
sed -i.bak '/WebUI\\ServerDomains=*/a WebUI\\Password_PBKDF2="@ByteArray(ARQ77eY1NUZaQsuDHbIMCA==:0WMRkYTUWVT9wVvdDtHAjU9b3b7uB8NR1Gur2hmQCvCDpm39Q+PsJRJPaCU51dEiz+dTzh8qbPsL8WkFljQYFQ==)"' "${CONFIG_ROOT:-.}"/"$container"/qBittorrent/qBittorrent.conf && rm "${CONFIG_ROOT:-.}"/"$container"/qBittorrent/qBittorrent.conf.bak
|
||||
echo "Update of ${container} configuration complete, restarting..."
|
||||
docker compose start "$container"
|
||||
}
|
||||
|
||||
function update_bazarr_config {
|
||||
echo "Updating ${container} configuration..."
|
||||
until [ -f "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml ]; do sleep 1; done
|
||||
sed -i.bak "s/base_url: ''/base_url: '\/$container'/" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
|
||||
sed -i.bak "s/use_radarr: false/use_radarr: true/" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
|
||||
sed -i.bak "s/use_sonarr: false/use_sonarr: true/" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
|
||||
until [ -f "${CONFIG_ROOT:-.}"/sonarr/config.xml ]; do sleep 1; done
|
||||
SONARR_API_KEY=$(sed -n 's/.*<ApiKey>\(.*\)<\/ApiKey>.*/\1/p' "${CONFIG_ROOT:-.}"/sonarr/config.xml)
|
||||
sed -i.bak "/sonarr:/,/^radarr:/ { s/apikey: .*/apikey: $SONARR_API_KEY/; s/base_url: .*/base_url: \/sonarr/; s/ip: .*/ip: sonarr/ }" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
|
||||
until [ -f "${CONFIG_ROOT:-.}"/radarr/config.xml ]; do sleep 1; done
|
||||
RADARR_API_KEY=$(sed -n 's/.*<ApiKey>\(.*\)<\/ApiKey>.*/\1/p' "${CONFIG_ROOT:-.}"/radarr/config.xml)
|
||||
sed -i.bak "/radarr:/,/^sonarr:/ { s/apikey: .*/apikey: $RADARR_API_KEY/; s/base_url: .*/base_url: \/radarr/; s/ip: .*/ip: radarr/ }" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
|
||||
sed -i.bak 's/^BAZARR_API_KEY=.*/BAZARR_API_KEY='"$(sed -n 's/.*apikey: \(.*\)*/\1/p' "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml | head -n 1)"'/' .env && rm .env.bak
|
||||
echo "Update of ${container} configuration complete, restarting..."
|
||||
docker compose restart "$container"
|
||||
}
|
||||
|
||||
for container in $(docker ps --format '{{.Names}}'); do
|
||||
if [[ "$container" =~ ^(radarr|sonarr|lidarr|prowlarr)$ ]]; then
|
||||
update_arr_config "$container"
|
||||
elif [[ "$container" =~ ^(bazarr)$ ]]; then
|
||||
update_bazarr_config "$container"
|
||||
elif [[ "$container" =~ ^(qbittorrent)$ ]]; then
|
||||
update_qbittorrent_config "$container"
|
||||
fi
|
||||
done
|
||||
1370
update-setup.sh
Executable file
1370
update-setup.sh
Executable file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user