All http to https redirect

I am trying to redirect all HTTP to HTTPS with following configuration
But when I open http url it isn't getting redirect to https.

traefik.toml
    ## static configuration
    [global]
      checkNewVersion = true

    [entryPoints]
      [entryPoints.web]
        address = ":80"
      [entryPoints.websecure]
        address = ":443"

    [providers]
      [providers.kubernetesCRD]
      [providers.file]
        directory = "/etc/traefik/providers/"
        watch = true

    [log]
      level = "INFO"

    [accessLog]

    [api]
      insecure = true
      dashboard = true
      debug = true

    [metrics]
      [metrics.prometheus]
        buckets = [0.1,0.3,1.2,5.0]
        addEntryPointsLabels = true
        addServicesLabels = true
        entryPoint = "web"

    [ping]
      entryPoint = "web"

    [certificatesResolvers]
      [certificatesResolvers.letsencrypt]
        [certificatesResolvers.letsencrypt.acme]
          email = "admin@domain.com"
          caServer = "https://acme-v02.api.letsencrypt.org/directory"
          storage = "acme.json"
          [certificatesResolvers.letsencrypt.acme.dnsChallenge]
            provider = "route53"
            delayBeforeCheck = 0
            resolvers = ["1.1.1.1:53", "8.8.8.8:53"]

dynamic.toml

    ## dynamic configuration
    [web.routers]
      [web.routers.https-redirect]
        entryPoints = ["web"]
        middlewares = ["https-redirect"]
        rule = "HostRegexp(`{host:.+}`)"
        service = "api@internal"

    [web.middlewares]
      [web.middlewares.https-redirect.redirectScheme]
        scheme = "https"
        permanent: true

What change I need here ?

It's either incomplete configuration, or it's wrong: it never references your dynamic.toml file.

As per traefik/file.md at master · traefik/traefik · GitHub I have following in traefik.toml

    [providers]
      [providers.kubernetesCRD]
      [providers.file]
        directory = "/etc/traefik/providers/"
        watch = true

Directory /etc/traefik/providers/ has dynamic.toml
Is it wrong ?

Sorry about that I missed it. Anything in the logs?

[web.routers] does not look right, I mean the web prefix. That's not something traefik would be aware of. This what dynamic configuration should look like.

Easiest method I found for a catch-all-redirect from http to https is this setup:

@lnxbil @zespri

I tried following config which didn't not work.

    ## dynamic configuration
    [http.routers]
      [http.routers.HTTPSRedirect]
        entryPoints = ["web"]
        rule = "PathPrefix(`/`)"
        middlewares = ["HTTPSRedirect"]
        service = "HTTPSRedirect"
        priority = 1

    [http.middlewares]
      [http.middlewares.HTTPSRedirect.redirectScheme]
        scheme = "https"
        permanent = true

    [http.services]
      [http.services.HTTPSRedirect.loadBalancer]
        [[http.services.HTTPSRedirect.loadBalancer.servers]]
          url = "http://localhost/"

There is no error in the traefik container.

Take a look at:

@ldez

Tried following config, still didn't work

    ## dynamic configuration
    [http.routers]
      [http.routers.redirecttohttps]
        entryPoints = ["web"]
        rule = "HostRegexp(`{host:.+}`)"
        middlewares = ["httpsredirect"]
        service = "noop"
    [http.middlewares]
      [http.middlewares.httpsredirect.redirectScheme]
        scheme = "https"

    [http.services]
      [http.services.noop.loadBalancer]
        [[http.services.noop.loadBalancer.servers]]
          url = "http://192.168.0.1"

I also tried your config and it does.

Since you are using kubernetes, I suspect that you did not do that part of configuration properly. Could be that your request simply never makes to traefik.

Could you please post your curl command you are using to test, the output of it, your IngressRoutes and your kubernetes manifest for traefik in the cluster.

manifest I used for deploy Traefik V2

resources.yaml
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: ingressroutes.traefik.containo.us
spec:
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: IngressRoute
    plural: ingressroutes
    singular: ingressroute
  scope: Namespaced

---

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: ingressroutetcps.traefik.containo.us
spec:
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: IngressRouteTCP
    plural: ingressroutetcps
    singular: ingressroutetcp
  scope: Namespaced

---

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: middlewares.traefik.containo.us
spec:
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: Middleware
    plural: middlewares
    singular: middleware
  scope: Namespaced

---

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: tlsoptions.traefik.containo.us
spec:
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: TLSOption
    plural: tlsoptions
    singular: tlsoption
  scope: Namespaced

---

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: traefik-ingress-controller
rules:
  - apiGroups:
      - ""
    resources:
      - services
      - endpoints
      - secrets
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
    resources:
      - ingresses/status
    verbs:
      - update
  - apiGroups:
      - traefik.containo.us
    resources:
      - middlewares
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - traefik.containo.us
    resources:
      - ingressroutes
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - traefik.containo.us
    resources:
      - ingressroutetcps
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - traefik.containo.us
    resources:
      - tlsoptions
    verbs:
      - get
      - list
      - watch

