Search code examples
traefik

Traefik different entrypoint and rule combos


I have a docker compose file, I want to host my container on example.com:8080 and api.example.com:443, I can accomplish that goal right now.

However I don't want 2 seperate service for that, I want to eliminate either my_api or abcxyz and have 1 service only and accomplish the same behavior, i.e. my container should be hosted at example.com:8080 and not on example.com:443 AND api.example.com:443 but not on api.example.com:8080

Is there a way to do it under 1 service.

version: "3"

services:
  traefik:
    image: traefik
    command:
      - --api.dashboard=false
      - --api.insecure=false
      - --providers.docker
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entrypoint.to=web-secure
      - --entrypoints.web.http.redirections.entrypoint.scheme=https
      - --entrypoints.web.http.redirections.entrypoint.permanent=true
      - --entrypoints.web-secure.address=:443
      - --entrypoints.spiderman.address=:8080
      - --providers.file.directory=/configuration/
      - --providers.file.watch=true
    ports:
      - 80:80
      - 443:443
      - 8080:8080
    volumes:
      - ./certificates.yml:/configuration/certificates.yml:ro
      - /etc/letsencrypt:/letsencrypt:ro
      - /var/run/docker.sock:/var/run/docker.sock
  my_api:
    image: traefik/whoami
    deploy:
      replicas: 5
    labels:
      - "traefik.http.routers.my_api.entrypoints=spiderman"
      - "traefik.http.routers.my_api.rule=Host(`example.com`)"
      - "traefik.http.routers.my_api.tls=true"
  abcxyz:
    image: traefik/whoami
    deploy:
      replicas: 5
    labels:
      - "traefik.http.routers.abcxyz.entrypoints=web-secure"
      - "traefik.http.routers.abcxyz.rule=Host(`api.example.com`)"
      - "traefik.http.routers.abcxyz.tls=true"

I could do -

    labels:
      - "traefik.http.routers.my_api.entrypoints=spiderman,web-secure"
      - "traefik.http.routers.my_api.rule=Host(`example.com`,`api.example.com`)"
      - "traefik.http.routers.my_api.tls=true"

but it would also serve at example.com:443 which I don't want because i want to host my cool wordpress site there! :)


Solution

  • I think you're looking for something like this:

    services:
      traefik:
        image: traefik
        command:
          - --api.dashboard=false
          - --api.insecure=false
          - --providers.docker
          - --entrypoints.web.address=:80
          - --entrypoints.web.http.redirections.entrypoint.to=web-secure
          - --entrypoints.web.http.redirections.entrypoint.scheme=https
          - --entrypoints.web.http.redirections.entrypoint.permanent=true
          - --entrypoints.web-secure.address=:443
          - --entrypoints.spiderman.address=:8080
        ports:
          - 127.0.0.3:80:80
          - 127.0.0.3:443:443
          - 127.0.0.3:8080:8080
        volumes:
          - /run/docker.sock:/run/docker.sock
      my_api:
        image: traefik/whoami
        hostname: my_api
        labels:
          - traefik.enable=true
    
          - traefik.http.routers.example_com.entrypoints=spiderman
          - traefik.http.routers.example_com.rule=Host(`example.com`)
          - traefik.http.routers.example_com.service=my_api
          - traefik.http.routers.example_com.tls=true
    
          - traefik.http.routers.my_api.entrypoints=web-secure
          - traefik.http.routers.my_api.rule=Host(`api.example.com`)
          - traefik.http.routers.my_api.tls=true
          - traefik.http.services.my_api.loadBalancer.server.port=80
    

    Note that here I've bound everything to local address 127.0.0.3 for testing, but of course that's not necessary; I did that to avoid conflicts with existing services I have listening on ports 80, 443, and 8080.

    Testing

    I've defined this shell function that ensures the various hostname:port combinations resolve correctly (you could edit /etc/hosts instead to accomplish the same thing) and shows the HTTP status code for each request:

    fetch() {
      curl -sf \
        --resolve api.example.com:443:127.0.0.3 \
        --resolve api.example.com:8080:127.0.0.3 \
        --resolve example.com:443:127.0.0.3 \
        --resolve example.com:8080:127.0.0.3 \
        -k -w '%{stderr}%{http_code}\n' $1
    }
    

    Using that, let's test our your various requirements.

    my container should be hosted at example.com:8080

    $ fetch https://example.com:8080 | grep -i host
    200
    Hostname: my_api
    Host: example.com:8080
    X-Forwarded-Host: example.com:8081
    

    and not on example.com:443

    $ fetch https://example.com:443 | grep -i host
    404
    

    AND api.example.com:443

    $ fetch https://api.example.com:443 | grep -i host
    200
    Hostname: my_api
    Host: api.example.com
    X-Forwarded-Host: api.example.com
    

    but not on api.example.com:8080

    $ fetch https://api.example.com:8080 | grep -i host
    404
    

    I think that covers your requirements!