External Pihole behind Traefik redirect /admin

Hi all,

i have pihole installed on a different machine, so pi hole do not run as a docker container next to Traefik.
What i have done is, that i added pihole as an external router to my config.yml.

If i access the URL via my browser, i can see the start page of pihole, but after fill in my admin credentials,
the site will always redirect to /admin

So, i navigate to

https://pihole.local.localdomain.com

I can see the pihole admin page.

But after i fill in my admin credentials, i will be redirected to

https://pihole.local.localdomain.com/admin

which is not available. White screen, no admin interface annymore.

If i then delete the /admin from the URL, i can see the admin panel again and i am logged in....

How is it possible with Traefik that there is not redirect to /admin, so i only want to use the URL
without /admin.

Is that possible?

Here is my config

http:
  routers:
    pihole:
      entryPoints:
        - "https"
      rule: "Host(`pihole.local.localdomain.com`)"
      middlewares:
        - default-headers
        - replacepathregex-pihole
        - addprefix-pihole
        - https-redirectscheme
      tls: {}
      service: pihole

  services:

    pihole:
      loadBalancer:
        servers:
          - url: "http://xxx.xxx.xxx.xxx:80"
        passHostHeader: true


  middlewares:

    addprefix-pihole:
      addPrefix:
        prefix: "/admin"

    replacepathregex-pihole:
      replacePathRegex:
         regex: "^/admin/(.*)"
         replacement: "/$$1"

    https-redirectscheme:
      redirectScheme:
        scheme: https
        permanent: true

    default-headers:
      headers:
        frameDeny: true
        sslRedirect: true
        browserXssFilter: true
        contentTypeNosniff: true
        forceSTSHeader: true
        stsIncludeSubdomains: true
        stsPreload: true
        stsSeconds: 15552000
        customFrameOptionsValue: SAMEORIGIN
        customRequestHeaders:
          X-Forwarded-Proto: https


Thanks and regards
Dan

Why do you have this? Messing with paths for a full-blown application usually does not work. Apps are mostly not path-aware and will redirect or link to fixed paths, which then don’t work anymore.

Best practice for multiple services on the same (reverse proxy) server is to use sub-domains.

I use the subdomain pihole.local.localdomain.... For each Service behind Traefik an own local subdomain. That just works fine for all my Services, execp pihole, because if i will open the sudomain for pihole and enter my credentials, pihole will redirect me to /admin, which does not exist. So i want to redirect back to the subdomain of pihole. But that isn't working.... :frowning:

Have you removed those?

Yes, still not working. Same effect as before.... .

Without the path manipulation your config looks okay, have you restarted Traefik?

Check Traefik debug log and access log. Check your target service log.

I had the same issue yesterday. The redirects don't get updated and pihole redirects you to the wrong pages constantly.

If you're willing to have /admin put in the URL automatically you can also just use the following middleware to redirect from the root to /admin automatically

    pihole-redirect:
      redirectRegex:
        regex: "^https?://pihole.domain.tld/$"
        replacement: "https://pihole.domain.tld/admin/"
1 Like

Hi,

thanks, this works fine.

The only thing is now, that always the path /admin is there.
It is ok for me..... But is there no way to work only with the base URL, without the addition of
the path /admin in the URL...?

Thanks and regards
dan

the setup below seems to be working for me.

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  annotations:
    kubernetes.io/ingress.class: traefik-internal
  name: pihole-dashboard
  namespace: pihole
spec:
  routes:
  - kind: Rule
    match: Host(`pihole.redacted.tld`)
    middlewares:
    - name: dashboard-redirect
    - name: dashboard-prefix
    services:
    - name: pihole-tcp
      port: 80
  tls: {}
---
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: dashboard-redirect
  namespace: pihole
spec:
  redirectRegex:
    regex: /admin/$
    replacement: /
---
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: dashboard-prefix
  namespace: pihole
spec:
  addPrefix:
    prefix: /admin
2 Likes