---

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: traefik-ingress-controller

roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: traefik-ingress-controller
subjects:
  - kind: ServiceAccount
    name: traefik-ingress-controller
    namespace: kube-system

---

apiVersion: v1
kind: ServiceAccount
metadata:
  namespace: kube-system
  name: traefik-ingress-controller

deployments.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: traefik-conf
  namespace: kube-system
data:
  traefik.toml: |
    ## static configuration
    [global]
      checkNewVersion = true

    [entryPoints]
      [entryPoints.web]
        address = ":80"
      [entryPoints.websecure]
        address = ":443"

    [providers]
      [providers.kubernetesCRD]
      [providers.file]
        directory = "/etc/traefik/providers/"
        watch = true

    [log]
      level = "INFO"

    [accessLog]

    [api]
      insecure = true
      dashboard = true
      debug = true

    [metrics]
      [metrics.prometheus]
        buckets = [0.1,0.3,1.2,5.0]
        addEntryPointsLabels = true
        addServicesLabels = true
        entryPoint = "web"

    [ping]
      entryPoint = "web"

    [certificatesResolvers]
      [certificatesResolvers.letsencrypt]
        [certificatesResolvers.letsencrypt.acme]
          email = "admin@domain.com"
          caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
          storage = "/etc/traefik/storage/acme.json"
          [certificatesResolvers.letsencrypt.acme.dnsChallenge]
            provider = "route53"
            delayBeforeCheck = 0
            resolvers = ["1.1.1.1:53", "8.8.8.8:53"]

  dynamic.toml: |
    ## dynamic configuration
    [http.routers]
      [http.routers.redirecttohttps]
        entryPoints = ["web"]
        rule = "HostRegexp(`{host:.+}`)"
        middlewares = ["httpsredirect"]
        service = "noop"

    [http.middlewares]
      [http.middlewares.httpsredirect.redirectScheme]
        scheme = "https"

    [http.services]
      [http.services.noop.loadBalancer]
        [[http.services.noop.loadBalancer.servers]]
          url = "http://192.168.0.1"

---

kind: DaemonSet
apiVersion: apps/v1
metadata:
  name: traefik
  namespace: kube-system
  labels:
    app: traefik
spec:
  selector:
    matchLabels:
      app: traefik
  minReadySeconds: 5
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: traefik
    spec:
      serviceAccountName: traefik-ingress-controller
      terminationGracePeriodSeconds: 30
      hostNetwork: true
      containers:
      - name: traefik
        image: traefik:v2.0.0
        env:
          - name: AWS_REGION
            valueFrom:
              configMapKeyRef:
                name: aws-config
                key: aws_region
          - name: AWS_HOSTED_ZONE_ID
            valueFrom:
              configMapKeyRef:
                name: aws-config
                key: aws_hosted_zone_id
          - name: AWS_ACCESS_KEY_ID
            valueFrom:
              secretKeyRef:
                name: aws-secret
                key: access_key
          - name: AWS_SECRET_ACCESS_KEY
            valueFrom:
              secretKeyRef:
                name: aws-secret
                key: secret_key
        ports:
          - name: web
            containerPort: 80
          - name: websecure
            containerPort: 443
          - name: admin
            containerPort: 8080
        securityContext:
          privileged: true
        volumeMounts:
          - mountPath: /etc/traefik/traefik.toml
            name: traefik-config
            subPath: traefik.toml
          - mountPath: /etc/traefik/providers/dynamic.toml
            name: traefik-config
            subPath: dynamic.toml
          - mountPath: /etc/traefik/storage/
            name: traefik-storage
      volumes:
      - name: traefik-config
        configMap:
          name: traefik-conf
      - name: traefik-storage
        hostPath:
          path: /tmp/traefik
          type: DirectoryOrCreate

---

kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: whoami
  namespace: kube-system
  labels:
    app: whoami
spec:
  replicas: 1
  selector:
    matchLabels:
      app: whoami
  template:
    metadata:
      labels:
        app: whoami
    spec:
      containers:
        - name: whoami
          image: containous/whoami
          ports:
            - name: web
              containerPort: 80

service.yaml
---

apiVersion: v1
kind: Service
metadata:
  name: traefik
  namespace: kube-system
spec:
  ports:
    - protocol: TCP
      name: web
      port: 80
      targetPort: 80
    - protocol: TCP
      name: admin
      port: 8080
      targetPort: 8080
    - protocol: TCP
      name: websecure
      port: 443
      targetPort: 443
  selector:
    app: traefik

---

kind: Service
apiVersion: v1
metadata:
  name: traefik-external
  namespace: kube-system
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
spec:
  type: LoadBalancer
  externalTrafficPolicy: Local
  selector:
    app: traefik
  ports:
    - name: web
      protocol: TCP
      port: 80
      targetPort: 80
    - name: websecure
      protocol: TCP
      port: 443
      targetPort: 443
      
---

apiVersion: v1
kind: Service
metadata:
  name: whoami
  namespace: kube-system
spec:
  ports:
    - protocol: TCP
      name: web
      port: 80
  selector:
    app: whoami

ingressroutes.yaml
---

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: traefik-admin
  namespace: kube-system
spec:
  entryPoints:
    - web
  routes:
    - match: Host(`traefik.dev.domain.ca`)
      kind: Rule
      services:
        - name: traefik
          port: 8080

---

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: traefik-admin-tls
  namespace: kube-system
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`traefik.dev.domain.ca`)
      kind: Rule
      services:
        - name: traefik
          port: 8080
  tls:
    certResolver: letsencrypt
    domains:
      - main: test.domain.ca
        sans:
          - "*.test.domain.ca"

---

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: whoami-notls
  namespace: kube-system
spec:
  entryPoints:
    - web
  routes:
    - match: Host(`test.domain.ca`) && PathPrefix(`/notls`)
      kind: Rule
      services:
        - name: whoami
          port: 80

---

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: whoami-tls
  namespace: kube-system
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`test.domain.ca`) && PathPrefix(`/tls`)
      kind: Rule
      services:
        - name: whoami
          port: 80
  tls:
    certResolver: letsencrypt
    domains:
      - main: test.domain.ca
        sans:
          - "test.domain.ca"
          - "*.test.domain.ca"

---

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: whoami-notls2
  namespace: kube-system
spec:
  entryPoints:
    - web
  routes:
    - match: Host(`dev.domain.ca`) && PathPrefix(`/notls`)
      kind: Rule
      services:
        - name: whoami
          port: 80

---

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: whoami-tls2
  namespace: kube-system
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`dev.domain.ca`) && PathPrefix(`/tls`)
      kind: Rule
      services:
        - name: whoami
          port: 80
  tls:
    certResolver: letsencrypt
    domains:
      - main: dev.domain.ca
        sans:
          - "dev.domain.ca"
          - "*.dev.domain.ca"

and curl output

curl http://test.domain.ca/notls
Hostname: whoami-6bd5c965c9-xt4kh
IP: 127.0.0.1
IP: 10.2.23.104
RemoteAddr: 10.2.23.76:47402
GET /notls HTTP/1.1
Host: test.domain.ca
User-Agent: curl/7.54.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 133.132.131.13
X-Forwarded-Host: test.domain.ca
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: ip-10-2-23-76.us-west-2.compute.internal
X-Real-Ip: 133.132.131.13

To me it looks, like what you are observing is because of this piece:

---

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: whoami-notls
  namespace: kube-system
spec:
  entryPoints:
    - web
  routes:
    - match: Host(`test.domain.ca`) && PathPrefix(`/notls`)
      kind: Rule
      services:
        - name: whoami
          port: 80

This matches, it does not contains the redirect so here you go. You other rule in dynamic.toml is probably not even checked, since this one (above) matched before.

I'm not sure about the matching order, would not be surprised if it's non-deterministic and/or not guaranteed.

Does this make sense?

I updated ingress routes to following, still no redirect.

ingressroutes.yaml
---

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: traefik-admin
  namespace: kube-system
spec:
  entryPoints:
    - web
  routes:
    - match: Host(`traefik.test.domain.ca`)
      kind: Rule
      services:
        - name: traefik
          port: 8080

---

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: traefik-admin-tls
  namespace: kube-system
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`traefik.test.domain.ca`)
      kind: Rule
      services:
        - name: traefik
          port: 8080
  tls:
    certResolver: letsencrypt
    domains:
      - main: test.domain.ca
        sans:
          - "*.test.domain.ca"

---

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: whoami-notls
  namespace: kube-system
spec:
  entryPoints:
    - web
  routes:
    - match: Host(`test.domain.ca`)
      kind: Rule
      services:
        - name: whoami
          port: 80

---

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: whoami-tls
  namespace: kube-system
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`test.domain.ca`)
      kind: Rule
      services:
        - name: whoami
          port: 80
  tls:
    certResolver: letsencrypt
    domains:
      - main: test.domain.ca
        sans:
          - "test.domain.ca"
          - "*.test.domain.ca"

---

Sorry, could you please explain why the change that you've made should change the outcome? To me it looks like it still has the same problem, more or less: http://test.domain.ca/notls will match Host(`test.domain.ca`) as well as Host(`test.domain.ca`) && PathPrefix(`/notls`), so I would expect no change, and this is what you reported. Is there another change that I missed?

It worked after removing IngressRoute which were created for entryPoints: web

ingressroutes.yaml
---

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: traefik-admin
  namespace: kube-system
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`traefik.test.domain.ca`)
      kind: Rule
      services:
        - name: traefik
          port: 8080
  tls:
    certResolver: default
    domains:
      - main: test.domain.ca
        sans:
          - "*.test.domain.ca"

---

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: whoami
  namespace: kube-system
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`test.domain.ca`)
      kind: Rule
      services:
        - name: whoami
          port: 80
  tls:
    certResolver: default
    domains:
      - main: test.domain.ca
        sans:
          - "*.test.domain.ca"

---