LemonSec/traefik/dynamic/middlewares.yml

129 lines
4.2 KiB
YAML

http:
middlewares:
# ============================================================================
# SECURITY MIDDLEWARES
# ============================================================================
# Security Headers - Comprehensive hardening
security-headers:
headers:
browserXssFilter: true
contentTypeNosniff: true
forceSTSHeader: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000 # 1 year
customFrameOptionsValue: "SAMEORIGIN"
contentSecurityPolicy: "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:; media-src 'self'; object-src 'none'; frame-ancestors 'self'; base-uri 'self'; form-action 'self';"
customResponseHeaders:
X-Robots-Tag: "noindex, nofollow"
X-Download-Options: "noopen"
X-Permitted-Cross-Domain-Policies: "none"
Permissions-Policy: "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()"
Referrer-Policy: "strict-origin-when-cross-origin"
sslProxyHeaders:
X-Forwarded-Proto: https
# Rate Limiting - External
rate-limit:
rateLimit:
average: 100
burst: 200
period: 1m
# Rate Limiting - Internal (more lenient)
rate-limit-internal:
rateLimit:
average: 300
burst: 500
period: 1m
# Rate Limiting - Strict (for auth endpoints)
rate-limit-strict:
rateLimit:
average: 10
burst: 20
period: 1m
# Geo-blocking (optional - configure countries as needed)
geo-block:
plugin:
geo-block:
allowLocalRequests: true
logLocalRequests: false
logAllowedRequests: false
logApiRequests: true
api: "https://get.geojs.io/v1/ip/country/{ip}"
apiTimeoutMs: 150
cacheSize: 1000
forceMonthlyUpdate: true
allowUnknownCountries: false
unknownCountryApiResponse: "nil"
blackListMode: false
# Countries allowed (ISO 3166-1 alpha-2)
countries:
- SE # Sweden
- NO # Norway
- DK # Denmark
- FI # Finland
# Add more as needed
# Compress responses
compress:
compress:
excludedContentTypes:
- text/event-stream
# Redirect to HTTPS (fallback)
redirect-https:
redirectScheme:
scheme: https
permanent: true
# Add X-Forwarded headers
forwarded-headers:
headers:
customRequestHeaders:
X-Forwarded-Port: "443"
sslProxyHeaders:
X-Forwarded-Proto: https
# Real IP from Cloudflare
cloudflare-real-ip:
plugin:
cloudflarewarp:
disableDefault: false
# ============================================================================
# AUTHENTICATION MIDDLEWARES
# ============================================================================
# Authelia forward auth (from Docker labels)
authelia:
forwardAuth:
address: "http://authelia:9091/api/verify?rd=https://auth.lemonlink.eu/"
trustForwardHeader: true
authResponseHeaders:
- Remote-User
- Remote-Groups
- Remote-Name
- Remote-Email
# Basic Auth fallback (for emergencies)
basic-auth:
basicAuth:
users:
# Generate with: htpasswd -nb admin yourpassword | sed -e s/\$/\$\$/g
# Replace $ with $$ in the hash for YAML
- "admin:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/" # admin:admin - CHANGE THIS!
realm: "LemonLink Secured"
# ============================================================================
# CROWDSEC MIDDLEWARE (enable when using crowdsec-bouncer-traefik container)
# ============================================================================
# crowdsec-bouncer:
# forwardAuth:
# address: http://crowdsec-bouncer-traefik:8080/api/v1/forwardAuth
# trustForwardHeader: true