###########################
version: "3.9"
####################
networks:
default:
driver: bridge
t2_proxy:
name: t2_proxy
driver: bridge
ipam:
config:
- subnet: 192.168.2.0/24
socket_proxy:
name: socket_proxy
driver: bridge
ipam:
config:
- subnet: 192.168.3.0/24
####################
secrets:
my_email:
file: $DOCKERDIR/secrets/my_email
cloudflare_email:
file: $DOCKERDIR/secrets/cloudflare_email
cloudflare_api_key:
file: $DOCKERDIR/secrets/cloudflare_api_key
cloudflare_api_token:
file: $DOCKERDIR/secrets/cloudflare_api_token
mysql_root_password:
file: $DOCKERDIR/secrets/mysql_root_password
redis_password:
file: $DOCKERDIR/secrets/redis_password
authelia_jwt_secret:
file: $DOCKERDIR/secrets/authelia_jwt_secret
authelia_session_secret:
file: $DOCKERDIR/secrets/authelia_session_secret
authelia_storage_mysql_password:
file: $DOCKERDIR/secrets/authelia_storage_mysql_password
authelia_session_redis_password:
file: $DOCKERDIR/secrets/authelia_session_redis_password
authelia_notifier_smtp_password:
file: $DOCKERDIR/secrets/authelia_notifier_smtp_password
authelia_duo_api_secret_key:
file: $DOCKERDIR/secrets/authelia_duo_api_secret_key
authelia_storage_encryption_key:
file: $DOCKERDIR/secrets/authelia_storage_encryption_key
####################
########################### EXTENSION FIELDS
# Common environment values
x-environment: &default-tz-puid-pgid
TZ: $TZ
PUID: $PUID
PGID: $PGID
# Proxy Network and Security
x-network-and-security: &network-and-security
networks:
- t2_proxy
security_opt:
- no-new-privileges:true
# Keys common to some of the services in basic-services.txt
x-common-keys-basic: &common-keys-basic
<<: *network-and-security
restart: always
# profiles:
# - basic
# Keys common to some of the dependent services/apps
x-common-keys-apps: &common-keys-apps
<<: *network-and-security
restart: unless-stopped
# profiles:
# - apps
# Keys common to some of the services in media-services.txt
x-common-keys-media: &common-keys-media
<<: *network-and-security
restart: "no"
# profiles:
# - media
####################
########################### SERVICES
services:
traefik:
<<: *common-keys-basic # See EXTENSION FIELDS at the top
container_name: traefik
image: traefik:2.9.6
command: # CLI arguments
- --global.checkNewVersion=true
- --global.sendAnonymousUsage=false
- --entryPoints.http.address=:80
- --entryPoints.https.address=:443
# Allow these IPs to set the X-Forwarded-* headers - Cloudflare IPs: https://www.cloudflare.com/ips/
- --entrypoints.https.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22
- --entryPoints.traefik.address=:8080
# - --entryPoints.ping.address=:8081
- --api=true
# - --api.insecure=true
- --api.dashboard=true
#- --ping=true
#- --pilot.token=$TRAEFIK_PILOT_TOKEN
# - --serversTransport.insecureSkipVerify=true
- --log=true
- --log.level=DEBUG # (Default: error) DEBUG, INFO, WARN, ERROR, FATAL, PANIC
- --accessLog=true
- --accessLog.filePath=/traefik.log
- --accessLog.bufferingSize=100 # Configuring a buffer of 100 lines
- --accessLog.filters.statusCodes=400-499
- --providers.docker=true
# - --providers.docker.endpoint=unix:///var/run/docker.sock # Use Docker Socket Proxy instead for improved security
- --providers.docker.endpoint=tcp://socket-proxy:2375
# Automatically set Host rule for services
# - --providers.docker.defaultrule=Host(`{{ index .Labels "com.docker.compose.service" }}.$DOMAINNAME0`)
- --providers.docker.exposedByDefault=false
# - --entrypoints.https.http.middlewares=chain-oauth@file
# - --entrypoints.https.http.tls.options=tls-opts@file
# Add dns-cloudflare as default certresolver for all services. Also enables TLS and no need to specify on individual services
- --entrypoints.https.http.tls.certresolver=dns-cloudflare
- --entrypoints.https.http.tls.domains[0].main=$DOMAINNAME
- --entrypoints.https.http.tls.domains[0].sans=*.$DOMAINNAME
# - --entrypoints.https.http.tls.domains[1].main=$DOMAINNAME1 # Pulls main cert for second domain
# - --entrypoints.https.http.tls.domains[1].sans=*.$DOMAINNAME1 # Pulls wildcard cert for second domain
- --providers.docker.network=t2_proxy
- --providers.docker.swarmMode=false
- --providers.file.directory=/rules # Load dynamic configuration from one or more .toml or .yml files in a directory
# - --providers.file.filename=/path/to/file # Load dynamic configuration from a file
- --providers.file.watch=true # Only works on top level files in the rules folder
# - --certificatesResolvers.dns-cloudflare.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory # LetsEncrypt Staging Server - uncomment when testing
- --certificatesResolvers.dns-cloudflare.acme.email=$CLOUDFLARE_EMAIL
- --certificatesResolvers.dns-cloudflare.acme.storage=/acme.json
- --certificatesResolvers.dns-cloudflare.acme.dnsChallenge.provider=cloudflare
- --certificatesResolvers.dns-cloudflare.acme.dnsChallenge.resolvers=1.1.1.1:53,1.0.0.1:53
- --certificatesResolvers.dns-cloudflare.acme.dnsChallenge.delayBeforeCheck=90 # To delay DNS check and reduce LE hitrate
networks:
t2_proxy:
ipv4_address: $TRAEFIK_IP # You can specify a static IP
socket_proxy:
#healthcheck:
# test: ["CMD", "traefik", "healthcheck", "--ping"]
# interval: 5s
# retries: 3
ports:
- target: 80
published: 80
protocol: tcp
mode: host
- target: 443
published: 443
protocol: tcp
mode: host
# - target: 8080
# published: 8080
# protocol: tcp
# mode: host
volumes:
- $DOCKERDIR/traefik2/rules:/rules # file provider directory
# - /var/run/docker.sock:/var/run/docker.sock:ro # Use Docker Socket Proxy instead for improved security
- $DOCKERDIR/traefik2/acme/acme.json:/acme.json # cert location - you must touch this file and change permissions to 600
- $DOCKERDIR/traefik2/traefik.log:/traefik.log # for fail2ban - make sure to touch file before starting container
#- $DOCKERDIR/shared:/shared
environment:
- CF_API_EMAIL_FILE=/run/secrets/cloudflare_email
- CF_API_KEY_FILE=/run/secrets/cloudflare_api_key
secrets:
- cloudflare_email
- cloudflare_api_key
labels:
#- "autoheal=true"
- "traefik.enable=true"
# HTTP-to-HTTPS Redirect
- "traefik.http.routers.http-catchall.entrypoints=http"
- "traefik.http.routers.http-catchall.rule=HostRegexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
# HTTP Routers
- "traefik.http.routers.traefik-rtr.entrypoints=https"
- "traefik.http.routers.traefik-rtr.rule=Host(`traefik.$DOMAINNAME`)"
## Services - API
- "traefik.http.routers.traefik-rtr.service=api@internal"
## Middlewares
- "traefik.http.routers.traefik-rtr.middlewares=chain-authelia@file"
###################################
# Docker Socket Proxy - Security Enchanced Proxy for Docker Socket
socket-proxy:
<<: *common-keys-basic # See EXTENSION FIELDS at the top
container_name: socket-proxy
image: tecnativa/docker-socket-proxy
networks:
socket_proxy:
ipv4_address: $SOCKETPROXY_IP # You can specify a static IP
privileged: true
ports:
- "127.0.0.1:2375:2375" # Port 2375 should only ever get exposed to the internal network. When possible use this line.
# I use the next line instead, as I want portainer to manage multiple docker endpoints within my home network.
# - "2375:2375"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
environment:
- LOG_LEVEL=info # debug,info,notice,warning,err,crit,alert,emerg
## Variables match the URL prefix (i.e. AUTH blocks access to /auth/* parts of the API, etc.).
# 0 to revoke access.
# 1 to grant access.
## Granted by Default
- EVENTS=1
- PING=1
- VERSION=1
## Revoked by Default
# Security critical
- AUTH=0
- SECRETS=0
- POST=1 # Watchtower
# Not always needed
- BUILD=0
- COMMIT=0
- CONFIGS=0
- CONTAINERS=1 # Traefik, portainer, etc.
- DISTRIBUTION=0
- EXEC=0
- IMAGES=1 # Portainer
- INFO=1 # Portainer
- NETWORKS=1 # Portainer
- NODES=0
- PLUGINS=0
- SERVICES=1 # Portainer
- SESSION=0
- SWARM=0
- SYSTEM=0
- TASKS=1 # Portainer
- VOLUMES=1 # Portainer
###################################
# Authelia
authelia:
container_name: authelia
# Check this before upgrading: https://github.com/authelia/authelia/blob/master/BREAKING.md
image: authelia/authelia:4.37.3
restart: always
# profiles:
# - core
# networks:
# - t2_proxy
networks:
t2_proxy:
ipv4_address: $AUTHELIA_IP # You can specify a static IP
depends_on:
- mariadb
- redis
# ports:
# - "9091:9091"
volumes:
- $DOCKERDIR/authelia:/config
# - $DOCKERDIR/authelia/notifications.txt:/config/notifications.txt
environment:
- TZ=$TZ
- AUTHELIA_JWT_SECRET_FILE=/run/secrets/authelia_jwt_secret
- AUTHELIA_SESSION_SECRET_FILE=/run/secrets/authelia_session_secret
- AUTHELIA_STORAGE_MYSQL_PASSWORD_FILE=/run/secrets/authelia_storage_mysql_password
- AUTHELIA_SESSION_REDIS_PASSWORD_FILE=/run/secrets/authelia_session_redis_password
- AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE=/run/secrets/authelia_notifier_smtp_password
- AUTHELIA_DUO_API_SECRET_KEY_FILE=/run/secrets/authelia_duo_api_secret_key
- AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE=/run/secrets/authelia_storage_encryption_key
secrets:
- authelia_jwt_secret
- authelia_session_secret
- authelia_storage_mysql_password
- authelia_notifier_smtp_password
- authelia_duo_api_secret_key
- authelia_storage_encryption_key
- authelia_session_redis_password
labels:
- "traefik.enable=true"
## HTTP Routers
- "traefik.http.routers.authelia-rtr.entrypoints=https"
- "traefik.http.routers.authelia-rtr.rule=Host(`authelia.$DOMAINNAME`)"
- "traefik.http.routers.authelia-rtr.tls=true"
## Middlewares
- "traefik.http.routers.authelia-rtr.middlewares=chain-authelia@file"
## HTTP Services
- "traefik.http.routers.authelia-rtr.service=authelia-svc"
- "traefik.http.services.authelia-svc.loadbalancer.server.port=9091"
###################################
# MariaDB - MySQL Database
# After starting container for first time dexec and mysqladmin -u root password <password>
mariadb:
<<: *common-keys-basic # See EXTENSION FIELDS at the top
container_name: mariadb
image: lscr.io/linuxserver/mariadb
networks:
t2_proxy:
ipv4_address: $MARIADB_IP # You can specify a static IP
volumes:
- $DOCKERDIR/mariadb/data:/config
environment:
- PUID=$PUID
- PGID=$PGID
- TZ=$TZ
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql_root_password
secrets:
- mysql_root_password
###################################
# Redis - Key-value Store
redis:
<<: *common-keys-basic # See EXTENSION FIELDS at the top
container_name: redis
image: redis:latest
environment:
- REDIS_PASSWORD_FILE=/run/secrets/redis_password
secrets:
- redis_password
entrypoint: redis-server --appendonly yes --requirepass $REDIS_PASSWORD --maxmemory 512mb --maxmemory-policy allkeys-lru
networks:
t2_proxy:
ipv4_address: $REDIS_IP # You can specify a static IP
# ports:
# - "$REDIS_PORT:6379"
volumes:
- $DOCKERDIR/redis/data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
###################################
nextcloud:
image: nextcloud:25.0.2
restart: unless-stopped
container_name: nextcloud
networks:
t2_proxy:
ipv4_address: $NEXTCLOUD_IP # You can specify a static IP
volumes:
- /home/leo/docker/nextcloud/data:/var/www/html
depends_on:
- mariadb
- redis
environment:
- MYSQL_HOST=mariadb
- MYSQL_DATABASE=$NEXTCLOUD_MYSQL_DATABASE
- MYSQL_USER=$NEXTCLOUD_MYSQL_USER
- MYSQL_PASSWORD=$NEXTCLOUD_MYSQL_PASSWORD
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql_root_password
- NEXTCLOUD_TRUSTED_DOMAINS=domainname.com
- REDIS_HOST=redis
# - REDIS_PORT=6379
- REDIS_PASSWORD_FILE=/run/secrets/redis_password
- TRUSTED_PROXIES=192.168.2.10
- OVERWRITEHOST=domainname.com
- OVERWRITEPROTOCOL=https
# - OVERWRITEPROTOCOL=https
# - APACHE_DISABLE_REWRITE_IP=1
# - APACHE_IP_BINDING=127.0.0.1
# - APACHE_PORT=11000
secrets:
- redis_password
- mysql_root_password
labels:
- "traefik.enable=true"
- "traefik.docker.network=t2_proxy"
- "traefik.http.routers.nextcloud.entrypoints=http"
- "traefik.http.routers.nextcloud.rule=Host(`$DOMAINNAME`,`www.$DOMAINNAME`)"
- "traefik.http.routers.nextcloud.tls=true"
- "traefik.http.routers.nextcloud.middlewares=nextcloud,nextcloud-redirect"
- "traefik.http.routers.https-nextcloud.entrypoints=https"
- "traefik.http.routers.https-nextcloud.rule=Host(`$DOMAINNAME`,`www.$DOMAINNAME`)"
- "traefik.http.routers.https-nextcloud.tls=true"
- "traefik.http.routers.https-nextcloud.middlewares=nextcloud,nextcloud-redirect"
- "traefik.http.middlewares.nextcloud.headers.stsSeconds=155520011"
- "traefik.http.middlewares.nextcloud.headers.stsIncludeSubdomains=true"
- "traefik.http.middlewares.nextcloud.headers.stsPreload=true"
- "traefik.http.middlewares.nextcloud-redirect.redirectregex.regex=/.well-known/(card|cal)dav"
- "traefik.http.middlewares.nextcloud-redirect.redirectregex.replacement=/remote.php/dav/"
- "traefik.http.middlewares.nextcloud-redirect.redirectregex.permanent=true"
- "traefik.http.services.nextcloud.loadbalancer.server.port=80"
- "traefik.http.routers.nextcloud.service=nextcloud"