Traefik 2 with docker autodiscovery + automatic https + http to https redirection + secure api + basic auth + influxdb metrics

Retour

Minimal version

http server with docker autodiscovery
Create a docker-compose.yml with this content

version: "3.3"

services:
  traefik:
    image: "traefik:v2.0.0"
    command:
      - --entrypoints.web.address=:80
      - --providers.docker=true
    ports:
      - "80:80"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"

  myapp:
    image: containous/whoami:v1.3.0
    labels:
      - traefik.http.routers.myapp.rule=Host(`test.raphaelpiccolo.com`)
    ports:
      - "8989:80"

Then

docker-compose up -d

curl http://test.raphaelpiccolo.com
curl http://test.raphaelpiccolo.com:8989

Both url work, to block second url, bind to localhost port :

- "127.0.0.1:8989:80"

It's also possible to remove ports specification completely if the image exposes the port, because traefik will find it.

complete version :

http server with docker autodiscovery
automatically redirect http to https if using websecure entrypoint
automatically generate https when needed
This file will store https certificates : /traefik/acme.json
wait 10 secs for letsencrypt to generate certificates. In the meantime the site is working but there is a certificate alert.
traefik api is now available https://traefik.raphaelpiccolo.com

Create a docker-compose.yml

version: "3.3"

