Add docker-compose configurations and SSL troubleshooting docs

- Added compose files for core, infrastructure, and dashboards stacks
- Added Traefik, Authelia, and DuckDNS configuration files
- Added dockge.managed and dockge.url labels to all services
- Updated Watchtower to latest version with DOCKER_API_VERSION=1.44
- Created comprehensive SSL certificate troubleshooting guide for DuckDNS issues
This commit is contained in:
2026-01-13 16:40:13 -05:00
parent bbcc4c19c9
commit a53effad10
10 changed files with 815 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
# Authelia Configuration
# Copy to /opt/stacks/authelia/configuration.yml
# IMPORTANT: Replace 'kelin-hass.duckdns.org' with your actual DuckDNS domain
server:
host: 0.0.0.0
port: 9091
log:
level: info
theme: dark
jwt_secret: ${AUTHELIA_JWT_SECRET}
default_redirection_url: https://auth.kelin-hass.duckdns.org
totp:
issuer: kelin-hass.duckdns.org
period: 30
skew: 1
authentication_backend:
file:
path: /config/users_database.yml
password:
algorithm: argon2id
iterations: 1
key_length: 32
salt_length: 16
memory: 1024
parallelism: 8
access_control:
default_policy: deny
rules:
# Bypass Authelia for Jellyfin (allow app access)
- domain: jellyfin.kelin-hass.duckdns.org
policy: bypass
# Bypass for Plex (allow app access)
- domain: plex.kelin-hass.duckdns.org
policy: bypass
# Bypass for Home Assistant (has its own auth)
- domain: ha.kelin-hass.duckdns.org
policy: bypass
# Protected: All other services require authentication
- domain: "*.kelin-hass.duckdns.org"
policy: one_factor
# Two-factor for admin services (optional)
# - domain:
# - "admin.kelin-hass.duckdns.org"
# - "portainer.kelin-hass.duckdns.org"
# policy: two_factor
session:
name: authelia_session
secret: ${AUTHELIA_SESSION_SECRET}
expiration: 1h
inactivity: 5m
remember_me_duration: 1M
domain: kelin-hass.duckdns.org
regulation:
max_retries: 3
find_time: 2m
ban_time: 5m
storage:
encryption_key: ${AUTHELIA_STORAGE_ENCRYPTION_KEY}
local:
path: /data/db.sqlite3
notifier:
# File-based notifications (for development/testing)
filesystem:
filename: /data/notification.txt

View File

@@ -0,0 +1,12 @@
###############################################################
# Users Database #
###############################################################
users:
kelin:
displayname: "kelin"
password: "$argon2id$v=19$m=65536,t=3,p=4$GirJvw4ecHIr1nnM3ALpwg$7+XjPev3P7AwEveRw5yiq5OmsitXYQp5xR8AxWjDNbI"
email: kelinfoxy@gmail.com
groups:
- admins
- dev

View File

