[GH-ISSUE #2597] enhance(badger): Expose configuration options for badger@http middleware #30027

Open
opened 2026-06-13 10:26:38 -05:00 by GiteaMirror · 14 comments
Owner

Originally created by @Christopher87R on GitHub (Mar 4, 2026).
Original GitHub issue: https://github.com/fosrl/pangolin/issues/2597

Describe the Bug

The log files do not show the user's IP address, but rather that of the Docker host. Basically, I have a standard

setup: Cloudflare Tunnel (proxy) - VM with Docker-based Pangolin and Traefik.

In Traefik, the forwardedHeaders: trustedIPs are configured and pangolin server has trust_proxy: 2 configured. If I use the fork github.com/hajimAIM/badger in version v1.2.1 instead of the badger traefik plugin github.com/fosrl/badger v1.3.1, it works as expected.

Image Image

Environment

  • OS Type & Version: Debian GNU/Linux 12 (bookworm)
  • Pangolin Version: 1.16.2
  • Gerbil Version: 1.3.0
  • Traefik Version: 3.6
  • Newt Version: not used - whoami on local VM
  • Badger Version: v1.3.1

To Reproduce

docker-compose.yml

name: pangolin
services:
  pangolin:
    image: docker.io/fosrl/pangolin:1.16.2
    container_name: pangolin
    restart: unless-stopped
    deploy:
      resources:
        limits:
          memory: 1g
        reservations:
          memory: 256m
    volumes:
      - ./config:/app/config
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3001/api/v1/"]
      interval: "10s"
      timeout: "10s"
      retries: 15
    networks:
      - pangolin

  gerbil:
    image: docker.io/fosrl/gerbil:1.3.0
    container_name: gerbil
    restart: unless-stopped
    depends_on:
      pangolin:
        condition: service_healthy
    command:
      - --reachableAt=http://gerbil:3004
      - --generateAndSaveKeyTo=/var/config/key
      - --remoteConfig=http://pangolin:3001/api/v1/
    volumes:
      - ./config/:/var/config
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    networks:
      - pangolin
      - cftunnel-transport
    ports:
      - 51820:51820/udp
      - 21820:21820/udp
      #- 443:443
      #- 80:80

  traefik:
    image: docker.io/traefik:v3.6
    container_name: traefik
    restart: unless-stopped
    network_mode: service:gerbil # Ports appear on the gerbil service
    depends_on:
      pangolin:
        condition: service_healthy
    command:
      - --configFile=/etc/traefik/traefik_config.yml
    volumes:
      - ./config/traefik:/etc/traefik:ro # Volume to store the Traefik configuration
      - ./config/letsencrypt:/letsencrypt # Volume to store the Let's Encrypt certificates
      - ./config/traefik/logs:/var/log/traefik # Volume to store Traefik logs
    environment:
      TZ: "Europe/Berlin"
      CF_API_EMAIL: "xxx"
      CF_DNS_API_TOKEN: "xxxx"
      CF_ZONE_API_TOKEN: "xxx"

  whoami:
    image: "traefik/whoami"
    container_name: whoami
    hostname: whoami
    depends_on:
      pangolin:
        condition: service_healthy
    restart: unless-stopped
    networks:
      - pangolin

  cf-tunnel:
    image: cloudflare/cloudflared:latest
    container_name: cf-tunnel
    hostname: cf-tunnel
    restart: unless-stopped
    networks:
      - cftunnel-transport
    command: tunnel --no-autoupdate run
    environment:
      - TUNNEL_TOKEN=xxx

networks:
  pangolin:
    driver: bridge
    name: pangolin
    enable_ipv6: true
  cftunnel-transport:
    driver: bridge
    name: cftunnel-transport
    enable_ipv6: true

config.yml

# To see all available options, please visit the docs:
# https://docs.pangolin.net/

gerbil:
    start_port: 51820
    base_endpoint: "xxx.goodsrv.de"

app:
    dashboard_url: "https://pangolin.xxx.me"
    log_level: "debug"
    #log_level: "info"
    telemetry:
        anonymous_usage: true

domains:
    domain1:
        base_domain: "xxx.me"

server:
    trust_proxy: 2
    secret: "xxx"
    cors:
        origins: ["https://pangolin.xxx.me"]
        methods: ["GET", "POST", "PUT", "DELETE", "PATCH"]
        allowed_headers: ["X-CSRF-Token", "Content-Type"]
        credentials: false
    maxmind_db_path: "./config/GeoLite2-Country.mmdb"

email:
    smtp_host: "xxx"
    smtp_port: 587
    smtp_user: "xxx"
    smtp_pass: "xxx"
    no_reply: "xxx"

flags:
    require_email_verification: true
    disable_signup_without_invite: true
    disable_user_create_org: false
    allow_raw_resources: true

traefik_config.yml

api:
  insecure: true
  dashboard: true

providers:
  http:
    endpoint: "http://pangolin:3001/api/v1/traefik-config"
    pollInterval: "5s"
  file:
    filename: "/etc/traefik/dynamic_config.yml"

experimental:
  plugins:
    badger:
      moduleName: "github.com/fosrl/badger"
      version: "v1.3.1"
    real-ip:
      moduleName: "github.com/Paxxs/traefik-get-real-ip"
      version: "v1.0.4"

log:
  level: "INFO"
  format: "common"
  maxSize: 100
  maxBackups: 3
  maxAge: 3
  compress: true

certificatesResolvers:
  letsencrypt:
    acme:
      httpChallenge:
        entryPoint: web
      email: "xxx"
      storage: "/letsencrypt/acme.json"
      caServer: "https://acme-v02.api.letsencrypt.org/directory"
  cloudflare:
    acme:
      email: xxx
      storage: /letsencrypt/acme_cf.json
      keyType: EC384
      dnschallenge:
        provider: cloudflare
        resolvers:
          - "1.1.1.1:53"
          - "1.0.0.1:53"

entryPoints:
  web:
    address: ":80"
    http:
      #middlewares:
      #  - real-ip@file
    forwardedHeaders:
      trustedIPs: &trustedIps
        # Cloudflare 2024 12 14 https://www.cloudflare.com/ips
        - 173.245.48.0/20
        - 103.21.244.0/22
        - 103.22.200.0/22
        - 103.31.4.0/22
        - 141.101.64.0/18
        - 108.162.192.0/18
        - 190.93.240.0/20
        - 188.114.96.0/20
        - 197.234.240.0/22
        - 198.41.128.0/17
        - 162.158.0.0/15
        - 104.16.0.0/13
        - 104.24.0.0/14
        - 172.64.0.0/13
        - 131.0.72.0/22
        - 2400:cb00::/32
        - 2606:4700::/32
        - 2803:f800::/32
        - 2405:b500::/32
        - 2405:8100::/32
        - 2a06:98c0::/29
        - 2c0f:f248::/32
        # local
        - 172.16.0.0/16
        - 172.17.0.0/16
        - 172.18.0.0/16
        - 172.19.0.0/16
        - 172.20.0.0/16
        - 172.21.0.0/16
        - 172.22.0.0/16
        - 172.23.0.0/16
        
    #proxyProtocol:
    #  trustedIPs: *trustedIps   
        
  websecure:
    address: ":443"
    forwardedHeaders:
      trustedIPs: *trustedIps
    #proxyProtocol:
    #    trustedIPs: *trustedIps 
    transport:
      respondingTimeouts:
        readTimeout: "30m"
    http:
      #middlewares:
      #  - real-ip@file
      #tls:
      #  certResolver: "letsencrypt"
      tls:
        certResolver: cloudflare
        domains:
          - main: xxx.me
      encodedCharacters:
        allowEncodedSlash: true
        allowEncodedQuestionMark: true

serversTransport:
  insecureSkipVerify: true

ping:
  entryPoint: "web"

tls:
  options:
    default:
      minVersion: VersionTLS13
      sniStrict: true
      cipherSuites:
        - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
        - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
      curvePreferences:
        - CurveP521
        - CurveP384

dynamic_config.yml

http:
  middlewares:
    badger:
      plugin:
        badger:
          disableForwardAuth: true
    redirect-to-https:
      redirectScheme:
        scheme: https
    real-ip:
      plugin:
        real-ip:
          enableLog: true # default: false, enable to see detailed logs
          deny403OnFail: true # default: false, when true returns 403 if no matching CDN header found
          eraseProxyHeaders: false # default: false, erase CDN-specific headers after processing
          Proxy:
            - proxyHeadername: X-From-Cdn
              proxyHeadervalue: cf-foo
              realIP: Cf-Connecting-Ip
              OverwriteXFF: true # default: false, v1.0.2 or above
            - proxyHeadername: "*"
              realIP: RemoteAddr

  routers:
    # HTTP to HTTPS redirect router
    main-app-router-redirect:
      rule: "Host(`pangolin.xxx.me`)"
      service: next-service
      entryPoints:
        - web
      middlewares:
        - redirect-to-https
        #- real-ip
        - badger

    # Next.js router (handles everything except API and WebSocket paths)
    next-router:
      rule: "Host(`pangolin.xxx.me`) && !PathPrefix(`/api/v1`)"
      service: next-service
      entryPoints:
        - websecure
      middlewares:
        #- real-ip
        - badger
      tls:
        certResolver: cloudflare
        domains:
          - main: "xxx.me"
            sans:
              - "*.xxx.me"

    # API router (handles /api/v1 paths)
    api-router:
      rule: "Host(`pangolin.xxx.me`) && PathPrefix(`/api/v1`)"
      service: api-service
      entryPoints:
        - websecure
      middlewares:
        #- real-ip
        - badger
      tls:
        certResolver: cloudflare
        domains:
          - main: "xxx.me"
            sans:
              - "*.xxx.me"

    # WebSocket router
    ws-router:
      rule: "Host(`pangolin.xxx.me`)"
      service: api-service
      entryPoints:
        - websecure
      middlewares:
        #- real-ip
        - badger
      tls:
        certResolver: cloudflare
        domains:
          - main: "xxx.me"
            sans:
              - "*.xxx.me"
  services:
    next-service:
      loadBalancer:
        servers:
          - url: "http://pangolin:3002"  # Next.js server

    api-service:
      loadBalancer:
        servers:
          - url: "http://pangolin:3000"  # API/WebSocket server

tcp:
  serversTransports:
    pp-transport-v1:
      proxyProtocol:
        version: 1
    pp-transport-v2:
      proxyProtocol:
        version: 2

Expected Behavior

I would expect my IPv4 (or IPv6, if applicable) address to be in the log file and also at Whoami under X-Real-Ip.

I would expect my IPv4 (or IPv6, if applicable) address to appear in the log file and also under X-Real-Ip in Whoami. This seems to work when I use the fork github.com/hajimAIM/badger in version v1.2.1 for Badger. However, I then have to deactivate the middleware.

Originally created by @Christopher87R on GitHub (Mar 4, 2026). Original GitHub issue: https://github.com/fosrl/pangolin/issues/2597 ### Describe the Bug The log files do not show the user's IP address, but rather that of the Docker host. Basically, I have a standard setup: Cloudflare Tunnel (proxy) - VM with Docker-based Pangolin and Traefik. In Traefik, the forwardedHeaders: trustedIPs are configured and pangolin server has trust_proxy: 2 configured. If I use the fork github.com/hajimAIM/badger in version v1.2.1 instead of the badger traefik plugin github.com/fosrl/badger v1.3.1, it works as expected. <img width="1282" height="255" alt="Image" src="https://github.com/user-attachments/assets/d0a7d01e-a25c-4fbb-8242-83e0e79cc7e5" /> <img width="610" height="829" alt="Image" src="https://github.com/user-attachments/assets/76c3c5af-d29b-4e82-a572-147ef6d63a42" /> ### Environment - OS Type & Version: Debian GNU/Linux 12 (bookworm) - Pangolin Version: 1.16.2 - Gerbil Version: 1.3.0 - Traefik Version: 3.6 - Newt Version: not used - whoami on local VM - Badger Version: v1.3.1 ### To Reproduce docker-compose.yml ``` name: pangolin services: pangolin: image: docker.io/fosrl/pangolin:1.16.2 container_name: pangolin restart: unless-stopped deploy: resources: limits: memory: 1g reservations: memory: 256m volumes: - ./config:/app/config healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3001/api/v1/"] interval: "10s" timeout: "10s" retries: 15 networks: - pangolin gerbil: image: docker.io/fosrl/gerbil:1.3.0 container_name: gerbil restart: unless-stopped depends_on: pangolin: condition: service_healthy command: - --reachableAt=http://gerbil:3004 - --generateAndSaveKeyTo=/var/config/key - --remoteConfig=http://pangolin:3001/api/v1/ volumes: - ./config/:/var/config cap_add: - NET_ADMIN - SYS_MODULE networks: - pangolin - cftunnel-transport ports: - 51820:51820/udp - 21820:21820/udp #- 443:443 #- 80:80 traefik: image: docker.io/traefik:v3.6 container_name: traefik restart: unless-stopped network_mode: service:gerbil # Ports appear on the gerbil service depends_on: pangolin: condition: service_healthy command: - --configFile=/etc/traefik/traefik_config.yml volumes: - ./config/traefik:/etc/traefik:ro # Volume to store the Traefik configuration - ./config/letsencrypt:/letsencrypt # Volume to store the Let's Encrypt certificates - ./config/traefik/logs:/var/log/traefik # Volume to store Traefik logs environment: TZ: "Europe/Berlin" CF_API_EMAIL: "xxx" CF_DNS_API_TOKEN: "xxxx" CF_ZONE_API_TOKEN: "xxx" whoami: image: "traefik/whoami" container_name: whoami hostname: whoami depends_on: pangolin: condition: service_healthy restart: unless-stopped networks: - pangolin cf-tunnel: image: cloudflare/cloudflared:latest container_name: cf-tunnel hostname: cf-tunnel restart: unless-stopped networks: - cftunnel-transport command: tunnel --no-autoupdate run environment: - TUNNEL_TOKEN=xxx networks: pangolin: driver: bridge name: pangolin enable_ipv6: true cftunnel-transport: driver: bridge name: cftunnel-transport enable_ipv6: true ``` config.yml ``` # To see all available options, please visit the docs: # https://docs.pangolin.net/ gerbil: start_port: 51820 base_endpoint: "xxx.goodsrv.de" app: dashboard_url: "https://pangolin.xxx.me" log_level: "debug" #log_level: "info" telemetry: anonymous_usage: true domains: domain1: base_domain: "xxx.me" server: trust_proxy: 2 secret: "xxx" cors: origins: ["https://pangolin.xxx.me"] methods: ["GET", "POST", "PUT", "DELETE", "PATCH"] allowed_headers: ["X-CSRF-Token", "Content-Type"] credentials: false maxmind_db_path: "./config/GeoLite2-Country.mmdb" email: smtp_host: "xxx" smtp_port: 587 smtp_user: "xxx" smtp_pass: "xxx" no_reply: "xxx" flags: require_email_verification: true disable_signup_without_invite: true disable_user_create_org: false allow_raw_resources: true ``` traefik_config.yml ``` api: insecure: true dashboard: true providers: http: endpoint: "http://pangolin:3001/api/v1/traefik-config" pollInterval: "5s" file: filename: "/etc/traefik/dynamic_config.yml" experimental: plugins: badger: moduleName: "github.com/fosrl/badger" version: "v1.3.1" real-ip: moduleName: "github.com/Paxxs/traefik-get-real-ip" version: "v1.0.4" log: level: "INFO" format: "common" maxSize: 100 maxBackups: 3 maxAge: 3 compress: true certificatesResolvers: letsencrypt: acme: httpChallenge: entryPoint: web email: "xxx" storage: "/letsencrypt/acme.json" caServer: "https://acme-v02.api.letsencrypt.org/directory" cloudflare: acme: email: xxx storage: /letsencrypt/acme_cf.json keyType: EC384 dnschallenge: provider: cloudflare resolvers: - "1.1.1.1:53" - "1.0.0.1:53" entryPoints: web: address: ":80" http: #middlewares: # - real-ip@file forwardedHeaders: trustedIPs: &trustedIps # Cloudflare 2024 12 14 https://www.cloudflare.com/ips - 173.245.48.0/20 - 103.21.244.0/22 - 103.22.200.0/22 - 103.31.4.0/22 - 141.101.64.0/18 - 108.162.192.0/18 - 190.93.240.0/20 - 188.114.96.0/20 - 197.234.240.0/22 - 198.41.128.0/17 - 162.158.0.0/15 - 104.16.0.0/13 - 104.24.0.0/14 - 172.64.0.0/13 - 131.0.72.0/22 - 2400:cb00::/32 - 2606:4700::/32 - 2803:f800::/32 - 2405:b500::/32 - 2405:8100::/32 - 2a06:98c0::/29 - 2c0f:f248::/32 # local - 172.16.0.0/16 - 172.17.0.0/16 - 172.18.0.0/16 - 172.19.0.0/16 - 172.20.0.0/16 - 172.21.0.0/16 - 172.22.0.0/16 - 172.23.0.0/16 #proxyProtocol: # trustedIPs: *trustedIps websecure: address: ":443" forwardedHeaders: trustedIPs: *trustedIps #proxyProtocol: # trustedIPs: *trustedIps transport: respondingTimeouts: readTimeout: "30m" http: #middlewares: # - real-ip@file #tls: # certResolver: "letsencrypt" tls: certResolver: cloudflare domains: - main: xxx.me encodedCharacters: allowEncodedSlash: true allowEncodedQuestionMark: true serversTransport: insecureSkipVerify: true ping: entryPoint: "web" tls: options: default: minVersion: VersionTLS13 sniStrict: true cipherSuites: - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 curvePreferences: - CurveP521 - CurveP384 ``` dynamic_config.yml ``` http: middlewares: badger: plugin: badger: disableForwardAuth: true redirect-to-https: redirectScheme: scheme: https real-ip: plugin: real-ip: enableLog: true # default: false, enable to see detailed logs deny403OnFail: true # default: false, when true returns 403 if no matching CDN header found eraseProxyHeaders: false # default: false, erase CDN-specific headers after processing Proxy: - proxyHeadername: X-From-Cdn proxyHeadervalue: cf-foo realIP: Cf-Connecting-Ip OverwriteXFF: true # default: false, v1.0.2 or above - proxyHeadername: "*" realIP: RemoteAddr routers: # HTTP to HTTPS redirect router main-app-router-redirect: rule: "Host(`pangolin.xxx.me`)" service: next-service entryPoints: - web middlewares: - redirect-to-https #- real-ip - badger # Next.js router (handles everything except API and WebSocket paths) next-router: rule: "Host(`pangolin.xxx.me`) && !PathPrefix(`/api/v1`)" service: next-service entryPoints: - websecure middlewares: #- real-ip - badger tls: certResolver: cloudflare domains: - main: "xxx.me" sans: - "*.xxx.me" # API router (handles /api/v1 paths) api-router: rule: "Host(`pangolin.xxx.me`) && PathPrefix(`/api/v1`)" service: api-service entryPoints: - websecure middlewares: #- real-ip - badger tls: certResolver: cloudflare domains: - main: "xxx.me" sans: - "*.xxx.me" # WebSocket router ws-router: rule: "Host(`pangolin.xxx.me`)" service: api-service entryPoints: - websecure middlewares: #- real-ip - badger tls: certResolver: cloudflare domains: - main: "xxx.me" sans: - "*.xxx.me" services: next-service: loadBalancer: servers: - url: "http://pangolin:3002" # Next.js server api-service: loadBalancer: servers: - url: "http://pangolin:3000" # API/WebSocket server tcp: serversTransports: pp-transport-v1: proxyProtocol: version: 1 pp-transport-v2: proxyProtocol: version: 2 ``` ### Expected Behavior I would expect my IPv4 (or IPv6, if applicable) address to be in the log file and also at Whoami under X-Real-Ip. I would expect my IPv4 (or IPv6, if applicable) address to appear in the log file and also under X-Real-Ip in Whoami. This seems to work when I use the fork github.com/hajimAIM/badger in version v1.2.1 for Badger. However, I then have to deactivate the middleware.
GiteaMirror added the enhancement label 2026-06-13 10:26:38 -05:00
Author
Owner

@Christopher87R commented on GitHub (Mar 10, 2026):

Could you please check this or can anybody help me with this issue?

<!-- gh-comment-id:4033045058 --> @Christopher87R commented on GitHub (Mar 10, 2026): Could you please check this or can anybody help me with this issue?
Author
Owner

@LaurenceJJones commented on GitHub (Mar 10, 2026):

when setting the trust proxy level, did you ensure to bring down the stack (ensure the pangolin network is removed) then bring it all back up?

This is not just a pangolin problem many traefik users in general have issues with the docker-proxy causing problems with real ip.

also stating "standard setup" is not correct, we generally dont suggest you put pangolin behind a reverse proxy (cloudflared is a tunneled reverse proxy) as it should be exposed to be the gateway ingress.

<!-- gh-comment-id:4033480915 --> @LaurenceJJones commented on GitHub (Mar 10, 2026): when setting the trust proxy level, did you ensure to bring down the stack (ensure the pangolin network is removed) then bring it all back up? This is not just a pangolin problem many traefik users in general have issues with the docker-proxy causing problems with real ip. also stating "standard setup" is not correct, we generally dont suggest you put pangolin behind a reverse proxy (cloudflared is a tunneled reverse proxy) as it should be exposed to be the gateway ingress.
Author
Owner

@AstralDestiny commented on GitHub (Mar 10, 2026):

x-trusted-ips: &trustedIPs
        # Cloudflare V4
        - 173.245.48.0/20
        - 103.21.244.0/22
        - 103.22.200.0/22
        - 103.31.4.0/22
        - 141.101.64.0/18
        - 108.162.192.0/18
        - 190.93.240.0/20
        - 188.114.96.0/20
        - 197.234.240.0/22
        - 198.41.128.0/17
        - 162.158.0.0/15
        - 104.16.0.0/13
        - 104.24.0.0/14
        - 172.64.0.0/13
        - 131.0.72.0/22
        # Cloudflare V6
        - 2400:cb00::/32
        - 2606:4700::/32
        - 2803:f800::/32
        - 2405:b500::/32
        - 2405:8100::/32
        - 2a06:98c0::/29
        - 2c0f:f248::/32

entryPoints:
  http:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: https
          scheme: https
          permanent: true
    forwardedHeaders:
      trustedIPs: *trustedIPs # This
  https:
    address: ":443"
    http3:
      advertisedPort: 443
    asDefault: true
    http:
      middlewares:
       - middlewares-secure-headers@file
      tls:
         options: default
         certResolver: dns
    forwardedHeaders:
      trustedIPs: *trustedIPs  # This

X-Forwarded-For: XXXX:XXXX:XXX:XXXX:XXXX:XXXX:XXXX:Xbd9, 162.158.158.100
X-Forwarded-Host: whoami.domain.com
X-Forwarded-Port: 443
X-Forwarded-Proto: https
X-Forwarded-Server: 8c7082c81666
X-Real-Ip: XXXX:XXXX:XXX:XXXX:XXXX:XXXX:XXXX:Xbd9
Image
server:
  external_port: 3000
  internal_port: 3001
  next_port: 3002
  internal_hostname: pangolin
  session_cookie_name: p_session_token
  resource_access_token_param: p_token
  resource_session_request_param: p_session_request
  resource_access_token_headers:
    id: P-Access-Token-Id
    token: P-Access-Token
  trust_proxy: 2
<!-- gh-comment-id:4033677354 --> @AstralDestiny commented on GitHub (Mar 10, 2026): ``` x-trusted-ips: &trustedIPs # Cloudflare V4 - 173.245.48.0/20 - 103.21.244.0/22 - 103.22.200.0/22 - 103.31.4.0/22 - 141.101.64.0/18 - 108.162.192.0/18 - 190.93.240.0/20 - 188.114.96.0/20 - 197.234.240.0/22 - 198.41.128.0/17 - 162.158.0.0/15 - 104.16.0.0/13 - 104.24.0.0/14 - 172.64.0.0/13 - 131.0.72.0/22 # Cloudflare V6 - 2400:cb00::/32 - 2606:4700::/32 - 2803:f800::/32 - 2405:b500::/32 - 2405:8100::/32 - 2a06:98c0::/29 - 2c0f:f248::/32 entryPoints: http: address: ":80" http: redirections: entryPoint: to: https scheme: https permanent: true forwardedHeaders: trustedIPs: *trustedIPs # This https: address: ":443" http3: advertisedPort: 443 asDefault: true http: middlewares: - middlewares-secure-headers@file tls: options: default certResolver: dns forwardedHeaders: trustedIPs: *trustedIPs # This ``` ``` X-Forwarded-For: XXXX:XXXX:XXX:XXXX:XXXX:XXXX:XXXX:Xbd9, 162.158.158.100 X-Forwarded-Host: whoami.domain.com X-Forwarded-Port: 443 X-Forwarded-Proto: https X-Forwarded-Server: 8c7082c81666 X-Real-Ip: XXXX:XXXX:XXX:XXXX:XXXX:XXXX:XXXX:Xbd9 ``` <img width="1753" height="120" alt="Image" src="https://github.com/user-attachments/assets/161bc402-86ef-4ce8-a9f4-7e81e86b51f3" /> ``` server: external_port: 3000 internal_port: 3001 next_port: 3002 internal_hostname: pangolin session_cookie_name: p_session_token resource_access_token_param: p_token resource_session_request_param: p_session_request resource_access_token_headers: id: P-Access-Token-Id token: P-Access-Token trust_proxy: 2 ```
Author
Owner

@AstralDestiny commented on GitHub (Mar 10, 2026):

If using cloudflared inspect your docker network and remove all the cloudflare v4/v6 and just put the docker ip range of cloudflared or the ipam you set for it.

docker inspect cloudflared, Find it's network name, docker network inspect
If it's on a different host then trust that host like 10.0.0.5/32

x-trusted-ips: &trustedIPs
        # Internal
        - 172.23.0.0/16 # Traefik 
        - XXXX:XXXX:XXXX:dd97::/64 # Newt

entryPoints:
  http:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: https
          scheme: https
          permanent: true
    forwardedHeaders:
      trustedIPs: *trustedIPs # This
  https:
    address: ":443"
    http3:
      advertisedPort: 443
    asDefault: true
    http:
      middlewares:
       - middlewares-secure-headers@file
      tls:
         options: default
         certResolver: dns
    forwardedHeaders:
      trustedIPs: *trustedIPs  # This
<!-- gh-comment-id:4033744539 --> @AstralDestiny commented on GitHub (Mar 10, 2026): If using cloudflared inspect your docker network and remove all the cloudflare v4/v6 and just put the docker ip range of cloudflared or the ipam you set for it. docker inspect cloudflared, Find it's network name, docker network inspect <network name> If it's on a different host then trust that host like 10.0.0.5/32 ``` x-trusted-ips: &trustedIPs # Internal - 172.23.0.0/16 # Traefik - XXXX:XXXX:XXXX:dd97::/64 # Newt entryPoints: http: address: ":80" http: redirections: entryPoint: to: https scheme: https permanent: true forwardedHeaders: trustedIPs: *trustedIPs # This https: address: ":443" http3: advertisedPort: 443 asDefault: true http: middlewares: - middlewares-secure-headers@file tls: options: default certResolver: dns forwardedHeaders: trustedIPs: *trustedIPs # This ```
Author
Owner

@Christopher87R commented on GitHub (Mar 10, 2026):

when setting the trust proxy level, did you ensure to bring down the stack (ensure the pangolin network is removed) then bring it all back up?

This is not just a pangolin problem many traefik users in general have issues with the docker-proxy causing problems with real ip.

also stating "standard setup" is not correct, we generally dont suggest you put pangolin behind a reverse proxy (cloudflared is a tunneled reverse proxy) as it should be exposed to be the gateway ingress.

Sure, I did a docker compose up -d --force-recreate
It works when I use github.com/hajimAIM/badger in version v1.2.1 - So I was surprised and assume that it is a bug.

If using cloudflared inspect your docker network and remove all the cloudflare v4/v6 and just put the docker ip range of cloudflared or the ipam you set for it.

docker inspect cloudflared, Find it's network name, docker network inspect If it's on a different host then trust that host like 10.0.0.5/32

x-trusted-ips: &trustedIPs
        # Internal
        - 172.23.0.0/16 # Traefik 
        - XXXX:XXXX:XXXX:dd97::/64 # Newt

entryPoints:
  http:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: https
          scheme: https
          permanent: true
    forwardedHeaders:
      trustedIPs: *trustedIPs # This
  https:
    address: ":443"
    http3:
      advertisedPort: 443
    asDefault: true
    http:
      middlewares:
       - middlewares-secure-headers@file
      tls:
         options: default
         certResolver: dns
    forwardedHeaders:
      trustedIPs: *trustedIPs  # This

I did exactly as you suggested and only entered the relevant IPs. Unfortunately, this did not work, and I still have the same problem.
By the way, the Cf-Connecting-Ip is deleted - whoami no longer displays it when I have Pangolin in between.
For CF Tunnel - Traefik - whoami, it works.

<!-- gh-comment-id:4034393885 --> @Christopher87R commented on GitHub (Mar 10, 2026): > when setting the trust proxy level, did you ensure to bring down the stack (ensure the pangolin network is removed) then bring it all back up? > > This is not just a pangolin problem many traefik users in general have issues with the docker-proxy causing problems with real ip. > > also stating "standard setup" is not correct, we generally dont suggest you put pangolin behind a reverse proxy (cloudflared is a tunneled reverse proxy) as it should be exposed to be the gateway ingress. Sure, I did a docker compose up -d --force-recreate It works when I use github.com/hajimAIM/badger in version v1.2.1 - So I was surprised and assume that it is a bug. > If using cloudflared inspect your docker network and remove all the cloudflare v4/v6 and just put the docker ip range of cloudflared or the ipam you set for it. > > docker inspect cloudflared, Find it's network name, docker network inspect If it's on a different host then trust that host like 10.0.0.5/32 > > ``` > x-trusted-ips: &trustedIPs > # Internal > - 172.23.0.0/16 # Traefik > - XXXX:XXXX:XXXX:dd97::/64 # Newt > > entryPoints: > http: > address: ":80" > http: > redirections: > entryPoint: > to: https > scheme: https > permanent: true > forwardedHeaders: > trustedIPs: *trustedIPs # This > https: > address: ":443" > http3: > advertisedPort: 443 > asDefault: true > http: > middlewares: > - middlewares-secure-headers@file > tls: > options: default > certResolver: dns > forwardedHeaders: > trustedIPs: *trustedIPs # This > ``` I did exactly as you suggested and only entered the relevant IPs. Unfortunately, this did not work, and I still have the same problem. By the way, the Cf-Connecting-Ip is deleted - whoami no longer displays it when I have Pangolin in between. For CF Tunnel - Traefik - whoami, it works.
Author
Owner

@Christopher87R commented on GitHub (Mar 11, 2026):

I have now tried everything again and unfortunately without success. I also looked at the source code and since the Cf-Connecting-Ip header is deleted, isTrusted does not seem to be true - for whatever reason. Perhaps the trusted IP list is not being applied?

<!-- gh-comment-id:4041115669 --> @Christopher87R commented on GitHub (Mar 11, 2026): I have now tried everything again and unfortunately without success. I also looked at the [source code](https://github.com/fosrl/badger/blob/e0a2d76844f7ee39346e0e51ee1812f43322717e/main.go#L434) and since the Cf-Connecting-Ip header is deleted, isTrusted does not seem to be true - for whatever reason. Perhaps the trusted IP list is not being applied?
Author
Owner

@Christopher87R commented on GitHub (Mar 12, 2026):

I have now explicitly set the IP ranges:

etworks:
  pangolin:
    driver: bridge
    name: pangolin
    enable_ipv6: false
    ipam:
      driver: default
      config:
      - subnet: ${NETWORKS_PANGOLIN_IPV4:-172.20.0.0/16}
  cftunnel-transport:
    driver: bridge
    name: cftunnel-transport
    enable_ipv6: false
    ipam:
      driver: default
      config:
      - subnet: ${NETWORKS_CFTUNNEL_IPV4:-172.24.0.0/16}

and adjusted the list of IPs accordingly:

    forwardedHeaders:
      trustedIPs: &trustedIPs
        - 172.24.0.0/16 

Still no success, the visitor's real IP is never displayed.

<!-- gh-comment-id:4049403899 --> @Christopher87R commented on GitHub (Mar 12, 2026): I have now explicitly set the IP ranges: ``` etworks: pangolin: driver: bridge name: pangolin enable_ipv6: false ipam: driver: default config: - subnet: ${NETWORKS_PANGOLIN_IPV4:-172.20.0.0/16} cftunnel-transport: driver: bridge name: cftunnel-transport enable_ipv6: false ipam: driver: default config: - subnet: ${NETWORKS_CFTUNNEL_IPV4:-172.24.0.0/16} ``` and adjusted the list of IPs accordingly: ``` forwardedHeaders: trustedIPs: &trustedIPs - 172.24.0.0/16 ``` Still no success, the visitor's real IP is never displayed.
Author
Owner

@Christopher87R commented on GitHub (Mar 13, 2026):

I have now done the following (perhaps a little rough and ready, but it works).
My Traefik config now uses Badger's locale plugin (to incorporate debug output).

experimental:
  localPlugins:
    badger:
      moduleName: “github.com/fosrl/badger”

I also have set the CF-Tunnel IP

    forwardedHeaders:
      trustedIPs: &trustedIps
        - 172.24.0.0/16
        - fd00:1:be:4::0/64
http:
  middlewares:
    badger:
      plugin:
        badger:
          disableForwardAuth: true
          disableDefaultCFIPs: true
          trustip:
          - 172.24.0.0/16
          - fd00:1:be:4::0/64

This works, and I have now incorporated the following output into the .go file:

func (p *Badger) isTrustedIP(remoteAddr string) bool {
	ipStr, _, err := net.SplitHostPort(remoteAddr)
	
	if err != nil {
		return false
	}
	ip := net.ParseIP(ipStr)
	log.Println("ip: ", ip)
	if ip == nil {
		return false
	}
	for _, network := range p.trustIP {
		log.Println("network: ", network)
		if network.Contains(ip) {
			return true
		}
	}
	return false
}
// Check if request comes from a trusted source
isTrusted := p.isTrustedIP(req.RemoteAddr)

log.Println("isTrusted: ", isTrusted, " IP: ", req.RemoteAddr)

The settings do not seem to be applied, because I get the following in the Traefik log file:

{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 ip:  172.24.0.2"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  173.245.48.0/20"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  103.21.244.0/22"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  103.22.200.0/22"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  103.31.4.0/22"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  141.101.64.0/18"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  108.162.192.0/18"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  190.93.240.0/20"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  188.114.96.0/20"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  197.234.240.0/22"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  198.41.128.0/17"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  162.158.0.0/15"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  104.16.0.0/13"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  104.24.0.0/14"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  172.64.0.0/13"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  131.0.72.0/22"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  2400:cb00::/32"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  2606:4700::/32"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  2803:f800::/32"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  2405:b500::/32"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  2405:8100::/32"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  2a06:98c0::/29"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network:  2c0f:f248::/32"}

The strange thing is that after restarting Traefik, the following is briefly visible:

{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:08+01:00","level":"error","message":"2026/03/13 09:14:08 ip:  172.24.0.2"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:08+01:00","level":"error","message":"2026/03/13 09:14:08 network:  172.24.0.0/16"}
{"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:08+01:00","level":"error","message":"2026/03/13 09:14:08 isTrusted:  true  IP:  172.24.0.2:38254"}

So something is going wrong here. Do you have any idea what it is and how I can narrow it down further? Unfortunately, I'm not really familiar with Go or a setup that would allow me to debug it.

Update: When I add the IP to the default IPs in ips.go, everything works fine.
It seems as if the IP list is always overwritten by the default IP list. This happens even when I explicitly deactivate the default IPs.
Am I doing something wrong in the settings?

@miloschwartz is this more a Badger bug?

<!-- gh-comment-id:4053505261 --> @Christopher87R commented on GitHub (Mar 13, 2026): I have now done the following (perhaps a little rough and ready, but it works). My Traefik config now uses Badger's locale plugin (to incorporate debug output). ``` experimental: localPlugins: badger: moduleName: “github.com/fosrl/badger” ``` I also have set the CF-Tunnel IP ``` forwardedHeaders: trustedIPs: &trustedIps - 172.24.0.0/16 - fd00:1:be:4::0/64 http: middlewares: badger: plugin: badger: disableForwardAuth: true disableDefaultCFIPs: true trustip: - 172.24.0.0/16 - fd00:1:be:4::0/64 ``` This works, and I have now incorporated the following output into the .go file: ``` func (p *Badger) isTrustedIP(remoteAddr string) bool { ipStr, _, err := net.SplitHostPort(remoteAddr) if err != nil { return false } ip := net.ParseIP(ipStr) log.Println("ip: ", ip) if ip == nil { return false } for _, network := range p.trustIP { log.Println("network: ", network) if network.Contains(ip) { return true } } return false } // Check if request comes from a trusted source isTrusted := p.isTrustedIP(req.RemoteAddr) log.Println("isTrusted: ", isTrusted, " IP: ", req.RemoteAddr) ``` The settings do not seem to be applied, because I get the following in the Traefik log file: ``` {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 ip: 172.24.0.2"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 173.245.48.0/20"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 103.21.244.0/22"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 103.22.200.0/22"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 103.31.4.0/22"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 141.101.64.0/18"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 108.162.192.0/18"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 190.93.240.0/20"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 188.114.96.0/20"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 197.234.240.0/22"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 198.41.128.0/17"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 162.158.0.0/15"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 104.16.0.0/13"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 104.24.0.0/14"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 172.64.0.0/13"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 131.0.72.0/22"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 2400:cb00::/32"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 2606:4700::/32"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 2803:f800::/32"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 2405:b500::/32"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 2405:8100::/32"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 2a06:98c0::/29"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:07+01:00","level":"error","message":"2026/03/13 09:14:07 network: 2c0f:f248::/32"} ``` The strange thing is that after restarting Traefik, the following is briefly visible: ``` {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:08+01:00","level":"error","message":"2026/03/13 09:14:08 ip: 172.24.0.2"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:08+01:00","level":"error","message":"2026/03/13 09:14:08 network: 172.24.0.0/16"} {"plugin":"plugin-badger","module":"github.com/fosrl/badger","runtime":"","time":"2026-03-13T09:14:08+01:00","level":"error","message":"2026/03/13 09:14:08 isTrusted: true IP: 172.24.0.2:38254"} ``` So something is going wrong here. Do you have any idea what it is and how I can narrow it down further? Unfortunately, I'm not really familiar with Go or a setup that would allow me to debug it. **Update:** When I add the IP to the default IPs in ips.go, everything works fine. It seems as if the IP list is always overwritten by the default IP list. This happens even when I explicitly deactivate the default IPs. Am I doing something wrong in the settings? @miloschwartz is this more a Badger bug?
Author
Owner

@Christopher87R commented on GitHub (Mar 25, 2026):

Could someone please take a look at this? To me, this clearly looks like a defect (see the analysis of the last 3 posts)

<!-- gh-comment-id:4127119677 --> @Christopher87R commented on GitHub (Mar 25, 2026): Could someone please take a look at this? To me, this clearly looks like a defect (see the analysis of the last 3 posts)
Author
Owner

@LaurenceJJones commented on GitHub (Mar 25, 2026):

As noted previously, Pangolin behind a reverse proxy is not a supported deployment method. For that reason, the issue being reported would not be classified as a defect in Pangolin, as the setup is outside the supported configuration.

Relevant code reference:
67ad9b651e/main.go (L403-L428)

Looking at the current implementation, Badger’s realip handling is fairly limited and does not fully support the reverse lookup logic that would be needed here.

The most practical workaround would be to define a custom header such as X-Real-Ip, which Cloudflare should already be setting. Otherwise, if you can avoid using a plugin that removes the CF-Connecting-Ip header, the existing fallback logic should allow it to work.

http:
  middlewares:
    badger:
      plugin:
        badger:
          disableForwardAuth: true
          disableDefaultCFIPs: true
          trustip:
          - 172.24.0.0/16
          - fd00:1:be:4::0/64
          customIPHeader: "X-Real-Ip"

Just note that the badger you define here is not the badger that is used in resources (this also caught me out recently), which is probably adding to the confusion as Pangolin defines badger@http not badger@file that gets the configuration from the config.yaml that pangolin defines and such it only have the trust integer.

<!-- gh-comment-id:4128806492 --> @LaurenceJJones commented on GitHub (Mar 25, 2026): As noted previously, Pangolin behind a reverse proxy is not a supported deployment method. For that reason, the issue being reported would not be classified as a defect in Pangolin, as the setup is outside the supported configuration. Relevant code reference: https://github.com/fosrl/badger/blob/67ad9b651eed00b74e65db5325cb3012a78ed50b/main.go#L403-L428 Looking at the current implementation, Badger’s realip handling is fairly limited and does not fully support the reverse lookup logic that would be needed here. The most practical workaround would be to define a custom header such as X-Real-Ip, which Cloudflare should already be setting. Otherwise, if you can avoid using a plugin that removes the CF-Connecting-Ip header, the existing fallback logic should allow it to work. ``` http: middlewares: badger: plugin: badger: disableForwardAuth: true disableDefaultCFIPs: true trustip: - 172.24.0.0/16 - fd00:1:be:4::0/64 customIPHeader: "X-Real-Ip" ``` **Just note that the badger you define here is not the badger that is used in resources** (this also caught me out recently), which is probably adding to the confusion as Pangolin defines `badger@http` not `badger@file` that gets the configuration from the `config.yaml` that pangolin defines and such it only have the trust integer.
Author
Owner

@LaurenceJJones commented on GitHub (Mar 25, 2026):

Editting looking back up, so on the traefik configuration you defined the trusted headers on both http and https entrypoints (even though your behind CF tunnel so https should basically be disabled)?

<!-- gh-comment-id:4128983618 --> @LaurenceJJones commented on GitHub (Mar 25, 2026): Editting looking back up, so on the traefik configuration you defined the trusted headers on both http and https entrypoints (even though your behind CF tunnel so https should basically be disabled)?
Author
Owner

@Christopher87R commented on GitHub (Mar 26, 2026):

Editting looking back up, so on the traefik configuration you defined the trusted headers on both http and https entrypoints (even though your behind CF tunnel so https should basically be disabled)?

Yep, I defined it or both, http and https. Shouldn't http be disabled basically?

How can I define the config for badger@http?

<!-- gh-comment-id:4135546989 --> @Christopher87R commented on GitHub (Mar 26, 2026): > Editting looking back up, so on the traefik configuration you defined the trusted headers on both http and https entrypoints (even though your behind CF tunnel so https should basically be disabled)? Yep, I defined it or both, http and https. Shouldn't http be disabled basically? How can I define the config for badger@http?
Author
Owner

@LaurenceJJones commented on GitHub (Mar 26, 2026):

How can I define the config for badger@http?

You cant and thats the issue because if you was doing typically cloudflare proxying (to public IP 80/433 port) we load the default cloudflare ranges and it works, but since its CF tunnel we have noway currently to define this for badger@http.

<!-- gh-comment-id:4135707385 --> @LaurenceJJones commented on GitHub (Mar 26, 2026): > How can I define the config for badger@http? You cant and thats the issue because if you was doing typically cloudflare proxying (to public IP 80/433 port) we load the default cloudflare ranges and it works, but since its CF tunnel we have noway currently to define this for `badger@http`.
Author
Owner

@github-actions[bot] commented on GitHub (Apr 10, 2026):

This issue has been automatically marked as stale due to 14 days of inactivity. It will be closed in 14 days if no further activity occurs.

<!-- gh-comment-id:4218926880 --> @github-actions[bot] commented on GitHub (Apr 10, 2026): This issue has been automatically marked as stale due to 14 days of inactivity. It will be closed in 14 days if no further activity occurs.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/pangolin#30027