Hi All,
Been using traefik for a while for my homelab and everything seems to work correctly, but wanted to check with the community if my setup is correct and if any security improvements could be made.
In addition I have some questions.
Labels
When adding taefik to a service, based on my setup, these are the labels I add. Do the TLS labels also need to added or are these loaded automatically? I have only have on container with them and all the rest without but not sure this is correct
labels:
- "traefik.enable=true"
- "traefik.http.routers.${APP_NAME}.entryPoints=https"
# is this needed or is it loaded automatically?
#- "traefik.http.routers.${APP_NAME}.tls=true"
#- "traefik.http.routers.${APP_NAME}.tls.certResolver=leresolver"
- "traefik.http.routers.${APP_NAME}.rule=Host(`${APP_SUBDOMAIN}.${GLOBAL_DOMAIN}`)"
- "traefik.http.routers.${APP_NAME}.middlewares=security-headers@file"
Forward Headers
I currently have the ForwardHeaders and TrustedIPs commented out. Is this benficial to have and if yes, how do I determine which IPs to put?
Security Headers
Am I missing anything important?
Below is my setup (I am using docker-socket-proxy, I use authentik for authentication, and also have nextcloud which required additional middlewares).
Thanks for and feedback you may have!
docker-compose.yml
services:
reverse-proxy:
image: traefik:latest
container_name: traefik
ports:
- "30080:80" # The HTTP port
- "30443:443" # The HTTPS port (is this needed?)
- "38080:8080" # The Web UI (enabled by --api.insecure=true)
env_file: stack.env
security_opt:
- no-new-privileges=true
volumes:
- ${GLOBAL_DATA_PATH}/traefik/traefik.yml:/traefik.yml:ro # Configuration with global options
- ${GLOBAL_DATA_PATH}/traefik/traefik-dynamic.yml:/traefik-dynamic.yml:ro # Configuration for with global dynamic options
- ${GLOBAL_DATA_PATH}/traefik/acme.json:/acme.json # LetsEncrypt ACME Configuration
- ${GLOBAL_DATA_PATH}/traefik/logs:/logs # Log File (optional)
labels:
- "com.centurylinklabs.watchtower.monitor-only=true" # Watchtower watch-only
healthcheck:
test: ["CMD", "traefik", "healthcheck", "--ping"]
restart: unless-stopped
networks:
- traefik-public
- socket-proxy # docker socket proxy
networks:
traefik-public:
external: true
socket-proxy:
external: true
traefik.yml
global:
checkNewVersion: true
sendAnonymousUsage: false
# Enable the API in insecure mode, which means that the API will be
# available directly on the entryPoint named traefik. If the entryPoint
# named traefik is not configured, it will be automatically created on
# port 8080.
api:
insecure: true
# Connection to docker host system (docker.sock)
# Attach labels to your containers and let Traefik do the rest!
# Traefik works with both Docker (standalone) Engine and Docker Swarm Mode.
# See: https://docs.traefik.io/providers/docker/
providers:
docker:
endpoint: "tcp://docker-socket-proxy:2375"
watch: true
exposedbydefault: false
network: socket-proxy
# filename is used for dynamic configuration
file:
filename: /traefik-dynamic.yml
# EntryPoints are the network entry points into Traefik. They define
# the port which will receive the packets, and whether to listen for
# TCP or UDP.
# See: https://docs.traefik.io/routing/entrypoints/
# NOTE: If a TLS section (i.e. any of its fields) is defined in your docker-compose.yml file,
# then the default configuration does not apply at all.
entryPoints:
# Standard HTTP redirects to HTTPS
http:
address: :80
http:
redirections:
entryPoint:
to: https
scheme: https
permanent: true
# should I have this? what IPs should I use
#forwardedHeaders:
# trustedIPs:
# - 127.0.0.1/32
# - 192.168.0.0/16
# - 172.16.0.0/12
# Standard HTTPS
https:
address: :443
http:
tls:
certResolver: leresolver
domains:
- main: MYDOMAIN.COM
# SANS are any other hostnames which Traefik should obtain a certificate for.
# If you are using DNS for LetsEncrypt, you can set a wildcard.
# Include all possible hostnames of this server.
sans:
- "*.MYDOMAIN.COM"
# should I have this? what IPs should I use
#forwardedHeaders:
# trustedIPs:
# - 127.0.0.1/32
# - 192.168.0.0/16
# - 172.16.0.0/12
# SMTP
smtp:
address: :25
# Enable ACME (Let's Encrypt): automatic SSL.
certificatesresolvers:
leresolver:
acme:
email: MY@EMAIL.COM
storage: acme.json
# Use HTTP-01 ACME challenge
# entryPoint: http
# Use a DNS-01 ACME challenge rather than HTTP-01 challenge.
# Mandatory for wildcard certificate generation.
dnsChallenge:
# Update this to your provider of choice and then ensure necessary variables are in the .env file to support it.
# see variable here: https://doc.traefik.io/traefik/https/acme/
provider: MYPROVIDER
delayBeforeCheck: 0
# A DNS server used to check whether the DNS is set up correctly before
# making the ACME request. Ideally a DNS server that isn't going to cache an old entry.
resolvers:
- "1.1.1.1:53"
# healthcheck
ping: {}
# enable logs
log:
filePath: "/logs/traefik.log"
# level: DEBUG
# enable access logs
accessLog:
filePath: "/logs/access.log"
retry: {}
traefik-dynamic.yml
# HTTP Middlewares Configuration
http:
middlewares:
# Security Headers Middleware
security-headers:
headers:
accessControlAllowMethods: 'GET, OPTIONS, PUT'
accesscontrolmaxage: 100
addVaryHeader: true
permissionsPolicy: "camera 'none'; geolocation 'none'; microphone 'none'; payment 'none'; usb 'none'; vr 'none';"
# The stsSeconds is the max-age of the Strict-Transport-Security header. If set to 0, would NOT include the header.
stsSeconds: 315360000
# The stsIncludeSubdomains is set to true, the includeSubDomains directive will be appended to the Strict-Transport-Security header.
stsIncludeSubdomains: true
# Set stsPreload to true to have the preload flag appended to the Strict-Transport-Security header.
stsPreload: true
# Set forceSTSHeader to true, to add the STS header even when the connection is HTTP.
forceSTSHeader: true
# Set frameDeny to true to add the X-Frame-Options header with the value of DENY.
frameDeny: true
# Set contentTypeNosniff to true to add the X-Content-Type-Options header with the value nosniff.
contentTypeNosniff: true
# Set browserXssFilter to true to add the X-XSS-Protection header with the value 1; mode=block.
browserXSSFilter: true
# The customFrameOptionsValue allows the X-Frame-Options header value to be set with a custom value. This overrides the FrameDeny option.
customFrameOptionsValue: 'SAMEORIGIN'
customRequestHeaders:
# The customResponseHeaders option lists the Header names and values to apply to the response.
X-Robots-Tag: 'noindex,nofollow,nosnippet,noarchive,notranslate,noimageindex'
customResponseHeaders:
server: ''
x-powered-by: ''
# Basic authentication middleware
simple-auth:
basicAuth:
users:
- "USERNAME:HASHEDPASSWORD"
# Authentik authentication
middlewares-authentik:
forwardAuth:
address: "http://server:9000/outpost.goauthentik.io/auth/traefik"
trustForwardHeader: true
authResponseHeaders:
- X-authentik-username
- X-authentik-groups
- X-authentik-email
- X-authentik-name
- X-authentik-uid
- X-authentik-jwt
- X-authentik-meta-jwks
- X-authentik-meta-outpost
- X-authentik-meta-provider
- X-authentik-meta-app
- X-authentik-meta-version
# The redirects for CalDAV or CardDAV does not work if Nextcloud is running behind a reverse proxy.
# https://docs.nextcloud.com/server/24/admin_manual/configuration_server/reverse_proxy_configuration.html
nextcloud-redirectregex-dav:
redirectRegex:
permanent: true
regex: "https://(.*)/.well-known/(card|cal)dav"
replacement: "https://${1}/remote.php/dav/"
# https://docs.nextcloud.com/server/24/admin_manual/issues/general_troubleshooting.html#service-discovery
nextcloud-redirectregex-other:
redirectRegex:
permanent: true
regex: "https://(.*)/.well-known/(webfinger|nodeinfo)"
replacement: "https://${1}/index.php/.well-known/{$2}"
# For linuxserver-nextcloud container
serversTransports:
ignore-cert:
insecureSkipVerify: true
# Set secure options by disabling insecure older TLS/SSL versions and insecure ciphers.
# SNIStrict disabled leaves TLS1.0 open. If you have problems with older clients, you can may need to relax these minimums.
# This configuration will give you an A+ SSL security score supporting TLS1.2 and TLS1.3
tls:
options:
default:
sniStrict: true
minVersion: VersionTLS12
curvePreferences:
- secp521r1
- secp384r1
cipherSuites:
- 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_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
mintls13:
minVersion: VersionTLS13