Skip to content

Template.yml

HHF Technology edited this page May 24, 2025 · 2 revisions
# Default middleware templates
middlewares:
  # Authentication middlewares
  - id: authelia
    name: Authelia
    type: forwardAuth
    config:
      address: "http://authelia:9091/api/authz/forward-auth"
      trustForwardHeader: true
      authResponseHeaders:
        - "Remote-User"
        - "Remote-Groups"
        - "Remote-Name"
        - "Remote-Email"

  - id: authentik
    name: Authentik
    type: forwardAuth
    config:
      address: "http://authentik:9000/outpost.goauthentik.io/auth/traefik"
      trustForwardHeader: true
      authResponseHeaders:
        - "X-authentik-username"
        - "X-authentik-groups"
        - "X-authentik-email"
        - "X-authentik-name"
        - "X-authentik-uid"

  - id: tinyauth
    name: Tiny Auth
    type: forwardAuth
    config:
      address: "http://tinyauth:10000/api/auth/traefik"      

  - id: basic-auth
    name: Basic Auth
    type: basicAuth
    config:
      users:
        - "admin:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"

  - id: digest-auth
    name: Digest Auth
    type: digestAuth
    config:
      users:
        - "test:traefik:a2688e031edb4be6a3797f3882655c05"

  - id: jwt-auth
    name: JWT Authentication
    type: forwardAuth
    config:
      address: "http://jwt-auth:8080/verify"
      trustForwardHeader: true
      authResponseHeaders:
        - "X-JWT-Sub"
        - "X-JWT-Name"
        - "X-JWT-Email"

  # Security middlewares
  - id: ip-whitelist
    name: IP Whitelist
    type: ipWhiteList
    config:
      sourceRange:
        - "127.0.0.1/32"
        - "192.168.1.0/24"
        - "10.0.0.0/8"

  - id: ip-allowlist
    name: IP Allow List
    type: ipAllowList
    config:
      sourceRange:
        - "127.0.0.1/32"
        - "192.168.1.0/24"
        - "10.0.0.0/8"

  - id: rate-limit
    name: Rate Limit
    type: rateLimit
    config:
      average: 100
      burst: 50

  - id: headers-standard
    name: Standard Security Headers
    type: headers
    config:
      accessControlAllowMethods:
        - GET
        - OPTIONS
        - PUT
      browserXssFilter: true
      contentTypeNosniff: true
      customFrameOptionsValue: "SAMEORIGIN"
      customResponseHeaders:
        X-Forwarded-Proto: "https"
        X-Robots-Tag: "none,noarchive,nosnippet,notranslate,noimageindex"
        Server: ""  # Empty string to remove Server header
        X-Powered-By: ""  # Empty string to remove X-Powered-By header
      forceSTSHeader: true
      hostsProxyHeaders:
        - X-Forwarded-Host
      permissionsPolicy: "camera=(), microphone=(), geolocation=(), payment=(), usb=(), vr=()"
      referrerPolicy: "same-origin"
      sslProxyHeaders:
        X-Forwarded-Proto: "https"
      stsIncludeSubdomains: true
      stsPreload: true
      stsSeconds: 63072000

  - id: in-flight-req
    name: In-Flight Request Limiter
    type: inFlightReq
    config:
      amount: 10
      sourceCriterion:
        ipStrategy:
          depth: 2
          excludedIPs:
            - "127.0.0.1/32"
        requestHost: true  # Added this option shown in the examples

  - id: pass-tls-cert
    name: Pass TLS Client Certificate
    type: passTLSClientCert
    config:
      pem: true

  # Path manipulation middlewares
  - id: add-prefix
    name: Add Prefix
    type: addPrefix
    config:
      prefix: "/api"

  - id: strip-prefix
    name: Strip Prefix
    type: stripPrefix
    config:
      prefixes:
        - "/api"
        - "/v1"
      forceSlash: true


  - id: replace-path
    name: Replace Path
    type: replacePath
    config:
      path: "/foo"

  - id: replace-path-regex
    name: Replace Path Regex
    type: replacePathRegex
    config:
      regex: "^/foo/(.*)"
      replacement: "/bar/$1"

  # Redirect middlewares
  - id: redirect-regex
    name: Redirect Regex
    type: redirectRegex
    config:
      regex: "^http://(.*)$"
      replacement: "https://${1}"
      permanent: true

  - id: redirect-scheme
    name: Redirect to HTTPS
    type: redirectScheme
    config:
      scheme: "https"
      port: "443"
      permanent: true

  # Content processing middlewares
  - id: compress
    name: Compress Response
    type: compress
    config:
      excludedContentTypes:
        - text/event-stream
      includedContentTypes:
        - text/html
        - text/plain
        - application/json
      minResponseBodyBytes: 1024
      encodings:
        - gzip
        - br

  - id: buffering
    name: Request/Response Buffering
    type: buffering
    config:
      maxRequestBodyBytes: 5000000
      memRequestBodyBytes: 2000000
      maxResponseBodyBytes: 5000000
      memResponseBodyBytes: 2000000
      retryExpression: "IsNetworkError() && Attempts() < 2"

  - id: content-type
    name: Content Type Auto-Detector
    type: contentType
    config: {}

  # Error handling and reliability middlewares
  - id: circuit-breaker
    name: Circuit Breaker
    type: circuitBreaker
    config:
      expression: "NetworkErrorRatio() > 0.20 || ResponseCodeRatio(500, 600, 0, 600) > 0.25"
      checkPeriod: "10s"
      fallbackDuration: "30s"
      recoveryDuration: "60s"
      responseCode: 503

  - id: retry
    name: Retry Failed Requests
    type: retry
    config:
      attempts: 3
      initialInterval: "100ms"

  - id: error-pages
    name: Custom Error Pages
    type: errors
    config:
      status:
        - "500-599"
      service: "error-handler-service"
      query: "/{status}.html"

  - id: grpc-web
    name: gRPC Web
    type: grpcWeb
    config:
      allowOrigins:
        - "*"

  # Special use case middlewares
  - id: nextcloud-dav
    name: Nextcloud WebDAV Redirect
    type: replacePathRegex
    config:
      regex: "^/.well-known/ca(l|rd)dav"
      replacement: "/remote.php/dav/"
  
  # Custom headers example with properly quoted values
  - id: custom-headers-example
    name: Custom Headers Example
    type: headers
    config:
      customRequestHeaders:
        X-Script-Name: "test"
        X-Custom-Value: "value with spaces"
        X-Custom-Request-Header: ""  # Empty string to remove header
      customResponseHeaders:
        X-Custom-Response-Header: "value"
        Server: ""  # Empty string to remove Server header
  
  # Plugin middleware templates
  - id: "geoblock"
    name: "Geoblock"
    type: "plugin"
    config:
      geoblock:
        silentStartUp: false
        allowLocalRequests: false
        logLocalRequests: false
        logAllowedRequests: false
        logApiRequests: false
        api: "https://get.geojs.io/v1/ip/country/{ip}"
        apiTimeoutMs: 750
        cacheSize: 15
        forceMonthlyUpdate: false
        allowUnknownCountries: false
        unknownCountryApiResponse: "nil"
        blackListMode: false
        addCountryHeader: false
        countries:
          - DE

  - id: "crowdsec"
    name: "Crowdsec"
    type: "plugin"
    config:
      crowdsec:
        enabled: true
        logLevel: INFO
        updateIntervalSeconds: 15
        updateMaxFailure: 0
        defaultDecisionSeconds: 15
        httpTimeoutSeconds: 10
        crowdsecMode: live
        crowdsecAppsecEnabled: true
        crowdsecAppsecHost: "crowdsec:7422"
        crowdsecAppsecFailureBlock: true
        crowdsecAppsecUnreachableBlock: true
        crowdsecAppsecBodyLimit: 10485760  # Using plain number to avoid scientific notation
        crowdsecLapiKey: "ENwhi7t7wEaFIn3aZTRbXNdowNDs6Ogr9tK/pzAtNz8"  # API key with special chars preserved exactly
        crowdsecLapiHost: "crowdsec:8080"
        crowdsecLapiScheme: "http"
        forwardedHeadersTrustedIPs:
          - "0.0.0.0/0"
        clientTrustedIPs:
          - "10.0.0.0/8"
          - "172.16.0.0/12"
          - "192.168.0.0/16"
          - "100.89.137.0/20"


  - id: error-pages-middleware
    name: Error Pages Middleware
    type: errors
    config:
      status:
        - "400-599"
      service: "error-pages-service"
      query: "/{status}.html"

  - id: "ipwhitelistshaper"
    name: "IP Whitelist Shaper"
    type: "plugin"
    config:
      ipwhitelistshaper:
        knockEndpoint: "/knock-knock"
        approvalURL: "https://wallos.development.hhf.technology"
        notificationURL: "https://discord.com/api/webhooks/adLcOAfyQZ4hbOD8UhJZCcDZNBFQs_wRHhRTK__zrg4eBFmaaUrphevVU6_BF9tC-GZT"
        defaultPrivateClassSources: true
        expirationTime: 300
        ipStrategyDepth: 0
        secretKey: ""
        excludedIPs: []
        whitelistedIPs:
          - "127.0.0.1/32"
          - "192.168.1.0/24"
          - "10.0.0.0/8"
        storageEnabled: true
        storagePath: "/plugins-storage/ipwhitelistshaper"
        saveInterval: 30

  - id: "bandwidthlimiter"
    name: "bandwidthlimiter"
    type: "plugin"
    config:
      bandwidthlimiter:
        defaultLimit: 1048576
        burstSize: 5242880
        bucketMaxAge: 1800
        expirationTime: 300
        ipStrategyDepth: 0
        cleanupInterval: 300
        persistenceFile: "/plugins-storage/bandwidth-state.json"
        saveInterval: 60

  - id: "tlsguard"
    name: "TLSGuard Authentication"
    type: "plugin"
    config:
      tlsguard:
        # User authentication based on client certificates
        # The plugin will check Common Name, DNS Names, and Email Addresses in the certificate
        usernameHeader: "User"  # Header that will contain the authenticated username
        users:
          # Map of certificate identifiers to usernames
          # Format: "certificate-identifier": "username"
          # The certificate identifier can be:
          # - Subject Common Name
          # - DNS Name (SAN)
          # - Email Address (SAN)
          alice: alice         # Common Name "alice" maps to username "alice"
          bob1: bob            # Common Name "bob1" maps to username "bob"
          charlie@example.org: charlie  # Email address maps to username "charlie"
        
        # Custom request headers to add based on certificate information
        # Template variables available: .Cert (the client certificate) and .Req (the HTTP request)
        requestHeaders:
          X-Cert-Mail: "[[.Cert.Subject.CommonName]]@domain.tld"
          X-Cert-Organization: "[[.Cert.Subject.Organization]]"
        
        # How often to refresh external configuration (if used)
        refreshInterval: "30m"  # Valid time units: s, m, h
        
        # External data source for dynamic configuration
        externalData:
          url: "https://api.example.com/config"
          dataKey: "data"  # Key in JSON response containing relevant data
          skipTlsVerify: false
          headers:
            Authorization: "Bearer api-token-here"
            Content-Type: "application/json"
        
        # Rule-based access control
        # These rules are used when no valid certificate is presented
        # or when additional access restrictions are needed
        rules:
          # IP range rule - allows access based on client IP address
          - type: "ipRange"
            ranges:
              - "127.0.0.1/8"      # Local loopback
              - "192.168.0.0/16"   # Private network
              - "10.0.0.0/8"       # Private network
            addInterface: true     # Automatically add local network ranges
          
          # Header rule - allows access based on request headers
          # - type: "header"
          #   headers:
          #     User-Agent: ".*Chrome.*"  # Regex pattern
          #     X-Api-Key: "valid-key"    # Exact match
          
          # Logical operator rules for combining other rules
          # - type: "allOf"  # All sub-rules must match (AND)
          #   rules:
          #     - type: "ipRange"
          #       ranges: ["192.168.1.0/24"]
          #     - type: "header"
          #       headers:
          #         User-Agent: ".*Firefox.*"
          
          # - type: "anyOf"  # Any sub-rule must match (OR)
          #   rules:
          #     - type: "ipRange"
          #       ranges: ["10.0.0.0/8"]
          #     - type: "header"
          #       headers:
          #         X-Special-Header: "allow-access"
          
          # - type: "noneOf"  # No sub-rule must match (NOT)
          #   rules:
          #     - type: "ipRange"
          #       ranges: ["1.2.3.4/32"]  # Block specific IP

  - id: "traefik-queue-manager"
    name: "Queue Manager"
    type: "plugin"
    config:
      traefik-queue-manager:
        # Enable/disable the queue manager
        enabled: true
        
        # Maximum number of concurrent users allowed before queueing
        maxEntries: 1
        
        # How long a session is valid for (valid time units: s, m, h)
        sessionTime: "60"
        
        # How often to purge expired sessions (valid time units: s, m, h)
        purgeTime: "300"
        
        # Path to the custom queue page HTML template
        # If not provided or file not found, a default template will be used
        queuePageFile: "queue-page.html"
        
        # HTTP response code for queue page (429 = Too Many Requests)
        httpResponseCode: 429
        
        # Content type of queue page
        httpContentType: "text/html; charset=utf-8"
        
        # Use cookies for visitor tracking (true) or IP+UserAgent hash (false)
        useCookies: true
        
        # Name of the cookie used for tracking (only used if useCookies is true)
        cookieName: "queue-manager-id"
        
        # Max age of the cookie in seconds (only used if useCookies is true)
        cookieMaxAge: 3600
        
        # Queue strategy: "fifo" (first in, first out) or "random"
        queueStrategy: "fifo"
        
        # Page refresh interval in seconds (how often the queue page auto-refreshes)
        refreshInterval: 30
        
        # Enable debug logging for troubleshooting
        debug: false

  - id: "statiq"
    name: "Statiq Static File Server"
    type: "plugin"
    config:
      statiq:
        root: "./static"
        enableDirectoryListing: false
        indexFiles:
          - "index.html"
          - "index.htm"
        spaMode: false
        spaIndex: "index.html"
        errorPage404: ""
        cacheControl:
          ".html": "max-age=3600"
          ".css": "max-age=86400"
          ".js": "max-age=86400"
          ".png": "max-age=604800"
          ".jpg": "max-age=604800"
          "*": "max-age=3600"

  - id: "statiq-spa"
    name: "Statiq (SPA Mode)"
    type: "plugin"
    config:
      statiq:
        root: "./spa"
        enableDirectoryListing: false
        indexFiles:
          - "index.html"
        spaMode: true
        spaIndex: "index.html"
        cacheControl:
          ".html": "max-age=3600"
          ".css": "max-age=86400"
          ".js": "max-age=86400"
          ".png": "max-age=604800"
          ".jpg": "max-age=604800"
          "*": "max-age=3600"
  
  - id: "statiq-dev"
    name: "Statiq (Development Mode)"
    type: "plugin"
    config:
      statiq:
        root: "./static"
        enableDirectoryListing: true
        indexFiles:
          - "index.html"
          - "index.htm"
        spaMode: false
        spaIndex: "index.html"
        cacheControl:
          "*": "no-cache, no-store, must-revalidate"
# Cloudflare Access Authentication Middleware Template
  - id: "cloudflare-access"
    name: "Cloudflare Access Authentication"
    type: "plugin"
    config:
      cloudflare-access:
        # Required: Your Cloudflare Access team domain (e.g., "https://yourteam.cloudflareaccess.com")
        teamDomain: "https://yourteam.cloudflareaccess.com"
        
        # Required: The Application Audience (AUD) tag from your Cloudflare Access application
        policyAUD: "1234abcd5678efgh9012ijkl3456mnop"
        
        # Optional: Set to true to skip the client ID verification (default: false)
        skipClientIDCheck: false
        
        # Optional: Set to true to skip the token expiry verification (default: false)
        skipExpiryCheck: false
        
        # Optional: Title shown on the access denied page (default: "Access Denied")
        blockPageTitle: "Access Denied"
        
        # Optional: Message shown on the access denied page
        blockPageMessage: "You don't have permission to access this resource. Please authenticate through Cloudflare Access."

Clone this wiki locally