I really liked Tom’s setup in this thread, so I built it as a single compose stack that keeps his “simple, clean, easy to back up” vibe, but swaps Nginx Proxy Manager for Traefik.
Traefik feels like a better fit here because it’s very container‑native: it watches Docker directly, so as soon as you spin up a service with the right labels it’s online behind the proxy, and Let’s Encrypt is just part of the config instead of something you click around a UI to wire up. All the routing, TLS, and SSO stuff live right next to each service in the compose file, which makes it much easier to manage.
I also wired in Authelia so you can put SSO in front of the various services like Homarr, IT Tools, CyberChef, Netdata, Dozzle, WUD, etc. while letting stuff like Jellyfin or Guacamole keep their own auth or stay internal if you prefer. BTW, Guacamole will use OIDC to authenticate with Authelia if you want. DNS and domains are handled via a .env-template (with DOMAIN, LE_EMAIL, TZ, and Traefik dashboard BasicAuth). Let’s Encrypt is pointed at staging by default so you can test everything without tripping rate limits; once it all looks good you flip it over to production.
WUD is in the stack for update visibility, but I left Watchtower out on purpose. If someone wants auto‑updates they can run Watchtower (I included a docker-compose.yml for it below) in a tiny separate compose and opt‑in only the containers they’re comfortable updating automatically.
Below I’ve included the .env-template, the single docker-compose.yml with all the apps Tom mentioned, and an optional docker-compose.yml for watchtower in case anyone wants to leverage it for auto updates. Be aware Watchtower can mess up some containers so choose wisely which ones you want auto updated.
docker-compose.yml:
# ------------------------------------------------------------------------------
# Traefik + Authelia Docker Compose Stack
#
# First-run setup:
# 1) Copy .env-template to .env
# 2) Edit .env and set at minimum:
# TZ=America/New_York
# DOMAIN=yourdomain.tld
# LE_EMAIL=you@yourdomain.tld
# BASIC_AUTH_USERS=admin:$apr1$... or bcrypt hash
# 3) Create public DNS records for every hostname used by this stack before
# testing certificates, for example:
# traefik.${DOMAIN}
# auth.${DOMAIN}
# homarr.${DOMAIN}
# rss.${DOMAIN}
# ladder.${DOMAIN}
# ai.${DOMAIN}
# tools.${DOMAIN}
# chef.${DOMAIN}
# netalertx.${DOMAIN}
# stats.${DOMAIN}
# guac.${DOMAIN}
# speed.${DOMAIN}
# logs.${DOMAIN}
# wud.${DOMAIN}
# media.${DOMAIN}
# 4) Create the external Docker network if it does not exist:
# docker network create proxy
# 5) Create required folders:
# mkdir -p \
# ./data/traefik/letsencrypt \
# ./data/traefik/logs \
# ./data/traefik/dynamic \
# ./data/authelia/config \
# ./data/homarr/config \
# ./data/freshrss/config \
# ./data/freshrss/data \
# ./data/openwebui \
# ./data/netalertx/config \
# ./data/netalertx/db \
# ./data/netdata/config \
# ./data/netdata/lib \
# ./data/netdata/cache \
# ./data/wud \
# ./data/jellyfin/config \
# ./data/jellyfin/media
# 6) Create ACME storage and lock down permissions:
# touch ./data/traefik/letsencrypt/acme.json
# chmod 600 ./data/traefik/letsencrypt/acme.json
# 7) Optional: create dynamic config files under:
# ./data/traefik/dynamic/
# 8) Leave Let's Encrypt staging enabled for initial testing so you can confirm
# routing, DNS, and challenge handling without hitting production rate limits.
# 9) After staging works, comment out the staging caServer line below and restart
# Traefik to request real production certificates.
#
# Example dynamic config file:
# ./data/traefik/dynamic/tls.yaml
# ---
# tls:
# options:
# default:
# minVersion: VersionTLS12
# sniStrict: true
#
# Traefik dashboard BasicAuth:
# 1) Generate a password hash with htpasswd, for example:
# htpasswd -nbB admin 'YourStrongPassword'
# or:
# htpasswd -nbm admin 'YourStrongPassword'
# 2) If placing the hash directly in docker-compose labels, escape $ as $$.
# 3) In this stack, the dashboard auth is read from BASIC_AUTH_USERS in .env.
#
# Updates:
# - WUD in this stack provides update awareness and notifications.
# - Watchtower is NOT included in this stack by default.
# - If you want automatic updates later, it is recommended to run Watchtower
# as a separate stack and enable it only for selected containers using:
# com.centurylinklabs.watchtower.enable=true
# - Recommended Watchtower mode:
# WATCHTOWER_LABEL_ENABLE=true
# so only explicitly labeled containers are auto-updated.
#
# Notes:
# - The dashboard auth protects only Traefik’s dashboard route.
# - Any label using authelia@docker can be commented out if you do not want SSO
# through Authelia on that specific service.
# ------------------------------------------------------------------------------
services:
socket-proxy:
image: tecnativa/docker-socket-proxy:latest
container_name: traefik_socket-proxy
restart: always
security_opt:
- no-new-privileges:true
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
LOG_LEVEL: info
CONTAINERS: 1
NETWORKS: 1
INFO: 1
VERSION: 1
EVENTS: 1
PING: 1
AUTH: 0
BUILD: 0
COMMIT: 0
CONFIGS: 0
DISTRIBUTION: 0
EXEC: 0
IMAGES: 0
NODES: 0
PLUGINS: 0
POST: 0
SECRETS: 0
SERVICES: 0
SESSION: 0
SWARM: 0
SYSTEM: 0
TASKS: 0
VOLUMES: 0
expose:
- "2375"
networks:
- proxy
traefik:
image: traefik:v3.1
container_name: traefik
restart: always
depends_on:
- socket-proxy
env_file:
- .env
environment:
TZ: ${TZ}
# Uncomment and fill only if using ACME DNS challenge with Cloudflare
# CF_API_EMAIL: ${CF_API_EMAIL}
# CF_API_KEY: ${CF_API_KEY}
# CF_DNS_API_TOKEN: ${CF_DNS_API_TOKEN}
# Uncomment and fill only if using ACME DNS challenge with DNSMadeEasy
# DNSMADEEASY_API_KEY: ${DNSMADEEASY_API_KEY}
# DNSMADEEASY_API_SECRET: ${DNSMADEEASY_API_SECRET}
# Uncomment and fill only if using ACME DNS challenge with GoDaddy
# GODADDY_API_KEY: ${GODADDY_API_KEY}
# GODADDY_API_SECRET: ${GODADDY_API_SECRET}
command:
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.endpoint=tcp://socket-proxy:2375"
- "--providers.docker.watch=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=proxy"
- "--providers.file.directory=/etc/traefik/dynamic"
- "--providers.file.watch=true"
- "--entrypoints.http.address=:80"
- "--entrypoints.https.address=:443"
# Uncomment below to redirect http to https globally
# - "--entrypoints.http.http.redirections.entryPoint.to=https"
# - "--entrypoints.http.http.redirections.entryPoint.scheme=https"
- "--serversTransport.insecureSkipVerify=true"
- "--log=true"
- "--log.level=DEBUG"
- "--accessLog=true"
- "--accessLog.filePath=/var/log/docker/traefik.log"
- "--accessLog.bufferingSize=100"
# Leave staging enabled for initial testing, then comment it out for prod.
- "--certificatesResolvers.le.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory"
- "--certificatesResolvers.le.acme.httpChallenge=true"
- "--certificatesResolvers.le.acme.httpChallenge.entryPoint=http"
# DNS challenge options, uncomment only if switching from HTTP to DNS challenge
# - "--certificatesResolvers.le.acme.dnsChallenge=true"
# - "--certificatesResolvers.le.acme.dnsChallenge.provider=cloudflare"
# - "--certificatesResolvers.le.acme.dnsChallenge.resolvers=1.1.1.1:53,8.8.8.8:53"
# - "--certificatesResolvers.le.acme.dnsChallenge.delayBeforeCheck=120"
- "--certificatesResolvers.le.acme.email=${LE_EMAIL}"
- "--certificatesResolvers.le.acme.storage=/etc/traefik/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
# Uncomment for local dashboard troubleshooting only
# - "8080:8080"
volumes:
- ./data/traefik/letsencrypt:/etc/traefik/letsencrypt
- ./data/traefik/logs:/var/log/docker
- ./data/traefik/dynamic:/etc/traefik/dynamic:ro
networks:
- proxy
logging:
options:
max-size: 10m
max-file: "5"
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.traefik.entrypoints=http"
- "traefik.http.routers.traefik.rule=Host(`traefik.${DOMAIN}`)"
- "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
- "traefik.http.routers.traefik-secure.entrypoints=https"
- "traefik.http.routers.traefik-secure.rule=Host(`traefik.${DOMAIN}`)"
- "traefik.http.routers.traefik-secure.tls=true"
- "traefik.http.routers.traefik-secure.tls.certresolver=le"
- "traefik.http.routers.traefik-secure.service=api@internal"
- "traefik.http.routers.traefik-secure.middlewares=traefik-auth@docker"
- "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
- "traefik.http.middlewares.traefik-auth.basicauth.users=${BASIC_AUTH_USERS}"
authelia:
image: authelia/authelia:latest
container_name: authelia
restart: always
env_file:
- .env
environment:
TZ: ${TZ}
volumes:
- ./data/authelia/config:/config
networks:
- proxy
logging:
options:
max-size: 10m
max-file: "5"
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.authelia.entrypoints=http"
- "traefik.http.routers.authelia.rule=Host(`auth.${DOMAIN}`)"
- "traefik.http.routers.authelia.middlewares=authelia-https-redirect"
- "traefik.http.routers.authelia-secure.entrypoints=https"
- "traefik.http.routers.authelia-secure.rule=Host(`auth.${DOMAIN}`)"
- "traefik.http.routers.authelia-secure.tls=true"
- "traefik.http.routers.authelia-secure.tls.certresolver=le"
- "traefik.http.routers.authelia-secure.service=authelia"
- "traefik.http.services.authelia.loadbalancer.server.port=9091"
- "traefik.http.middlewares.authelia.forwardauth.address=http://authelia:9091/api/authz/forward-auth"
- "traefik.http.middlewares.authelia.forwardauth.trustForwardHeader=true"
- "traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email"
- "traefik.http.middlewares.authelia-https-redirect.redirectscheme.scheme=https"
homarr:
image: ghcr.io/homarr-labs/homarr:latest
container_name: homarr
restart: always
env_file:
- .env
environment:
TZ: ${TZ}
SECRET_ENCRYPTION_KEY: replace_me
volumes:
- ./data/homarr/config:/appdata
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- proxy
logging:
options:
max-size: 10m
max-file: "5"
# ports:
# - "7575:7575" # Enable for troubleshooting
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.homarr.entrypoints=http"
- "traefik.http.routers.homarr.rule=Host(`homarr.${DOMAIN}`)"
- "traefik.http.routers.homarr.middlewares=homarr-https-redirect"
- "traefik.http.routers.homarr-secure.entrypoints=https"
- "traefik.http.routers.homarr-secure.rule=Host(`homarr.${DOMAIN}`)"
- "traefik.http.routers.homarr-secure.tls=true"
- "traefik.http.routers.homarr-secure.tls.certresolver=le"
- "traefik.http.routers.homarr-secure.service=homarr"
- "traefik.http.routers.homarr-secure.middlewares=authelia@docker" # Comment out if you do not want SSO with Authelia
- "traefik.http.services.homarr.loadbalancer.server.port=7575"
freshrss:
image: freshrss/freshrss:latest
container_name: freshrss
restart: always
env_file:
- .env
environment:
TZ: ${TZ}
PUID: 999
PGID: 999
volumes:
- ./data/freshrss/config:/config
- ./data/freshrss/data:/var/www/FreshRSS/data
networks:
- proxy
logging:
options:
max-size: 10m
max-file: "5"
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.freshrss.entrypoints=http"
- "traefik.http.routers.freshrss.rule=Host(`rss.${DOMAIN}`)"
- "traefik.http.routers.freshrss.middlewares=freshrss-https-redirect"
- "traefik.http.routers.freshrss-secure.entrypoints=https"
- "traefik.http.routers.freshrss-secure.rule=Host(`rss.${DOMAIN}`)"
- "traefik.http.routers.freshrss-secure.tls=true"
- "traefik.http.routers.freshrss-secure.tls.certresolver=le"
- "traefik.http.routers.freshrss-secure.service=freshrss"
- "traefik.http.routers.freshrss-secure.middlewares=authelia@docker" # Comment out if you do not want SSO with Authelia
- "traefik.http.services.freshrss.loadbalancer.server.port=80"
ladder13:
image: ghcr.io/wasi-master/13ft:latest
container_name: ladder13
restart: always
env_file:
- .env
environment:
TZ: ${TZ}
networks:
- proxy
logging:
options:
max-size: 10m
max-file: "5"
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.ladder13.entrypoints=http"
- "traefik.http.routers.ladder13.rule=Host(`ladder.${DOMAIN}`)"
- "traefik.http.routers.ladder13.middlewares=ladder13-https-redirect"
- "traefik.http.routers.ladder13-secure.entrypoints=https"
- "traefik.http.routers.ladder13-secure.rule=Host(`ladder.${DOMAIN}`)"
- "traefik.http.routers.ladder13-secure.tls=true"
- "traefik.http.routers.ladder13-secure.tls.certresolver=le"
- "traefik.http.routers.ladder13-secure.service=ladder13"
- "traefik.http.routers.ladder13-secure.middlewares=authelia@docker" # Comment out if you do not want SSO with Authelia
- "traefik.http.services.ladder13.loadbalancer.server.port=5000"
openwebui:
image: ghcr.io/open-webui/open-webui:main
container_name: openwebui
restart: always
env_file:
- .env
environment:
TZ: ${TZ}
volumes:
- ./data/openwebui:/app/backend/data
networks:
- proxy
logging:
options:
max-size: 10m
max-file: "5"
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.openwebui.entrypoints=http"
- "traefik.http.routers.openwebui.rule=Host(`ai.${DOMAIN}`)"
- "traefik.http.routers.openwebui.middlewares=openwebui-https-redirect"
- "traefik.http.routers.openwebui-secure.entrypoints=https"
- "traefik.http.routers.openwebui-secure.rule=Host(`ai.${DOMAIN}`)"
- "traefik.http.routers.openwebui-secure.tls=true"
- "traefik.http.routers.openwebui-secure.tls.certresolver=le"
- "traefik.http.routers.openwebui-secure.service=openwebui"
- "traefik.http.routers.openwebui-secure.middlewares=authelia@docker" # Comment out if you do not want SSO with Authelia
- "traefik.http.services.openwebui.loadbalancer.server.port=8080"
it-tools:
image: ghcr.io/corentinth/it-tools:latest
container_name: it-tools
restart: always
env_file:
- .env
environment:
TZ: ${TZ}
networks:
- proxy
logging:
options:
max-size: 10m
max-file: "5"
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.ittools.entrypoints=http"
- "traefik.http.routers.ittools.rule=Host(`tools.${DOMAIN}`)"
- "traefik.http.routers.ittools.middlewares=ittools-https-redirect"
- "traefik.http.routers.ittools-secure.entrypoints=https"
- "traefik.http.routers.ittools-secure.rule=Host(`tools.${DOMAIN}`)"
- "traefik.http.routers.ittools-secure.tls=true"
- "traefik.http.routers.ittools-secure.tls.certresolver=le"
- "traefik.http.routers.ittools-secure.service=ittools"
- "traefik.http.routers.ittools-secure.middlewares=authelia@docker" # Comment out if you do not want SSO with Authelia
- "traefik.http.services.ittools.loadbalancer.server.port=80"
cyberchef:
image: ghcr.io/gchq/cyberchef:latest
container_name: cyberchef
restart: always
env_file:
- .env
environment:
TZ: ${TZ}
networks:
- proxy
logging:
options:
max-size: 10m
max-file: "5"
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.cyberchef.entrypoints=http"
- "traefik.http.routers.cyberchef.rule=Host(`chef.${DOMAIN}`)"
- "traefik.http.routers.cyberchef.middlewares=cyberchef-https-redirect"
- "traefik.http.routers.cyberchef-secure.entrypoints=https"
- "traefik.http.routers.cyberchef-secure.rule=Host(`chef.${DOMAIN}`)"
- "traefik.http.routers.cyberchef-secure.tls=true"
- "traefik.http.routers.cyberchef-secure.tls.certresolver=le"
- "traefik.http.routers.cyberchef-secure.service=cyberchef"
- "traefik.http.routers.cyberchef-secure.middlewares=authelia@docker" # Comment out if you do not want SSO with Authelia
- "traefik.http.services.cyberchef.loadbalancer.server.port=80"
netalertx:
image: jokobsk/netalertx:latest
container_name: netalertx
restart: always
env_file:
- .env
environment:
TZ: ${TZ}
volumes:
- ./data/netalertx/config:/app/config
- ./data/netalertx/db:/app/db
networks:
- proxy
logging:
options:
max-size: 10m
max-file: "5"
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.netalertx.entrypoints=http"
- "traefik.http.routers.netalertx.rule=Host(`netalertx.${DOMAIN}`)"
- "traefik.http.routers.netalertx.middlewares=netalertx-https-redirect"
- "traefik.http.routers.netalertx-secure.entrypoints=https"
- "traefik.http.routers.netalertx-secure.rule=Host(`netalertx.${DOMAIN}`)"
- "traefik.http.routers.netalertx-secure.tls=true"
- "traefik.http.routers.netalertx-secure.tls.certresolver=le"
- "traefik.http.routers.netalertx-secure.service=netalertx"
- "traefik.http.services.netalertx.loadbalancer.server.port=20211"
netdata:
image: netdata/netdata:stable
container_name: netdata
restart: always
env_file:
- .env
environment:
TZ: ${TZ}
cap_add:
- SYS_PTRACE
security_opt:
- apparmor:unconfined
volumes:
- ./data/netdata/config:/etc/netdata
- ./data/netdata/lib:/var/lib/netdata
- ./data/netdata/cache:/var/cache/netdata
- /etc/passwd:/host/etc/passwd:ro
- /etc/group:/host/etc/group:ro
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /etc/os-release:/host/etc/os-release:ro
networks:
- proxy
logging:
options:
max-size: 10m
max-file: "5"
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.netdata.entrypoints=http"
- "traefik.http.routers.netdata.rule=Host(`stats.${DOMAIN}`)"
- "traefik.http.routers.netdata.middlewares=netdata-https-redirect"
- "traefik.http.routers.netdata-secure.entrypoints=https"
- "traefik.http.routers.netdata-secure.rule=Host(`stats.${DOMAIN}`)"
- "traefik.http.routers.netdata-secure.tls=true"
- "traefik.http.routers.netdata-secure.tls.certresolver=le"
- "traefik.http.routers.netdata-secure.service=netdata"
- "traefik.http.routers.netdata-secure.middlewares=authelia@docker" # Comment out if you do not want SSO with Authelia
- "traefik.http.services.netdata.loadbalancer.server.port=19999"
guacd:
image: guacamole/guacd:latest
container_name: guacd
restart: always
networks:
- proxy
logging:
options:
max-size: 10m
max-file: "5"
guacamole:
image: guacamole/guacamole:latest
container_name: guacamole
restart: always
env_file:
- .env
environment:
TZ: ${TZ}
GUACD_HOSTNAME: guacd
depends_on:
- guacd
networks:
- proxy
logging:
options:
max-size: 10m
max-file: "5"
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.guacamole.entrypoints=http"
- "traefik.http.routers.guacamole.rule=Host(`guac.${DOMAIN}`)"
- "traefik.http.routers.guacamole.middlewares=guacamole-https-redirect"
- "traefik.http.routers.guacamole-secure.entrypoints=https"
- "traefik.http.routers.guacamole-secure.rule=Host(`guac.${DOMAIN}`)"
- "traefik.http.routers.guacamole-secure.tls=true"
- "traefik.http.routers.guacamole-secure.tls.certresolver=le"
- "traefik.http.routers.guacamole-secure.service=guacamole"
- "traefik.http.services.guacamole.loadbalancer.server.port=8080"
openspeedtest:
image: openspeedtest/latest:latest
container_name: openspeedtest
restart: always
env_file:
- .env
environment:
TZ: ${TZ}
networks:
- proxy
logging:
options:
max-size: 10m
max-file: "5"
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.openspeedtest.entrypoints=http"
- "traefik.http.routers.openspeedtest.rule=Host(`speed.${DOMAIN}`)"
- "traefik.http.routers.openspeedtest.middlewares=openspeedtest-https-redirect"
- "traefik.http.routers.openspeedtest-secure.entrypoints=https"
- "traefik.http.routers.openspeedtest-secure.rule=Host(`speed.${DOMAIN}`)"
- "traefik.http.routers.openspeedtest-secure.tls=true"
- "traefik.http.routers.openspeedtest-secure.tls.certresolver=le"
- "traefik.http.routers.openspeedtest-secure.service=openspeedtest"
- "traefik.http.routers.openspeedtest-secure.middlewares=authelia@docker" # Comment out if you do not want SSO with Authelia
- "traefik.http.services.openspeedtest.loadbalancer.server.port=3000"
dozzle:
image: amir20/dozzle:latest
container_name: dozzle
restart: always
env_file:
- .env
environment:
TZ: ${TZ}
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- proxy
logging:
options:
max-size: 10m
max-file: "5"
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.dozzle.entrypoints=http"
- "traefik.http.routers.dozzle.rule=Host(`logs.${DOMAIN}`)"
- "traefik.http.routers.dozzle.middlewares=dozzle-https-redirect"
- "traefik.http.routers.dozzle-secure.entrypoints=https"
- "traefik.http.routers.dozzle-secure.rule=Host(`logs.${DOMAIN}`)"
- "traefik.http.routers.dozzle-secure.tls=true"
- "traefik.http.routers.dozzle-secure.tls.certresolver=le"
- "traefik.http.routers.dozzle-secure.service=dozzle"
- "traefik.http.routers.dozzle-secure.middlewares=authelia@docker" # Comment out if you do not want SSO with Authelia
- "traefik.http.services.dozzle.loadbalancer.server.port=8080"
wud:
image: getwud/wud:latest
container_name: wud
restart: always
env_file:
- .env
environment:
TZ: ${TZ}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data/wud:/store
networks:
- proxy
logging:
options:
max-size: 10m
max-file: "5"
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.wud.entrypoints=http"
- "traefik.http.routers.wud.rule=Host(`wud.${DOMAIN}`)"
- "traefik.http.routers.wud.middlewares=wud-https-redirect"
- "traefik.http.routers.wud-secure.entrypoints=https"
- "traefik.http.routers.wud-secure.rule=Host(`wud.${DOMAIN}`)"
- "traefik.http.routers.wud-secure.tls=true"
- "traefik.http.routers.wud-secure.tls.certresolver=le"
- "traefik.http.routers.wud-secure.service=wud"
- "traefik.http.services.wud.loadbalancer.server.port=3000"
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
restart: always
env_file:
- .env
environment:
TZ: ${TZ}
PUID: 999
PGID: 999
volumes:
- ./data/jellyfin/config:/config
- ./data/jellyfin/media:/media
networks:
- proxy
logging:
options:
max-size: 10m
max-file: "5"
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.jellyfin.entrypoints=http"
- "traefik.http.routers.jellyfin.rule=Host(`media.${DOMAIN}`)"
- "traefik.http.routers.jellyfin.middlewares=jellyfin-https-redirect"
- "traefik.http.routers.jellyfin-secure.entrypoints=https"
- "traefik.http.routers.jellyfin-secure.rule=Host(`media.${DOMAIN}`)"
- "traefik.http.routers.jellyfin-secure.tls=true"
- "traefik.http.routers.jellyfin-secure.tls.certresolver=le"
- "traefik.http.routers.jellyfin-secure.service=jellyfin"
- "traefik.http.services.jellyfin.loadbalancer.server.port=8096"
networks:
proxy:
external: true
.env-template:
# Copy this file to .env and adjust values for your environment.
TZ=America/New_York
DOMAIN=domain.tld
# Email used for Let's Encrypt registration.
LE_EMAIL=admin@domain.tld
# Traefik dashboard basic auth hash.
# Generate with one of:
# htpasswd -nbB admin 'CHANGE_ME'
# htpasswd -nbm admin 'CHANGE_ME'
#
# If you paste directly into .env, keep single $ signs here.
BASIC_AUTH_USERS=admin:$apr1$replace$replacewithhtpasswdhash
# Uncomment and fill only if using ACME DNS challenge with Cloudflare
# CF_API_EMAIL=
# CF_API_KEY=
# CF_DNS_API_TOKEN=
# Uncomment and fill only if using ACME DNS challenge with DNSMadeEasy
# DNSMADEEASY_API_KEY=
# DNSMADEEASY_API_SECRET=
# Uncomment and fill only if using ACME DNS challenge with GoDaddy
# GODADDY_API_KEY=
# GODADDY_API_SECRET=
Watchtower docker-compose.yml (if desired):
services:
watchtower:
image: containrrr/watchtower:latest
container_name: watchtower
restart: unless-stopped
env_file:
- .env
environment:
TZ: ${TZ}
WATCHTOWER_LABEL_ENABLE: "true"
WATCHTOWER_CLEANUP: "true"
WATCHTOWER_INCLUDE_RESTARTING: "true"
WATCHTOWER_POLL_INTERVAL: "300"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: --label-enable --cleanup --interval 300
logging:
options:
max-size: 10m
max-file: "5"
All the instuctions are in the docker-compose.yml comments on top. Ping me if you have any questions. Hopefully this helps someone.
Thanks