Docker4drupal: Traefik v2 https support

Created on 25 Oct 2019  路  11Comments  路  Source: wodby/docker4drupal

I am am trying to up the latest version of docker4drupal to work with Traefik v2. I had it working previously with v1.x of Traefik but am struggling to transition to configure v2.

I have tried to follow the lets encrypt guidelines on traefik website but there seems to be some issue with generating the certificate on a dev environment.

Any guidelines on how to achieve this would be welcome.

Most helpful comment

Can folks actually explain the examples beyond just pasting code above? The setup for v1 was pretty simple but v2 was not working at all.

However it shows the website in http, and the "404 page not found" error in https.

This is exactly my experience. I was looking here, which a handful of places on the net keep referencing: https://containo.us/blog/traefik-2-0-docker-101-fc2893944b9d/

I found that article confusing, the blog post links to multiple files in git and each one is slightly different.

To get HTTP -> HTTPS redirection working, I finally stumbled upon this post. Adapting that, I was finally able to get a self signed certificate and https redirection working.

Here is what I have:

  apache:
    image: wodby/apache:$APACHE_TAG
    container_name: "${PROJECT_NAME}_apache"
    environment:
      APACHE_LOG_LEVEL: debug
      APACHE_BACKEND_HOST: php
      APACHE_VHOST_PRESET: php
      APACHE_DOCUMENT_ROOT: /var/www/html/docroot
    volumes:
      - ./:/var/www/html:cached # User-guided caching
    labels:
      - traefik.http.middlewares.${PROJECT_NAME}_apache_https.redirectscheme.scheme=https
      - traefik.http.routers.${PROJECT_NAME}_apache.entrypoints=web
      - traefik.http.routers.${PROJECT_NAME}_apache.rule=Host(`${PROJECT_BASE_URL}`)
      - traefik.http.routers.${PROJECT_NAME}_apache.middlewares=${PROJECT_NAME}_apache_https@docker
      - traefik.http.routers.${PROJECT_NAME}_apache_https.rule=Host(`${PROJECT_BASE_URL}`)
      - traefik.http.routers.${PROJECT_NAME}_apache_https.tls=true
      - traefik.http.routers.${PROJECT_NAME}_apache_https.entrypoints=websecure

  traefik:
    image: traefik:v2.0
    container_name: "${PROJECT_NAME}_traefik"
    command:
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --providers.docker
      - --providers.file.directory=/etc/traefik/dynamic_conf
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - ./tools/certs:/tools/certs
      - ./tools/traefik/config.yml:/etc/traefik/dynamic_conf/conf.yml:ro
      - /var/run/docker.sock:/var/run/docker.sock

traefik config.yml:

tls:
  certificates:
    - certFile: /tools/certs/cert.crt
      keyFile: /tools/certs/cert.key

Note that the labels in each service are _very_ particular about format, and double check you have no spelling errors. The apache labels are important, as it describes the entrypoints and what to do with them.

This was a lot harder to figure out than I was expecting, and depending on where you look on the internet there are various write ups on what to do. Nothing worked except for the blog post above. The contanious one is confusing and was of no help whatsoever.

I am using a self signed certificate (openssl, but mkcert is probably very similar) so we can get local https with browser trust supported - my containers can't be seen by Lets Encrypt since these are for local development only, so no certificate is ever sent back.

This answer was helpful: https://stackoverflow.com/a/60072381/295112

IMO it would be super helpful for docker4drupal to come with HTTPS enabled and redirecting by default since that is how all production applications are running these days anyway. It shouldn't take hours to figure out how to make it happen (blaming traefik not d4d maintainers) and it seems we are not the only ones.

All 11 comments

Hi, if anyone is interested, I got Traefik 2.0 working with TLS with support for multiple projects.

Here is my setup:

docker-compose.yml

nginx:
  image: wodby/nginx:$NGINX_TAG
  container_name: "${PROJECT_NAME}_nginx"
  depends_on:
    - php
  environment:
    NGINX_STATIC_OPEN_FILE_CACHE: "off"
    NGINX_ERROR_LOG_LEVEL: debug
    NGINX_BACKEND_HOST: php
    NGINX_SERVER_ROOT: /var/www/html/web
    NGINX_VHOST_PRESET: $NGINX_VHOST_PRESET
  volumes:
    - ./:/var/www/html
    - docker-sync-unison:/var/www/common # Docker-sync for macOS users
  labels:
      - "traefik.http.routers.${PROJECT_NAME}_nginx.entrypoints=web"
      - "traefik.http.middlewares.${PROJECT_NAME}_https_nginx.redirectscheme.scheme=https"
      - "traefik.http.routers.${PROJECT_NAME}_https_nginx.rule=Host(`${PROJECT_NAME}.docker.localhost`)"
      - "traefik.http.routers.${PROJECT_NAME}_https_nginx.entrypoints=web-secure"
      - "traefik.http.routers.${PROJECT_NAME}_https_nginx.tls=true"

