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