Search code examples
dockerreverse-proxydocker-swarmtraefik

Traefik custom error middleware for HTTP status 502 doesn’t work


I would like to serve custom error pages for common HTTP error codes. I was following this tutorial. For this purpose, I created the following docker-compose.yml file to test the functionality. It consists of:

  1. errorPageHandler which is a nginx server which is able to return static HTML pages (404.html and 502.html).

  2. whoami1 which routes the request to port 80 of traefik/whoami image

  3. whoami2 which routes the request to non-existent port 81 of traefik/whoami image which results in 502 - Bad Gateway

version: "3.7"

services:
  errorPageHandler:
    image: "nginx:latest"
    networks:
      - traefik-net
    volumes:
      - "./ErrorPages:/usr/share/nginx/ErrorPages"
      - "./default.conf:/etc/nginx/conf.d/default.conf"
    deploy:
      replicas: 1
      labels:
        # enable Traefik for this service
        - "traefik.enable=true"
        - "traefik.docker.network=traefik-net"

        # router (catches all requests with lowest possible priority)
        - "traefik.http.routers.error-router.rule=HostRegexp(`{catchall:.*}`)"
        - "traefik.http.routers.error-router.priority=1"
        - "traefik.http.routers.error-router.middlewares=error-pages-middleware"

        # middleware
        - "traefik.http.middlewares.error-pages-middleware.errors.status=400-599"
        - "traefik.http.middlewares.error-pages-middleware.errors.service=error-pages-service"
        - "traefik.http.middlewares.error-pages-middleware.errors.query=/{status}.html"

        # service
        - "traefik.http.services.error-pages-service.loadbalancer.server.port=80"
  
  whoami1:
    image: "traefik/whoami"
    networks:
      - traefik-net
    deploy:
      replicas: 1
      labels:
        # enable Traefik for this service
        - "traefik.enable=true"
        - "traefik.docker.network=traefik-net"

        # router
        - "traefik.http.routers.whoami1.rule=HostRegexp(`whoami1.local`)"
        - "traefik.http.routers.whoami1.service=whoami1"
        
        # service
        - "traefik.http.services.whoami1.loadbalancer.server.port=80"
        - "traefik.http.services.whoami1.loadbalancer.server.scheme=http"
        
  whoami2:
    image: "traefik/whoami"
    networks:
      - traefik-net
    deploy:
      replicas: 1
      labels:
        # enable Traefik for this service
        - "traefik.enable=true"
        - "traefik.docker.network=traefik-net"

        # router
        - "traefik.http.routers.whoami2.rule=HostRegexp(`whoami2.local`)"
        - "traefik.http.routers.whoami2.service=whoami2"
        
        # service
        - "traefik.http.services.whoami2.loadbalancer.server.port=81" # purposely wrong port
        - "traefik.http.services.whoami2.loadbalancer.server.scheme=http"

networks:
  traefik-net:
    external: true
    name: traefik-net

Folder ErrorPages contains two static HTML files, 404.html and 502.html. Content of default.conf is:

server {
    listen       80;
    server_name  localhost;

    error_page  404    /404.html;
    error_page  502    /502.html;

    location / {
        root  /usr/share/nginx/ErrorPages;
        internal;
    }
}

I added the following entries to my hosts file (172.15.16.17 is IP of the server where Traefik and all of the mentioned services are deployed):

172.15.16.17 error404.local
172.15.16.17 whoami1.local
172.15.16.17 whoami2.local

My observations:

  1. When I visit http://error404.local, Traefik routes the request to nginx and 404.html is returned. This is expected behavior because http://error404.local doesn't match any of the routes defined in Traefik.

  2. When I visit http://whoami1.local, Traefik routes request to whoami1 service and information about container is displayed on the page (expected behavior).

  3. When I visit http://whoami2.local, Traefik doesn't route request to nginx service, but it displays its default Bad Gateway page. Why doesn't it route the request to the nginx?


Solution

  • The traefik routers (whoami1 and whoami2) needs to use the error middleware that you defined

    https://doc.traefik.io/traefik/middlewares/http/errorpages/ Traefik error middleware docs

    So add the following labels to their respective containers

    - "traefik.http.whoami1.middlewares=error-pages-middleware"
    
    - "traefik.http.whoami2.middlewares=error-pages-middleware"
    

    the Traefik dashboard will show that the routes are using the middleware (refer image) One of my routes from my traefik dashboard

    Another option would be to add the middleware to the entrypoint so that all routes use the error middleware (Add this to traefik container compose)

    command:
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.websecure.http.middlewares=error-pages-middleware@docker"