Trying to understand HostRegexp not working for optional groups

I'm trying to get started with traefik and have a simple setup with httpd docker-stack and separate traefik docker-stack.

for the httpd-service my labels look as follows:

services.my-httpd:

    labels:
      traefik.enable: true
      traefik.frontend.priority: 10
      traefik.constraint-label: traefik-ingress
      traefik.http.services.http.loadbalancer.server.port: 80
      traefik.http.routers.http.rule: HostRegexp(`${PROJECT_DOMAIN}.docker`, `(.*).${PROJECT_DOMAIN}.docker`)
      traefik.http.routers.http.entrypoints: http,https

$PROJECT_DOMAIN comes from docker .env:
PROJECT_DOMAIN="my-foobar.com.docker"

(my-foobar.com.docker is resolved to 127.0.0.1:80)

I know about regex and checked the regex is working using regex-pal website too be shure I'm not in any mistake.

My intend is as follows:
I want configureable PROJECT_DOMAIN depending on I'm running on local-stack or development.
Second approach tested here is to use PROD-Domain and append ".docker" for local testing.

For HostRegexp I would assume full Regex-Support? Just wondering at this point dot's (".") don't need any escaping here nor there is any in-build shorthand-function like escapeRegexp(...) required to be used in the HostRegexp-Rule.

But okay, I'm assuming HostRegexp somehow does this on it's own for now.
I would expect for one of these tested Regexp's:

  • (.*).${PROJECT_DOMAIN}.docker
  • (.)${PROJECT_DOMAIN}(.docker)
  • (.*.)?${PROJECT_DOMAIN}(.docker)?

That it will match for these domains, assuming PROJECT_DOMAIN is "my-foobar.com":
my-foobar.com
test.my-foobar.com
test.my-foobar.com.docker

all of these should work as I understand HostRegexp using regular Regex-Rules as seen above. But for me all of them result in 404 not found. Host-Rules are listed without error in traefik-dashboard.
Is there any validation for invalid regexp's?!

Can anybody please declare for me how exactly (or not) I can use HostRegexp or if it does not support full regexp language?!

Thanks in advice.

Some progress on my own.

This rule seems to work after re-studying the traefik-docs for host-rules:

HostRegexp(${PROJECT_DOMAIN}{dev-domain:(.docker)?}, {subhost:.+}.${PROJECT_DOMAIN}{dev-domain:(.docker)?})

Obviously we have to use {group-name: [regexp]} patterns. This is a little bit confusing, as usually {..} has it's own meaning in regex-language and at first-glance this looks a little bit creepy.

If there are any feedback or improvement for that HostRegexp please let me know.

if you're using Docker/Docker Desktop, why not put a default rule and config for docker in the static config that handles all domains?

services:
  traefik:
    image: traefik:latest
    volumes:
      # Traefik requires access to docker.sock to read docker labels
      - /var/run/docker.sock:/var/run/docker.sock:ro # Access to Docker
      # Traefik has dynamic rules and logs
      - ./traefik/rules:/rules # Traefik configuration
      - ./traefik/logs:/logs # keep logs
    ports:
      - 80:80
    command:
      ... # Other static commands
      # EntryPoints web ports
      - "--entryPoints.web.address=:80"
      # Setup the docker provider, and basic rules to grab the docker service name as the host name
      - "--providers.docker=true"
      - "--providers.docker.endpoint=unix:///var/run/docker.sock"
      - "--providers.docker.exposedByDefault=true"
      - "--providers.docker.defaultRule=HostRegexp(`{{ index .Labels \"com.docker.compose.service\" }}.{anydomain:.*}`)"
    ... # Other static commands

alternatively, if you want to limit the domains from a .env file, then pass through the environment variable for any dynamic rule files, and change the default rule slightly:

    environment:
      # For file provider rules, we need a variable we can use
      - DOMAINNAME=${DOMAINNAME}
    command:
      ... # etc
      - "--providers.docker.defaultRule=Host(`{{ index .Labels \"com.docker.compose.service\" }}.${DOMAINNAME}`)"
      ... # etc

In a dynamic rule file, you can reference that environment variable for non-docker websites, just ensure the DNS actually sends the request to your docker traefik service (eg *.domain.int--> traefik ip address)

http:
  routers:
    modem-rtr:
      entryPoints: 
        - web
      rule: "Host(`modem.{{env "DOMAINNAME"}}`)"
      service: modem-svc

  services:
    modem-svc:
      loadBalancer:
        servers:
          - url: "http://192.168.184.1"  # A non-docker ip address

If your httpd-service only exposes 1 port by default, you won't need any labels on that docker container, docker provider should pick it up just fine using the service name, but if it exposes more than one, and not picking the right one, then you can just add 1 label:

services:
  my-foobar:
    labels:
      # Docker image has more than one EXPOSE command, I want this port
      - "traefik.http.services.yourhttpdthingy-svc.loadbalancer.server.port=3000"

test the entry points

curl http://my-foobar.docker.localhost # a docker service
curl http://modem.yourdomain.int       # a proxied address
1 Like

for sub domains with .env:

      - "--providers.docker.defaultRule=Host(`{{ index .Labels \"com.docker.compose.service\" }}.${DOMAINNAME}`) || Host(`test.{{ index .Labels \"com.docker.compose.service\" }}.${DOMAINNAME}`)"

or all domains with regex and an OR statement

      - "--providers.docker.defaultRule=HostRegexp(`{{ index .Labels \"com.docker.compose.service\" }}.{anydomain:.*}`) || HostRegexp(`{anysubdomain:.*}.{{ index .Labels \"com.docker.compose.service\" }}.{anydomain:.*}`)"

and of course, if you dont want default rules like this, you can just put them on the label instead

    labels:
      # Web Ui Rules
      - "traefik.http.routers.my-foobar.Rule=HostRegexp(`my-foobar.{anydomain:.*}`) || HostRegexp(`test.my-foobar.{anydomain:.*}`)"
      - "traefik.http.routers.my-foobar.service=my-foobar-svc"
      - "traefik.http.services.my-foobar-svc.loadbalancer.server.port=80"