that worked great for me. thank you @ajschmidt8
Here's a version for others not using k8s

http:
  routers:
    pihole:
      entryPoints:
        - websecure
      rule: "Host(`dns.domain.tld`)"
      service: pihole
      tls: 
        certResolver: le
      middlewares:
        - pihole-redirectregex
        - pihole-addprefix

  middlewares:
    pihole-addprefix:
      addPrefix:
        prefix: /admin
    pihole-redirectregex:
      redirectRegex:
        regex: /admin/$
        replacement: /

2 Likes

I was wondering if anything has changed with version 3. I recently started using Traefik and I used this exact configuration for my PiHole. The initial redirect to the https://nn.acb.xyz/admin works fine but as soon as I login I get the following:

Failed Host Check: nn.acb.xyz vs 192.168.10.07, pihole, pi.hole, localhost

(where 192.168.10.07 is my pihole IP)

I am not sure what is going wrong here. Any tips?

I kept getting 307 redirections in a loop to the same address because I had put the redirectRegex middleware before the addPrefix :person_facepalming: !
By the way, when you need to log back in after a period of inactivity, you will be redirected to a /admin/dns_records.php for example. This page does not exist as the /admin is supposed to be removed and the proposed solutions above do not help when there is anything after it.
So here is my regex solution:

http:
  middlewares:
    pihole-redirect:
      redirectRegex:
        regex: "^https?://([\\w.-]+)/admin(.*)$"
        replacement: "https://${1}${2}"
    pihole-prefix:
      addPrefix:
        prefix: /admin

Regex explanations: The ${1} and ${2} in the replace correspond respectively to the first and second capturing groups (in parentheses). For the first it can only match the host part with word characters (double escape for yaml), dots and minus signs while the second matches anything that may follow /admin. The first question mark matches http and https.
PS: If you truly need to support http, create a capture group http(s?) in the regex and the replacement string should look like this "http${1}://${2}${3}"

PiHole v6 changed a few thing so here is my new midleware (pihole-prefix is not needed anymore) to redirect from / to /admin:

http:
  middlewares:
    pihole-redirect:
      redirectRegex:
        regex: "^https://([\\w.-]+)$"
        replacement: "https://${1}/admin"

I have been using it for a while now but I only just stumbled on my previous reply so I thought I might give an update.

Hello. I am testing traefik since I wanted to convert over from NPM. Trying to get pihole redirect to work but am getting the 403 error page using your code.

This is what I’ve added . It think my formatting is correct.

  middlewares:
    pihole-redirect:
      redirectRegex:
        regex: "^https://([\\w.-]+)$"
        replacement: "https://${1}/admin"

  routers:
    pihole:
      entryPoints:
        - "https"
      rule: "Host(`pi-hole.xxx.com`)"
      middlewares:
        - pihole-redirect
      tls: {}
      service: pihole

  services:
    pihole:
      loadBalancer:
        servers:
          - url: "http://192.168.1.247:80"
        passHostHeader: true

Enable and check Traefik debug log (doc), any "ERR" in logs? Enable and check Traefik access log in JSON format (doc), what’s the output during requests?

I see these logs.

access.log

