feature/traefik-authelia-integration: Integrate Authelia to secure sensitive access to other containers #1

Open
aki wants to merge 5 commits from feature/traefik-authelia-integration into main
5 changed files with 280 additions and 56 deletions
Showing only changes of commit 67ff6d585c - Show all commits

View File

@ -36,9 +36,10 @@ 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 Hostname ---
# Primary hostname used by Traefik for routing. Derived from Tailscale settings by default.
HOSTNAME=${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}
# --- 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!)
@ -62,18 +63,16 @@ HOMEPAGE_VAR_WEATHER_UNIT=metric
# --- Authelia Settings ---
# Generate strong random secrets for these using tools like `openssl rand -hex 32`
AUTHELIA_JWT_SECRET= # Example: your_strong_jwt_secret
AUTHELIA_SESSION_SECRET= # Example: your_strong_session_secret
AUTHELIA_STORAGE_ENCRYPTION_KEY= # Example: your_strong_storage_encryption_key
AUTHELIA_REDIS_PASSWORD= # Example: your_strong_redis_password
# 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
# Google OIDC Provider Settings (Get from Google Cloud Console - https://console.cloud.google.com/apis/credentials)
AUTHELIA_GOOGLE_OIDC_CLIENT_ID= # Example: your-google-client-id.apps.googleusercontent.com
AUTHELIA_GOOGLE_OIDC_CLIENT_SECRET= # Example: GOCSPX-your-google-client-secret
# Authelia Session Configuration
AUTHELIA_SESSION_DOMAIN=${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}
AUTHELIA_DEFAULT_REDIRECT_URL=https://${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}/home
# 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)

3
.gitignore vendored
View File

@ -1,6 +1,9 @@
*.env
*.bak
.idea
docker-compose.override.yml
/authelia/*.yml
!/authelia/*.example.yml
/homepage/logs
/homepage/*.yaml
/homepage/*.css

View 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

View 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

View File

@ -13,18 +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
network_mode: service:tailscale # Add this line
# ports: # Remove this section
# - "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/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}"]
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
@ -42,8 +81,9 @@ services:
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.sonarr.rule=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
@ -71,8 +111,9 @@ services:
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.radarr.rule=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
@ -100,8 +141,9 @@ services:
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.lidarr.rule=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
@ -131,8 +173,9 @@ services:
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.bazarr.rule=Host(`${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}`) && 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
@ -165,10 +208,10 @@ services:
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.jellyseerr.rule=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=^/(.+)$
@ -239,8 +282,9 @@ services:
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.prowlarr.rule=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
@ -262,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
@ -281,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(`${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}`) && 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
@ -338,8 +378,9 @@ services:
restart: always
labels:
- traefik.enable=true
- traefik.http.routers.sabnzbd.rule=PathPrefix(`/sabnzbd`) # Simplified rule
- 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
@ -359,7 +400,7 @@ services:
- PUID=${USER_ID}
- PGID=${GROUP_ID}
- TZ=${TIMEZONE}
- JELLYFIN_PublishedServerUrl=${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}/jellyfin
- JELLYFIN_PublishedServerUrl=https://${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}/jellyfin
volumes:
- ${CONFIG_ROOT:-.}/jellyfin:/config:Z
- ${DATA_ROOT}:/data:Z
@ -373,8 +414,9 @@ services:
retries: 10
labels:
- traefik.enable=true
- traefik.http.routers.jellyfin.rule=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
@ -403,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(`${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}`) && 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
@ -467,7 +509,6 @@ services:
- 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
@ -478,11 +519,17 @@ services:
[sh, -c, "cp -n /app/config/tpl/*.yaml /app/config && node server.js"]
labels:
- traefik.enable=true
# Change path to /home and use specific Tailscale host
- traefik.http.routers.homepage.rule=Host(`${TAILSCALE_HOSTNAME}.${TAILSCALE_TAILNET_DOMAIN}`) && PathPrefix(`/home`)
- traefik.http.routers.homepage.rule=Host(`${APP_HOSTNAME}`) && PathPrefix(`/`) # Changed rule to root
- traefik.http.routers.homepage.entrypoints=web
# Authelia middleware will be added in a later commit
- 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
@ -502,23 +549,22 @@ services:
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/docker.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
extra_hosts: # Add this section
extra_hosts:
- host.docker.internal:172.17.0.1
restart: always
command:
@ -542,8 +588,6 @@ 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://localhost:80..."
tailscale funnel --bg http://localhost:80
@ -553,10 +597,9 @@ services:
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: