A global http -> https redirection?

Hi,
Thanks for your work on this great project. I like a lot the new features of traefik 2.

I'm currently migrating a v1 configuration to a v2 one.
From what I gather if I want an http -> https redirection I have to add a RedirectScheme middleware to a router. The issue is that I'd prefer not to add that particular configuration to all of my services manually. I feel like the https decision doesn't belong to the service.

Is there any way or any plan to achieve this globally? Maybe a concept of global middleware that would apply to all routers?

Cheers,
Pierre

1 Like

Hi,

I faced same issue when I first tried v2 on a project.

On v1, it was simply defined:

[entryPoints]
  [entryPoints.http]
  address = ":80"
    [entryPoints.http.redirect]
    entryPoint = "https"
  [entryPoints.https]
  address = ":443"
    [entryPoints.https.tls]

On v2, with middlewares, we got more flexibility but we lost (basic) simple features.

Tried to find a way for this but with no success.

The only way that should work, is to add a middleware at EntryPoints level (similar to v1), but as I see, RedirectScheme is available only at HTTP level.

(EntryPoints have only: transport,proxyProtocol and forwardHeaders).

Any workaround for this?

1 Like

Hello

On my side I defined a router on the traefik container itself, attached to entry point "web", catching all hosts and redirecting to https.
And then I only define TLS router attached only to "websecure" entry point on the services themselves.

This way, only one router listen on "web" entry point, and it redirect everything on https. And the services only listen on "websecure" entry point.
Downsides I see for now:

  • As I have a catch all on http, I'm not sure I could easily expose something else on http if needed
  • when requesting a specific host which is not defined, you get an SSL error instead of standard 404 default backend

With the following example, when you go to http://localhost, you're redirected to https.

docker-compose example:

version: "3.3"

services:

  traefik:
    image: "traefik:v2.0.0-alpha8-alpine"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.http-catchall.rule=hostregexp(`{host:[a-z-.]+}`)"
      - "traefik.http.routers.http-catchall.entrypoints=web"
      - "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - "./traefik.toml:/etc/traefik.toml"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"

  whoami:
    image: containous/whoami
    expose:
      - "80"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`localhost`)"
      - "traefik.http.routers.whoami.entrypoints=websecure"
      - "traefik.http.routers.whoami.tls=true"

traefik.toml:

[global]
  sendAnonymousUsage = true

[providers.docker]
  exposedByDefault = false

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

Not sure it's the best way to do this, but it seems to work.

4 Likes

Interesting. So from the way things look, it seems these "names" are global. So if there's a large team they need to watch out to make sure there are name clashes.

Thank you, this was pretty helpful!

I did this in my docker-compose to redirect, but this need to be done on every service to be exposed. this is no a catch all solution but you will get more controll over what is exposed on http and https.

  whoami:
    image: containous/whoami
    labels:
      # listen for http request and redirect to https
      - "traefik.http.routers.whoami-http.middlewares=https-redirect@file"
      - "traefik.http.routers.whoami-http.rule=Host(`whoami.example.test`)"

      # listen for https requests and use forward auth.
      # Terminate SSL, whoami doesnt listen on SSL traffic, whoami is listening on plain text unencrypted http connections.
      # https://docs.traefik.io/v2.0/routing/routers/#tls
      - "traefik.http.routers.whoami.tls"
      - "traefik.http.routers.whoami.rule=Host(`whoami.example.test`)"
      - "traefik.http.routers.whoami.middlewares=forward-auth@file"

seems overly complicated and verbose, is it really needed to create two routers for each service?

Yes you need to read 2 routers for each redirection.

We know the problem and we plan to think about a new redirection system.


I link another thread to this thread, because it's the same subject:

1 Like

I ran into this problem on a kubernets,

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: admin
spec:
  entryPoints:
    - web
    - websecure
  routes:
  - match: Host(`pwjtest.zhixueyun.com`) && PathPrefix(`/`)
    kind: Rule
    services:
    - name: traefik
      port: 18080
    #  scheme: https
    middlewares:
    - name: admin-https
    - name: admin-auth
    #- name: admin-header
  tls:
    secretName: supersecret
---
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: admin-https
spec:
  redirectScheme:
    scheme: https
    permanent: true
    port: 443
---
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: admin-auth
spec:
  basicAuth:
    secret: authsecret

访问http://domain 会出现404,并不会重定向http://domain.访问http://domain是正常的.

With two routers, write HTTP as one router and HTTPS as one router, and successfully redirect HTTPS with the following configuration.

apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: test-redirectregex
spec:
  redirectRegex:
    regex: ^http://localhost/(.*)
    replacement: https://mydomain/${1}


I don't know if this is my own configuration problem or a bug.

I tried to solve this by using the file backend so that the number of labels in my docker-compose.yml will be reduced. In my setup I used my own traefik Docker container that already ships with the configuration. I don't know if this is useful or not (and may or may not be included in the documentation) but I wanted to share it anyway:

  • static configuration
[entryPoints.http]
  address = ":80"
[entryPoints.https]
  address = ":443"
  • dynamic configuration
# dummy service
[http.services.DefaultHTTPSRedirect.loadBalancer]
  [[http.services.DefaultHTTPSRedirect.loadBalancer.servers]]
    url = "http://localhost/"

# router with PathPrefix /, so everything will be matched
[http.routers.DefaultHTTPSRedirect]
  entryPoints = [ "http" ]
  rule = "PathPrefix(`/`)"
  middlewares = [ "DefaultHTTPSRedirect" ]
  service = "DefaultHTTPSRedirect"
  # lowest possible priority so that the match can be overwritten by anyone
  priority = 1

[http.middlewares.DefaultHTTPSRedirect.RedirectScheme]
  scheme = "https"
  permanent = true
1 Like

It's a bit of traefik idiosyncrasy, is not it? That one has to specify http.services.DefaultHTTPSRedirect.loadBalancer.servers.url which is never used because of the middleware, but traefik would error out if you omit.

Yes, it is :smiley:

You can define everything also inside of a docker-compose.yml with labels and then can omit the service part, because that is autogenerated, but in the file case - as you wrote - you'll run into an error. Maybe using an internal redirecting to api@internal as a service (so something like this) will help to reduce the amount of unnecessary configuration, but the service attribute must unfortunately be set.

To all those searching: seems to be implemented now in Traefik v2:

https://docs.traefik.io/routing/entrypoints/#redirection