301 redirect to HTTPS www does not contain HSTS headers

Hi!

I currently have a global HTTP -> HTTPS redirect (which works fine) but after I canonicalize my URL to contain "www", Traefik won't include my "headers" middleware.

HSTS "standard" suggests to redirect to HTTPS first before adding or removing "www". It seems like my middleware chain isn't including the headers I provided once I've been redirected to HTTPS:

I'm still relatively new to learning web stuff and Traefik, It works amazingly so far but I'm just having trouble making my website HSTS ready.

Any help is appreciated :slight_smile:

traefik.yml (static config):

global:
    sendAnonymousUsage: false

log:
    format: "common"
    level:  "ERROR"

api:
    dashboard: true

providers:
    file:
        filename: "config.yml"
    docker:
        endpoint:         "tcp://docker-socket-proxy:2375"
        network:          "traefik-web"
        exposedByDefault: false

entryPoints:
    web:
        address: ":80"
    web-secure:
        address: ":443"

certificatesResolvers:
    le:
        acme:
            email:   "foo@bar.net"
            keyType: "EC256"
            storage: "acme.json"
            dnsChallenge:
                provider: "cloudflare"
                resolvers:
                    - "1.1.1.1:53"
                    - "1.0.0.1:53"
                    - "8.8.8.8:53"
                    - "8.8.4.4:53"

config.yml (dynamic config):

http:
    middlewares:
        https-redirect:
            redirectScheme:
                scheme:    "https"
                permanent: true
        www-redirect:
            redirectRegex:
                regex:       "^https://(foo\\.net.*)"
                replacement: "https://www.${1}"
                permanent:   true
        response-headers:
            headers:
                sslRedirect:             true
                contentTypeNosniff:      true
                browserXssFilter:        true
                forceSTSHeader:          true
                stsPreload:              true
                stsIncludeSubdomains:    true
                stsSeconds:              31536000
                customFrameOptionsValue: "SAMEORIGIN"
        api-auth:
            basicAuth:
                users:
                    - "[[REDACTED]]:[[REDACTED]]"
        insecure-chain:
            chain:
                middlewares:
                    - "https-redirect"
        secure-and-www-chain:
            chain:
                middlewares:
                    - "response-headers"
                    - "www-redirect"
        secure-chain:
            chain:
                middlewares:
                    - "response-headers"

tls:
    options:
        default:
            sniStrict:  true
            minVersion: "VersionTLS12"
            mintls13:
                minVersion: "VersionTLS13"
            cipherSuites:
                - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
                - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
                - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
                - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
                - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305"
                - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"

docker-compose.yml:

version: "3.7"

services:
    # docker socket proxy (for security)
    docker-socket-proxy:
        image:      "tecnativa/docker-socket-proxy"
        restart:    "unless-stopped"
        privileged: true
        environment:
            CONTAINERS: 1
        networks:
            - "docker-socket-proxy"
        volumes:
            - "/var/run/docker.sock:/var/run/docker.sock:ro" # docker socket

    # reverse proxy
    traefik:
        image:   "traefik:v2.1.6"
        restart: "unless-stopped"
        env_file:
            - "./traefik/traefik.env"
        networks:
            - "internal"
            - "docker-socket-proxy"
            - "traefik-web"
        ports:
            - "80:80"
            - "443:443"
            - "8080:8080"
        volumes:
            - "./traefik/traefik.yml:/traefik.yml:ro" # static configuration config file
            - "./traefik/config.yml:/config.yml:ro"   # dynamic configuration config file
            - "./traefik/acme.json:/acme.json"        # save traefik SSL cert data here
        labels: # dynamic configuration
            # enable docker service so traefik can see it
            - "traefik.enable=true"

            # redirect all HTTP requests to HTTPS
            - "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
            - "traefik.http.routers.http-catchall.entrypoints=web"
            - "traefik.http.routers.http-catchall.middlewares=insecure-chain@file"

            # wildcard SSL
            - "traefik.http.routers.traefik.tls.domains[0].main=foo.net"
            - "traefik.http.routers.traefik.tls.domains[0].sans=*.foo.net"

            # route dashboard
            - "traefik.http.routers.traefik.rule=Host(`traefik.foo.net`)"
            - "traefik.http.routers.traefik.entrypoints=web-secure"
            - "traefik.http.routers.traefik.tls=true"
            - "traefik.http.routers.traefik.tls.certresolver=le"
            - "traefik.http.routers.traefik.middlewares=secure-chain@file,api-auth@file"
            - "traefik.http.routers.traefik.service=api@internal"

    # primary website
    main:
        build:   "./main"
        restart: "unless-stopped"
        networks:
            - "internal"
            - "traefik-web"
        # volumes:
        #     - "./main/app/Cargo.lock:/usr/src/app/Cargo.lock"
        labels:
            # enable this service so traefik can see it
            - "traefik.enable=true"

            # route main website (rust)
            - "traefik.http.routers.main.rule=Host(`foo.net`, `www.foo.net`)"
            - "traefik.http.routers.main.entrypoints=web-secure"
            - "traefik.http.routers.main.tls=true"
            - "traefik.http.routers.main.tls.certresolver=le"
            - "traefik.http.routers.main.middlewares=secure-and-www-chain@file"
            - "traefik.http.services.main.loadbalancer.server.port=9200"

networks:
    internal:
        internal: true
    docker-socket-proxy:
        internal: true
    traefik-web:
        external: false

Actually, Adding on to my original post...

Could this issue be related to: https://github.com/containous/traefik/issues/5890 ?

I assume it's fixed once stable is at 2.2.0
Edit: Or not... I tried the rc2 release and my headers are still not added to any of my redirects. Am I misunderstanding this?

Still not sure about this. Does anyone have any advice for this? Maybe I'm missing a flag for the redirects? Without having HSTS headers on HTTPS redirects, sites can't be eligible for HSTS preload list.

I also tried with more basic settings and stripping the "www" prefix, but the same issue happens:

Initial request @ "http://www.foo.net" (global HTTP->HTTPS redirect):

Then, the second redirect (which should have HSTS headers from my chain):

Bump.

This is still an issue I'm struggling with and I'm still not able to add my domain to the HSTS preload list.

The 2nd HTTPS redirect to "www" should contain headers I've added, but it doesn't.

On top of that, How come "forceSTSHeader" isn't adding the headers on redirects?