First I want to apologise, as I am still learning a lot around how Traefik (and Docker) work and the below is (especially to those who know what they're doing) a bit of a mess and a combination of multiple different tutorials, guides and trials.
Whilst I have a working container using Cloudflare DNS and my external domain running v2.10.5, it uses CLI within the docker compose which I have learnt has limitations which I now want to overcome.
I want to be able to route (using labels) BOTH for both my external domain (eg. dockerapp.mydomain.com
) and use it for my local network (eg. dockerapp.my.lan
) with certificates.
✓ Currently *.mydomain.com
works perfectly with certificate from Cloudflare
✓ *.my.lan
routes correctly (forwarding setup in Adguard) using labels
✗ Haven't been able to get/use a certificate made via mkcert for *.my.lan
(Tried using smallstep/step-ca and another online service but decided to simplify)
☐ Note: I intend to add Authelia etc and further expand the security but only once I have the base working)
If anyone is able to help indicate what I am missing, that would be greatly appreciated. I sort of know the logic of what I want to achieve here (using different routers and defining when to use certresolver=dns-cloudflare
and when I want to fall-back to a locally stored one) but I haven't been able to achieve it yet.
I know it is something to do with where I am declaring what, and how my labels work, but despite 30+ versions and variations, no joy.
Q?: Given I have a semi working version for essential external sites and I'm asking for help here, I'm also questioning if for this replacement setup I should use Traefik 3?
Here is where I am so far:
Host folders:
$APPDATA/traefikv2-pluslocal
├──acme
│ └──acme.json
├──config
│ └─traefik.yml
└──rules
├─middlewares-chains.yml
├─middlewares.yml
├─routers.yml
└─tls.yml
$LOGS/traefikv2-pluslocal
├─access.log
└─traefik.log
$SHARED
└─.htpasswd
$CERTS/LAN:
├─cert.pem
└─key.pem
Traefik 'docker-compose' (via Portainer Stack)
version: "3.9"
networks:
default:
driver: bridge
t2_proxy:
name: t2_proxy
driver: bridge
ipam:
config:
- subnet: 172.19.0.0/24
services:
############################# FRONTENDS
# Traefik 2 - Reverse Proxy
traefik:
container_name: traefik
image: traefik:2.10.5
networks:
t2_proxy:
ipv4_address: 172.19.0.254
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:
- /var/run/docker.sock:/var/run/docker.sock:ro # Change to Proxy once working
- $CERTS/LAN:/lancerts
- $SHARED:/shared
- $LOGS/traefikv2-pluslocal:/logs
- $APPDATA/traefikv2-pluslocal/config:/etc/traefik/ # config file
- $APPDATA/traefikv2-pluslocal/rules:/rules # file provider directory
- $APPDATA/traefikv2-pluslocal/acme/acme.json:/acme.json # cert location
- $APPDATA/acme/acme-local.json:/acme-local.json # secondary/local cert? Unsure if needed?
environment:
- TZ=$TZ
- CF_API_EMAIL=$CLOUDFLARE_EMAIL
- CF_API_KEY=$CLOUDFLARE_API_KEY
- DOMAINNAME
- PUID=1000
- PGID=1000
security_opt:
- no-new-privileges:true
env_file:
- stack.env
restart: always
labels:
- "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`)"
- "traefik.http.routers.traefik-rtr.tls=true"
# Traefik Local Router
- "traefik.http.routers.traefik-local-rtr.entrypoints=https"
- "traefik.http.routers.traefik-local-rtr.rule=Host(`traefik.$LOCAL_DOMAIN`)"
- "traefik.http.routers.traefik-local-rtr.tls=true"
# Certs
- "traefik.http.routers.traefik-rtr.tls.certresolver=dns-cloudflare" # Unsure if needed here? Have tried with and without
- "traefik.http.routers.traefik-rtr.tls.domains[0].main=$DOMAINNAME"
- "traefik.http.routers.traefik-rtr.tls.domains[0].sans=*.$DOMAINNAME"
- "traefik.http.routers.traefik-local-rtr.tls.domains[1].main=$LOCAL_DOMAIN" # Cert for second domain?
- "traefik.http.routers.traefik-local-rtr.tls.domains[1].sans=*.$LOCAL_DOMAIN" # Cert for second domain
## Services - API
- "traefik.http.routers.traefik-rtr.service=api@internal"
- "traefik.http.routers.traefik-local-rtr.service=api@internal"
## Middlewares
- "traefik.http.routers.traefik-rtr.middlewares=chain-basic-auth@file"
- "traefik.http.routers.traefik-local-rtr.middlewares=chain-basic-auth@file"
traefik.yml
global:
checkNewVersion: true
sendAnonymousUsage: true
serversTransport:
insecureSkipVerify: true
entryPoints:
http: # HTTP non-secure Entrypoint
address: :80
forwardedHeaders:
trustedIPs:
# Cloudflare IPs
- 103.21.244.0/22
# (List shortened for this post)
# Local IPs
- 10.0.0.0/8 #LocalDefault
- 127.0.0.1/32 #Localhost
- 192.168.0.0/16 #Local Network
# Docker Networks
- 172.18.0.0/16
- 172.19.0.0/16 #t2_proxy
# (List shortened for this post)
http:
redirections:
entryPoint:
to: https
scheme: https
https: # Secure Entrypoint
address: :443
forwardedHeaders:
trustedIPs:
# Cloudflare IPs
- 103.21.244.0/22
# (List shortened for this post)
# Local IPs
- 10.0.0.0/8 #LocalDefault
- 127.0.0.1/32 #Localhost
- 192.168.0.0/16 #Local Network
# Docker Networks
- 172.18.0.0/16
- 172.19.0.0/16 #t2_proxy
# (List shortened for this post)
http:
tls:
options: tls-opts@file
certResolver: dns-cloudflare
domains:
- main: mydomain.com
sans:
- '*.mydomain.com'
api:
dashboard: true
debug: true
ping: {}
log:
level: DEBUG
filePath: "/logs/traefik.log"
accessLog:
filePath: "/logs/access.log"
bufferingSize: 100
filters:
statusCodes:
- "204-299"
- "400-499"
- "500-599"
providers:
docker:
watch: true
endpoint: "unix:///var/run/docker.sock" # TODO Update to socket proxy once working
exposedByDefault: false
network: "t2_proxy"
swarmMode: false
file:
directory: "/rules" #Dynamic config files
watch: true
certificatesResolvers:
dns-cloudflare:
acme:
email: "myemail@mydomain.com"
storage: "/acme.json"
dnsChallenge:
provider: "cloudflare"
resolvers:
- "1.1.1.1:53"
- "1.0.0.1:53"
middlewares.yml
http:
middlewares:
middlewares-basic-auth:
basicAuth:
usersFile: "/shared/.htpasswd" # be sure to mount the volume through docker-compose.yml
realm: "Traefik 2 Basic Auth"
middlewares-rate-limit:
rateLimit:
average: 100
burst: 50
middlewares-https-redirectscheme:
redirectScheme:
scheme: https
permanent: true
middlewares-secure-headers:
headers:
accessControlAllowMethods:
- GET
- OPTIONS
- PUT
accessControlMaxAge: 100
hostsProxyHeaders:
- "X-Forwarded-Host"
stsSeconds: 63072000
stsIncludeSubdomains: true
stsPreload: true
forceSTSHeader: true
#customFrameOptionsValue: "allow-from https:{{env "DOMAINNAME"}}" #CSP takes care of this but may be needed for organizr.
contentTypeNosniff: true
browserXssFilter: true
# sslForceHost: true # add sslHost to all of the services
# sslHost: "{{env "DOMAINNAME"}}"
referrerPolicy: "same-origin"
permissionsPolicy: "camera=(), microphone=(), geolocation=(), payment=(), usb=(), vr=()"
customResponseHeaders:
X-Robots-Tag: "none,noarchive,nosnippet,notranslate,noimageindex,"
server: ""
# https://community.traefik.io/t/how-to-make-websockets-work-with-traefik-2-0-setting-up-rancher/1732
# X-Forwarded-Proto: "https"
middlewares-compress:
compress: {}
middlewares-local-ipwhitelist: # Only Allow Local networks
ipWhiteList:
sourceRange:
- 10.0.0.0/8 #LocalDefault
- 127.0.0.1/32 #Localhost
- 192.168.0.0/16 #Local Network
# Docker Networks
- 172.18.0.0/16
# (List shortened for this post)
routers.yml
http:
routers:
localrouter:
entryPoints:
- "https"
rule: "Host(`my.lan`)"
middlewares:
- "chain-no-auth"
tls:
domains:
- "my.lan"
- "*.my.lan"
http-catchall:
entryPoints:
- "http"
rule: HostRegexp(`{host:.+}`)"
middlewares:
- "redirect-to-https"
serversTransports:
localtransport:
serverName: localserver
certificates:
- certFile: /lancerts/cert.pem
keyFile: /lancerts/key.pem
tls.yml
tls:
certificates:
- certFile: /lancerts/cert.pem
keyFile: /lancerts/key.pem
options:
tls-opts:
minVersion: VersionTLS12
cipherSuites:
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
- TLS_FALLBACK_SCSV # Client is doing version fallback. See RFC 7507
curvePreferences:
- CurveP521
- CurveP384
sniStrict: true
middlewares-chains.yml
http:
middlewares:
chain-no-auth:
chain:
middlewares:
- middlewares-rate-limit
- middlewares-https-redirectscheme
- middlewares-secure-headers
- middlewares-compress
chain-basic-auth:
chain:
middlewares:
- middlewares-rate-limit
- middlewares-https-redirectscheme
- middlewares-secure-headers
- middlewares-basic-auth
- middlewares-compress
chain-local-no-auth:
chain:
middlewares:
- middlewares-rate-limit
- middlewares-https-redirectscheme
- middlewares-secure-headers
- middlewares-compress
- middlewares-local-ipwhitelist
chain-local-basic-auth:
chain:
middlewares:
- middlewares-rate-limit
- middlewares-https-redirectscheme
- middlewares-secure-headers
- middlewares-basic-auth
- middlewares-compress
- middlewares-local-ipwhitelist
Example Service 'docker-compose' (via Portainer Stack)
---
version: '3'
services:
overseerr:
image: overseerr
container_name: overseerr
│
ports:
- 28055:5055
restart: unless-stopped
env_file:
- stack.env
labels:
- "traefik.enable=true"
## HTTP Routers
- "traefik.http.routers.overseerr-rtr.entrypoints=https"
- "traefik.http.routers.overseerr-rtr.rule=Host(`request.$DOMAINNAME`,`request.$LOCAL_DOMAIN`)"
- "traefik.http.routers.overseerr-rtr.tls=true"
## Middlewares
- "traefik.http.routers.overseerr-rtr.middlewares=chain-no-auth@file"
## HTTP Services
- "traefik.http.routers.overseerr-rtr.service=overseerr-svc"
- "traefik.http.services.overseerr-svc.loadbalancer.server.port=5055"
networks:
default:
external: true
name: t2_proxy