Metainformationen zur Seite
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| Beide Seiten der vorigen RevisionVorhergehende ÜberarbeitungNächste Überarbeitung | Vorhergehende Überarbeitung | ||
| server:traefik [2025/09/12 10:45] – walbaum | server:traefik [2025/09/25 15:05] (aktuell) – walbaum | ||
|---|---|---|---|
| Zeile 275: | Zeile 275: | ||
| chain: | chain: | ||
| middlewares: | middlewares: | ||
| - | - " | + | - " |
| - | - "CSP-global" | + | - " |
| + | - "CSP-base" | ||
| secure-traefik: | secure-traefik: | ||
| chain: | chain: | ||
| middlewares: | middlewares: | ||
| - | - " | + | |
| - | - "CSP-global" | + | |
| - | - "traefik-auth" | + | - "cors-default" |
| + | - "CSP-base" | ||
| secure-idservice: | secure-idservice: | ||
| chain: | chain: | ||
| middlewares: | middlewares: | ||
| - | - " | + | - " |
| + | - " | ||
| - " | - " | ||
| Zeile 294: | Zeile 297: | ||
| chain: | chain: | ||
| middlewares: | middlewares: | ||
| - | - " | + | - " |
| + | - " | ||
| - " | - " | ||
| Zeile 300: | Zeile 304: | ||
| chain: | chain: | ||
| middlewares: | middlewares: | ||
| - | - " | + | - " |
| + | - " | ||
| - " | - " | ||
| Zeile 306: | Zeile 311: | ||
| chain: | chain: | ||
| middlewares: | middlewares: | ||
| - | - " | + | - " |
| + | - " | ||
| - " | - " | ||
| Zeile 312: | Zeile 318: | ||
| chain: | chain: | ||
| middlewares: | middlewares: | ||
| - | - " | + | - " |
| + | - " | ||
| - " | - " | ||
| Zeile 318: | Zeile 325: | ||
| chain: | chain: | ||
| middlewares: | middlewares: | ||
| - | - " | + | |
| + | | ||
| + | - " | ||
| + | - " | ||
| - " | - " | ||
| - | - " | ||
| secure-digiphyll: | secure-digiphyll: | ||
| chain: | chain: | ||
| middlewares: | middlewares: | ||
| + | - " | ||
| - " | - " | ||
| + | - " | ||
| - " | - " | ||
| Zeile 331: | Zeile 342: | ||
| chain: | chain: | ||
| middlewares: | middlewares: | ||
| - | - " | + | - " |
| + | - " | ||
| + | - " | ||
| - " | - " | ||
| Zeile 337: | Zeile 350: | ||
| chain: | chain: | ||
| middlewares: | middlewares: | ||
| - | - " | + | - " |
| + | - " | ||
| - " | - " | ||
| Zeile 343: | Zeile 357: | ||
| chain: | chain: | ||
| middlewares: | middlewares: | ||
| + | - " | ||
| - " | - " | ||
| + | - " | ||
| - " | - " | ||
| Zeile 349: | Zeile 365: | ||
| chain: | chain: | ||
| middlewares: | middlewares: | ||
| - | - " | + | - " |
| + | - " | ||
| - " | - " | ||
| Zeile 355: | Zeile 372: | ||
| chain: | chain: | ||
| middlewares: | middlewares: | ||
| - | - " | + | - " |
| + | - " | ||
| - " | - " | ||
| Zeile 361: | Zeile 379: | ||
| chain: | chain: | ||
| middlewares: | middlewares: | ||
| + | - " | ||
| - " | - " | ||
| - | - "CSP-global" | + | |
| + | | ||
| </ | </ | ||
| \\ | \\ | ||
| Zeile 371: | Zeile 391: | ||
| ipWhiteList: | ipWhiteList: | ||
| sourceRange: | sourceRange: | ||
| - | | + | |
| - | - " | + | - " |
| traefik-auth: | traefik-auth: | ||
| Zeile 379: | Zeile 399: | ||
| - " | - " | ||
| + | # Core security baseline used by most services | ||
| + | security-headers-base: | ||
| + | headers: & | ||
| + | addVaryHeader: | ||
| + | |||
| + | # Response header hardening | ||
| + | contentTypeNosniff: | ||
| + | browserXssFilter: | ||
| + | referrerPolicy: | ||
| + | permissionsPolicy: | ||
| + | |||
| + | # HSTS | ||
| + | forceSTSHeader: | ||
| + | stsSeconds: 31536000 | ||
| + | stsPreload: false | ||
| + | # Keep includeSubdomains off in base to avoid accidental lock-in; use variant below when desired. | ||
| + | # stsIncludeSubdomains: | ||
| + | |||
| + | # X-Frame-Options — deny by default (use CSP frame-ancestors for granular control) | ||
| + | frameDeny: true | ||
| + | # customFrameOptionsValue: | ||
| + | |||
| + | # TLS/Proxy awareness | ||
| + | sslRedirect: | ||
| + | sslProxyHeaders: | ||
| + | X-Forwarded-Proto: | ||
| + | hostsProxyHeaders: | ||
| + | - " | ||
| + | |||
| + | # Standard response scrubbing | ||
| + | customResponseHeaders: | ||
| + | Server: "" | ||
| + | X-Powered-By: | ||
| + | X-Robots-Tag: | ||
| + | |||
| + | # Upstream request adjustments (to your apps) | ||
| + | customRequestHeaders: | ||
| + | X-Forwarded-Proto: | ||
| + | |||
| + | # Variant: noindex | ||
| security-headers-noindex: | security-headers-noindex: | ||
| headers: | headers: | ||
| - | accessControlAllowMethods: | + | <<: *SEC_BASE |
| - | - GET | + | |
| - | - OPTIONS | + | |
| - | - PUT | + | X-Robots-Tag: |
| - | accessControlMaxAge: 100 | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | X-Forwarded-Proto: | + | |
| - | Server: "" | + | |
| - | x-powered-by: | + | |
| - | customRequestHeaders: | + | |
| - | X-Forwarded-Proto: | + | |
| - | Cache-Control: | + | |
| - | customFrameOptionsValue: | + | |
| - | sslProxyHeaders: | + | |
| - | X-Forwarded-Proto: | + | |
| - | sslRedirect: | + | |
| - | referrerPolicy: | + | |
| - | hostsProxyHeaders: | + | |
| - | - " | + | |
| - | contentTypeNosniff: | + | |
| - | browserXssFilter: | + | |
| - | forceSTSHeader: | + | |
| - | stsSeconds: 31536000 | + | |
| - | stsPreload: false | + | |
| - | permissionsPolicy: | + | |
| - | frameDeny: true | + | |
| - | security-headers: | + | |
| + | | ||
| headers: | headers: | ||
| - | accessControlMaxAge: 100 | + | <<: *SEC_BASE |
| - | addVaryHeader: | + | |
| - | customResponseHeaders: | + | # |
| - | X-Robots-Tag: | + | # |
| - | X-Forwarded-Proto: | + | |
| - | Server: "" | + | |
| - | accessControlAllowMethods: | + | |
| - | - GET | + | |
| - | - OPTIONS | + | |
| - | - PUT | + | |
| - | accessControlAllowHeaders: | + | |
| - | | + | |
| - | | + | |
| - | X-Forwarded-Proto: | + | |
| - | Cache-Control: | + | |
| - | | + | |
| - | | + | |
| - | X-Forwarded-Proto: | + | |
| - | sslRedirect: | + | |
| - | referrerPolicy: | + | |
| - | | + | |
| - | - "X-Forwarded-Host" | + | |
| - | contentTypeNosniff: | + | |
| - | browserXssFilter: | + | |
| - | forceSTSHeader: | + | |
| - | stsSeconds: 31536000 | + | |
| - | stsPreload: false | + | |
| - | permissionsPolicy: | + | |
| - | frameDeny: true | + | |
| - | security-headers-allowframes: | + | |
| + | | ||
| headers: | headers: | ||
| - | accessControlMaxAge: 100 | + | <<: *SEC_BASE |
| - | | + | stsIncludeSubdomains: |
| - | customResponseHeaders: | + | stsSeconds: 63072000 |
| - | X-Robots-Tag: | + | |
| - | accessControlAllowMethods: | + | |
| - | - GET | + | |
| - | - OPTIONS | + | |
| - | - PUT | + | |
| - | X-Forwarded-Proto: | + | |
| - | Server: "" | + | |
| - | X-Powered-By: | + | |
| - | customRequestHeaders: | + | |
| - | X-Forwarded-Proto: | + | |
| - | Cache-Control: | + | |
| - | CustomFrameOptionsValue: | + | |
| - | sslProxyHeaders: | + | |
| - | X-Forwarded-Proto: | + | |
| - | sslRedirect: | + | |
| - | referrerPolicy: | + | |
| - | hostsProxyHeaders: | + | |
| - | - " | + | |
| - | contentTypeNosniff: | + | |
| - | browserXssFilter: | + | |
| - | forceSTSHeader: | + | |
| - | | + | |
| - | stsSeconds: 63072000 | + | |
| - | stsPreload: false | + | |
| - | permissionsPolicy: | + | |
| - | | + | |
| + | cache-public: | ||
| headers: | headers: | ||
| - | addVaryHeader: | + | |
| - | | + | Cache-Control: |
| - | X-Robots-Tag: | + | |
| - | X-Forwarded-Proto: | + | |
| - | Server: "" | + | |
| - | accessControlAllowMethods: | + | |
| - | - GET | + | |
| - | - OPTIONS | + | |
| - | - PUT | + | |
| - | accessControlAllowHeaders: | + | |
| - | accessControlAllowOriginList: | + | |
| - | - https:// | + | |
| - | - https:// | + | |
| - | accessControlMaxAge: | + | |
| - | # customFrameOptionsValue: | + | |
| - | | + | |
| - | X-Forwarded-Proto: | + | |
| - | | + | |
| - | sslProxyHeaders: | + | |
| - | X-Forwarded-Proto: | + | |
| - | sslRedirect: | + | |
| - | referrerPolicy: | + | |
| - | hostsProxyHeaders: | + | |
| - | - " | + | |
| - | contentTypeNosniff: | + | |
| - | browserXssFilter: | + | |
| - | forceSTSHeader: | + | |
| - | stsIncludeSubdomains: | + | |
| - | stsSeconds: 63072000 | + | |
| - | stsPreload: false | + | |
| - | permissionsPolicy: fullscreen=(self " | + | |
| - | # x-frame-options: | + | |
| - | security-headers-librechat: | + | |
| + | cors-default: | ||
| + | | ||
| + | accessControlAllowMethods: | ||
| + | - GET | ||
| + | - OPTIONS | ||
| + | - PUT | ||
| + | accessControlAllowHeaders: | ||
| + | accessControlMaxAge: | ||
| + | addVaryHeader: | ||
| + | |||
| + | cors-collections: | ||
| headers: | headers: | ||
| - | accessControlAllowMethods: | + | <<: *CORS_DEFAULT |
| - | - GET | + | |
| - | - OPTIONS | + | - https:// |
| - | - PUT | + | - https://pictures.smns-bw.org |
| - | accessControlMaxAge: 100 | + | |
| - | | + | |
| - | customResponseHeaders: | + | |
| - | X-Robots-Tag: " | + | |
| - | X-Forwarded-Proto: | + | |
| - | server: "" | + | |
| - | x-powered-by: "" | + | |
| - | | + | |
| - | X-Forwarded-Proto: | + | |
| - | Cache-Control: | + | |
| - | customFrameOptionsValue: | + | |
| - | sslProxyHeaders: | + | |
| - | X-Forwarded-Proto: | + | |
| - | sslRedirect: | + | |
| - | referrerPolicy: | + | |
| - | hostsProxyHeaders: | + | |
| - | - " | + | |
| - | contentTypeNosniff: | + | |
| - | browserXssFilter: | + | |
| - | forceSTSHeader: | + | |
| - | # stsIncludeSubdomains: | + | |
| - | # stsSeconds: 63072000 | + | |
| - | stsPreload: false | + | |
| - | permissionsPolicy: | + | |
| - | frameDeny: true | + | |
| - | | + | |
| + | CSP-base: | ||
| headers: | headers: | ||
| - | accessControlAllowMethods: | + | contentSecurityPolicy: & |
| - | - GET | + | |
| - | - OPTIONS | + | |
| - | - PUT | + | |
| - | | + | |
| - | addVaryHeader: | + | |
| - | customResponseHeaders: | + | |
| - | X-Robots-Tag: " | + | |
| - | X-Forwarded-Proto: " | + | |
| - | server: "" | + | |
| - | | + | |
| - | X-Forwarded-Proto: " | + | |
| - | Cache-Control: | + | |
| - | customFrameOptionsValue: | + | |
| - | | + | |
| - | X-Forwarded-Proto: " | + | |
| - | sslRedirect: | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | stsPreload: false | + | |
| - | permissionsPolicy: | + | |
| - | frameDeny: false | + | |
| + | # If you still reference CSP-global anywhere, just point it to the base: | ||
| CSP-global: | CSP-global: | ||
| headers: | headers: | ||
| - | | + | |
| - | default-src ' | + | |
| - | | + | # Deltas below (only where different from base) |
| - | form-action ' | + | |
| - | connect-src ' | + | |
| - | style-src ' | + | |
| - | script-src ' | + | |
| CSP-dokuwiki: | CSP-dokuwiki: | ||
| headers: | headers: | ||
| - | | + | |
| - | default-src ' | + | default-src ' |
| - | frame-ancestors ' | + | frame-ancestors ' |
| - | frame-src *.smns-bw.org *.google.com; | + | frame-src *.smns-bw.org *.google.com; |
| - | base-uri ' | + | base-uri ' |
| - | form-action ' | + | form-action ' |
| - | img-src ' | + | img-src ' |
| - | connect-src ' | + | connect-src ' |
| - | font-src ' | + | font-src ' |
| - | style-src ' | + | style-src ' |
| - | script-src ' | + | script-src ' |
| CSP-idservice: | CSP-idservice: | ||
| headers: | headers: | ||
| - | | + | |
| - | default-src ' | + | default-src ' |
| - | frame-ancestors ' | + | frame-ancestors ' |
| - | base-uri ' | + | |
| - | form-action ' | + | base-uri ' |
| - | img-src ' | + | form-action ' |
| - | connect-src ' | + | img-src ' |
| - | font-src ' | + | connect-src ' |
| - | style-src ' | + | font-src ' |
| - | script-src ' | + | style-src ' |
| + | script-src ' | ||
| CSP-librechat: | CSP-librechat: | ||
| headers: | headers: | ||
| - | | + | |
| - | default-src ' | + | default-src ' |
| - | frame-ancestors ' | + | frame-ancestors ' |
| - | frame-src *.smns-bw.org; | + | frame-src *.smns-bw.org; |
| - | base-uri ' | + | base-uri ' |
| - | form-action ' | + | form-action ' |
| - | img-src ' | + | img-src ' |
| - | connect-src ' | + | connect-src ' |
| - | font-src ' | + | font-src ' |
| - | style-src ' | + | style-src ' |
| - | script-src ' | + | script-src ' |
| + | # Fixed: removed invalid ' | ||
| CSP-awstats: | CSP-awstats: | ||
| headers: | headers: | ||
| - | | + | |
| - | default-src ' | + | default-src ' |
| - | frame-ancestors ' | + | frame-ancestors ' |
| - | frame-src *.smns-bw.org; | + | frame-src *.smns-bw.org; |
| - | base-uri ' | + | base-uri ' |
| - | form-action ' | + | form-action ' |
| - | img-src ' | + | img-src ' |
| - | connect-src ' | + | connect-src ' |
| - | font-src ' | + | font-src ' |
| - | style-src ' | + | style-src ' |
| - | style-src-elem https:// | + | style-src-elem https:// |
| - | script-src ' | + | script-src ' |
| - | script-src-elem https:// | + | script-src-elem https:// |
| CSP-h5p: | CSP-h5p: | ||
| headers: | headers: | ||
| - | | + | |
| - | default-src ' | + | default-src ' |
| - | frame-ancestors https:// | + | frame-ancestors https:// |
| - | frame-src *.smns-bw.org; | + | frame-src *.smns-bw.org; |
| - | base-uri ' | + | base-uri ' |
| - | form-action ' | + | form-action ' |
| - | img-src ' | + | img-src ' |
| - | connect-src ' | + | connect-src ' |
| - | font-src ' | + | font-src ' |
| - | style-src ' | + | style-src ' |
| - | script-src ' | + | script-src ' |
| CSP-biocase: | CSP-biocase: | ||
| headers: | headers: | ||
| - | | + | |
| - | default-src ' | + | default-src ' |
| - | frame-ancestors ' | + | frame-ancestors ' |
| - | frame-src *.smns-bw.org; | + | frame-src *.smns-bw.org; |
| - | base-uri ' | + | base-uri ' |
| - | form-action ' | + | form-action ' |
| - | img-src ' | + | img-src ' |
| - | connect-src ' | + | connect-src ' |
| - | font-src ' | + | font-src ' |
| - | style-src ' | + | style-src ' |
| - | script-src ' | + | script-src ' |
| CSP-prestashop: | CSP-prestashop: | ||
| headers: | headers: | ||
| - | | + | |
| - | default-src ' | + | default-src ' |
| - | frame-ancestors ' | + | frame-ancestors ' |
| - | frame-src *.smns-bw.org; | + | frame-src *.smns-bw.org; |
| - | base-uri ' | + | base-uri ' |
| - | form-action ' | + | form-action ' |
| - | img-src ' | + | img-src ' |
| - | connect-src ' | + | connect-src ' |
| - | font-src ' | + | font-src ' |
| - | style-src ' | + | style-src ' |
| - | style-src-elem https:// | + | style-src-elem https:// |
| - | script-src ' | + | script-src ' |
| + | # Base + broader font-src | ||
| CSP-webmin: | CSP-webmin: | ||
| headers: | headers: | ||
| - | | + | |
| - | default-src ' | + | default-src ' |
| - | img-src ' | + | |
| - | font-src ' | + | |
| + | font-src ' | ||
| + | style-src ' | ||
| + | script-src ' | ||
| + | # Fixed: stray " | ||
| CSP-collections: | CSP-collections: | ||
| headers: | headers: | ||
| - | | + | |
| - | default-src ' | + | default-src ' |
| - | frame-ancestors ' | + | frame-ancestors ' |
| - | frame-src *.smns-bw.org; | + | frame-src *.smns-bw.org; |
| - | base-uri ' | + | base-uri ' |
| - | form-action ' | + | form-action ' |
| - | style-src ' | + | style-src ' |
| - | connect-src ' | + | connect-src ' |
| - | font-src ' | + | font-src ' |
| - | img-src ' | + | img-src ' |
| - | script-src ' | + | script-src ' |
| + | # Fixed: removed invalid ' | ||
| CSP-ent: | CSP-ent: | ||
| headers: | headers: | ||
| - | | + | |
| - | default-src ' | + | default-src ' |
| - | base-uri ' | + | base-uri ' |
| - | form-action ' | + | form-action ' |
| - | style-src-elem https:// | + | style-src-elem https:// |
| - | connect-src 'self' ' | + | connect-src ' |
| - | script-src-elem | + | script-src-elem https:// |
| - | img-src ' | + | img-src ' |
| CSP-digiphyll: | CSP-digiphyll: | ||
| headers: | headers: | ||
| - | | + | |
| - | default-src ' | + | default-src ' |
| - | frame-ancestors ' | + | frame-ancestors ' |
| - | frame-src *.smns-bw.org https:// | + | frame-src *.smns-bw.org https:// |
| - | base-uri ' | + | base-uri ' |
| - | form-action ' | + | form-action ' |
| - | img-src ' | + | img-src ' |
| - | connect-src ' | + | connect-src ' |
| - | font-src ' | + | font-src ' |
| - | style-src ' | + | style-src ' |
| - | script-src ' | + | script-src ' |
| + | # Fixed: removed invalid ' | ||
| CSP-geometroidea: | CSP-geometroidea: | ||
| headers: | headers: | ||
| - | | + | |
| - | default-src ' | + | default-src ' |
| - | style-src ' | + | style-src ' |
| - | font-src ' | + | font-src ' |
| - | img-src ' | + | img-src ' |
| my-traefik-plugin-cookie-path-prefix: | my-traefik-plugin-cookie-path-prefix: | ||
| Zeile 743: | Zeile 679: | ||
| errors: | errors: | ||
| status: | status: | ||
| - | | + | service: error-pages-webportal@docker |
| - | | + | - " |
| - | query: "/ | + | |
| # another-service-errors: | # another-service-errors: | ||
| Zeile 772: | Zeile 708: | ||
| # sniStrict: true | # sniStrict: true | ||
| </ | </ | ||
| + | |||
| + | ===== Traefik security headers and CSP (DRY config) ===== | ||
| + | |||
| + | Last updated: 25.09.2025 | ||
| + | |||
| + | ==== High‑level design ==== | ||
| + | |||
| + | * One baseline for security headers: security-headers-base | ||
| + | * Small header variants you can compose: -noindex, -allowframes, | ||
| + | * Separate CORS middlewares: | ||
| + | * One base CSP: CSP-base (+ per‑service CSP middlewares that only add what’s different) | ||
| + | * Chains compose the above into per‑service “one-liners” you reference from docker-compose labels. | ||
| + | |||
| + | ==== Security headers ==== | ||
| + | |||
| + | === Baseline (security-headers-base) === | ||
| + | |||
| + | Sets the shared hardening and sane defaults. Highlights: | ||
| + | |||
| + | * addVaryHeader: | ||
| + | * contentTypeNosniff: | ||
| + | * browserXssFilter: | ||
| + | * referrerPolicy: | ||
| + | * permissionsPolicy: | ||
| + | * HSTS: forceSTSHeader: | ||
| + | * X-Frame-Options: | ||
| + | * TLS/proxy awareness: sslRedirect: | ||
| + | * Scrub response headers (customResponseHeaders): | ||
| + | * Upstream request header: customRequestHeaders.X-Forwarded-Proto: | ||
| + | Rationale: | ||
| + | |||
| + | * Default deny framing (clickjacking defense); enable per service via -allowframes and control who via CSP. | ||
| + | * Keep includeSubdomains off by default to avoid accidental HSTS lock-in; use the variant when needed. | ||
| + | |||
| + | ==== Variants you can compose ==== | ||
| + | |||
| + | * security-headers-noindex | ||
| + | * Same as base, but X-Robots-Tag: | ||
| + | * security-headers-allowframes | ||
| + | * Same as base, but frameDeny: false (use CSP frame-ancestors to specify who can frame) | ||
| + | * security-headers-hsts-subdomains | ||
| + | * Same as base, but stsIncludeSubdomains: | ||
| + | * cache-public | ||
| + | * Adds Cache-Control: | ||
| + | |||
| + | ==== CORS middlewares ==== | ||
| + | |||
| + | * cors-default | ||
| + | * accessControlAllowMethods: | ||
| + | * accessControlAllowHeaders: | ||
| + | * accessControlMaxAge: | ||
| + | * addVaryHeader: | ||
| + | * cors-collections | ||
| + | * Inherits cors-default + accessControlAllowOriginList: | ||
| + | * https:// | ||
| + | * https:// | ||
| + | |||
| + | ==== Content Security Policy (CSP) ==== | ||
| + | |||
| + | === Base CSP (CSP-base) === | ||
| + | |||
| + | Applies to most services unchanged. | ||
| + | |||
| + | <code yaml> CSP-base: headers: contentSecurityPolicy: | ||
| + | |||
| + | Notes: | ||
| + | |||
| + | * Only one CSP header is honored. Don’t stack multiple CSP middlewares in a single chain; “last header wins.” | ||
| + | * Use Report-Only during testing by duplicating to contentSecurityPolicyReportOnly. | ||
| + | |||
| + | ==== How to add a new service ==== | ||
| + | |||
| + | * If defaults are enough: | ||
| + | * Use secure-global chain. | ||
| + | * If it needs framing: | ||
| + | * Use security-headers-allowframes in the chain and set CSP frame-ancestors to the exact allowlist. | ||
| + | * If it needs special CORS: | ||
| + | * Add or create a cors-< | ||
| + | * If it needs special CSP: | ||
| + | * Copy CSP-base to CSP-< | ||
| + | * Wire it in docker-compose: | ||
| + | * traefik.http.routers.< | ||
| + | ==== Verification (quick commands) ==== | ||
| + | |||
| + | * Check headers: | ||
| + | * curl -sI https://< | ||
| + | * Check CSP is present (and only once): | ||
| + | * curl -sI https://< | ||
| + | * Check CORS (preflight example): | ||
| + | * curl -sI -X OPTIONS https://< | ||
| + | * Check robots indexing: | ||
| + | * curl -sI https://< | ||
| + | |||
| + | ==== Operational notes ==== | ||
| + | |||
| + | * Prefer CSP frame-ancestors over X-Frame-Options for precise embedding control. | ||
| + | * Consider a Report-Only CSP during rollouts (duplicate middleware with contentSecurityPolicyReportOnly). | ||
| + | * HSTS includeSubdomains is opt-in via variant to avoid unintentional hard lock-in. | ||
| + | * If a page doesn’t render: check the browser console for CSP violations first; add only the specific host/type needed. | ||
| + | ==== Appendix: Anchor usage ==== | ||
| + | We used YAML anchors to stay DRY: | ||
| + | |||
| + | * & | ||
| + | * & | ||
| + | This keeps the source config compact while allowing targeted overrides. | ||
| ===== Traefik v3 Healthcheck (Docker) ===== | ===== Traefik v3 Healthcheck (Docker) ===== | ||
| Zeile 879: | Zeile 920: | ||
| * [[https:// | * [[https:// | ||
| - | Authored for SMNS IT by Chattie and AI Programmer | + | Authored for SMNS IT by Chattie and AI Programmer |