9

I am trying to build a Traefik dynamic configuration that has a rule for "Host(app.localhost)" in development but uses "Host(realname.com)" in production. I'm also using Docker but I don't think that is relevant to my question. My question is: is there an idiomatic way to use environment variables in my dynamic configuration?

The docs mention Go templates but I don't understand it beyond that. It's really lacking. I've also considered something like envsubst but was hoping to not have to install another tool.

I'm using Traefik 2.0+. Also, I must use the File Provider as I'm using a self-signed cert locally for TLS. From Traefik's documentation:

In the above example, we've used the file provider to handle these definitions. It is the only available method to configure the certificates (as well as the options and the stores). However, in Kubernetes, the certificates can and must be provided by secrets.

adam-beck
  • 5,659
  • 5
  • 20
  • 34
  • Are you using Traefik as a native install or is it a docker container itself? Also, What version of Traefik are you using? – abmblob Feb 18 '20 at 09:04
  • @ABMRuman I've added the version of Traefik I'm using. I did mention that I'm using Docker but that shouldn't matter, right? I just want to know if there is a way to provide dynamic configuration to the dynamic configuration file. Whew! That's a mouthful. I guess, with Docker, I can point to different files but I was hoping to avoid having 2 separate (1 for prod; 1 for dev) configurations. – adam-beck Feb 18 '20 at 11:09
  • 1
    **I did mention that I'm using Docker but that shouldn't matter, right?** Well it kinda does matter... Because if you are using a traefik docker image, you can simply define your configs in a `docker-compose.yml` and take advantage of environment variable file used by it, i.e. `.env`, and set your environment variables there... On the other hand, if traefik itself is not a docker container, you will have to use config file or CLI to set the configs. – abmblob Feb 18 '20 at 11:39
  • I have the environment variables set in my docker-compose file. But how would I go about getting them into my traefik dynamic configuration? – adam-beck Feb 18 '20 at 12:13
  • You can use any environment variable defined in your `.env` file like this: `${HOST}` – abmblob Feb 18 '20 at 12:31
  • One more question, from the updates in the question, I understand that you are using `self-signed` certificate locally, but are you also using Kubernetes to deploy in production or you just need a solution for your localhost? – abmblob Feb 18 '20 at 16:02

3 Answers3

11

Using traefik v2.0+ docker image, you can simply use docker-compose and define your environment variables in .env file. Then use labels like this below example.

Example

Uses File provider to add self-signed TLS certificates for localhost using traefik CLI command:
--providers.file.filename=/etc/traefik/certs.toml

.env file in local:

# Environment variables for docker-compose.yml
LOG_LEVEL=DEBUG
NETWORK=net

## dashboard configs
DASHBOARD_HOST=app.localhost
CONFIG_PATH=./config
CERT_PATH=./certs

.env file in production:

# Environment variables for docker-compose.yml
# LOG_LEVEL=INFO
LOG_LEVEL=ERROR
NETWORK=net

## dashboard configs
DASHBOARD_HOST=realname.com
CONFIG_PATH=./config
CERT_PATH=./certs

docker-compose.yml:

version: "3.5"

services:
  traefik:
    # Setting container_name disables running multinple instances of this service
    container_name: traefik
    image: traefik:v2.1
    command:
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --log.level=${LOG_LEVEL}
      - --providers.docker
      - --providers.docker.exposedbydefault=false
      - --providers.file.filename=/etc/traefik/certs.toml
      - --api
    ports:
      - "80:80"
      - "443:443"
    networks:
      - net
    volumes:
      - "${CERT_PATH}:/certs"
      - "${CONFIG_PATH}:/etc/traefik"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
    labels:
      # set this lebel to `false` and the rest is history
      traefik.enable: true
      # middleware redirect
      traefik.http.middlewares.redirect-to-https.redirectscheme.scheme: https

      # redirection HTTP to HTTPS
      traefik.http.routers.http_catchall.rule: hostregexp(`{host:.+}`)
      traefik.http.routers.http_catchall.entrypoints: web
      traefik.http.routers.http_catchall.middlewares: redirect-to-https

      # dashboard
      traefik.http.routers.traefik.rule: Host(`${DASHBOARD_HOST}`)
      traefik.http.routers.traefik.entrypoints: websecure
      traefik.http.routers.traefik.service: api@internal
      traefik.http.routers.traefik.tls: true

networks:
  net:
    external: false
    name: ${NETWORK}

config/certs.toml:

[tls.stores.default.defaultCertificate]
  certFile = "/certs/cert.crt"
  keyFile = "/certs/cert.key"

certs/cert.crt:

-----BEGIN CERTIFICATE-----
<THE CERTIFICATE STRING>
-----END CERTIFICATE-----

certs/cert.key:

-----BEGIN RSA PRIVATE KEY-----
<THE RSA PRIVATE KEY STRING>
-----END RSA PRIVATE KEY-----

docker-compose will replace all the variables like ${DASHBOARD_HOST} with the values defined in .env file.

Then, you can validate your config using: docker-compose config
Run using: docker-compose up -d

-d flag is for detached mode, runs containers in the background

Source Files: You can refer to this repository on github to find an elaborate version of this example, on how to setup traefik v2 using docker-compose for self-signed or to automatically acquire Let's Encrypt wildcard certificates.

abmblob
  • 361
  • 2
  • 14
  • I upvoted this answer but I realized I left out a very critical piece of information: I must use the File Provider. The reason is because locally I'm using a self-signed cert for TLS. According to Traefik's docs, the File Provider is the only way to configure certificates. – adam-beck Feb 18 '20 at 13:22
  • @adam-beck first of all, thank you so much for the upvote and making me 100+ :D. Secondly, If you look closely to the repository I linked, I have added configuration for file provider in [docker-compose.yml](https://github.com/abmruman/traefik-docker-compose/blob/master/docker-compose.yml#L14) for self-signed certificates. I will try to update my answer accordingly. :) – abmblob Feb 18 '20 at 15:58
  • @adam-beck I have updated my answer. The example in the answer uses **file provider** to add self-signed TLS certificate. Hope this will solve your problem. – abmblob Feb 18 '20 at 22:50
0

Unless traefik supports some way of using environment variables for dynamic-configuration as with static-configurations your are usually stuck with sed or envsubst templating configurations at startup.

invad0r
  • 908
  • 1
  • 7
  • 20
  • 1
    It does! See https://doc.traefik.io/traefik/providers/file/#go-templating "Traefik supports using Go templating to automatically generate repetitive portions of configuration files." **but** "Go Templating only works with dedicated dynamic configuration files. Templating does not work in the Traefik main static configuration file." – ponsfrilus Feb 02 '21 at 19:58
0

To make your env variables available in dynamic configuration with Go templating you just have to use env function from sprig library.

# ./configs/traefik.yml
providers:
    docker: {}
    file:
        filename: "/etc/traefik/config.yml"
# ./configs/config.yml
routers:
    my-router:
        rule: 'Host(`{{ env "MY_HOST" }}`)'

or with default development value app.localhost:

# ./configs/config.yml
routers:
    my-router:
        rule: 'Host(`{{ env "MY_HOST" | default "app.localhost" }}`)'

Also note that if you're using docker-compose file you should make those envs available in traefik's container context:

# docker-compose.yml

services:
    traefik:
        image: traefik:v2.9
        environment:
            MY_HOST: ${MY_HOST}
            # or with default value
            # MY_HOST: ${MY_HOST:-http://app.localhost}
        volumes:
            - "./configs/:/etc/traefik/:ro"
aleksxor
  • 7,535
  • 1
  • 22
  • 27