traefik.yml

Place it separately from your projects and start with docker-compose -f traefik.yml up

version: '3'

services:
  traefik:
    image: traefik:v2.0
    command:
      - "--api.insecure=true"
      - "--providers.docker"
      - "--log.level=DEBUG"
      - "--configFile=./myconfigfile.toml"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.web-secure.address=:443"
    networks:
      - "xxxx"
    ports:
      - '80:80'
      - '8080:8080'
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./certs/:/certs/
    container_name: traefik

networks:
  xxxx:
    external:
      name: xxxx_default

myconfigfile.toml

# dynamic configuration
[http.routers]
  [http.routers.Router-1]
    rule = "Host(`docker.localhost`)"
    service = "service-id"
    # will terminate the TLS request
    [http.routers.Router-1.tls]
      options = "myTLSOptions"

[[tls.certificates]]
    certFile = "/certs/cert.pem"
    keyFile = "/certs/key.pem"

[tls.options]
  [tls.options.default]
    minVersion = "VersionTLS12"

  [tls.options.myTLSOptions]
    minVersion = "VersionTLS13"
    cipherSuites = [
        "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
        "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
        "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
        "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
        "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
        "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
        ]

To enable https you need to do only 2 steps

  1. Enable automatic cetrifs generation
services:
  traefik:
    image: "traefik:v2.0.0"
    command:
      # add these lines
      - --entrypoints.websecure.address=:443
      - [email protected]
      - --certificatesresolvers.le.acme.storage=/acme.json
      - --certificatesresolvers.le.acme.tlschallenge=true
    ports:
      # add 443 port
      - "443:443"

[email protected] - change on yours email address

  1. Enable automatic certifs generation for container (e.g. nginx)

    nginx:
    image: wodby/nginx:$NGINX_TAG
    container_name: "${PROJECT_NAME}_nginx"
    depends_on:
      - php
    environment:
      NGINX_STATIC_OPEN_FILE_CACHE: "off"
      NGINX_ERROR_LOG_LEVEL: debug
      NGINX_BACKEND_HOST: php
      NGINX_SERVER_ROOT: /var/www/html/web
      NGINX_VHOST_PRESET: $NGINX_VHOST_PRESET
    volumes:
      - ./:/var/www/html
    labels:
      - "traefik.http.routers.${PROJECT_NAME}_nginx.rule=Host(`${PROJECT_BASE_URL}`)"
     # add these lines
      - "traefik.http.routers.${PROJECT_NAME}_nginx.tls.certresolver=le"
      - "traefik.http.routers.${PROJECT_NAME}_nginx.entrypoints=websecure"
    

Complete.

Could you explain it? I use it for local development so no LE ACME for me. I use mkcert to generate certificates and Traefik works with both http and https. However it shows the website in http, and the "404 page not found" error in https. How to setup to redirect https traffic to the other containers (Apache, phpMyAdmin etc.) on port 80 so that Traefik does the TLS termination here?

docker-compose.yml

  nginx:
    image: wodby/nginx:$NGINX_TAG
    container_name: "${PROJECT_NAME}_nginx"
    depends_on:
      - php
    environment:
      NGINX_STATIC_OPEN_FILE_CACHE: "off"
      NGINX_CLIENT_MAX_BODY_SIZE: 10G
      NGINX_ERROR_LOG_LEVEL: debug
      NGINX_BACKEND_HOST: php
      NGINX_VHOST_PRESET: php
      NGINX_SERVER_ROOT: /var/www/html/public
      NGINX_STATIC_EXT_REGEX: css|cur|js|htc|ico|xml|otf|ttf|eot|woff|woff2|svg|mp4|svgz|ogg|ogv|pdf|pptx?|zip|tgz|gz|rar|bz2|doc|xls|exe|tar|mid|midi|wav|bmp|rtf|txt|map
    volumes:
      - ./:/var/www/html
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.${PROJECT_NAME}_nginx.entrypoints=http"
      - "traefik.http.routers.${PROJECT_NAME}_nginx.rule=Host(`${PROJECT_NAME}.localhost`)"
      - "traefik.http.middlewares.${PROJECT_NAME}_nginx-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.${PROJECT_NAME}_nginx.middlewares=${PROJECT_NAME}_nginx-https-redirect"
      - "traefik.http.routers.${PROJECT_NAME}_nginx-secure.entrypoints=https"
      - "traefik.http.routers.${PROJECT_NAME}_nginx-secure.rule=Host(`${PROJECT_NAME}.localhost`)"
      - "traefik.http.routers.${PROJECT_NAME}_nginx-secure.tls=true"
      - "traefik.http.routers.${PROJECT_NAME}_nginx-secure.service=${PROJECT_NAME}_nginx"
      - "traefik.http.services.${PROJECT_NAME}_nginx.loadbalancer.server.port=80"