192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET / HTTP/2.0" 403 3814 "-" "-" 1 "pihole@file" "http://192.168.1.247:80" 2ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/vendor/fonts/source-sans-pro/source-sans-pro.css?v=1755000704 HTTP/2.0" 200 3516 "-" "-" 2 "pihole@file" "http://192.168.1.247:80" 0ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/vendor/icheck/icheck-bootstrap.min.css?v=1755000704 HTTP/2.0" 200 12504 "-" "-" 4 "pihole@file" "http://192.168.1.247:80" 0ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/vendor/animate/animate.min.css?v=1755000704 HTTP/2.0" 200 71727 "-" "-" 5 "pihole@file" "http://192.168.1.247:80" 1ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/vendor/nprogress/nprogress.min.css?v=1755000704 HTTP/2.0" 200 1090 "-" "-" 8 "pihole@file" "http://192.168.1.247:80" 1ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/vendor/bootstrap/css/bootstrap.min.css?v=1755000704 HTTP/2.0" 200 121457 "-" "-" 3 "pihole@file" "http://192.168.1.247:80" 2ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/style/themes/default-dark.css?v=1755000704 HTTP/2.0" 200 14259 "-" "-" 13 "pihole@file" "http://192.168.1.247:80" 1ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/vendor/select2/select2.min.css?v=1755000704 HTTP/2.0" 200 14966 "-" "-" 10 "pihole@file" "http://192.168.1.247:80" 2ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/vendor/font-awesome/css/all.min.css?v=1755000704 HTTP/2.0" 200 73890 "-" "-" 7 "pihole@file" "http://192.168.1.247:80" 2ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/vendor/adminLTE/adminlte.min.js?v=1755000704 HTTP/2.0" 200 13611 "-" "-" 16 "pihole@file" "http://192.168.1.247:80" 1ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/vendor/waitMe-js/waitMe.min.css?v=1755000704 HTTP/2.0" 200 14044 "-" "-" 9 "pihole@file" "http://192.168.1.247:80" 2ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/vendor/bootstrap-notify/bootstrap-notify.min.js?v=1755000704 HTTP/2.0" 200 9428 "-" "-" 17 "pihole@file" "http://192.168.1.247:80" 1ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/style/pi-hole.css?v=1755000704 HTTP/2.0" 200 28532 "-" "-" 12 "pihole@file" "http://192.168.1.247:80" 2ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/vendor/jquery/jquery.min.js?v=1755000704 HTTP/2.0" 200 87533 "-" "-" 14 "pihole@file" "http://192.168.1.247:80" 2ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/vendor/adminLTE/AdminLTE.min.css?v=1755000704 HTTP/2.0" 200 106547 "-" "-" 11 "pihole@file" "http://192.168.1.247:80" 2ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/scripts/js/utils.js?v=1755000704 HTTP/2.0" 200 20843 "-" "-" 20 "pihole@file" "http://192.168.1.247:80" 0ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/vendor/waitMe-js/modernized-waitme-min.js?v=1755000704 HTTP/2.0" 200 3661 "-" "-" 18 "pihole@file" "http://192.168.1.247:80" 1ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/vendor/nprogress/nprogress.min.js?v=1755000704 HTTP/2.0" 200 7445 "-" "-" 19 "pihole@file" "http://192.168.1.247:80" 0ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/vendor/bootstrap/js/bootstrap.min.js?v=1755000704 HTTP/2.0" 200 39680 "-" "-" 15 "pihole@file" "http://192.168.1.247:80" 2ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/vendor/bstreeview/bstreeview.min.css?v=1755000704 HTTP/2.0" 200 723 "-" "-" 6 "pihole@file" "http://192.168.1.247:80" 42ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/img/boxed-bg-dark.png HTTP/2.0" 200 11633 "-" "-" 21 "pihole@file" "http://192.168.1.247:80" 0ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/vendor/fonts/source-sans-pro/source-sans-pro-v13-latin-600.woff2 HTTP/2.0" 200 15948 "-" "-" 22 "pihole@file" "http://192.168.1.247:80" 0ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/vendor/fonts/source-sans-pro/source-sans-pro-v13-latin-regular.woff2 HTTP/2.0" 200 16112 "-" "-" 24 "pihole@file" "http://192.168.1.247:80" 0ms
192.168.1.112 - - [15/Sep/2025:09:37:26 +0000] "GET /admin/vendor/font-awesome/webfonts/fa-solid-900.woff2 HTTP/2.0" 200 158220 "-" "-" 23 "pihole@file" "http://192.168.1.247:80" 0ms

traefik.log

