Cloudflare SSL with Traefik and Let’s Encrypt

Using Traefik with Let’s Encrypt is very simple however when using Cloudflare with strict SSL mode to proxy traffic it becomes a bit more difficult. If the option is set in Cloudflare to redirect HTTP to HTTPS it also causes more problems with HTTP validation.

The main issue with strict SSL mode is the server will need to have a valid SSL certificate. Since I am using HTTP based validation and Traefik would not yet have the certificate available Traefik would serve the response using a default self signed certificate. Cloudflare would then reject the servers response since its not a trusted certificate.

The below steps work around the problems I encountered when using Traefik with a Docker Swarm.

Cloudflare Configuration

In the Cloudflare dashboard, select the domain and go to SSL/TLS -> Overview. Set the SSL/TLS encryption mode to “Full (strict)” if not already set:

The “Always Use HTTPS” option that is in SSL/TLS -> Edge Certificates needs to be set to off:

Go to Rules -> Page Rules and create a new page rule. Set the URL to the following:

*domain.com/.well-known/acme-challenge/*

Then for the settings area set the option for “SSL” to be “Off”:

Next create another rule to handle the HTTPS redirect (this is the replacement for the “Always Use HTTPS” option that was turned off earlier). Set the URL to the following:

*domain.com/*

And set the setting for “Always Use HTTPS”:

On the page rules page, make sure the ACME challenge rule is in position 1 and the always use HTTPS rule is in position 2:

Traefik Configuration

In the Traefik Docker Compose file, add the certificate resolver for Let’s Encrypt with the httpchallenge entry type.

My entry point for HTTP connections is named “web” so the configuration looks like this:

services:
  traefik:
...
    command:
...
      ## Enable docker provider
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      ## Set inbound connections port for HTTP
      - "--entrypoints.web.address=:80"
      ## Set inbound connections port for HTTPS
      - "--entrypoints.websecure.address=:443"
      ## Configure LetsEncrypt HTTP01 challenge
      - "--certificatesresolvers.le-http.acme.email=letsencrypt@gbe0.com"
      - "--certificatesresolvers.le-http.acme.storage=/certificates/certificates.json"
      - "--certificatesresolvers.le-http.acme.keytype=EC384"
      - "--certificatesresolvers.le-http.acme.httpchallenge.entrypoint=web"
...

Then in the service that Traefik is serving, set the certresolver to the new one created above:

services:
  gbe0-com:
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=traefik_gbe0-com"
      - "traefik.http.routers.gbe0-com.entrypoints=websecure"
      - "traefik.http.routers.gbe0-com.rule=Host(`gbe0.com`,`www.gbe0.com`)"
      - "traefik.http.routers.gbe0-com.service=gbe0-com"
      - "traefik.http.routers.gbe0-com.tls=true"
      - "traefik.http.routers.gbe0-com.tls.certresolver=le-http"
      - "traefik.http.services.gbe0-com.loadbalancer.server.port=8080"
      - "traefik.http.services.gbe0-com.loadbalancer.healthcheck.hostname=gbe0.com"
      - "traefik.http.services.gbe0-com.loadbalancer.healthcheck.path=/health"
      - "traefik.http.services.gbe0-com.loadbalancer.healthcheck.port=8080"

Traefik may need to be restarted if there was existing failed SSL requests, but it should then be getting SSL’s just fine.

Leave a Reply

Your email address will not be published. Required fields are marked *