Get client IP addresses in PHP container behind Traefik

Hi, I’m trying to get the visitor’s IP addresses in my PHP webapp (and its logs). This is my setup:

  • Virtual Private Server running Debian 12, hosted in a data center, reachable via SSH
  • Docker 28.0.4 installed and running smoothly
  • Traefik:latest (v3) container is bound to ports 80 and 443 of the host
  • Several containers with PHP webapps, all on individual (sub-)domains, secured through Let’s Encrypt certificates
  • All services are reachable and work as expected. Some have their private database container.
  • I use docker compose to manage my collection of containers

In the logs of all containers, I see Docker’s gateway IP-address (172.x.x.x) as source of a request. The X-Forwarded-For and X-Real-IP HTTP-headers are present, but contain 172.x.x.x, too. It is only in Traefik’s logs that I occasionally see a public IP-address.

Question 1: How can I debug where the public IP gets dropped, and the gateway’s address pops in its place?

Question 2: What is the simplest docker-compose setup for my situation?

I have seen so many forum- and blog posts about this issue, I don’t know what to do next.

Thanks for your help,
FWieP

Lets assume the Traefik container uses network_mode: host to have raw access to the host’s network interfaces, then Treafik is able to see the source ip of coming requests. A major drawback is that a container using network_mode can not be part of any container network. This is suboptimal for a reverse proxy container.

Though, if you would initiate the swarm mode on your host, and deploy your compose file as swarm stack, you could leverage mode: host in the long syntax in the port mapping section of the service to retain the source ip without needing network_mode: host (which wouldn’t work with swarm anyway).

Thanks for this quick reply. Would you care to elaborate on the swarm mode?

This is a simplified example of my setup (Traefik and a whoami-container). The network named proxy, I created by issuing docker network create proxy. At the moment, it’s a bridge-network that connects all the webapp-containers and Traefik.

services:
  traefik:
    image: traefik:latest
    restart: unless-stopped
    command:
      - --api=true
      - --api.insecure=true
      - --accesslog=true
      - --certificatesresolvers.myresolver.acme.email=example@example.com
      - --certificatesresolvers.myresolver.acme.storage=/acme.json
      - --certificatesresolvers.myresolver.acme.tlschallenge=true
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entrypoint.permanent=true
      - --entrypoints.web.http.redirections.entrypoint.scheme=https
      - --entrypoints.web.http.redirections.entrypoint.to=websecure
      - --entrypoints.websecure.address=:443
      - --entrypoints.websecure.http.tls=true
      - --entrypoints.websecure.http.tls.certresolver=myresolver
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
    ports:    
      - "80:80"
      - "443:443"
    networks:
      - proxy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - "./acme.json:/acme.json:rw"
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro

  whoami:
    image: traefik/whoami:latest
    restart: unless-stopped
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.mywhoami.rule=Host(`example.com`) && PathPrefix(`/whoami`)"
      - "traefik.http.routers.mywhoami.tls.certresolver=myresolver"
      - "traefik.http.services.mywhoami.loadbalancer.server.port=80"
    networks:
      - proxy
  
networks:
  proxy:
    external: true

How could I enable swarm mode in this example?

Thanks,
FWieP

Quick start:
Activate swarm mode on your docker host: docker swarm init
Deploy your compose file as swarm stack: docker stack deploy --compose-file compose.yaml stackdemo

For everything else I have point you to the docs: Swarm mode | Docker Docs.

The swarm mode is enabled for the Docker Engine, not for a compose file. You will need to change the ports part to the long syntax,as I shared in my previous post.

You might also need to add deploy: to your service definition, like described here: https://docs.docker.com/reference/compose-file/deploy/

update: I thought I shared a link to the long syntax for port mappings. Seems I forget. Here it is https://docs.docker.com/reference/compose-file/services/#long-syntax-3

Thanks again. I will dive into the docs and do my best.

Kind regards,
FWieP

1 Like