Compare commits
22 Commits
b8079666bd
...
feature/tr
| Author | SHA1 | Date | |
|---|---|---|---|
| 79a7a0d4c6 | |||
| 93e709841b | |||
| 78338661b0 | |||
| 9f8ff41bf4 | |||
| 67ff6d585c | |||
| cf78372b71 | |||
| 8c5cdb111d | |||
| 42ee02d8e7 | |||
| 83016e268c | |||
| 3539cc3d3e | |||
| 4db5c27755 | |||
| 8051ea33e3 | |||
| cc51dd386c | |||
| 3ce7262e38 | |||
| a0fb667642 | |||
| bccf28da84 | |||
| 3f05975393 | |||
| 44cdc60ab3 | |||
| dc54b33281 | |||
| 6c1e6b5700 | |||
| 7162827ab3 | |||
| fba2c07e2c |
105
.env.example
105
.env.example
@@ -1,32 +1,81 @@
|
|||||||
|
# --- Docker Compose Settings ---
|
||||||
|
# Comma-separated list of optional service profiles to enable (e.g., lidarr,sabnzbd,adguardhome)
|
||||||
COMPOSE_PROFILES=
|
COMPOSE_PROFILES=
|
||||||
|
# Path separator for COMPOSE_FILE (use ';' for Windows)
|
||||||
COMPOSE_PATH_SEPARATOR=:
|
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
|
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
|
USER_ID=1000
|
||||||
|
# Linux Group ID. Find yours with `id -g`. Crucial for file permissions.
|
||||||
GROUP_ID=1000
|
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"
|
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="."
|
CONFIG_ROOT="."
|
||||||
|
# Main directory on host containing media libraries (movies, TV, music, books).
|
||||||
DATA_ROOT="/mnt/data"
|
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"
|
DOWNLOAD_ROOT="/mnt/data/torrents"
|
||||||
|
# Upload location for Immich (if profile enabled)
|
||||||
IMMICH_UPLOAD_LOCATION="/mnt/data/photos"
|
IMMICH_UPLOAD_LOCATION="/mnt/data/photos"
|
||||||
PIA_LOCATION=ca
|
|
||||||
PIA_USER=
|
# --- Tailscale Settings ---
|
||||||
PIA_PASS=
|
# Required. Auth key from Tailscale Admin Console (Settings > Keys). Use a reusable or ephemeral key.
|
||||||
PIA_LOCAL_NETWORK="192.168.0.0/16"
|
TAILSCALE_AUTHKEY=
|
||||||
HOSTNAME=localhost
|
# Desired hostname for this NAS within your Tailscale network.
|
||||||
HOMEASSISTANT_HOSTNAME=
|
TAILSCALE_HOSTNAME=tailscale-nas
|
||||||
IMMICH_HOSTNAME=
|
# Required. Your Tailnet domain (e.g., your-tailnet-name.ts.net).
|
||||||
ADGUARD_HOSTNAME=
|
TAILSCALE_TAILNET_DOMAIN=your-tailnet.ts.net
|
||||||
ADGUARD_USERNAME=
|
# Optional tags to apply to the Tailscale node (e.g., tag:nas).
|
||||||
ADGUARD_PASSWORD=
|
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_USERNAME=admin
|
||||||
QBITTORRENT_PASSWORD=adminadmin
|
QBITTORRENT_PASSWORD=adminadmin
|
||||||
DNS_CHALLENGE=true
|
# Calibre-Web Credentials (if profile enabled)
|
||||||
DNS_CHALLENGE_PROVIDER=cloudflare
|
CALIBRE_USERNAME=admin
|
||||||
LETS_ENCRYPT_CA_SERVER="https://acme-v02.api.letsencrypt.org/directory"
|
CALIBRE_PASSWORD=admin123
|
||||||
LETS_ENCRYPT_EMAIL=
|
# Immich Database Password (if profile enabled)
|
||||||
CLOUDFLARE_EMAIL=
|
IMMICH_DB_PASSWORD=postgres
|
||||||
CLOUDFLARE_DNS_API_TOKEN=
|
|
||||||
CLOUDFLARE_ZONE_API_TOKEN=
|
# --- 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=
|
SONARR_API_KEY=
|
||||||
RADARR_API_KEY=
|
RADARR_API_KEY=
|
||||||
LIDARR_API_KEY=
|
LIDARR_API_KEY=
|
||||||
@@ -37,16 +86,12 @@ JELLYSEERR_API_KEY=
|
|||||||
SABNZBD_API_KEY=
|
SABNZBD_API_KEY=
|
||||||
IMMICH_API_KEY=
|
IMMICH_API_KEY=
|
||||||
HOMEASSISTANT_ACCESS_TOKEN=
|
HOMEASSISTANT_ACCESS_TOKEN=
|
||||||
HOMEPAGE_VAR_TITLE="Docker-Compose NAS"
|
# AdGuard Home Credentials (if profile enabled)
|
||||||
HOMEPAGE_VAR_SEARCH_PROVIDER=google
|
ADGUARD_USERNAME=
|
||||||
HOMEPAGE_VAR_HEADER_STYLE=boxed
|
ADGUARD_PASSWORD=
|
||||||
HOMEPAGE_VAR_WEATHER_CITY=
|
|
||||||
HOMEPAGE_VAR_WEATHER_LAT=
|
# --- Optional Service Settings ---
|
||||||
HOMEPAGE_VAR_WEATHER_LONG=
|
# Decluttarr Settings (if profile enabled)
|
||||||
HOMEPAGE_VAR_WEATHER_UNIT=metric
|
|
||||||
IMMICH_DB_PASSWORD=postgres
|
|
||||||
CALIBRE_USERNAME=admin
|
|
||||||
CALIBRE_PASSWORD=admin123
|
|
||||||
DECLUTTARR_TEST_RUN=True
|
DECLUTTARR_TEST_RUN=True
|
||||||
DECLUTTARR_REMOVE_TIMER=60
|
DECLUTTARR_REMOVE_TIMER=60
|
||||||
DECLUTTARR_REMOVE_FAILED=True
|
DECLUTTARR_REMOVE_FAILED=True
|
||||||
@@ -54,3 +99,9 @@ DECLUTTARR_REMOVE_FAILED_IMPORTS=True
|
|||||||
DECLUTTARR_REMOVE_METADATA_MISSING=True
|
DECLUTTARR_REMOVE_METADATA_MISSING=True
|
||||||
DECLUTTARR_REMOVE_MISSING_FILES=True
|
DECLUTTARR_REMOVE_MISSING_FILES=True
|
||||||
DECLUTTARR_REMOVE_ORPHANS=True
|
DECLUTTARR_REMOVE_ORPHANS=True
|
||||||
|
|
||||||
|
# --- 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
|
*.env
|
||||||
|
*.bak
|
||||||
.idea
|
.idea
|
||||||
docker-compose.override.yml
|
docker-compose.override.yml
|
||||||
|
/authelia/*.yml
|
||||||
|
!/authelia/*.example.yml
|
||||||
/homepage/logs
|
/homepage/logs
|
||||||
/homepage/*.yaml
|
/homepage/*.yaml
|
||||||
/homepage/*.css
|
/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
|
||||||
@@ -3,42 +3,67 @@ services:
|
|||||||
image: ghcr.io/traefik/traefik:3.3
|
image: ghcr.io/traefik/traefik:3.3
|
||||||
container_name: traefik
|
container_name: traefik
|
||||||
restart: always
|
restart: always
|
||||||
environment:
|
|
||||||
- CLOUDFLARE_EMAIL=${CLOUDFLARE_EMAIL}
|
|
||||||
- CLOUDFLARE_DNS_API_TOKEN=${CLOUDFLARE_DNS_API_TOKEN}
|
|
||||||
- CLOUDFLARE_ZONE_API_TOKEN=${CLOUDFLARE_ZONE_API_TOKEN}
|
|
||||||
- LETS_ENCRYPT_EMAIL=${LETS_ENCRYPT_EMAIL}
|
|
||||||
command:
|
command:
|
||||||
- --ping=true
|
- --ping=true
|
||||||
- --providers.docker=true
|
- --providers.docker=true
|
||||||
- --providers.docker.exposedbydefault=false
|
- --providers.docker.exposedbydefault=false
|
||||||
- --entrypoints.web.address=:80
|
- --entrypoints.web.address=:80
|
||||||
- --entrypoints.web-secure.address=:443
|
- --entrypoints.web-secure.address=:443
|
||||||
- --entrypoints.web.http.redirections.entryPoint.to=web-secure
|
|
||||||
- --entrypoints.web.http.redirections.entryPoint.scheme=https
|
|
||||||
- --entrypoints.web.http.redirections.entrypoint.permanent=true
|
|
||||||
- --experimental.plugins.rewrite-body.modulename=github.com/packruler/rewrite-body
|
- --experimental.plugins.rewrite-body.modulename=github.com/packruler/rewrite-body
|
||||||
- --experimental.plugins.rewrite-body.version=v1.2.0
|
- --experimental.plugins.rewrite-body.version=v1.2.0
|
||||||
- --experimental.plugins.rewriteHeaders.modulename=github.com/XciD/traefik-plugin-rewrite-headers
|
- --experimental.plugins.rewriteHeaders.modulename=github.com/XciD/traefik-plugin-rewrite-headers
|
||||||
- --experimental.plugins.rewriteHeaders.version=v0.0.3
|
- --experimental.plugins.rewriteHeaders.version=v0.0.3
|
||||||
- --certificatesresolvers.myresolver.acme.dnschallenge=${DNS_CHALLENGE:-true}
|
- --providers.docker.network=docker-compose-nas
|
||||||
- --certificatesresolvers.myresolver.acme.dnschallenge.provider=${DNS_CHALLENGE_PROVIDER:-cloudflare}
|
- --providers.docker.endpoint=unix:///var/run/docker.sock
|
||||||
- --certificatesresolvers.myresolver.acme.dnschallenge.resolvers=1.1.1.1:53,8.8.8.8:53
|
network_mode: service:tailscale
|
||||||
- --certificatesresolvers.myresolver.acme.caserver=${LETS_ENCRYPT_CA_SERVER:-https://acme-v02.api.letsencrypt.org/directory}
|
|
||||||
- --certificatesresolvers.myresolver.acme.email=${LETS_ENCRYPT_EMAIL}
|
|
||||||
- --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
|
|
||||||
ports:
|
|
||||||
- "80:80"
|
|
||||||
- "443:443"
|
|
||||||
volumes:
|
volumes:
|
||||||
- ${CONFIG_ROOT:-.}/letsencrypt:/letsencrypt
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
- "/var/run/docker.sock:/var/run/docker.sock:ro"
|
|
||||||
extra_hosts:
|
|
||||||
- host.docker.internal:172.17.0.1
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "traefik", "healthcheck", "--ping"]
|
test: ["CMD", "traefik", "healthcheck", "--ping"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
retries: 10
|
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:
|
sonarr:
|
||||||
image: lscr.io/linuxserver/sonarr
|
image: lscr.io/linuxserver/sonarr
|
||||||
container_name: sonarr
|
container_name: sonarr
|
||||||
@@ -47,8 +72,8 @@ services:
|
|||||||
- PGID=${GROUP_ID}
|
- PGID=${GROUP_ID}
|
||||||
- TZ=${TIMEZONE}
|
- TZ=${TIMEZONE}
|
||||||
volumes:
|
volumes:
|
||||||
- ${CONFIG_ROOT:-.}/sonarr:/config
|
- ${CONFIG_ROOT:-.}/sonarr:/config:Z
|
||||||
- ${DATA_ROOT}:/data
|
- ${DATA_ROOT}:/data:Z
|
||||||
restart: always
|
restart: always
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "--fail", "http://127.0.0.1:8989/sonarr/ping"]
|
test: ["CMD", "curl", "--fail", "http://127.0.0.1:8989/sonarr/ping"]
|
||||||
@@ -56,9 +81,9 @@ services:
|
|||||||
retries: 10
|
retries: 10
|
||||||
labels:
|
labels:
|
||||||
- traefik.enable=true
|
- 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.tls=true
|
- traefik.http.routers.sonarr.entrypoints=web
|
||||||
- traefik.http.routers.sonarr.tls.certresolver=myresolver
|
- traefik.http.routers.sonarr.middlewares=https-proto@docker,authelia-auth@docker
|
||||||
- traefik.http.services.sonarr.loadbalancer.server.port=8989
|
- traefik.http.services.sonarr.loadbalancer.server.port=8989
|
||||||
- homepage.group=Media
|
- homepage.group=Media
|
||||||
- homepage.name=Sonarr
|
- homepage.name=Sonarr
|
||||||
@@ -77,8 +102,8 @@ services:
|
|||||||
- PGID=${GROUP_ID}
|
- PGID=${GROUP_ID}
|
||||||
- TZ=${TIMEZONE}
|
- TZ=${TIMEZONE}
|
||||||
volumes:
|
volumes:
|
||||||
- ${CONFIG_ROOT:-.}/radarr:/config
|
- ${CONFIG_ROOT:-.}/radarr:/config:Z
|
||||||
- ${DATA_ROOT}:/data
|
- ${DATA_ROOT}:/data:Z
|
||||||
restart: always
|
restart: always
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "--fail", "http://127.0.0.1:7878/radarr/ping"]
|
test: ["CMD", "curl", "--fail", "http://127.0.0.1:7878/radarr/ping"]
|
||||||
@@ -86,9 +111,9 @@ services:
|
|||||||
retries: 10
|
retries: 10
|
||||||
labels:
|
labels:
|
||||||
- traefik.enable=true
|
- 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.tls=true
|
- traefik.http.routers.radarr.entrypoints=web
|
||||||
- traefik.http.routers.radarr.tls.certresolver=myresolver
|
- traefik.http.routers.radarr.middlewares=https-proto@docker,authelia-auth@docker
|
||||||
- traefik.http.services.radarr.loadbalancer.server.port=7878
|
- traefik.http.services.radarr.loadbalancer.server.port=7878
|
||||||
- homepage.group=Media
|
- homepage.group=Media
|
||||||
- homepage.name=Radarr
|
- homepage.name=Radarr
|
||||||
@@ -107,8 +132,8 @@ services:
|
|||||||
- PGID=${GROUP_ID}
|
- PGID=${GROUP_ID}
|
||||||
- TZ=${TIMEZONE}
|
- TZ=${TIMEZONE}
|
||||||
volumes:
|
volumes:
|
||||||
- ${CONFIG_ROOT:-.}/lidarr:/config
|
- ${CONFIG_ROOT:-.}/lidarr:/config:Z
|
||||||
- ${DATA_ROOT}:/data
|
- ${DATA_ROOT}:/data:Z
|
||||||
restart: always
|
restart: always
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "--fail", "http://127.0.0.1:8686/lidarr/ping"]
|
test: ["CMD", "curl", "--fail", "http://127.0.0.1:8686/lidarr/ping"]
|
||||||
@@ -116,9 +141,9 @@ services:
|
|||||||
retries: 10
|
retries: 10
|
||||||
labels:
|
labels:
|
||||||
- traefik.enable=true
|
- 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.tls=true
|
- traefik.http.routers.lidarr.entrypoints=web
|
||||||
- traefik.http.routers.lidarr.tls.certresolver=myresolver
|
- traefik.http.routers.lidarr.middlewares=https-proto@docker,authelia-auth@docker
|
||||||
- traefik.http.services.lidarr.loadbalancer.server.port=8686
|
- traefik.http.services.lidarr.loadbalancer.server.port=8686
|
||||||
- homepage.group=Media
|
- homepage.group=Media
|
||||||
- homepage.name=Lidarr
|
- homepage.name=Lidarr
|
||||||
@@ -139,8 +164,8 @@ services:
|
|||||||
- PGID=${GROUP_ID}
|
- PGID=${GROUP_ID}
|
||||||
- TZ=${TIMEZONE}
|
- TZ=${TIMEZONE}
|
||||||
volumes:
|
volumes:
|
||||||
- ${CONFIG_ROOT:-.}/bazarr/config:/config
|
- ${CONFIG_ROOT:-.}/bazarr/config:/config:Z
|
||||||
- ${DATA_ROOT}:/data
|
- ${DATA_ROOT}:/data:Z
|
||||||
restart: always
|
restart: always
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "--fail", "http://127.0.0.1:6767/bazarr/ping"]
|
test: ["CMD", "curl", "--fail", "http://127.0.0.1:6767/bazarr/ping"]
|
||||||
@@ -148,9 +173,9 @@ services:
|
|||||||
retries: 10
|
retries: 10
|
||||||
labels:
|
labels:
|
||||||
- traefik.enable=true
|
- 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.tls=true
|
- traefik.http.routers.bazarr.entrypoints=web
|
||||||
- traefik.http.routers.bazarr.tls.certresolver=myresolver
|
- traefik.http.routers.bazarr.middlewares=https-proto@docker,authelia-auth@docker
|
||||||
- traefik.http.services.bazarr.loadbalancer.server.port=6767
|
- traefik.http.services.bazarr.loadbalancer.server.port=6767
|
||||||
- homepage.group=Download
|
- homepage.group=Download
|
||||||
- homepage.name=Bazarr
|
- homepage.name=Bazarr
|
||||||
@@ -168,7 +193,7 @@ services:
|
|||||||
- LOG_LEVEL=debug
|
- LOG_LEVEL=debug
|
||||||
- TZ=${TIMEZONE}
|
- TZ=${TIMEZONE}
|
||||||
volumes:
|
volumes:
|
||||||
- ${CONFIG_ROOT:-.}/jellyseerr:/app/config
|
- ${CONFIG_ROOT:-.}/jellyseerr:/app/config:Z
|
||||||
restart: always
|
restart: always
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test:
|
test:
|
||||||
@@ -183,11 +208,10 @@ services:
|
|||||||
retries: 10
|
retries: 10
|
||||||
labels:
|
labels:
|
||||||
- traefik.enable=true
|
- 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.tls=true
|
- traefik.http.routers.jellyseerr.entrypoints=web
|
||||||
- traefik.http.routers.jellyseerr.tls.certresolver=myresolver
|
|
||||||
- traefik.http.services.jellyseerr.loadbalancer.server.port=5055
|
- 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-stripprefix.stripPrefix.prefixes=/jellyseerr
|
||||||
- traefik.http.middlewares.jellyseerr-rewriteHeaders.plugin.rewriteHeaders.rewrites[0].header=location
|
- 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].regex=^/(.+)$
|
||||||
@@ -250,7 +274,7 @@ services:
|
|||||||
- PGID=${GROUP_ID}
|
- PGID=${GROUP_ID}
|
||||||
- TZ=${TIMEZONE}
|
- TZ=${TIMEZONE}
|
||||||
volumes:
|
volumes:
|
||||||
- ${CONFIG_ROOT:-.}/prowlarr:/config
|
- ${CONFIG_ROOT:-.}/prowlarr:/config:Z
|
||||||
restart: always
|
restart: always
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "--fail", "http://127.0.0.1:9696/prowlarr/ping"]
|
test: ["CMD", "curl", "--fail", "http://127.0.0.1:9696/prowlarr/ping"]
|
||||||
@@ -258,9 +282,9 @@ services:
|
|||||||
retries: 10
|
retries: 10
|
||||||
labels:
|
labels:
|
||||||
- traefik.enable=true
|
- 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.tls=true
|
- traefik.http.routers.prowlarr.entrypoints=web
|
||||||
- traefik.http.routers.prowlarr.tls.certresolver=myresolver
|
- traefik.http.routers.prowlarr.middlewares=https-proto@docker,authelia-auth@docker
|
||||||
- traefik.http.services.prowlarr.loadbalancer.server.port=9696
|
- traefik.http.services.prowlarr.loadbalancer.server.port=9696
|
||||||
- homepage.group=Download
|
- homepage.group=Download
|
||||||
- homepage.name=Prowlarr
|
- homepage.name=Prowlarr
|
||||||
@@ -282,8 +306,9 @@ services:
|
|||||||
- TZ=${TIMEZONE}
|
- TZ=${TIMEZONE}
|
||||||
labels:
|
labels:
|
||||||
- traefik.enable=true
|
- 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.tls=true
|
- 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
|
- traefik.http.services.flaresolverr.loadbalancer.server.port=8191
|
||||||
profiles:
|
profiles:
|
||||||
- flaresolverr
|
- flaresolverr
|
||||||
@@ -297,34 +322,24 @@ services:
|
|||||||
- WEBUI_PORT=8080
|
- WEBUI_PORT=8080
|
||||||
- DOCKER_MODS=ghcr.io/gabe565/linuxserver-mod-vuetorrent
|
- DOCKER_MODS=ghcr.io/gabe565/linuxserver-mod-vuetorrent
|
||||||
volumes:
|
volumes:
|
||||||
- ${CONFIG_ROOT:-.}/qbittorrent:/config
|
- ${CONFIG_ROOT:-.}/qbittorrent:/config:Z
|
||||||
- ${DOWNLOAD_ROOT}:/data/torrents
|
- ${DOWNLOAD_ROOT}:/data/torrents:Z
|
||||||
restart: always
|
restart: always
|
||||||
healthcheck:
|
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:
|
test:
|
||||||
["CMD", "curl", "--fail", "http://127.0.0.1:8080", "https://google.com"]
|
["CMD", "curl", "--fail", "http://127.0.0.1:8080", "https://google.com"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
retries: 10
|
retries: 10
|
||||||
network_mode: "service:vpn"
|
|
||||||
depends_on:
|
|
||||||
vpn:
|
|
||||||
condition: service_healthy
|
|
||||||
labels:
|
labels:
|
||||||
- traefik.enable=true
|
- 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.tls=true
|
- traefik.http.routers.qbittorrent.entrypoints=web
|
||||||
- traefik.http.routers.qbittorrent.tls.certresolver=myresolver
|
|
||||||
- traefik.http.services.qbittorrent.loadbalancer.server.port=8080
|
- traefik.http.services.qbittorrent.loadbalancer.server.port=8080
|
||||||
- traefik.http.routers.qbittorrent.middlewares=qbittorrent-strip-slash,qbittorrent-stripprefix
|
- traefik.http.routers.qbittorrent.middlewares=https-proto@docker,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
|
- 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.regex=(^.*\/qbittorrent$$)
|
||||||
- traefik.http.middlewares.qbittorrent-strip-slash.redirectregex.replacement=$$1/
|
- traefik.http.middlewares.qbittorrent-strip-slash.redirectregex.replacement=$$1/
|
||||||
- traefik.http.middlewares.qbittorrent-strip-slash.redirectregex.permanent=false
|
- traefik.http.middlewares.qbittorrent-strip-slash.redirectregex.permanent=false
|
||||||
#- com.centurylinklabs.watchtower.depends-on=/vpn
|
|
||||||
- homepage.group=Download
|
- homepage.group=Download
|
||||||
- homepage.name=qBittorrent
|
- homepage.name=qBittorrent
|
||||||
- homepage.icon=qbittorrent.png
|
- homepage.icon=qbittorrent.png
|
||||||
@@ -332,45 +347,14 @@ services:
|
|||||||
- homepage.description=Bittorrent client
|
- homepage.description=Bittorrent client
|
||||||
- homepage.weight=2
|
- homepage.weight=2
|
||||||
- homepage.widget.type=qbittorrent
|
- homepage.widget.type=qbittorrent
|
||||||
- homepage.widget.url=http://vpn:8080
|
- homepage.widget.url=http://qbittorrent:8080
|
||||||
- homepage.widget.username=${QBITTORRENT_USERNAME}
|
- homepage.widget.username=${QBITTORRENT_USERNAME}
|
||||||
- homepage.widget.password=${QBITTORRENT_PASSWORD}
|
- homepage.widget.password=${QBITTORRENT_PASSWORD}
|
||||||
vpn:
|
|
||||||
image: ghcr.io/thrnz/docker-wireguard-pia:latest
|
|
||||||
container_name: vpn
|
|
||||||
volumes:
|
|
||||||
- ${CONFIG_ROOT:-.}/pia:/pia
|
|
||||||
- ${CONFIG_ROOT:-.}/pia-shared:/pia-shared
|
|
||||||
cap_add:
|
|
||||||
- NET_ADMIN
|
|
||||||
- SYS_MODULE
|
|
||||||
environment:
|
|
||||||
- LOC=${PIA_LOCATION}
|
|
||||||
- USER=${PIA_USER}
|
|
||||||
- PASS=${PIA_PASS}
|
|
||||||
- QBT_USER=${QBITTORRENT_USERNAME}
|
|
||||||
- QBT_PASS=${QBITTORRENT_PASSWORD}
|
|
||||||
- LOCAL_NETWORK=${PIA_LOCAL_NETWORK}
|
|
||||||
- PORT_FORWARDING=1
|
|
||||||
- PORT_PERSIST=1
|
|
||||||
- PORT_SCRIPT=/pia-shared/portupdate-qbittorrent.sh
|
|
||||||
- FIREWALL=0
|
|
||||||
sysctls:
|
|
||||||
- net.ipv4.conf.all.src_valid_mark=1
|
|
||||||
- net.ipv6.conf.default.disable_ipv6=1
|
|
||||||
- net.ipv6.conf.all.disable_ipv6=1
|
|
||||||
- net.ipv6.conf.lo.disable_ipv6=1
|
|
||||||
healthcheck:
|
|
||||||
test: ping -c 1 www.google.com || exit 1
|
|
||||||
interval: 30s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 3
|
|
||||||
restart: always
|
|
||||||
unpackerr:
|
unpackerr:
|
||||||
image: ghcr.io/unpackerr/unpackerr:latest
|
image: ghcr.io/unpackerr/unpackerr:latest
|
||||||
container_name: unpackerr
|
container_name: unpackerr
|
||||||
volumes:
|
volumes:
|
||||||
- ${DOWNLOAD_ROOT}:/data/torrents
|
- ${DOWNLOAD_ROOT}:/data/torrents:Z
|
||||||
restart: always
|
restart: always
|
||||||
user: ${USER_ID}:${GROUP_ID}
|
user: ${USER_ID}:${GROUP_ID}
|
||||||
environment:
|
environment:
|
||||||
@@ -389,14 +373,14 @@ services:
|
|||||||
- PGID=${GROUP_ID}
|
- PGID=${GROUP_ID}
|
||||||
- TZ=${TIMEZONE}
|
- TZ=${TIMEZONE}
|
||||||
volumes:
|
volumes:
|
||||||
- ${CONFIG_ROOT:-.}/sabnzbd:/config
|
- ${CONFIG_ROOT:-.}/sabnzbd:/config:Z
|
||||||
- ${DATA_ROOT}:/data
|
- ${DATA_ROOT}:/data:Z
|
||||||
restart: always
|
restart: always
|
||||||
labels:
|
labels:
|
||||||
- traefik.enable=true
|
- 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.tls=true
|
- traefik.http.routers.sabnzbd.entrypoints=web
|
||||||
- traefik.http.routers.sabnzbd.tls.certresolver=myresolver
|
- traefik.http.routers.sabnzbd.middlewares=https-proto@docker,authelia-auth@docker
|
||||||
- traefik.http.services.sabnzbd.loadbalancer.server.port=8080
|
- traefik.http.services.sabnzbd.loadbalancer.server.port=8080
|
||||||
- homepage.group=Download
|
- homepage.group=Download
|
||||||
- homepage.name=Sabnzbd
|
- homepage.name=Sabnzbd
|
||||||
@@ -416,10 +400,10 @@ services:
|
|||||||
- PUID=${USER_ID}
|
- PUID=${USER_ID}
|
||||||
- PGID=${GROUP_ID}
|
- PGID=${GROUP_ID}
|
||||||
- TZ=${TIMEZONE}
|
- TZ=${TIMEZONE}
|
||||||
- JELLYFIN_PublishedServerUrl=${HOSTNAME}/jellyfin
|
- JELLYFIN_PublishedServerUrl=https://${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}/jellyfin
|
||||||
volumes:
|
volumes:
|
||||||
- ${CONFIG_ROOT:-.}/jellyfin:/config
|
- ${CONFIG_ROOT:-.}/jellyfin:/config:Z
|
||||||
- ${DATA_ROOT}:/data
|
- ${DATA_ROOT}:/data:Z
|
||||||
ports:
|
ports:
|
||||||
- "7359:7359/udp"
|
- "7359:7359/udp"
|
||||||
- "1900:1900/udp"
|
- "1900:1900/udp"
|
||||||
@@ -430,9 +414,9 @@ services:
|
|||||||
retries: 10
|
retries: 10
|
||||||
labels:
|
labels:
|
||||||
- traefik.enable=true
|
- 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.tls=true
|
- traefik.http.routers.jellyfin.entrypoints=web
|
||||||
- traefik.http.routers.jellyfin.tls.certresolver=myresolver
|
- traefik.http.routers.jellyfin.middlewares=https-proto@docker # Only HTTPS, no auth
|
||||||
- traefik.http.services.jellyfin.loadbalancer.server.port=8096
|
- traefik.http.services.jellyfin.loadbalancer.server.port=8096
|
||||||
- homepage.group=Media
|
- homepage.group=Media
|
||||||
- homepage.name=Jellyfin
|
- homepage.name=Jellyfin
|
||||||
@@ -453,18 +437,17 @@ services:
|
|||||||
- DOCKER_MODS=linuxserver/mods:universal-calibre
|
- DOCKER_MODS=linuxserver/mods:universal-calibre
|
||||||
- OAUTHLIB_RELAX_TOKEN_SCOPE=1
|
- OAUTHLIB_RELAX_TOKEN_SCOPE=1
|
||||||
volumes:
|
volumes:
|
||||||
- ${CONFIG_ROOT:-.}/calibre-web:/config
|
- ${CONFIG_ROOT:-.}/calibre-web:/config:Z
|
||||||
- ${DATA_ROOT}/books:/books
|
- ${DATA_ROOT}/books:/books:Z
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
labels:
|
labels:
|
||||||
- traefik.enable=true
|
- traefik.enable=true
|
||||||
- traefik.http.middlewares.calibre-headers.headers.customRequestHeaders.X-Scheme=https
|
- 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-headers.headers.customRequestHeaders.X-Script-Name=/calibre
|
||||||
- traefik.http.middlewares.calibre-stripprefixregex.stripPrefixRegex.regex=/calibre
|
- traefik.http.middlewares.calibre-stripprefixregex.stripPrefixRegex.regex=/calibre
|
||||||
- traefik.http.routers.calibre.middlewares=calibre-headers,calibre-stripprefixregex
|
- traefik.http.routers.calibre.middlewares=https-proto@docker,calibre-headers,calibre-stripprefixregex,authelia-auth@docker
|
||||||
- traefik.http.routers.calibre.rule=(Host(`${HOSTNAME}`) && PathPrefix(`/calibre`))
|
- traefik.http.routers.calibre.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/calibre`) # Added Host check
|
||||||
- traefik.http.routers.calibre.tls=true
|
- traefik.http.routers.calibre.entrypoints=web
|
||||||
- traefik.http.routers.calibre.tls.certresolver=myresolver
|
|
||||||
- traefik.http.services.calibre.loadbalancer.server.port=8083
|
- traefik.http.services.calibre.loadbalancer.server.port=8083
|
||||||
- homepage.group=Media
|
- homepage.group=Media
|
||||||
- homepage.name=Calibre-Web
|
- homepage.name=Calibre-Web
|
||||||
@@ -526,20 +509,27 @@ services:
|
|||||||
- HOMEPAGE_VAR_WEATHER_LONG=${HOMEPAGE_VAR_WEATHER_LONG}
|
- HOMEPAGE_VAR_WEATHER_LONG=${HOMEPAGE_VAR_WEATHER_LONG}
|
||||||
- HOMEPAGE_VAR_WEATHER_TIME=${TIMEZONE}
|
- HOMEPAGE_VAR_WEATHER_TIME=${TIMEZONE}
|
||||||
- HOMEPAGE_VAR_WEATHER_UNIT=${HOMEPAGE_VAR_WEATHER_UNIT}
|
- HOMEPAGE_VAR_WEATHER_UNIT=${HOMEPAGE_VAR_WEATHER_UNIT}
|
||||||
- HOMEPAGE_ALLOWED_HOSTS=${HOSTNAME}
|
- HOMEPAGE_ALLOWED_HOSTS=${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}
|
||||||
volumes:
|
volumes:
|
||||||
- ${CONFIG_ROOT:-.}/homepage:/app/config
|
- ${CONFIG_ROOT:-.}/homepage:/app/config:Z
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
- ${DATA_ROOT}:/data
|
- ${DATA_ROOT}:/data:Z
|
||||||
restart: always
|
restart: always
|
||||||
command:
|
command:
|
||||||
[sh, -c, "cp -n /app/config/tpl/*.yaml /app/config && node server.js"]
|
[sh, -c, "cp -n /app/config/tpl/*.yaml /app/config && node server.js"]
|
||||||
labels:
|
labels:
|
||||||
- traefik.enable=true
|
- 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.tls=true
|
- traefik.http.routers.homepage.entrypoints=web
|
||||||
- traefik.http.routers.homepage.tls.certresolver=myresolver
|
# - traefik.http.routers.homepage.priority=10 # Removed priority
|
||||||
- traefik.http.services.homepage.loadbalancer.server.port=3000
|
# 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:
|
watchtower:
|
||||||
image: ghcr.io/containrrr/watchtower:latest
|
image: ghcr.io/containrrr/watchtower:latest
|
||||||
container_name: watchtower
|
container_name: watchtower
|
||||||
@@ -556,6 +546,60 @@ services:
|
|||||||
- AUTOHEAL_CONTAINER_LABEL=all
|
- AUTOHEAL_CONTAINER_LABEL=all
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.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}
|
||||||
|
environment:
|
||||||
|
TS_AUTHKEY: ${TAILSCALE_AUTHKEY}
|
||||||
|
TS_EXTRA_ARGS: "--advertise-tags=${TAILSCALE_TAGS:-tag:nas}"
|
||||||
|
TS_STATE_DIR: "/var/lib/tailscale"
|
||||||
|
TS_USERSPACE: "false"
|
||||||
|
ENABLE_FUNNEL_HTTPS: ${ENABLE_FUNNEL_HTTPS:-false}
|
||||||
|
volumes:
|
||||||
|
- ${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
|
||||||
|
extra_hosts:
|
||||||
|
- 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."
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
echo "Tailscale forwarding configured. Container will remain running."
|
||||||
|
wait
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
default:
|
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