Environment variable in a dynamic file

What did you do?

I apologize in advance if I make any mistake creating this issue, this is my first one on github,I'll try to be concise.
I configured the dashboard and api routers using a dynamic file, setting a rule that uses an environmental variable (DOMAIN_NAME) as so:

[http]
  [http.routers]
    [http.routers.dashboard]
      middlewares = ["dashboard_redirect", "dashboard_stripprefix"]
      service = "dashboard@internal"
      rule = "Host(`traefik.{{env "DOMAIN_NAME"}}`) && PathPrefix(`/`)"
      priority = 1000
      
    [http.routers.api]
      service = "api@internal"
      rule = "Host(`traefik.{{env "DOMAIN_NAME"}}`) && PathPrefix(`/api`)"
      priority = 1001

   [http.middlewares]
    [http.middlewares.dashboard_redirect.redirectRegex]
      regex = "^(http:\\/\\/(\\[[\\w:.]+\\]|[\\w\\._-]+)(:\\d+)?)\\/$"
      replacement = "${1}/dashboard/"
      permanent = true

    [http.middlewares.dashboard_stripprefix.stripPrefix]
      prefixes = ["/dashboard/", "/dashboard"]

the issue is the accepted syntax is the one above which isn't the right syntax for a toml file, I think the quotes encapsulating DOMAIN_NAME should be escaped with a \

What did you see instead?

using escaped auotes triggers an error where traefik can't seem to accept the syntax, this is the error:

ERR github.com/traefik/traefik//v3/pkg/provider/file/file.go:150 > Error occurred during watcher callback error="/dynamic/api.toml: template: :6: unexpected \"\\\\\" in operand" providerName=file

but using the escaped quotes in the static file seems to work fine, for example this is my providers configuration in a toml static file:

[providers]  
  [providers.docker]
    exposedByDefault = false
    defaultRule = "Host(`{{ .ContainerName }}.{{env \"DOMAIN_NAME\"}}`)"

  [providers.file]
    directory = "/dynamic"
    watch = true

What version of Traefik are you using?

Version: 3.1.2
Codename: comte
Go version: go1.22.5
Built: 2024-08-06T13:37:51Z
OS/Arch: linux/amd64

What is your environment & configuration?

Platform: Debian 12.6.0
Container Manage: Podman

traefik.toml:

################################################################
# Global configuration
################################################################
[global]
  checkNewVersion = true
  sendAnonymousUsage = false


################################################################
# Entrypoints configuration
################################################################
[entryPoints]
  [entryPoints.web]
    address = ":80"
      [entryPoints.web.http]
        [entryPoints.web.http.redirections]
          [entryPoints.web.http.redirections.entryPoint]
            to = "websecure"
            scheme = "https"

  [entryPoints.websecure]
    address = ":443"
    asDefault = true
      [entryPoints.websecure.http]
        [entryPoints.websecure.http.tls]
          certResolver = "letsencrypt"


################################################################
# Traefik logs configuration
################################################################
[log]
  level = "DEBUG"


################################################################
# API and dashboard configuration
################################################################
[api]
  insecure = false
  dashboard = true

################################################################
# Ping configuration
################################################################
[ping]


################################################################
# Docker configuration backend
################################################################
[providers]  
  [providers.docker]
    exposedByDefault = false
    defaultRule = "Host(`{{ .ContainerName }}.{{env \"DOMAIN_NAME\"}}`)"

  [providers.file]
    directory = "/dynamic"
    watch = true

################################################################
# Let's Encrypt
################################################################
[certificatesresolvers.letsencrypt.acme]
  email = "fluky@bdi.brr"
  storage = "/letsencrypt/acme.json"
  preferredchain="ISRG Root X1"
  keytype="RSA4096"
  [certificatesResolvers.letsencrypt.acme.tlsChallenge]

dynamic file:

[http]
  [http.routers]
    [http.routers.dashboard]
      middlewares = ["dashboard_redirect", "dashboard_stripprefix"]
      service = "dashboard@internal"
      rule = "Host(`traefik.{{env "DOMAIN_NAME"}}`) && PathPrefix(`/`)"
      priority = 1000
      
    [http.routers.api]
      service = "api@internal"
      rule = "Host(`traefik.{{env "DOMAIN_NAME"}}`) && PathPrefix(`/api`)"
      priority = 1001

   [http.middlewares]
    [http.middlewares.dashboard_redirect.redirectRegex]
      regex = "^(http:\\/\\/(\\[[\\w:.]+\\]|[\\w\\._-]+)(:\\d+)?)\\/$"
      replacement = "${1}/dashboard/"
      permanent = true

    [http.middlewares.dashboard_stripprefix.stripPrefix]
      prefixes = ["/dashboard/", "/dashboard"]

compose.yml:

services:

  traefik:
    image: "docker.io/traefik:v3.1"
    container_name: "traefik"
    ports:
      - "8080:80"
      - "8443:443"
    env_file:
      -.traefik.env
    volumes:
      - "/run/user/%U/podman/podman.sock:/var/run/docker.sock:ro"
      - "/%h/letsencrypt:/letsencrypt"
      - "/%h/traefik/traefik.toml:/etc/traefik/traefik.toml"
      - "/%h/traefik/dynamic:/dynamic"
    healthcheck:
      test: ["CMD", "traefik", "healthcheck", "--ping"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 10s

  whoami:
    image: "docker.io/traefik/whoami"
    container_name: "whoami"
    labels:
      - "traefik.enable=true"

I posted this as github issue but I was told that it looks like a configuration issue on my side, even tho the configuration I gave works, so I don't have a problem making it work in the case of dynamic files but when it comes to static file it accepts the right syntax, it's just I noticed that the go file (file.go line 150) accepts a wrong syntax for a toml file referencing an env variable using a go template (unless i'm mistaken). So I was advised to come here and ask help from the community.

Just a comment: In my opinion toml is rather a legacy format and not really used. Toml has too much repetition, it’s bloated, Docker compose is using yaml and Kubernetes is using yaml, no one really uses toml anymore.

1 Like

you've got a point there, but who I am as a person we,ll make me beat my head to know if it's a bug or working as intended :sweat_smile:

Just in case someone stumbles upon it, I tried with a .yml and traefik doesn't accept escaping characters either but it doesn't work without them so I used simple quotes as so:

.
.
.
      rule = 'Host(`traefik.{{env "DOMAIN_NAME"}}`) && PathPrefix(`/`)'
.
.
.

EDIT:
while it works for thee static file:

providers:
  docker:
    exposedByDefault: false
    defaultRule: "Host(`{{ .ContainerName }}.{{env \"DOMAIN_NAME\"}}`)"