What is the recommended way to configure multiple domains from an env var in Traefik?

Viewed 1106

Since I need to configure multiple domains, I would like to define the list of these domains in an environment variable.

According to the routers section of the documentation, we should use this format:

Host(`example.com`, ...)

Is there a recommended way to populate this expected list from an environment variable (I use this configuration in a Docker Compose file)?

Since:

To set the value of a rule, use backticks ` or escaped double-quotes ".

I'd like to mention the following can't work with Host(${DOMAINS}) because the domains contained in backticks are interpreted as commands:

$ export DOMAINS="`example.com`, `example2.com`"

zsh: command not found: example.com
zsh: command not found: example2.com

The following format works with export:

$ export DOMAINS="\"example.com\", \"example2.com\""
$ echo $DOMAINS
"example.com", "example2.com"

But from an .env file with DOMAINS="\"example.com\", \"example2.com\"", I get in Traefik:

Cannot issue for \"\\\"example.com\\\", \\\"example2.com\\\"\": Domain name contains an invalid character"
2 Answers

I finally found a way to do it, by escaping the backtick character in the export command:

export DOMAINS="\`example.com\`, \`example2.com\`"

However, if we want to use a .env file we need to remove the space after the comma since the argument has to be quoted to support space and in that case any additional escape on " or `, even multiple, won't work.

So, in a .env file, it has to be:

DOMAINS=`example.com`,`example2.com`

Using environment variables, you can run docker-compose with -e (--environment) argument:

export MY_DOMAIN="example.com"
docker-compose --environment EXAMPLE_DOMAIN=$MY_DOMAIN up -d

or

MY_DOMAIN="example.com" docker-compose --environment EXAMPLE_DOMAIN=$MY_DOMAIN up -d

Variable $EXAMPLE_DOMAIN would be available in docker-compose environment:

docker-compose.yml:

version: "3.7"
services:
  nginx:
    image: nodejs
    labels:
      - traefik.http.routers.example_https.rule=Host(`${EXAMPLE_DOMAIN }`)

Also you can setup domain names via dynamic toml file, but you need to create this file by custom script using your variables. Share the dynamic config volume to host, if you need to update domain names dynamically:

## Dynamic configuration
[http.routers]
  [http.routers.routerbar]
    rule = "Host(`example.com`)
    [http.routers.routerbar.tls]
      certResolver = "bar"
      [[http.routers.routerbar.tls.domains]]
        main = "example.com"
        sans = ["*.example.com"]

Dynamic yaml file available to configure domains, but you will need to create it from env vars available by yourself as well:

http:
  routers:
    routerbar:
      rule: "Host(`example.com`)"
      tls:
        certResolver: "bar"
        domains:
          - main: "example.com"
            sans:
              - "*.example.com"

Furthermore, domain names could be assigned during image build stage. You will need to pass build arguments on local Dockerfile via docker-compose.yml configuration.

Related