Hi there,
I'm trying to get X-Forwarded-For to include the real IP address of the client, when using IPv4 and IPv6.
Currently it works for IPv4, but on IPv6 requests, it shows the docker bridge interface.
Currently whoami service says (snip means I censored it):
Hostname: 5af160072009
IP: 127.0.0.1
IP: 172.19.0.3
RemoteAddr: 172.19.0.2:33494
GET / HTTP/1.1
Host: whoami.<snip>.fi
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36 Edg/88.0.705.63
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,fi;q=0.8
Dnt: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
X-Forwarded-For: 172.17.0.1
X-Forwarded-Host: whoami.<snip>.fi
X-Forwarded-Port: 443
X-Forwarded-Proto: https
X-Forwarded-Server: 2bac83b05f97
X-Real-Ip: 172.17.0.1
Docker Compose for Traefik:
version: "3.7"
services:
## Traefik - Reverse Proxy
traefik:
container_name: traefik
image: traefik:latest # the picodon tag refers to v2.3.x
restart: always
command: # CLI arguments
- --global.checkNewVersion=true
- --global.sendAnonymousUsage=false
- --entryPoints.http.address=:80
# - --entrypoints.http.http.redirections.entryPoint.to=https # entrypoints.<your_entrypoint_name>.http.redirections...
- --entryPoints.https.address=:443
- --entryPoints.https.forwardedHeaders.trustedIPs=::/0,0.0.0.0/0
- --entryPoints.https.proxyProtocol.trustedIPs=::/0,0.0.0.0/0
- --entrypoints.https.http.tls.certresolver=dns-cloudflare
- --entrypoints.https.http.tls.domains[0].main=$DOMAINNAME
- --entrypoints.https.http.tls.domains[0].sans=*.$DOMAINNAME
- --entrypoints.https.http.tls.domains[1].main=$DOMAIN
- --entrypoints.https.http.tls.domains[1].sans=*.$DOMAIN
- --entrypoints.https.http.tls.domains[1].main=$DOMAINDEV
- --entrypoints.https.http.tls.domains[2].sans=*.$DOMAINDEV
- --entryPoints.traefik.address=:8080
- --api=true
- --api.insecure=true
- --api.dashboard=true
# - --serversTransport.insecureSkipVerify=true
- --log=true
- --log.level=DEBUG # (Default: error) DEBUG, INFO, WARN, ERROR, FATAL, PANIC
- --accessLog=true
- --accessLog.filePath=/traefik.log
- --accessLog.bufferingSize=100 # Configuring a buffer of 100 lines
- --accessLog.filters.statusCodes=400-499
- --providers.docker=true
- --providers.docker.exposedByDefault=false
- --providers.docker.network=traefik_proxy
- --providers.docker.swarmMode=false
- --providers.file.directory=/rules # Load dynamic configuration from one or more .toml or .yml files in a directory.
- --providers.file.watch=true # Only works on top level files in the rules folder
# - --certificatesResolvers.dns-cloudflare.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory # LetsEncrypt Staging Server - uncomment when testing
- --certificatesResolvers.dns-cloudflare.acme.email=$CLOUDFLARE_EMAIL
- --certificatesResolvers.dns-cloudflare.acme.storage=/acme.json
- --certificatesResolvers.dns-cloudflare.acme.dnsChallenge.provider=cloudflare
- --certificatesresolvers.dns-cloudflare.acme.dnschallenge.resolvers=$DNS_RESOLVER # pihole IP
networks:
traefik_proxy:
docker_socket:
ports:
- target: 80
published: 80
protocol: tcp
mode: host
- target: 8080
published: 8080
protocol: tcp
mode: host
- target: 443
published: 443
protocol: tcp
mode: host
security_opt:
- no-new-privileges:true # https://docs.docker.com/engine/reference/run/#security-configuration
volumes:
- $TRAEFIK2DIR/traefik/rules:/rules # file provider directory
- /var/run/docker.sock:/var/run/docker.sock:ro
- $TRAEFIK2DIR/traefik/acme/acme.json:/acme.json
environment:
- CF_API_EMAIL=$CLOUDFLARE_EMAIL
- CF_API_KEY=$CLOUDFLARE_API_KEY
secrets:
- "cf-api-email"
- "cf-api-key"
labels:
- "traefik.enable=true"
# HTTP Routers
- "traefik.http.routers.traefik-rtr.entrypoints=https"
- "traefik.http.routers.traefik-rtr.rule=Host(`traefik.$DOMAINNAME`)"
- "traefik.http.routers.traefik-rtr.priority=10"
## Middlewares
- "traefik.http.routers.traefik-rtr.middlewares=traefik-headers,rate-limit@file,authelia@docker"
- "traefik.http.middlewares.traefik-headers.headers.accesscontrolallowmethods=GET, OPTIONS, PUT"
- "traefik.http.middlewares.traefik-headers.headers.accesscontrolalloworiginlist=https://$DOMAINNAME"
- "traefik.http.middlewares.traefik-headers.headers.accesscontrolmaxage=100"
- "traefik.http.middlewares.traefik-headers.headers.addvaryheader=true"
- "traefik.http.middlewares.traefik-headers.headers.allowedhosts=traefik.$DOMAINNAME"
- "traefik.http.middlewares.traefik-headers.headers.hostsproxyheaders=X-Forwarded-Host"
- "traefik.http.middlewares.traefik-headers.headers.sslredirect=true"
- "traefik.http.middlewares.traefik-headers.headers.sslhost=traefik.$DOMAINNAME"
- "traefik.http.middlewares.traefik-headers.headers.sslforcehost=true"
- "traefik.http.middlewares.traefik-headers.headers.sslproxyheaders.X-Forwarded-Proto=https"
- "traefik.http.middlewares.traefik-headers.headers.stsseconds=63072000"
- "traefik.http.middlewares.traefik-headers.headers.stsincludesubdomains=true"
- "traefik.http.middlewares.traefik-headers.headers.stspreload=true"
- "traefik.http.middlewares.traefik-headers.headers.forcestsheader=true"
- "traefik.http.middlewares.traefik-headers.headers.framedeny=true"
# - "traefik.http.middlewares.traefik-headers.headers.customframeoptionsvalue=SAMEORIGIN" # This option overrides FrameDeny
- "traefik.http.middlewares.traefik-headers.headers.contenttypenosniff=true"
- "traefik.http.middlewares.traefik-headers.headers.browserxssfilter=true"
# - "traefik.http.middlewares.traefik-headers.headers.contentsecuritypolicy=frame-ancestors 'none'; object-src 'none'; base-uri 'none';"
- "traefik.http.middlewares.traefik-headers.headers.referrerpolicy=same-origin"
- "traefik.http.middlewares.traefik-headers.headers.featurepolicy=camera 'none'; geolocation 'none'; microphone 'none'; payment 'none'; usb 'none'; vr 'none';"
- "traefik.http.middlewares.traefik-headers.headers.customresponseheaders.X-Robots-Tag=none,noarchive,nosnippet,notranslate,noimageindex,"
## Services - API
- "traefik.http.routers.traefik-rtr.service=api@internal"
## API Forward Auth Bypass # Used for willfantom/SUI - automatic traefik dashboard
- "traefik.http.routers.traefik-bypass.entrypoints=https"
- "traefik.http.routers.traefik-bypass.rule=Host(`traefik.$DOMAINNAME`)"
- "traefik.http.routers.traefik-bypass.middlewares=traefik-headers,traefik-basicauth,rate-limit@file"
- "traefik.http.middlewares.traefik-basicauth.basicauth.users=$MY_USERNAME:$TRAEFIK_PASSWORD"
- "traefik.http.routers.traefik-bypass.priority=20"
- "traefik.http.routers.traefik-bypass.service=api@internal"
whoami service:
whoami:
container_name: whoami
image: containous/whoami:v1.3.0
restart: always
networks:
- traefik_proxy
security_opt:
- no-new-privileges:true
labels:
- "traefik.enable=true"
# HTTP Routers
- "traefik.http.routers.whoami-rtr.entrypoints=https"
- "traefik.http.routers.whoami-rtr.rule=Host(`whoami.$DOMAINNAME`)"
## Middlewares
- "traefik.http.routers.whoami-rtr.middlewares=chain-authelia@file"
## HTTP Services
- "traefik.http.routers.whoami-rtr.service=whoami-svc"
- "traefik.http.services.whoami-svc.loadbalancer.server.port=80"
chain-authelia:
[http.middlewares]
[http.middlewares.chain-authelia.chain]
middlewares = ["secure-headers","cloudflare-ipwhitelist", "authelia@docker"]
cloudflare-ipwhitelist:
[http.middlewares]
[http.middlewares.cloudflare-ipwhitelist.ipWhiteList]
sourceRange = [
"172.0.0.0/8",
"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/12",
"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"
]
#[http.middlewares.test-ipwhitelist.ipWhiteList.ipStrategy]
# depth = 2
secure-headers
[http.middlewares]
[http.middlewares.secure-headers.headers]
accessControlAllowMethods= ["GET", "OPTIONS", "PUT"]
accessControlMaxAge = 100
hostsProxyHeaders = ["X-Forwarded-Host", "Cf-Connecting-Ip"]
sslRedirect = true
stsSeconds = 63072000
stsIncludeSubdomains = true
stsPreload = true
forceSTSHeader = true
contentTypeNosniff = true
browserXssFilter = true
referrerPolicy = "same-origin"
featurePolicy = "camera 'none'; geolocation 'none'; microphone 'none'; payment 'none'; usb 'none'; vr 'none';"
[http.middlewares.secure-headers.headers.customResponseHeaders]
X-Robots-Tag = "none,noarchive,nosnippet,notranslate,noimageindex,"