traefik:
    image: traefik
    container_name: traefik
    security_opt:
      - no-new-privileges:true
    ports:
      - 80:80
      - 443:443
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik.yml:/traefik.yml:ro
      - ./traefik.dynamic.yml:/traefik.dynamic.yml:ro
      - ./certs:/certs
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.entrypoints=http"
      - "traefik.http.routers.traefik.rule=Host(`traefik.localhost`)"
      - "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
      - "traefik.http.routers.traefik-secure.entrypoints=https"
      - "traefik.http.routers.traefik-secure.rule=Host(`traefik.localhost`)"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.http.routers.traefik-secure.service=api@internal"
      - "traefik.http.services.traefik.loadbalancer.server.port=8080"

traefik.yml

api:
  dashboard: true

log:
  level: DEBUG
  filePath: "debug.log"
  format: json

accessLog:
  filePath: "access.log"
  bufferingSize: 100

entryPoints:
  http:
    address: ":80"
  https:
    address: ":443"

providers:
  file:
    filename: /traefik.dynamic.yml
    watch: true
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false

traefik.dynamic.yml

tls:
  stores:
    default:
      defaultCertificate:
        certFile: /certs/localhost+5.pem
        keyFile: /certs/localhost+5-key.pem
  certificates:
    - certFile: /certs/localhost+5.pem
      keyFile: /certs/localhost+5-key.pem

certificates are generated by mkcert for ${PROJECT_NAME}.localhost, varnish.${PROJECT_NAME}.localhost traefik.localhost and localhost.

Need to replace ${PROJECT_NAME} to your project name.

Can folks actually explain the examples beyond just pasting code above? The setup for v1 was pretty simple but v2 was not working at all.

However it shows the website in http, and the "404 page not found" error in https.

This is exactly my experience. I was looking here, which a handful of places on the net keep referencing: https://containo.us/blog/traefik-2-0-docker-101-fc2893944b9d/

I found that article confusing, the blog post links to multiple files in git and each one is slightly different.

To get HTTP -> HTTPS redirection working, I finally stumbled upon this post. Adapting that, I was finally able to get a self signed certificate and https redirection working.

Here is what I have:

  apache:
    image: wodby/apache:$APACHE_TAG
    container_name: "${PROJECT_NAME}_apache"
    environment:
      APACHE_LOG_LEVEL: debug
      APACHE_BACKEND_HOST: php
      APACHE_VHOST_PRESET: php
      APACHE_DOCUMENT_ROOT: /var/www/html/docroot
    volumes:
      - ./:/var/www/html:cached # User-guided caching
    labels:
      - traefik.http.middlewares.${PROJECT_NAME}_apache_https.redirectscheme.scheme=https
      - traefik.http.routers.${PROJECT_NAME}_apache.entrypoints=web
      - traefik.http.routers.${PROJECT_NAME}_apache.rule=Host(`${PROJECT_BASE_URL}`)
      - traefik.http.routers.${PROJECT_NAME}_apache.middlewares=${PROJECT_NAME}_apache_https@docker
      - traefik.http.routers.${PROJECT_NAME}_apache_https.rule=Host(`${PROJECT_BASE_URL}`)
      - traefik.http.routers.${PROJECT_NAME}_apache_https.tls=true
      - traefik.http.routers.${PROJECT_NAME}_apache_https.entrypoints=websecure

  traefik:
    image: traefik:v2.0
    container_name: "${PROJECT_NAME}_traefik"
    command:
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --providers.docker
      - --providers.file.directory=/etc/traefik/dynamic_conf
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - ./tools/certs:/tools/certs
      - ./tools/traefik/config.yml:/etc/traefik/dynamic_conf/conf.yml:ro
      - /var/run/docker.sock:/var/run/docker.sock

traefik config.yml:

tls:
  certificates:
    - certFile: /tools/certs/cert.crt
      keyFile: /tools/certs/cert.key

Note that the labels in each service are _very_ particular about format, and double check you have no spelling errors. The apache labels are important, as it describes the entrypoints and what to do with them.

