# Traefik v2 simple trick to bypass basic Auth

**URL:** <https://community.traefik.io/t/traefik-v2-simple-trick-to-bypass-basic-auth/2012>\
**Category:** Traefik v2\
**Tags:** docker, middleware\
**Created:** [September 29, 2019, 9:46am UTC](https://community.traefik.io/t/traefik-v2-simple-trick-to-bypass-basic-auth/2012 "2019-09-29T09:46:54Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![edger](https://avatars.discourse-cdn.com/v4/letter/e/f19dbf/32.png) [@edger](https://community.traefik.io/u/edger)\
**Post date:** [September 29, 2019, 9:46am UTC](https://community.traefik.io/t/traefik-v2-simple-trick-to-bypass-basic-auth/2012/1 "2019-09-29T09:46:54Z")

</div>

I have spend a huge amount of time to find a way to bypass basic authentication depending on source IP/network and never find a way to do so. But yesterday i finally succeeded to manage this need.

note : i am using Traefik with Docker without Swarm. I am not an export and i am learning.

## Goal:

**bypass basic auth** for a defined list of networks/ip using a **single host rule** and a **single entrypoint**

## Trick

Create 2 routers with the same host rule and use HeadersRegexp

```auto
http:
  routers:
    router1:
      entryPoints:
        - websecure
      rule: Host(`mysinglehostrule`)
      middlewares:
         - Security-Headers@file
         - BasicAuthMiddleware@file
      service: myservice
      tls:
        options: default
        certResolver: xxx
        domains:
          - main: xxxxxx
            sans:
              - "*.xxxxxxxxx"
    router2:
      entryPoints:
        - websecure
      rule: Host(`mysinglehostrule`) && HeadersRegexp(`X-Real-Ip`, `(^127\.)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)`)
      middlewares:
         - Security-Headers@file
         - AgentsNetworksIpWhitelist@file
      service: myservice
      tls:
        options: default
        certResolver: xxx
        domains:
          - main: xxxxxx
            sans:
              - "*.xxxxxxx"
  services:
    myservice:
    ..........

```

In this example i would whitelist RFC 1918 but you can adapt to your taste 🙂

Hope it can help someone........

Have a nice day.

---

<div class="post-metadata">

**Author:** ![zespri](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/zespri/32/310_2.png) [@zespri](https://community.traefik.io/u/zespri)\
**Post date:** [September 29, 2019, 7:21pm UTC](https://community.traefik.io/t/traefik-v2-simple-trick-to-bypass-basic-auth/2012/2 "2019-09-29T19:21:14Z")

</div>

Thank you for sharing this. People are really keen on "complete working examples" here, so this could be improved by posting the rest of the configuration, that one can paste into the files and up with their docker-compose (or just docker).

---

<div class="post-metadata">

**Author:** ![edger](https://avatars.discourse-cdn.com/v4/letter/e/f19dbf/32.png) [@edger](https://community.traefik.io/u/edger)\
**Post date:** [October 2, 2019, 5:11pm UTC](https://community.traefik.io/t/traefik-v2-simple-trick-to-bypass-basic-auth/2012/3 "2019-10-02T17:11:24Z")

</div>

Hi Zespri, thank you for your feedback.  
It's not that easy to give a full working example without double checking private informations have been changed.  
Here is a more complete configuration.

- traefik docker-compose.yml

```auto
version: "3.3"

services:

  traefik:
    image: "traefik:v2.0"
    container_name: "traefik"
    networks:
      - traefik
      - dockerproxy
    ports:
      - "80:80"
      - "443:443"

    volumes:
      - /srv/conf/traefik/traefik.yml:/etc/traefik/traefik.yml
      - /srv/conf/traefik/dynamic:/etc/traefik/dynamic
      - /srv/data/traefik/letsencrypt:/letsencrypt
      - /srv/data/traefik/log:/var/log
    environment:
      - provider1_ENDPOINT=ep
      - provider1_APPLICATION_KEY=ak
  

    restart: always
    labels:
      - traefik.enable=true
      - traefik.docker.network=traefik-net

      - traefik.http.routers.traefik-dash2.rule=Host("traefik-dash.dom.com")
      - traefik.http.routers.traefik-dash2.entrypoints=websecure
      - traefik.http.routers.traefik-dash2.tls=true
      - traefik.http.routers.traefik-dash2.tls.options=default
      - traefik.http.routers.traefik-dash2.tls.certresolver=provider1
      - traefik.http.routers.traefik-dash2.tls.domains[0].main=dom.com
      - traefik.http.routers.traefik-dash2.tls.domains[0].sans=*.dom.com
      - traefik.http.routers.traefik-dash2.middlewares=too much
      - traefik.http.routers.traefik-dash2.service=api@internal

  dockerproxy:
    image: tecnativa/docker-socket-proxy
    container_name: dockerproxy
    networks:
      - dockerproxy
    expose:
      - "2375"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:z"
    restart: always
    environment:
      - CONTAINERS=1
    labels:
      - traefik.enable=false

networks:
    traefik:
      external:
        name: traefik-net
    dockerproxy:

```

- traefik.yml

```auto
global:
  checkNewVersion: true
  sendAnonymousUsage: true

serversTransport:
  insecureSkipVerify: true

EntryPoints:
  web:
    address: :80
  websecure:
    address: :443

log:
# level: INFO
  level: DEBUG
  filePath: "/var/log/traefik.log"

accessLog:
  filePath: "/var/log/access.log"
  bufferingSize: 100
  fields:
    defaultMode: keep
    headers:
      defaultMode: keep
      names:
          User-Agent: keep

providers:
  providersThrottleDuration: 10s
  docker:
    watch: true
    endpoint: tcp://dockerproxy:2375
    exposedByDefault: false
    swarmMode: false
  file:
    directory: /etc/traefik/dynamic/
    watch: true

api:
  dashboard: true
  debug: true

certificatesResolvers:
  provider1:
    acme:
      email: bob@alice.com
      #caServer: https://acme-staging-v02.api.letsencrypt.org/directory
      storage: /letsencrypt/acme.json
      dnsChallenge:
        provider: provider1

```

- the dynamic configuration file dynamic/myExternalService.yml

```auto
http:
  routers:
    cpydio-secure:
      entryPoints:
        - websecure
      rule: Host(`pydio.dom.com`)
      middlewares:
         - Security-Headers@file
         - pydioBasicAuth
         - pydioMaxRequestBody
      service: cpydio-service
      tls:
        options: default
        certResolver: provider1
        domains:
          - main: dom.com
            sans:
              - "*.dom.com"
    cpydio-secure-int:
      entryPoints:
        - websecure
      rule: Host(`pydio.dom.com`) && HeadersRegexp(`X-Real-Ip`, `(^127\.)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)|(^88\.184\.222\.179)|(^78\.244\.93\.94)`)
      middlewares:
         - Security-Headers@file
         - pydioMaxRequestBody
      service: cpydio-service
      tls:
        options: default
        certResolver: provider1
        domains:
        domains:
          - main: dom.com
            sans:
              - "*.dom.com"
  services:
    cpydio-service:
      loadBalancer:
        servers:
          - url: "https://w.x.y.z:443"
        passHostHeader: true

  middlewares:
    pydioBasicAuth:
      basicAuth:
        realm: "RRRRRRRRRR"
        users:
        - user:passssssssssssssssssssssssssssssssssss
    pydioMaxRequestBody:
      buffering:
        maxRequestBodyBytes: 2048000000

```

hope this is better.

Best regards,

---

<div class="post-metadata">

**Author:** ![petehenshall](https://avatars.discourse-cdn.com/v4/letter/p/85e7bf/32.png) [@petehenshall](https://community.traefik.io/u/petehenshall)\
**Post date:** [April 20, 2020, 11:55am UTC](https://community.traefik.io/t/traefik-v2-simple-trick-to-bypass-basic-auth/2012/4 "2020-04-20T11:55:42Z")

</div>

A simple example that works, based on inspiration in this post.

In short you have two routers + priorities with the highest granting without auth middleware and the next priority the production-facing rule.

HTH, cost me a morning to bash that one out.

```auto
version: '3'

services:
  traefik:
    # The official v2 Traefik docker image
    image: traefik:v2.2
    container_name: "traefik"
    # Enables the web UI and tells Traefik to listen to docker
    command: --api.insecure=true --providers.docker
    ports:
      # The HTTP port
      - "80:80"
      # The Web UI (enabled by --api.insecure=true)
      - "8080:8080"
    volumes:
      # So that Traefik can listen to the Docker events
      - /var/run/docker.sock:/var/run/docker.sock

  whoami:
    # A container that exposes an API to show its IP address
    image: containous/whoami
    labels:
      - "traefik.http.routers.whoami2.rule=Host(`whoami.localhost`) && HeadersRegexp(`X-Real-Ip`, `^(192\\.168\\.99\\.2)`)"
      - "traefik.http.routers.whoami2.priority=100"
      - "traefik.http.routers.whoami2.middlewares=secured2"
      - "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"
      - "traefik.http.routers.whoami.priority=99"
      - "traefik.http.routers.whoami.middlewares=secured"
      - "traefik.http.middlewares.secured.chain.middlewares=auth"
      - "traefik.http.middlewares.secured2.chain.middlewares="
      - "traefik.http.middlewares.auth.basicauth.users=test1:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/"
      #- "traefik.http.middlewares.known-ips.ipwhitelist.sourceRange=192.168.1.7,127.0.0.1/32"

```

---

<div class="post-metadata">

**Author:** ![unknownusserr](https://avatars.discourse-cdn.com/v4/letter/u/57b2e6/32.png) [@unknownusserr](https://community.traefik.io/u/unknownusserr)\
**Post date:** [March 19, 2021, 11:15am UTC](https://community.traefik.io/t/traefik-v2-simple-trick-to-bypass-basic-auth/2012/5 "2021-03-19T11:15:03Z")

</div>

This somehow doesn't work for me in traefik 2.4.2 - does it work for you?

---

<div class="post-metadata">

**Author:** ![bard](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/bard/32/5766_2.png) [@bard](https://community.traefik.io/u/bard)\
**Post date:** [August 21, 2022, 9:36am UTC](https://community.traefik.io/t/traefik-v2-simple-trick-to-bypass-basic-auth/2012/6 "2022-08-21T09:36:29Z")

</div>

[Reviving the topic since it's at the top of Google search results.]

This is working for me with Traefik 2.6.1 using `ClientIp` condition instead of `HeadersRegexp` to check for both hosts and subnets. It uses Kubernetes syntax but should be easily adaptable.

```yaml
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  namespace: example-namespace
  name: example-ingressroute
  labels:
    app: example
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`example.com`)
      kind: Rule
      priority: 99
      services:
        - name: example-service
          port: 3000
    - match: Host(`example.com`) && ! ClientIP(`12.34.56.78/32`, `10.0.0.0/8`)
      kind: Rule
      priority: 100
      services:
        - name: example-service
          port: 3000
      middlewares:
        - name: basicauth-middleware
          namespace: example-namespace
  tls:
    secretName: example-cert

```

---

<div class="post-metadata">

**Author:** ![miff2000](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/miff2000/32/10353_2.png) [@miff2000](https://community.traefik.io/u/miff2000)\
**Post date:** [May 8, 2025, 5:14am UTC](https://community.traefik.io/t/traefik-v2-simple-trick-to-bypass-basic-auth/2012/7 "2025-05-08T05:14:01Z")

</div>

This is a great approach! Thanks!
