Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

osama_abdullah's avatar

not receiving real IP of the client from Nginx in docker swarm mode

When I used nginx in docker swarm mode I always got the IP of the nginx container instead of the real public IP of the user.

my stack:

version: '3.9'

services:
  nginx_proxy:
    image: 'nginx'
    ports:
      - '80:80'
      - '443:443'

after some searches on the internet if found a solution but it causes another problem the solution is to change the ports to:

version: '3.9'

services:
  nginx_proxy:
    image: 'nginx'
    ports:
      - mode: host
        protocol: tcp
        published: 443
        target: 443
      - mode: host
        protocol: tcp
        published: 80
        target: 80

After this change the nginx will get the real public IP but only one replica will work you can not run more than one even if you are specifying in your stack on one will work and it will show:

ID             NAME                  MODE         REPLICAS   IMAGE         
ga5w8633lm8q   nginx-proxy_nginx     replicated   1/5        nginx:latest
0 likes
1 reply
LaryAI's avatar
Level 58

The issue is that the default behavior of Docker Swarm is to use an overlay network, which hides the client's IP address. To get the real IP address of the client, you need to use the mode: host option in the ports section of the docker-compose.yml file. However, this causes the issue of only one replica working. To solve this, you can use a reverse proxy like Traefik or HAProxy to distribute the traffic to multiple replicas. Here's an example docker-compose.yml file using Traefik:

version: '3.9'

services:
  nginx:
    image: nginx
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.nginx.rule=Host(`example.com`)"
      - "traefik.http.services.nginx.loadbalancer.server.port=80"
    networks:
      - traefik

networks:
  traefik:
    external: true

This configuration sets up a single Nginx service with Traefik as the reverse proxy. The traefik.enable=true label tells Traefik to use this service. The traefik.http.routers.nginx.rule=Host('example.com') label tells Traefik to route traffic for example.com to this service. The traefik.http.services.nginx.loadbalancer.server.port=80 label tells Traefik to use port 80 for load balancing. Finally, the networks section sets up the traefik network as an external network, which allows Traefik to access the Nginx service.

Please or to participate in this conversation.