This was a lot harder to figure out than I was expecting, and depending on where you look on the internet there are various write ups on what to do. Nothing worked except for the blog post above. The contanious one is confusing and was of no help whatsoever.

I am using a self signed certificate (openssl, but mkcert is probably very similar) so we can get local https with browser trust supported - my containers can't be seen by Lets Encrypt since these are for local development only, so no certificate is ever sent back.

This answer was helpful: https://stackoverflow.com/a/60072381/295112

IMO it would be super helpful for docker4drupal to come with HTTPS enabled and redirecting by default since that is how all production applications are running these days anyway. It shouldn't take hours to figure out how to make it happen (blaming traefik not d4d maintainers) and it seems we are not the only ones.

Unfortunately I haven't had luck with getting the http to https redirect to work.

I keep getting field not found redirectscheme and when commenting out the first line, I also then get middleware \"docker4drupal_apache_https@docker\" does not exist".

Otherwise the configuration worked for https and http.

I think the issue for me ended up being - traefik.http.routers.${PROJECT_NAME}_apache.middlewares=${PROJECT_NAME}_apache_https@docker, and removing @docker from the end. Then Kevin's configuration worked for me.

It helped me. There are enough instructions to understand how to configure that

Note: remember that if you make a mistake in the labels with route name you will get a 404 error in the browser without any logs for traefik.

https://docs.traefik.io/user-guides/docker-compose/acme-tls/

   nginx:
    image: wodby/nginx:$NGINX_TAG
    container_name: "${PROJECT_NAME}_nginx"
    depends_on:
      - php
    environment:
      NGINX_STATIC_OPEN_FILE_CACHE: "off"
      NGINX_ERROR_LOG_LEVEL: debug
      NGINX_BACKEND_HOST: php
      NGINX_SERVER_ROOT: /var/www/html/docroot
      NGINX_VHOST_PRESET: $NGINX_VHOST_PRESET
    #      NGINX_DRUPAL_FILE_PROXY_URL: http://example.com
    volumes:
      - ./www:/var/www/html
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.${PROJECT_NAME}_nginx.rule=Host(`${PROJECT_BASE_URL}`)"
      - "traefik.http.routers.${PROJECT_NAME}_nginx.entrypoints=websecure"
      - "traefik.http.routers.${PROJECT_NAME}_nginx.tls.certresolver=myresolver"
  traefik:
    image: traefik
    container_name: "traefik"
    command:
      #- "--log.level=DEBUG"
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.myresolver.acme.tlschallenge=true"
      #- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
      - "--certificatesresolvers.myresolver.acme.email=your_email@gmail.com"
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
    ports:
      - "443:443"
      - "8080:8080"
    volumes:
      - "./letsencrypt:/letsencrypt"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"

It helped me. There are enough instructions to understand how to configure that

https://docs.traefik.io/user-guides/docker-compose/acme-tls/

That page mentions:

For the TLS challenge you will need:

  • A publicly accessible host allowing connections on port 443 with docker & docker-compose installed.

Are we not talking about local dev environments here??
So this is unrelated + again, everyone, please stop just dumping code here without any further explanation.

On an older Traefik version on a LOCAL development environment, on macOS, I got HTTPS working the following way:

docker-compose.yml:

  traefik:
    image: traefik:v1.7.16-alpine
    container_name: "${PROJECT_NAME}_traefik"
    command: -c /dev/null --web --docker --logLevel=INFO --defaultEntryPoints='https' --entryPoints="Name:https Address::443 TLS:/certs/mysite_cert.pem,/certs/mysite_cert-key.pem" --entryPoints="Name:http Address::80 Redirect.EntryPoint:https"
    ports:
      - '8000:80'
      - '443:443'
    volumes:
      - ./certs:/certs/
      - /var/run/docker.sock:/var/run/docker.sock

mysite_cert.pem and mysite_cert-key.pem needs to be adjusted to your own certificates naming.

I generated self-signed certificates using mkcert, see: https://github.com/FiloSottile/mkcert/blob/master/README.md

I placed the certificates in a certs folder, at the project root (where docker-compose.yml file is).
There is no redirection. Only direct access on HTTPS, but it works and is sufficient for my needs.

Note that I was still getting errors with the above settings until I restarted Docker desktop then all went fine.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

quietone1 picture quietone1  路  10Comments

jayjaydluffy picture jayjaydluffy  路  5Comments

AminSarafraz picture AminSarafraz  路  4Comments

VladSavitsky picture VladSavitsky  路  6Comments

featherbelly picture featherbelly  路  5Comments