Environment variable syntax in traefik.yml

I tried following:

traefik.yml

letsencrypt:
  acme:
    email: $ACME_EMAIL
---
letsencrypt:
  acme:
    email: ${ACME_EMAIL}
---
letsencrypt:
  acme:
    email: '{{ env "ACME_EMAIL" }}'

and always get variation of the following error in Traefik container logs:

https://acme-staging-v02.api.letsencrypt.org/acme/new-acct :: urn:ietf:params:acme:error:invalidEmail :: Error creating new account :: \"${ACME_EMAIL}\" is not a valid e-mail address"

In the end I hardcoded email in yml.

But then in dynamic.yml this syntax works fine and environment variable is loaded:

user-auth:
  basicAuth:
    users: 
      - '{{ env "TRAEFIC_AUTH" }}'

Also I want to have staging and production certificate resolver but I have single acme.json file that I don't like to manually delete/create every time I change resolver.

traefik.yml

letsencryptStaging:
  acme:
   email: email@hotmail.com
   caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
   storage: acme-staging.json
   keyType: EC384
   httpChallenge:
   entryPoint: web
   
letsencryptProduction:
  acme:
   email: email@hotmail.com
   caServer: "https://acme-v02.api.letsencrypt.org/directory"
   storage: acme-production.json
   keyType: EC384
   httpChallenge:
   entryPoint: web

I am not confident that Treafik and Lets Encrypt will respect certificate file named other than acme.json, like acme-staging.json and acme-production.json so that I don't have to manually delete and create that file every time I change certificate resolver?

docker-compose.yml

services:
  traefik:
  image: "traefik:v2.5.6"
...
  environment:
    - ACME_EMAIL
    - TRAEFIC_AUTH
  volumes:
    - ./traefik-data/acme-staging.json:/acme-staging.json
    - ./traefik-data/acme-production.json:/acme-production.json

Did you make any progress with this? I really dislike hardcoding values like this as I automate all deployments and for now I haven't figured it out.

Hello @bonovski,

As you are using docker-compose, you can use the CLI to set the static configuration, as well a some dynamic configuration. Here's how I did it for my docker-compose stack : make-my-server/traefik at master · tomMoulard/make-my-server · GitHub

Besides, If I am not mistaken, setting environment variables like this sets them to be empty. I would go with :

services:
  traefik:
...
  environment:
      ACME_EMAIL: changeme@changeme.org
      TRAEFIC_AUTH: ...

Hope it helps :slight_smile:

If you, like me, want to use traefik.yml as your static configuration instead of command arguments or environment vars in your docker-compose.yml (given that the three static configuration methods are mutually exclusive), you have to remember that Go templating is only supported in dynamic configuration files. That means you need to add a build step to your deployment that creates the traefik.yml file with your desired variable substitutions.

In my case, I deploy from CI, so the production CI environment has an ACME_EMAIL env var available, and I use a short build script which generates traefik.yml by doing variable substitution on a traefik.tpl file. GNU envsubst can do this, as well as npx envsub, but I usually use this Bash incantation because pretty much every CI environment has Bash readily available:

eval "cat <<EOF
$(<conf/traefik.tpl)
EOF
" > conf/traefik.yml

Then the output traefik.yml is packaged up with docker-compose.yml for delivery to my production server.

If you need to have a single deployable artifact for multiple environments, you'll need to get creative and do that environment substitution within the environment before running docker compose up, or override the entrypoint: for your traefik service so that traefik's container is forced to do the env substitution on the file prior to running its usual /entrypoint.sh command with your supplied parameters. (This may be difficult since the traefik docker image does not contain Bash.)