Description
I've been trying to figure out my problem for about a month now. I'm not sure there's a solution or what the problem is.
I'm using Docker Desktop on Windows and Docker Desktop for Linux on Ubuntu.
I'm creating containers connected by a Bridge network and want to maintain isolation for all containers and for all ports except 80 and 443 for Nginx. Unfortunately, in the Nginx container logs, I see the requestor's IP as the Docker network gateway IP.
What I've already tried:
-
The ngx_http_realip_module module in Nginx itself:
Add the following lines to the Nginx configuration:
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.1.1; # My host's IP in the ISP's network
real_ip_header X-Forwarded-For;
real_ip_recursive on;
Result: The IP is the same. The X-Forwarded-For header contains 172.18.0.1 or 172.22.0.1.
-
The same, but with the proxy protocol:
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.1.1;
real_ip_header proxy_protocol;
real_ip_recursive on;
And setting in all configuration files:
listen 80 proxy_protocol;
listen [::]:80 proxy_protocol;
listen 443 ssl proxy_protocol;
listen [::]:443 ssl proxy_protocol;
Result is the same.
-
Disable userland-proxy
Tried both through the UI and through the configuration on both systems.
Result is the same.
Reproduce
- Use service Nginx in my docker-compose.yaml file for build network and container.
- Use any container like a service
- Provide traffic through Nginx container
- View Nginx logs or any container for make sure if IP is incorrect
Expected behavior
I can see IP from request header before docker bridge network.
docker version
Client:
Version: 29.5.3
API version: 1.54
Go version: go1.26.4
Git commit: d1c06ef
Built: Wed Jun 3 18:03:06 2026
OS/Arch: windows/amd64
Context: desktop-linux
Server: Docker Desktop 4.78.0 (229452)
Engine:
Version: 29.5.3
API version: 1.54 (minimum version 1.40)
Go version: go1.26.4
Git commit: 285b471
Built: Wed Jun 3 17:59:56 2026
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: v2.2.4
GitCommit: 193637f7ee8ae5f5aa5248f49e7baa3e6164966e
runc:
Version: 1.3.5
GitCommit: v1.3.5-0-g488fc13e
docker-init:
Version: 0.19.0
GitCommit: de40ad0
docker info
Client:
Version: 29.5.3
Context: desktop-linux
Debug Mode: false
Plugins:
agent: Docker AI Agent Runner (Docker Inc.)
Version: v1.73.0
Path: C:\Program Files\Docker\cli-plugins\docker-agent.exe
ai: Docker AI Agent - Ask Gordon (Docker Inc.)
Version: v1.25.0
Path: C:\Program Files\Docker\cli-plugins\docker-ai.exe
buildx: Docker Buildx (Docker Inc.)
Version: v0.34.1-desktop.1
Path: C:\Program Files\Docker\cli-plugins\docker-buildx.exe
compose: Docker Compose (Docker Inc.)
Version: v5.1.4
Path: C:\Program Files\Docker\cli-plugins\docker-compose.exe
debug: Get a shell into any image or container (Docker Inc.)
Version: 0.0.47
Path: C:\Program Files\Docker\cli-plugins\docker-debug.exe
desktop: Docker Desktop commands (Docker Inc.)
Version: v0.3.0
Path: C:\Program Files\Docker\cli-plugins\docker-desktop.exe
dhi: CLI for managing Docker Hardened Images (Docker Inc.)
Version: v0.0.4
Path: C:\Program Files\Docker\cli-plugins\docker-dhi.exe
extension: Manages Docker extensions (Docker Inc.)
Version: v0.2.31
Path: C:\Program Files\Docker\cli-plugins\docker-extension.exe
init: Creates Docker-related starter files for your project (Docker Inc.)
Version: v1.4.0
Path: C:\Program Files\Docker\cli-plugins\docker-init.exe
mcp: Docker MCP Plugin (Docker Inc.)
Version: v0.42.2
Path: C:\Program Files\Docker\cli-plugins\docker-mcp.exe
model: Docker Model Runner (Docker Inc.)
Version: v1.2.1
Path: C:\Program Files\Docker\cli-plugins\docker-model.exe
offload: Docker Offload (Docker Inc.)
Version: v0.6.3
Path: C:\Program Files\Docker\cli-plugins\docker-offload.exe
pass: Docker Pass Secrets Manager Plugin (beta) (Docker Inc.)
Version: v0.1.4
Path: C:\Program Files\Docker\cli-plugins\docker-pass.exe
sandbox: Docker Sandbox (Docker Inc.)
Version: v0.12.0
Path: C:\Program Files\Docker\cli-plugins\docker-sandbox.exe
scout: Docker Scout (Docker Inc.)
Version: v1.21.0
Path: C:\Program Files\Docker\cli-plugins\docker-scout.exe
Server:
Containers: 5
Running: 4
Paused: 0
Stopped: 1
Images: 5
Server Version: 29.5.3
Storage Driver: overlayfs
driver-type: io.containerd.snapshotter.v1
Logging Driver: json-file
Cgroup Driver: cgroupfs
Cgroup Version: 2
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
CDI spec directories:
/etc/cdi
/var/run/cdi
Discovered Devices:
cdi: docker.com/gpu=webgpu
Swarm: inactive
Runtimes: io.containerd.runc.v2 nvidia runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 193637f7ee8ae5f5aa5248f49e7baa3e6164966e
runc version: v1.3.5-0-g488fc13e
init version: de40ad0
Security Options:
seccomp
Profile: builtin
cgroupns
Kernel Version: 6.18.33.1-microsoft-standard-WSL2
Operating System: Docker Desktop
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 3.825GiB
Name: docker-desktop
ID: e6f2c2ec-5c2d-4a4f-abbc-c979824f34e4
Docker Root Dir: /var/lib/docker
Debug Mode: false
HTTP Proxy: http.docker.internal:3128
HTTPS Proxy: http.docker.internal:3128
No Proxy: hubproxy.docker.internal
Labels:
com.docker.desktop.address=npipe://\\.\pipe\docker_cli
Experimental: false
Insecure Registries:
hubproxy.docker.internal:5555
::1/128
127.0.0.0/8
Live Restore Enabled: false
Firewall Backend: iptables
Additional Info
Example logs (Windows):
172.18.0.1 - - [23/Jun/2026:18:10:59 +0000] "GET /hub/api/rest/users/me?fields=guest,endUserAgreementConsent(accepted,majorVersion,minorVersion) HTTP/2.0" 200 29 "https://youtrack.aycon.su/projects/TR/agiles/195-2/current" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36" "-"
172.18.0.1 - - [23/Jun/2026:18:10:59 +0000] "GET /hub/api/rest/settings/public?fields=endUserAgreement(enabled,text,majorVersion,minorVersion,requiredForREST) HTTP/2.0" 200 109 "https://youtrack.aycon.su/projects/TR/agiles/195-2/current" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36" "-"
172.18.0.1 - - [23/Jun/2026:18:15:00 +0000] "GET /SDK/webLanguage HTTP/1.1" 404 146 "-" "Mozilla/5.0" "-"
172.18.0.1 - - [23/Jun/2026:18:16:59 +0000] "GET / HTTP/1.1" 400 248 "-" "Mozilla/5.0" "-"
172.18.0.1 - - [23/Jun/2026:18:19:27 +0000] "GET / HTTP/1.1" 200 529 "-" "Go-http-client/1.1" "-"
172.18.0.1 - - [23/Jun/2026:18:21:28 +0000] "GET / HTTP/1.1" 200 529 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36 Edg/90.0.818.46" "-"
172.18.0.1 - - [23/Jun/2026:18:21:38 +0000] "GET /SDK/webLanguage HTTP/1.1" 404 178 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36 Edg/90.0.818.46" "-"
172.18.0.1 - - [23/Jun/2026:18:22:30 +0000] "GET / HTTP/1.1" 200,896 "-" "Mozilla/5.0" "-"
172.18.0.1 - - [23/Jun/2026:18:22:36 +0000] "GET /robots.txt HTTP/1.1" 200 306 "-" "Mozilla/5.0 (compatible; FreePBX-Scanner/1.0)" "-"
172.18.0.1 - - [23/Jun/2026:18:22:36 +0000] "GET /robots.txt HTTP/1.1" 400 248 "-" "Mozilla/5.0 (compatible; FreePBX-Scanner/1.0)" "-"
172.18.0.1 - - [23/Jun/2026:18:23:14 +0000] "GET /.git/index HTTP/1.1" 404 178 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36" "-"
Example logs (Ubuntu):
172.22.0.1 - - [21/Jun/2026:13:16:53 +0000] "GET /.env HTTP/1.1" 404 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36" "-"
172.22.0.1 - - [21/Jun/2026:13:16:53 +0000] "POST / HTTP/1.1" 405,552 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36" "-"
172.22.0.1 - - [21/Jun/2026:13:16:54 +0000] "GET /.env HTTP/1.1" 200 306 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36" "-"
172.22.0.1 - - [21/Jun/2026:13:16:54 +0000] "POST / HTTP/1.1" 405,552 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36" "-"
172.22.0.1 - - [21/Jun/2026:13:20:21 +0000] "GET /dispatch.asp HTTP/1.1" 404 178 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36 Edg/90.0.818.46" "-"
172.22.0.1 - - [21/Jun/2026:13:22:30 +0000] "GET /robots.txt HTTP/1.1" 200 306 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" "-"
172.22.0.1 - - [21/Jun/2026:13:22:33 +0000] "GET / HTTP/1.0" 200 896 "-" "-" "-"
172.22.0.1 - - [21/Jun/2026:13:23:41 +0000] "GET / HTTP/1.1" 200 896 "-" "curl/7.68.0" "-"
172.22.0.1 - - [21/Jun/2026:13:23:51 +0000] "GET / HTTP/1.1" 200 896 "-" "curl/7.68.0" "-"
172.22.0.1 - - [21/Jun/2026:13:26:12 +0000] "SSH-2.0-Go" 400 150 "-" "-" "-"
172.22.0.1 - - [21/Jun/2026:13:27:20 +0000] "GET /login HTTP/1.1" 404 146 "-" "Go-http-client/1.1" "-"
172.22.0.1 - - [21/Jun/2026:13:29:05 +0000] "GET / HTTP/1.1" 200 529 "-" "Hello from Palo Alto Networks, find out more about our scans in https://docs-cortex.paloaltonetworks.com/r/1/Cortex-Xpanse/Scanning-activity" "-"
172.22.0.1 - - [21/Jun/2026:13:30:37 +0000] "GET / HTTP/1.1" 200 529 "-" "visionheight.com/scan Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/126.0.0.0 Safari/537.36" "-"
My docker-compose.yaml file:
services:
auth_db:
build:
context: ./auth_db
dockerfile: Dockerfile
volumes:
- ./auth_db/data:/var/lib/postgresql/18/docker
env_file:
- ./auth_db/.env
shm_size: 128mb
restart: always
# expose:
# - "5432"
ports:
- "5432:5432"
networks:
- services_web
auth_service:
build:
context: ./auth_service
dockerfile: Dockerfile
container_name: auth_service
restart: always
expose:
- "8080"
depends_on:
- auth_db
networks:
- services_web
web_service:
build:
context: ./web_service
dockerfile: Dockerfile
container_name: web_service
volumes:
- ./web_service/dist:/app/dist
environment:
- WATCHPACK_POLLING=true
depends_on:
- auth_service
networks:
- services_web
youtrack:
image: jetbrains/youtrack:2026.1.13570
container_name: youtrack
restart: always
isolation: default
expose:
- "8080"
volumes:
- ./youtrack/data:/opt/youtrack/data
- ./youtrack/conf:/opt/youtrack/conf
- ./youtrack/logs:/opt/youtrack/logs
- ./youtrack/backups:/opt/youtrack/backups
networks:
- services_web
nginx:
image: nginx:latest
container_name: nginx_proxy
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/sites-enabled:/etc/nginx/sites-enabled:ro
- ./nginx/mime.types:/etc/nginx/mime.types:ro
- ./nginx/logs/access.log:/var/log/nginx/access.log
- ./nginx/logs/error.log:/var/log/nginx/error.log
- ./web_service/dist:/usr/share/nginx/static:ro
- ./certbot/certs/archive/$RS_DOMAIN/fullchain1.pem:/etc/nginx/ssl/fullchain.pem:ro
- ./certbot/certs/archive/$RS_DOMAIN/privkey1.pem:/etc/nginx/ssl/privkey.pem:ro
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
# environment:
# - NGINX_ENTRYPOINT_QUIET_LOGS=1
depends_on:
- youtrack
- web_service
- auth_service
networks:
- services_web
networks:
services_web:
driver: bridge
My /etc/nginx/conf.d/default.conf file:
server {
listen 80 proxy_protocol;
listen [::]:80 proxy_protocol;
server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
My /etc/nginx/nginx.conf file:
# User & group that will be used by worker processes.
# For security use a user & group with limited privileges.
user www-data www-data;
# The file that will store a processes id of the main process.
pid /run/nginx.pid;
# Number of worker processes. The optimial value depends on many things:
# number of CPU cores, number of storage drives, etc. Setting it to a total
# number of CPU cores is good starting point, or just leave it to `auto`.
# Max number of connections = worker_processes * worker_connections
worker_processes auto;
# Max number of open files (RLIMIT_NOFILE) for worker processes.
# Should be > worker_connections.
worker_rlimit_nofile 8192;
error_log /var/log/nginx/error.log error;
events {
# Max number of simultaneous connections that can be opened by the worker
# processes. The simultaneous connections cannot exceed the maximum
# number of open files, thus: worker_connections < worker_rlimit_nofile.
worker_connections 8000;
}
http {
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.1.1;
# real_ip_header X-Forwarded-For;
real_ip_header proxy_protocol;
real_ip_recursive on;
# Enable or disable emitting nginx version on response's header.
server_tokens off;
# Max size & bucket size for the server names hash table.
server_names_hash_max_size 1024;
server_names_hash_bucket_size 32;
# Max size & bucket size for the mime types hash table.
types_hash_max_size 2048;
types_hash_bucket_size 32;
# Speed up static file transfers by using the sendfile() rather than the
# read() and write() combination. sendfile() has the ability to transfer
# data from the file descriptor.
sendfile on;
# Optimize the amount of data that is being sent at once. Prevent Nginx
# from sending a partial frame. As a result it will increases the
# throughput, since TCP frames will be filled up before being sent out.
# You also need to activate the `sendfile` option.
tcp_nopush on;
# By default, the TCP stack implements a mechanism to delay sending the
# data up to 200ms. To force a socket to send the data in its buffer
# immediately we can turn this option on.
tcp_nodelay on;
# A timeout of which a keep-alive connection will stay open. Longer
# duration are better for client, especially on SSL, the downside is the
# worker connection is occupied longer.
keepalive_timeout 20s;
# Mime types.
include mime.types;
default_type application/octet-stream;
# Update the charset to match the updated mime.types.
# By efault the `text/html` is always included by the charset module.
charset_types
text/css
text/plain
text/vnd.wap.wml
application/javascript
application/json
application/rss+xml
application/xml;
# Request log format.
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
# Enable gzip compression.
gzip on;
# Gzip compression level (1-9).
# 5 is a perfect compromise between size and CPU usage, offering about
# 75% reduction for most ASCII files (almost identical to level 9).
gzip_comp_level 5;
# Don't compress a small file that is unlikely to shrink much. The small
# file is also usually ended up in larger file sizes after gzipping.
gzip_min_length 256;
# Compress data even for a proxied connection.
gzip_proxied any;
# Cache both the regular and the gzipped versions of a resource whenever
# client's Accept-Encoding capabilities header varies.
gzip_vary on;
# Compress all of the following mime-types, `text/html` is always
# compressed.
gzip_types
application/atom+xml
application/javascript
application/json
application/ld+json
application/manifest+json
application/rss+xml
application/vnd.geo+json
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/opentype
image/bmp
image/svg+xml
image/x-icon
text/cache-manifest
text/css
text/plain
text/vcard
text/vnd.rim.location.xloc
text/vtt
text/x-component
text/x-cross-domain-policy;
# Include other custom configurations.
include conf.d/*.conf;
# Include site configurations.
include sites-enabled/*;
}
My /etc/nginx/sites-enabled/youtrack.aycon.su.conf file:
server {
listen 80 proxy_protocol;
listen [::]:80 proxy_protocol;
# The www and non-www host server name.
server_name youtrack.aycon.su;
# Redirect to the non-www HTTPS version.
return 301 https://youtrack.aycon.su$request_uri;
}
server {
http2 on;
listen 443 ssl proxy_protocol;
listen [::]:443 ssl proxy_protocol;
server_name youtrack.aycon.su;
client_max_body_size 200m;
ssl_certificate ssl/fullchain.pem;
ssl_certificate_key ssl/privkey.pem;
location / {
proxy_pass http://youtrack:8080;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_buffering off;
}
}
My /etc/nginx/sites-enabled/tail-resone.aycon.su.conf file:
server {
listen 80 proxy_protocol;
listen [::]:80 proxy_protocol;
server_name tail-resone.aycon.su;
return 301 https://tail-resone.aycon.su$request_uri;
}
server {
http2 on;
listen 443 ssl proxy_protocol;
listen [::]:443 ssl proxy_protocol;
server_name tail-resone.aycon.su;
ssl_certificate ssl/fullchain.pem;
ssl_certificate_key ssl/privkey.pem;
root /usr/share/nginx/static/;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /auth/ {
proxy_pass http://auth_service:8080/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_buffering off;
}
}
Description
I've been trying to figure out my problem for about a month now. I'm not sure there's a solution or what the problem is.
I'm using Docker Desktop on Windows and Docker Desktop for Linux on Ubuntu.
I'm creating containers connected by a Bridge network and want to maintain isolation for all containers and for all ports except 80 and 443 for Nginx. Unfortunately, in the Nginx container logs, I see the requestor's IP as the Docker network gateway IP.
What I've already tried:
The ngx_http_realip_module module in Nginx itself:
Add the following lines to the Nginx configuration:
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.1.1; # My host's IP in the ISP's network
real_ip_header X-Forwarded-For;
real_ip_recursive on;
Result: The IP is the same. The X-Forwarded-For header contains 172.18.0.1 or 172.22.0.1.
The same, but with the proxy protocol:
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.1.1;
real_ip_header proxy_protocol;
real_ip_recursive on;
And setting in all configuration files:
listen 80 proxy_protocol;
listen [::]:80 proxy_protocol;
listen 443 ssl proxy_protocol;
listen [::]:443 ssl proxy_protocol;
Result is the same.
Disable userland-proxy
Tried both through the UI and through the configuration on both systems.
Result is the same.
Reproduce
Expected behavior
I can see IP from request header before docker bridge network.
docker version
Client: Version: 29.5.3 API version: 1.54 Go version: go1.26.4 Git commit: d1c06ef Built: Wed Jun 3 18:03:06 2026 OS/Arch: windows/amd64 Context: desktop-linux Server: Docker Desktop 4.78.0 (229452) Engine: Version: 29.5.3 API version: 1.54 (minimum version 1.40) Go version: go1.26.4 Git commit: 285b471 Built: Wed Jun 3 17:59:56 2026 OS/Arch: linux/amd64 Experimental: false containerd: Version: v2.2.4 GitCommit: 193637f7ee8ae5f5aa5248f49e7baa3e6164966e runc: Version: 1.3.5 GitCommit: v1.3.5-0-g488fc13e docker-init: Version: 0.19.0 GitCommit: de40ad0docker info
Additional Info
Example logs (Windows):
Example logs (Ubuntu):
My docker-compose.yaml file:
My /etc/nginx/conf.d/default.conf file:
My /etc/nginx/nginx.conf file:
My /etc/nginx/sites-enabled/youtrack.aycon.su.conf file:
My /etc/nginx/sites-enabled/tail-resone.aycon.su.conf file: