Traefik

Configuration for the Traefik web server.

Traefik most often logs to stdout. If using Docker, it will be accessible using docker logs -n0 -f <traefik_container_name>. You can configure other ways to log traefik, see its documentation.

By default, Traefik logs to the Common Log Format, which is described in this section. But its log format is often configured to json, which gives much more detailed logs. That's what we'll describe here.

When logging using the json format, all is printed on one line, allowing for easy regex parsing.

Here's what it looks like pretty printed:

{
  "ClientAddr": "1.2.3.4:2048",
  "ClientHost": "1.2.3.4",
  "ClientPort": "2048",
  "DownstreamContentSize": 252,
  "DownstreamStatus": 200,
  "Duration": 1000,
  "OriginContentSize": 252,
  "OriginDuration": 900,
  "OriginStatus": 206,
  "Overhead": 10000,
  "RequestAddr": "domain.name",
  "RequestContentSize": 0,
  "RequestCount": 123,
  "RequestHost": "domain.name",
  "RequestMethod": "GET",
  "RequestPath": "/login",
  "RequestPort": "-",
  "RequestProtocol": "HTTP/2.0",
  "RequestScheme": "https",
  "RetryAttempts": 0,
  "RouterName": "my-service@docker",
  "ServiceAddr": "172.1.0.1:80",
  "ServiceName": "my-service@docker",
  "downstream_Header1": "...",
  "downstream_Header2": "...",
  "entryPointName": "websecure",
  "level": "info",
  "msg": "",
  "origin_Header1": "...",
  "origin_Header2": "...",
  "request_Header1": "...",
  "request_Header2": "...",
  "time": "YYYY-MM-DDTHH:MM:SS+UT:C0"
}

As a pattern, we'll use ip. See here.

A regex for traefik can look like this:

@'.*,"ClientHost":"<ip>",.*,"DownstreamStatus":401,.*,"RequestPath":"/login".*'

Or this:

@'.*,"ClientHost":"<ip>",.*,"DownstreamStatus":401,.*,"RequestHost":"domain.name",.*,"RequestPath":"/login".*'

Adjust domain.name according to your domain

Example:

{
  streams: {
    traefik: {
      cmd: ['tail', '-n0', '-f', '/var/lib/traefik/access.log'],
      filters: {
        website: {
          regex: [ @',"ClientHost":"<ip>",.*,"DownstreamStatus":403,.*,"RequestHost":"website.example",.*,"RequestPath":"/login",' ],
          retry: 3,
          retryperiod: '3h',
          actions: banFor('24h'),
        },
      },
    },
  },
}

You can decide that all 401, Unauthorized, and 403, Forbidden, are suspicious, and have a filter for any 401 and 403:

{
  streams: {
    traefik: {
      cmd: ['docker', 'logs', '-n0', '-f', 'traefik'],
      filters: {
        website: {
          regex: [ @',"ClientHost":"<ip>",.*,"DownstreamStatus":(401|403),' ],
          retry: 15,
          retryperiod: '5m',
          actions: banFor('1h'),
        },
      },
    },
  },
}