@@ -0,0 +1,151 @@
# Core Infrastructure Stack
# Essential services required for the homelab to function
# Deploy this stack FIRST before any other services
# Place in /opt/stacks/core/docker-compose.yml
services:
# DuckDNS - Dynamic DNS updater
# Updates your public IP automatically for Let's Encrypt SSL
duckdns:
image: lscr.io/linuxserver/duckdns:latest
container_name: duckdns
restart: unless-stopped
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ}
- SUBDOMAINS=${DUCKDNS_SUBDOMAINS} # Your subdomain(s), comma separated
- TOKEN=${DUCKDNS_TOKEN} # Your DuckDNS token
- UPDATE_IP=ipv4 # or ipv6, or both
volumes:
- /opt/stacks/core/duckdns:/config
labels:
- "homelab.category=infrastructure"
- "homelab.description=Dynamic DNS updater"
# Traefik - Reverse proxy with automatic SSL
# Routes all traffic and manages Let's Encrypt certificates
traefik:
image: traefik:v2.11
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- traefik-network
ports:
- "80:80" # HTTP
- "443:443" # HTTPS
- "8080:8080" # Dashboard (protected with Authelia)
dns:
- 1.1.1.1
- 8.8.8.8
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- /opt/stacks/core/traefik/traefik.yml:/traefik.yml:ro
- /opt/stacks/core/traefik/dynamic:/dynamic:ro
- /opt/stacks/core/traefik/acme.json:/acme.json
environment:
- CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN} # If using Cloudflare DNS challenge
- DUCKDNS_TOKEN=${DUCKDNS_TOKEN} # If using DuckDNS
- LEGO_DISABLE_CNAME_SUPPORT=true # Disable CNAME support to avoid authoritative NS queries
- LEGO_EXPERIMENTAL_DNS_TCP_SUPPORT=true # Use TCP for DNS queries
- LEGO_DNS_TIMEOUT=60 # DNS timeout in seconds
- LEGO_DNS_RESOLVERS=1.1.1.1:53,8.8.8.8:53 # Force use of specific DNS resolvers
- LEGO_DISABLE_CP=true # Disable authoritative nameserver propagation check
- DUCKDNS_PROPAGATION_TIMEOUT=600 # Increase propagation timeout to 10 minutes
labels:
- "dockge.managed=true"
- "dockge.url=https://traefik.${DOMAIN}"
- "traefik.enable=true"
# Dashboard
- "traefik.http.routers.traefik.rule=Host(`traefik.${DOMAIN}`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
- "traefik.http.routers.traefik.tls.domains[0].main=${DOMAIN}"
- "traefik.http.routers.traefik.tls.domains[0].sans=*.${DOMAIN}"
- "traefik.http.routers.traefik.middlewares=authelia@docker"
- "traefik.http.routers.traefik.service=api@internal"
# Global HTTP to HTTPS redirect
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=web"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
depends_on:
- duckdns
# Authelia - SSO authentication
# Protects all admin services with single sign-on
authelia:
image: authelia/authelia:4.37
container_name: authelia
restart: unless-stopped
networks:
- traefik-network
volumes:
- /opt/stacks/core/authelia/configuration.yml:/config/configuration.yml:ro
- /opt/stacks/core/authelia/users_database.yml:/config/users_database.yml
- authelia-data:/data
environment:
- TZ=${TZ}
- AUTHELIA_JWT_SECRET=${AUTHELIA_JWT_SECRET}
- AUTHELIA_SESSION_SECRET=${AUTHELIA_SESSION_SECRET}
- AUTHELIA_STORAGE_ENCRYPTION_KEY=${AUTHELIA_STORAGE_ENCRYPTION_KEY}
labels:
- "dockge.managed=true"
- "dockge.url=https://auth.${DOMAIN}"
- "traefik.enable=true"
- "traefik.http.routers.authelia.rule=Host(`auth.${DOMAIN}`)"
- "traefik.http.routers.authelia.entrypoints=websecure"
- "traefik.http.routers.authelia.tls=true"
- "traefik.http.services.authelia.loadbalancer.server.port=9091"
# Authelia middleware for other services
- "traefik.http.middlewares.authelia.forwardauth.address=http://authelia:9091/api/verify?rd=https://auth.${DOMAIN}"
- "traefik.http.middlewares.authelia.forwardauth.trustForwardHeader=true"
- "traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email"
depends_on:
- traefik
# Gluetun - VPN client (Surfshark WireGuard)
# Routes download clients through VPN for security
gluetun:
image: qmcgaw/gluetun:latest
container_name: gluetun
restart: unless-stopped
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
networks:
- homelab-network
- traefik-network
ports:
- "8888:8888/tcp" # HTTP proxy
- "8388:8388/tcp" # Shadowsocks
- "8388:8388/udp" # Shadowsocks
- "8081:8080" # qBittorrent web UI
- "6881:6881" # qBittorrent
- "6881:6881/udp" # qBittorrent
volumes:
- /opt/stacks/core/gluetun:/gluetun
environment:
- VPN_SERVICE_PROVIDER=surfshark
- VPN_TYPE=openvpn
- OPENVPN_USER=${SURFSHARK_USERNAME}
- OPENVPN_PASSWORD=${SURFSHARK_PASSWORD}
- SERVER_COUNTRIES=${VPN_SERVER_COUNTRIES:-Netherlands}
- TZ=${TZ}
labels:
- "homelab.category=infrastructure"
- "homelab.description=VPN client for secure downloads"
volumes:
authelia-data:
driver: local
networks:
traefik-network:
external: true
homelab-network:
external: true

View File

@@ -0,0 +1,5 @@
/config/duck.log {
rotate 5
size 100k
compress
}

View File

@@ -0,0 +1,16 @@
{
"letsencrypt": {
"Account": {
"Email": "kelinfoxy@gmail.com",
"Registration": {
"body": {
"status": "valid"
},
"uri": "https://acme-v02.api.letsencrypt.org/acme/acct/2959423246"
},
"PrivateKey": "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",
"KeyType": "4096"
},
"Certificates": null
}
}

View File

@@ -0,0 +1,31 @@
# Traefik Dynamic Configuration
# Copy to /opt/stacks/traefik/dynamic/routes.yml
# Add custom routes here that aren't defined via Docker labels
http:
routers:
# Example custom route
# custom-service:
# rule: "Host(`custom.example.com`)"
# entryPoints:
# - websecure
# middlewares:
# - authelia@docker
# tls:
# certResolver: letsencrypt
# service: custom-service
services:
# Example custom service
# custom-service:
# loadBalancer:
# servers:
# - url: "http://192.168.1.100:8080"
middlewares:
# Additional middlewares can be defined here
# Example: Rate limiting
# rate-limit:
# rateLimit:
# average: 100
# burst: 50

View File

@@ -0,0 +1,56 @@
# Traefik Static Configuration
# Copy to /opt/stacks/traefik/traefik.yml
global:
checkNewVersion: true
sendAnonymousUsage: false
api:
dashboard: true
insecure: false # Dashboard accessible via Traefik route with Authelia
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
http:
tls:
certResolver: letsencrypt
certificatesResolvers:
letsencrypt:
acme:
email: kelinfoxy@gmail.com
storage: /acme.json
# Use DNS challenge for wildcard certificate support
dnsChallenge:
provider: duckdns
delayBeforeCheck: 300 # Wait 5 minutes before checking DNS propagation
resolvers:
- "1.1.1.1:53"
- "8.8.8.8:53"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false # Only expose services with traefik.enable=true
network: traefik-network
file:
directory: /dynamic
watch: true
log:
level: DEBUG # DEBUG, INFO, WARN, ERROR
filePath: /var/log/traefik/traefik.log
accessLog:
filePath: /var/log/traefik/access.log
bufferingSize: 100