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.

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\"}}`)"

For anyone who stumbled upon it, this worked for me in the dynamic file:

http:
  routers:
    construction-page:
      rule: 'Host(`{{ env "DOMAIN" }}`) || Host(`{{ env "LOCAL_DOMAIN" }}.local`) || Host(`{{ env "SERVER_IP" }}`)'
      service: construction-page
      entryPoints:
        - web