2025-09-15T02:53:12Z WRN Could not find network named "traefik" for container "/error-pages1". Maybe you're missing the project's prefix in the label? container=error-pages-traefik-4d2066146e4d47411888a47952b414fb48ea16fd809a78df3c83efd44aaef2f0 providerName=docker serviceName=error-pages
2025-09-15T02:53:12Z WRN Defaulting to first available network (&{"proxy" "172.20.0.2" '\x00' "" "b50985db2e459abcc997c6585ec19ba906aeb237fae3e06125908e46ec7d8cf4"}) for container "/error-pages1". container=error-pages-traefik-4d2066146e4d47411888a47952b414fb48ea16fd809a78df3c83efd44aaef2f0 providerName=docker serviceName=error-pages
2025-09-15T03:45:21Z ERR Error occurred during watcher callback error="yaml: unmarshal errors:\n  line 54: mapping key \"service\" already defined at line 47\n  line 53: mapping key \"tls\" already defined at line 48" providerName=file
2025-09-15T03:46:17Z ERR Error occurred during watcher callback error="yaml: unmarshal errors:\n  line 54: mapping key \"service\" already defined at line 47\n  line 53: mapping key \"tls\" already defined at line 48" providerName=file
2025-09-15T03:47:18Z ERR Error occurred during watcher callback error="yaml: unmarshal errors:\n  line 53: mapping key \"tls\" already defined at line 48" providerName=file
2025-09-15T03:47:34Z ERR EntryPoint doesn't exist entryPointName=websecure routerName=pihole@file
2025-09-15T03:47:34Z ERR No valid entryPoint for this router routerName=pihole@file
2025-09-15T03:47:34Z ERR EntryPoint doesn't exist entryPointName=websecure routerName=pihole@file
2025-09-15T03:47:34Z ERR No valid entryPoint for this router routerName=pihole@file
2025-09-15T03:47:34Z ERR Router uses a nonexistent certificate resolver certificateResolver=le routerName=pihole@file
2025-09-15T03:47:53Z ERR EntryPoint doesn't exist entryPointName=websecure routerName=pihole@file
2025-09-15T03:47:53Z ERR No valid entryPoint for this router routerName=pihole@file
2025-09-15T03:47:53Z ERR EntryPoint doesn't exist entryPointName=websecure routerName=pihole@file
2025-09-15T03:47:53Z ERR No valid entryPoint for this router routerName=pihole@file
2025-09-15T03:47:53Z ERR Router uses a nonexistent certificate resolver certificateResolver=le routerName=pihole@file
2025-09-15T03:49:01Z ERR EntryPoint doesn't exist entryPointName=websecure routerName=pihole@file
2025-09-15T03:49:01Z ERR No valid entryPoint for this router routerName=pihole@file
2025-09-15T03:49:01Z ERR EntryPoint doesn't exist entryPointName=websecure routerName=pihole@file
2025-09-15T03:49:01Z ERR No valid entryPoint for this router routerName=pihole@file
2025-09-15T03:50:20Z ERR EntryPoint doesn't exist entryPointName=websecure routerName=pihole@file
2025-09-15T03:50:20Z ERR No valid entryPoint for this router routerName=pihole@file
2025-09-15T04:02:23Z ERR Error occurred during watcher callback error="field not found, node: redirect" providerName=file
2025-09-15T04:08:03Z ERR error="middleware \"pihole-prefix@file\" does not exist" entryPointName=https routerName=pihole@file
2025-09-15T04:51:46Z ERR Error occurred during watcher callback error="yaml: unmarshal errors:\n  line 25: mapping key \"https-redirectscheme\" already defined at line 16" providerName=file
2025-09-15T07:46:50Z INF I have to go...
2025-09-15T07:46:50Z INF Stopping server gracefully
2025-09-15T07:46:51Z INF Server stopped
2025-09-15T07:46:51Z INF Shutting down

Well, you should work on the errors, I think they are pretty descriptive.

Pihole is working. It is the redirect of omitting the /admin that is not. Wonder why it is working for @ benji and not for all. Pihole is running the latest v6. The errors were me commenting out the middlewares entries.