Provide static ssl certificate for all routers/services

Hi,

could anybody give me an example as docker-compose.yml how i can use existing ssl-cert/key files provided as /certs/default-cert.pem and /certs/default-key.pem for each dynamic router which I add?

All I am trying is not working, e.g.

version: '3.2'
services:
  app:
    image: traefik:v2.0
    restart: unless-stopped
    ports:
    - "80:80"
    - "443:443"
    - "5432:5432"
    volumes:
    - /var/run/docker.sock:/var/run/docker.sock:ro
    - ${traefik_certs_folder:-./certs}:/certs
    environment:
      TRAEFIK_API: "true"
      TRAEFIK_API_INSECURE: "true"
      TRAEFIK_SERVERSTRANSPORT_INSECURESKIPVERIFY: "true"
      TRAEFIK_ENTRYPOINTS_HTTPS: "true"
      TRAEFIK_ENTRYPOINTS_HTTPS_ADDRESS: ":443"
      TRAEFIK_LOG_LEVEL: "DEBUG"
      TRAEFIK_PROVIDERS_DOCKER: "true"
      TRAEFIK_PROVIDERS_DOCKER_NETWORK: "proxy"
      TRAEFIK_PROVIDERS_DOCKER_EXPOSEDBYDEFAULT: "false"
      TRAEFIK_PING: "true"
    labels:
    - "traefik.enable=true"
    - "traefik.docker.network=proxy"
    - "traefik.http.routers.traefik-https.entrypoints=https"
    - "traefik.http.routers.traefik-https.tls=true"
    - "traefik.http.routers.traefik-https.rule=Host(`${host:-traefik.localhost}`)"
    - "traefik.http.services.traefik.loadbalancer.server.port=8080"
    - "traefik.tls.stores.default.defaultCertificate.certFile=/certs/default-cert.pem"
    - "traefik.tls.stores.default.defaultCertificate.keyFile=/certs/default-key.pem"

networks:
  default:
    external:
      name: proxy

traefik always complains about no default certificate and is generating a new one. This is annoying because this certificate is shared among all services and is always created when a new service arrives

app_1  | time="2019-09-25T13:51:54Z" level=info msg="Configuration loaded from environment variables."
app_1  | time="2019-09-25T13:51:54Z" level=info msg="Traefik version 2.0.0 built on 2019-09-16T17:35:17Z"
app_1  | time="2019-09-25T13:51:54Z" level=debug msg="Static configuration loaded {\"global\":{\"checkNewVersion\":true},\"serversTransport\":{\"insecureSkipVerify\":true,\"maxIdleConnsPerHost\":200},\"entryPoints\":{\"https\":{\"address\":\":443\",\"transport\":{\"lifeCycle\":{\"graceTimeOut\":10000000000},\"respondingTimeouts\":{\"idleTimeout\":180000000000}},\"forwardedHeaders\":{}},\"traefik\":{\"address\":\":8080\",\"transport\":{\"lifeCycle\":{\"graceTimeOut\":10000000000},\"respondingTimeouts\":{\"idleTimeout\":180000000000}},\"forwardedHeaders\":{}}},\"providers\":{\"providersThrottleDuration\":2000000000,\"docker\":{\"watch\":true,\"endpoint\":\"unix:///var/run/docker.sock\",\"defaultRule\":\"Host(`{{ normalize .Name }}`)\",\"network\":\"proxy\",\"swarmModeRefreshSeconds\":15000000000}},\"api\":{\"insecure\":true,\"dashboard\":true},\"ping\":{\"entryPoint\":\"traefik\"},\"log\":{\"level\":\"DEBUG\",\"format\":\"common\"}}"
app_1  | time="2019-09-25T13:51:54Z" level=info msg="\nStats collection is disabled.\nHelp us improve Traefik by turning this feature on :)\nMore details on: https://docs.traefik.io/v2.0/contributing/data-collection/\n"
app_1  | time="2019-09-25T13:51:54Z" level=debug msg="No default certificate, generating one"
app_1  | time="2019-09-25T13:51:54Z" level=debug msg="Start TCP Server" entryPointName=traefik
app_1  | time="2019-09-25T13:51:54Z" level=info msg="Starting provider aggregator.ProviderAggregator {}"
app_1  | time="2019-09-25T13:51:54Z" level=debug msg="Start TCP Server" entryPointName=https
app_1  | time="2019-09-25T13:51:54Z" level=info msg="Starting provider *docker.Provider {\"watch\":true,\"endpoint\":\"unix:///var/run/docker.sock\",\"defaultRule\":\"Host(`{{ normalize .Name }}`)\",\"network\":\"proxy\",\"swarmModeRefreshSeconds\":15000000000}"
app_1  | time="2019-09-25T13:51:54Z" level=debug msg="Provider connection established with docker 19.03.2 (API 1.40)" providerName=docker
app_1  | time="2019-09-25T13:51:54Z" level=debug msg="Filtering disabled container" providerName=docker container=/mailcollect_app.1.t9wwpkp1y0d3534bt69ensxs8-6a82a8f4673ccf227aa09ef298ea6dfe8c890820140ee9a599fb60f5472bfb62
app_1  | time="2019-09-25T13:51:54Z" level=debug msg="Configuration received from provider docker: {\"http\":{\"routers\":{\"traefik-https\":{\"entryPoints\":[\"https\"],\"service\":\"traefik\",\"rule\":\"Host(`traefik.localhost`)\",\"tls\":{}}},\"services\":{\"traefik\":{\"loadBalancer\":{\"servers\":[{\"url\":\"http://10.13.2.176:8080\"}],\"passHostHeader\":true}}}},\"tcp\":{}}" providerName=docker
app_1  | time="2019-09-25T13:51:54Z" level=debug msg="Creating middleware" entryPointName=https routerName=traefik-https@docker serviceName=traefik middlewareName=pipelining middlewareType=Pipelining
app_1  | time="2019-09-25T13:51:54Z" level=debug msg="Creating load-balancer" entryPointName=https routerName=traefik-https@docker serviceName=traefik
app_1  | time="2019-09-25T13:51:54Z" level=debug msg="Creating server 0 http://10.13.2.176:8080" entryPointName=https routerName=traefik-https@docker serviceName=traefik serverName=0
app_1  | time="2019-09-25T13:51:54Z" level=debug msg="Added outgoing tracing middleware traefik" routerName=traefik-https@docker entryPointName=https middlewareName=tracing middlewareType=TracingForwarder
app_1  | time="2019-09-25T13:51:54Z" level=debug msg="Creating middleware" entryPointName=https middlewareType=Recovery middlewareName=traefik-internal-recovery
app_1  | time="2019-09-25T13:51:54Z" level=debug msg="No default certificate, generating one"