services:
  traefik:
    image: "traefik:v2.0.0"
    command:
      # listen port 443 and name it websecure
      - --entrypoints.websecure.address=:443
      # listen port 80 and name it web
      - --entrypoints.web.address=:80
      # you need to enable traefik on each container
      - --providers.docker.exposedByDefault=false
      # listen for docker changes
      - --providers.docker=true
      # activate traefik api
      - --api
      # use letencrypt to generate certificates
      - --certificatesresolvers.le.acme.email=rafi.piccolo@gmail.com
      - --certificatesresolvers.le.acme.storage=/traefik/acme.json
      - --certificatesresolvers.le.acme.tlschallenge=true
      # set logging level
      - --log.level=INFO
      # activate accesslog in a separate file
      - --accesslog=true
      - --accesslog.filepath=/traefik/access.log
      # activate metrics exporting to influxdb
      - --metrics.influxdb=true
      - --metrics.influxdb.address=influxdb.raphaelpiccolo.com:8089
      - --metrics.influxdb.database=traefik
      - --metrics.influxdb.username=root
      - --metrics.influxdb.password=root
      - --metrics.influxdb.addServicesLabels=true
      # config file for more settings : tls ciphers for grade A on ssllabs
      - --providers.file.filename=/traefik/traefik.toml
      - --providers.file.watch=true
    labels:
      - traefik.enable=true

      # create a middleware named redirect-to-https, to automatically redirect http to https 
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true"

      # create a middleware to redirect to www
      - traefik.http.middlewares.redirect-to-www.redirectregex.regex=(https|http)://(?:www.)?(.*)
      - traefik.http.middlewares.redirect-to-www.redirectregex.replacement=https://www.$${2}

      # create a middleware to redirect to non-www
      - traefik.http.middlewares.redirect-to-nonwww.redirectregex.regex=(https|http)://(www\.(.*))
      - traefik.http.middlewares.redirect-to-nonwww.redirectregex.replacement=https://$${3}

      # apply middleware "redirect-to-https", to all hosts connected to "web" entrypoint
      - "traefik.http.routers.redirs.rule=hostregexp(`{host:.+}`)"
      - "traefik.http.routers.redirs.entrypoints=web"
      - "traefik.http.routers.redirs.middlewares=redirect-to-https"

      # create a middleware named auth, to request a basic authentification of users
      # you can generate a user:password pair with this command :
      # echo $(htpasswd -nb user password) | sed -e s/\\$/\\$\\$/g
      - traefik.http.middlewares.auth.basicauth.users=user:$$apr1$$WH5iVjXW$$bda85jX7RQGGcCs3hnP8b0

      # create a middleware named admin, to request a basic authentification for admin
      - traefik.http.middlewares.admin.basicauth.users=admin:$$apr1$$SIIXcmeY$$GAkMymzdfhwACgQvM9PNy1

      # create a middleware named securityheaders to automatically set security headers to pass : https://securityheaders.com/
      - "traefik.http.middlewares.securityheaders.headers.framedeny=true"
      - "traefik.http.middlewares.securityheaders.headers.customFrameOptionsValue=sameorigin"
      - "traefik.http.middlewares.securityheaders.headers.referrerPolicy=same-origin"
      - "traefik.http.middlewares.securityheaders.headers.BrowserXssFilter=true"
      - "traefik.http.middlewares.securityheaders.headers.ContentTypeNosniff=true"
      - "traefik.http.middlewares.securityheaders.headers.ForceSTSHeader=true"
      - "traefik.http.middlewares.securityheaders.headers.SSLRedirect=true"
      - "traefik.http.middlewares.securityheaders.headers.STSIncludeSubdomains=true"
      - "traefik.http.middlewares.securityheaders.headers.STSPreload=true"
      - "traefik.http.middlewares.securityheaders.headers.STSSeconds=315360000"

      # api secure
      - "traefik.http.routers.traefik.rule=Host(`traefik.raphaelpiccolo.com`)"
      - "traefik.http.routers.traefik.service=api@internal"
      - "traefik.http.routers.traefik.middlewares=securityheaders,admin"
      - "traefik.http.routers.traefik.tls.certresolver=le"
      - "traefik.http.routers.traefik.entrypoints=websecure"

    ports:
      # web entrypoint
      - "80:80"
      # websecure entrypoint
      - "443:443"
    volumes:
      # to listen docker changes
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      # to save https certificates
      - "./traefik:/traefik"

  myapp:
    image: containous/whoami:v1.3.0
    labels:
      # domain name for this container : you can specify multiple domains
      - traefik.http.routers.myapp.rule=Host(`raphaelpiccolo.com`, `www.raphaelpiccolo.com`)
      # set a basic auth on a container + securityheaders
      - traefik.http.routers.myapp.middlewares=auth,securityheaders,redirect-to-www
      # use https
      - traefik.http.routers.myapp.tls.certresolver=le
      - traefik.http.routers.myapp.entrypoints=websecure
    ports:
      - "127.0.0.1:9090:80"

  # proxy to host (172.17.0.1) port (19999)
  # get docker host ip (usable from inside a container) : ip addr show docker0
  # displays : 172.17.0.1
  netdata:
    image: alpine/socat
    container_name: netdata
    restart: always
    command: tcp-listen:80,fork,reuseaddr tcp-connect:172.17.0.1:19999
    labels:
      - traefik.http.routers.netdata.rule=Host(`netdata.flatbay.fr`)
      # when the container has many ports you can indicate to traefik which one he should connect to the domain
      - traefik.http.services.netdata.loadbalancer.server.port=80
      # if you want to specify tls options (see traefik.toml)
      - traefik.http.routers.netdata.tls.options=notsafe@file
      - traefik.http.routers.netdata.tls.certresolver=le
      - traefik.http.routers.netdata.entrypoints=websecure
      - traefik.http.routers.netdata.middlewares=securityheaders,admin

  portainer:
    image: portainer/portainer
    container_name: portainer
    restart: always
    ports:
      - "127.0.0.1:19000:9000"
    # no auth because we add the admin basic auth with traefik
    command: --no-auth
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./portainer:/data
    labels:
      - traefik.http.routers.portainer.rule=Host(`portainer.flatbay.fr`)
      - traefik.http.routers.portainer.tls.certresolver=le
      - traefik.http.routers.portainer.entrypoints=websecure
      - traefik.http.routers.portainer.middlewares=securityheaders,admin

create traefik.toml
only usefull if grade A on ssllabs

[tls.options]
  [tls.options.default]
    minVersion = "VersionTLS12"
    cipherSuites = [
        "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
        "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
        "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
        "TLS_AES_128_GCM_SHA256",
        "TLS_AES_256_GCM_SHA384",
        "TLS_CHACHA20_POLY1305_SHA256"
    ]
    sniStrict = true
  [tls.options.notsafe]

other technique to create a service to redirect to host

in traefik.toml

[http]
  [http.routers]
    [http.routers.netdata]
      rule = "Host(`netdata.flatbay.fr`)"
      service = "netdata"

  [http.services]
    [http.services.netdata.loadBalancer]
      [[http.services.netdata.loadBalancer.servers]]
        url = "http://172.17.0.1:19999/"