<p>I'm after a very simple requirement - yet seems impossible to make Traefik redirect traffic from HTTP to HTTPS when behind an external load balancer.</p>

<p>This is my GCE ingress</p>

<pre><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  namespace: platform
  name: public-ingress
  annotations:
    kubernetes.io/ingress.global-static-ip-name: "kubernetes-cluster-dev-ip"
    kubernetes.io/ingress.class: "gce"
    ingress.gcp.kubernetes.io/pre-shared-cert: "application-dev-ssl,application-dev-graphql-ssl"
spec:
  backend:
    serviceName: traefik-ingress-service
    servicePort: 80
</code></pre>

<p>Which receive traffic from HTTP(S) then forward to Traefik to port 80.</p>

<p>I initially tried to using Traefik way of redirecting matching the schema with this configuration:</p>

<pre><code>[entryPoints]
  [entryPoints.http]
    address = ":80"
    compress = true
    [entryPoints.http.redirect]
    entryPoint = "https"
  [entryPoints.https]
    address = ":443"
    compress = true
    [entryPoints.https.tls] 
</code></pre>

<p>But obviously gets into an infinite redirect loop because of the load balancer always proxy traffic to Traefik port 80.</p>

<p>The simple solution to make this work is exactly what GCE suggests
<a href="https://github.com/kubernetes/ingress-gce#ingress-cannot-redirect-http-to-https" rel="nofollow noreferrer">https://github.com/kubernetes/ingress-gce#ingress-cannot-redirect-http-to-https</a></p>

<p>Being able to check for the <code>http_x_forwarded_proto</code> header and redirect based on that.</p>

<p>Nginx equivalent</p>

<pre><code># Replace '_' with your hostname.
server_name _;
if ($http_x_forwarded_proto = "http") {
    return 301 https://$host$request_uri;
}
</code></pre>

<p>Can someone advice what's the best way of handling this with Traefik, please!</p>

<p>To recap, you have a GCE L7 (Layer 7) load balancer proxying another L7 load balancer in Traefik that you can potentially use it to proxy to another backend service. So looks like you have something like this:</p>

<pre><code>GCE L7 LB HTTP 80
=&gt; Forwarded to Traefik HTTP 80
=&gt; Redirect initial request to HTTPS 443 
=&gt; The client thinks it needs to talk to GCE L7 LB HTTPS 443
=&gt; GCE L7 LB HTTP 443
=&gt; Forwarded to Traefik HTTP 80
=&gt; Infinite loop
</code></pre>

<p>and you need to have something like this:</p>

<pre><code>GCE L7 LB HTTP 80
=&gt; Forwarded to Traefik HTTP 80
=&gt; Redirect initial request to HTTPS 443 
=&gt; The client thinks it needs to talk to GCE L7 LB HTTPS 443
=&gt; GCE L7 LB HTTP 443
=&gt; Forwarded to Traefik HTTP 443
</code></pre>

<p>It's not documented anywhere if Traefik redirects to HTTPS based on the value of <code>http_x_forwarded_proto</code> being <code>http</code>, but that would be the general assumption. In any case, the <code>Ingress</code> doesn't know anything about an HTTPS backend (you didn't specify how you configured the HTTPS GCE LB endpoint).</p>

<p>You can see that it's documented <a href="https://github.com/kubernetes/ingress-gce#backend-https" rel="nofollow noreferrer">here</a> how to make the GCE LB directly create an HTTPS endpoint that forward directly to your HTTPS backend. Basically, you can try adding the <code>service.alpha.kubernetes.io/app-protocols</code> annotation to the HTTPS Traefik service:</p>

<pre><code>apiVersion: v1
kind: Service
metadata:
  name: traefik-https
  annotations:
      service.alpha.kubernetes.io/app-protocols: '{"my-https-port":"HTTPS"}'
  labels:
    app: echo
spec:
  type: NodePort
  ports:
  - port: 443
    protocol: TCP
    name: my-https-port
  selector:
    app: traefik
</code></pre>

<p>So you would have something like this:</p>

<pre><code>GCE L7 LB HTTP 80
=&gt; Forwarded to Traefik HTTP 80
=&gt; Redirect initial request to HTTPS 443 
=&gt; The client thinks it needs to talk to GCE L7 LB HTTPS 443
=&gt; GCE L7 LB HTTP 443
=&gt; Forwarded to Traefik HTTPS service
=&gt; Service forward to Traefik port 443
</code></pre>

<p>Hope this helps.</p>