thanks in advance

I found I had to move my dynamic SSL certificate definitions into a separate TOML/YML config file and use the File Provider to reference it.

certificates.yml

---
tls:
  certificates:
    - certFile: "/private.crt"
      keyFile: "/private.key"
      stores:
        - default
  stores:
    default:
      defaultCertificate:
        certFile: "/private.crt"
        keyFile: "/private.key"

Add this to the Docker Command:

--providers.file.filename=/my/path/to/certificates.yml

Or use the rather undocumented TRAEFIK_PROVIDERS_FILE_FILENAME="/my/path/to/certificates.yml" env variable.

As a note, I'd highly recommend having a static configuration file for Traefik rather than using the ENV variables and use the Docker labels for service discovery, including for the Traefik dashboard and API as you're doing above. https://docs.traefik.io/v2.0/getting-started/configuration-overview/ gives a great overview of configuration in Traefik and the difference between "Static" config and "Dynamic" config - you might find that helpful.

https://docs.traefik.io/v2.0/reference/static-configuration/env/

Sure, it's listed, but it doesn't say much except:

`TRAEFIK_PROVIDERS_FILE_FILENAME` :
Override default configuration template. For advanced users :)

Not sure that's a helpful bit of documentation. In fact, I'd go as far as to say that might even just be a copy-and-paste or "merge" error somewhere upstream. It might be for advanced users, but the "advanced" documentation or usage of that simply doesn't exist anywhere. I LOVE Traefik, but documenting the millions of ways of configuring things, or pushing a "preferred method" would be helpful - especially as V2 is so new. Anyhoo, this is entirely off topic.

1 Like

@Schodemeiss good catch :+1: I will fix that.

No worries at all. It -might- even be correct in that it changes the default loading of "traefik.yml/toml" to whatever this ENV var is set to, in which case, that might trip some people up, hence the "Advanced User Warning" - but still, this is all guesses. I'd love to make some contributions to the Traefik docs once I've got to grips with V2 a little more.

Probably more important to document how to get user created certificates into Traefik without having to use File Providers as per the original post. I couldn't find a way except as I mention in my first reply.

Thanks for the hint. Adding the following content to a file and adding that file as a file-provider using the env var TRAEFIK_PROVIDERS_FILE_FILENAME did the trick.

---
tls:
  stores:
    default:
      defaultCertificate:
        certFile: "/certs/default-cert.pem"
        keyFile: "/certs/default-key.pem"

Although it makes no sense to me. It is dynamic configuration and all dynamic configuration should also be addable by docker-labels via the docker-provider, but the reference states that this configuration cannot be made.

@Schodemeiss you suggest not to use environment variables as static configuration. Why is that? It is clearly supported by traefik and a convenient way to set up traefik without having another config-file.

Some configuration values can be "watched" by Traefik and be reloaded without restarting the application. Things such as swapping out the certificates. You can simply load in a new configuration file and Traefik will pick up on the changes. I don't believe Traefik watches the environment variables in the same way.

Secondly, if you end up with some fairly complex configuration, IMHO, it's much easier to parse when looking at it in TOML or YAML than a big list of ENV variables.

Finally, if you when using Docker you can also use Docker Configs (https://docs.docker.com/engine/swarm/configs/) or Docker Secrets (https://docs.docker.com/engine/swarm/secrets/) and have the configuration stored and deployed elsewhere should you require that separation. IE; an IT Security team might store the certificates in Secrets and deploy the application on your behalf, whilst leaving the configuration control file up to someone else in a separate repository. Of this course, this might not apply to your use case, but storing certificates in Secrets means you can also load those certs into other containers should they need it without having to store multiple copies of the certificates all over the place.

The static configuration is never watched, so it's the same thing to use CLI flags, env vars, or file on this point.

Isn't the TLS configuration dynamic? So providing those using a File Provider should mean you can swap these out easily, right? Says so right in the docs. https://docs.traefik.io/v2.0/https/tls/

TLS configuration cannot be define by using the env vars because it's in the static configuration.

In the v2, the static and the dynamic configuration cannot be put in the same file.

Ok, so we're not wrong putting the TLS certs inside a separate file and defining them there? And they can be swapped out live?

You are not wrong at all:

  1. as it's not a part of the static configuration, the TLS certs definition cannot be define by flags, env vars or file (traefik.toml)
  2. use a dedicated file only to manage certs makes maintenance easier.
  3. the files of the dynamic configuration are watched.
1 Like

Ace, thank-you for the clarification. Great job on Traefik BTW. Really want to help contribute someway besides on here when I get some time.

1 Like