-
Notifications
You must be signed in to change notification settings - Fork 18.7k
Document how to get real remote client ip for service running in container #15086
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hi! Please read this important information about creating issues. If you are reporting a new issue, make sure that we do not have any duplicates already open. You can ensure this by searching the issue list for this repository. If there is a duplicate, please close your issue and add a comment to the existing issue instead. If you suspect your issue is a bug, please edit your issue description to include the BUG REPORT INFORMATION shown below. If you fail to provide this information within 7 days, we cannot debug your issue and will close it. We will, however, reopen it if you later provide the information. This is an automated, informational response. Thank you. For more information about reporting issues, see https://github.com/docker/docker/blob/master/CONTRIBUTING.md#reporting-other-issues BUG REPORT INFORMATIONUse the commands below to provide key information from your environment:
Provide additional environment details (AWS, VirtualBox, physical, etc.): List the steps to reproduce the issue: Describe the results you received: Describe the results you expected: Provide additional info you think is important: ----------END REPORT --------- #ENEEDMOREINFO |
Description of problem: I have an hard time figuring out how to get the real remote ip of a client connecting to a (web) service inside a container which port is exposed to a port on the host. So far the solution seems to be either one of:
Here are related issues: #7540 None of the current solutions seems to be "right" and they all seem temporary. Can you clarify/explain how things should be, even if that means that the current docker 1.7.1 is bugged in that regard and that we have to use hack X or Y until things are fixed in 1.8.0.
Client version: 1.7.1
Client API version: 1.19
Go version (client): go1.4.2
Git commit (client): 786b29d
OS/Arch (client): linux/amd64
Server version: 1.7.1
Server API version: 1.19
Go version (server): go1.4.2
Git commit (server): 786b29d
OS/Arch (server): linux/amd64
Containers: 1
Images: 508
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Backing Filesystem: extfs
Dirs: 510
Dirperm1 Supported: false
Execution Driver: native-0.2
Logging Driver: json-file
Kernel Version: 3.13.0-58-generic
Operating System: Ubuntu 14.04.2 LTS
CPUs: 4
Total Memory: 15.64 GiB
Name: philippe-desktop
ID: QLBB:VYAR:TKYL:NZQN:MGON:SNU4:7BLV:XFEJ:AIGR:LZY6:LCIF:GHBU
Linux philippe-desktop 3.13.0-58-generic #97-Ubuntu SMP Wed Jul 8 02:56:15 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux Environment details (AWS, VirtualBox, physical, etc.): Physical How reproducible: Easily. Steps to Reproduce:
Actual Results: We get docker0 bridge ip. Expected Results: We get the remote client ip. Additional info: Creating issues in this format is a PITA and goes against github flow. |
This is the correct answer, and is soon to become the default action (see #14856) Edit: If this solution seems unsatisfactory, can you explain your thoughts on the matter? |
Alright, thanks! |
the problem is that if you use |
Ok, what's the latest recommended solution if
|
Also, can we re-open this issue if #14856 was reverted? Or has it been documented somewhere? |
+1 for reopen, as "no userland proxy" is not viable at the moment. |
+1 to reopen from me. Looking for the real IP address to set SSL via a reverse proxy |
+1 this issue is really scary. |
+1 we need more documentation on this subject and workable solution. |
+1 |
+1 |
+1 need to know which IP source connect to my app, and fail2ban if needed |
Since we already have so many +1s, let's have another. And a minimal setup I used to test this & exhibit the problem: http://serverfault.com/questions/813298/ |
Another +1 here. Need to have true client IP address for logging and security purposes. Re-open with some documentation please :) |
+1 here. Really need to get true client IP address. |
1 similar comment
+1 here. Really need to get true client IP address. |
+1 here.
|
Failed using the geoip module.... |
+1 The NAT should only be used on outbound traffic and not on inbound traffic |
+1 here |
+1 here. Need the real IP address for access statistics, logging and security purposes. |
+1 This is a real problem. We need the real IP for our firewall |
+1. Please reopen the issue. |
+1 IMO this should be flagged as critical and fixed ASAP |
You may read through all the 100+ comments in here to find out why this happens, but...
If you do manage to establish a correctly working HTTP reverse-proxy behaviour from your exposed container's HTTP server to the upstream containers running your other services, you'll notice the value of $remote_addr on every request logged on your http server logs will be the default gateway of the virtual interface (so 127.X.0.1... etc) for all incoming requests. , as opposed to the "correct" (quotations used for anyone unfamiliar with IP spoofing and proper XFF chain validations) value of the client's IP, and depending on the request, you'll see no value in the X-Forwarded-For header. You want to keep both the bridged network container capabilities while being able to report the "real" $remote_addr of the request, the only gimmik that does this on a deployment on windows hosts is to use another non containarized reverse proxy to front for your exposed container and attach an XFF header with the reported remote_addr value of the client at the time the request was made, this is easy to do and I recommend it, you get to keep your compose / swarm deployment because even if the iptables docker daemon sets up spoof the value of the $remote_addr you'll still have this value on the XFF header chain, you'll simply be losing the value of your new reverse-proxy's $remote_addr, which you know anyway and can pass along the upstream with simple configuration. The other option involves dabbling with the host's running exposed containers iptables, I wouldn't attempt this on windows if my life depended on it, the user Struanb posted a shellscript for it and there's more comments that might help you should you want to enjoy doing that yourself. This issue being up for 7 years and still causing problems tells me that anyone who came across this should start looking into Kubernettes as a container orcheastration tool instead. |
For some reason this also doesn't work for me. Rebooting the host doesn't change that. (Running ubuntu 20.04) |
It will be a decade soon :P |
I'm still having this same issue... |
Turns out the problem was I was using docker rootless mode. You can either use normal docker or you can use rootless and install the slirpn4netns package and change the port forwarder, following these steps (the section about changing the port forwarder): https://rootlesscontaine.rs/getting-started/docker/#changing-the-port-forwarder |
InsightsThe below is focused on Linux host, so may not be as helpful to Windows / macOS users (although I've read the desktop apps are meant to handle networking better these days and Local connections:
Remote connections:
Is there anything else missing? What kind of remote IP sources are problematic to everyone here? I have documented config + test detailing a common remote client IP container scenario with Caddy (reverse-proxy / web server like nginx). If you experience this issue, perhaps you can try follow that as a reproduction? Gateway IP via local client connectionHere is a reference for
You will find the only difference for the remote IP presently (Docker v23, linux) via this setting depends on if you're accessing a container from the host indirectly, or via another container through the host IP:
Gateway IP from an external client connectionWhen the host receives an actual remote client from another system via an external interface IP (that containers have published ports to be reachable). This should retain the remote client IP across that bridged connection using NAT:
Thread summary / highlights
Many other comments only contribute additional information regarding Provide more info with your
|
Great. You save my life. |
This thread once again just point out THE STILL EXISITING NEED for a good working and EASY to implemet solution. I guess it's hard for the NGINX devs to do it.. otherwise I won't understand, why a search shows so many threads accross several boards withing 7+ (?) years. Personally I prefer to have ONE instance of NGINX to mange all incoming http/s directly OR to proxy them to my dockerized services. My services are spread across different docker-networks. No chance to set my dockerized NGINX to host-mode. But without real-IP I face serveral security issues. fail2ban does not work and, and, and ...... (sorry for contributing nothing else than my frustration.) |
At least contribute a minimal example that can help express the issue you're facing, along with version of Docker. From Docker v27 onwards IPv6 is no longer experimental opt-in, it should be available by default IIRC, thus the concern of inbound clients to the host via IPv6 shouldn't be an issue anymore? What other situation are you still having trouble with? Sharing this information when you add a comment would be helpful:
It works in Docker, I've explained how. I've demonstrated it plenty of times on issues. But users don't seem to want to read? Provide the information requested above, I can probably explain why it's not working for you. |
Happy new year 2025 everybody! It was decade now, with the support of Claude Sonnet and GPT-4o I still unable to do this on WSL2 on Windows, does anyone have success solution on WSL2? I'm using double Caddy server to maintain IP outside docker but still failed. Does kubernetes or anything else can preserve IP on WSL2? I'm willing to learn it this new year |
@hiepxanh you don't say which networking mode you are using for wsl2, and depending on that, and whether you are using a browser running in wsl2 or windows, it may or may not be possible to do this. Generally, it is better to develop software that doesn't rely on specific ip addresses these days, especially for development. |
You are correct. double proxy server can help workaround missing source IP. I used to using Asus router hosting a website and I need client source IP for analytic tracking and prevent spam. So it have no option to preserve source IP. Three months to debugging and find out this solution After that setup the host caddy proxy at port 80 then proxy X-real-clientIP to your docker caddy at port 8080 for example and the inside caddy can use it WORKING SOLUTION: using DOUBLE Caddy at host machine to preserve X-forward-forto maintain X-Forward-For having Source IP 0) ROUTER CONFIG: openWRT proxy 80 and proxy 443 to 192.168.1.95 at port 80 with external address1) HOST SERVER CONFIG: download Caddy then add caddy at statup program:
2) CADDY DOCKER CONFIG: Caddy at docker require trusted_proxies labelservices:
caddy:
image: lucaslorentz/caddy-docker-proxy:ci-alpine
restart: always
labels:
caddy.servers.trusted_proxies: static private_ranges
ports:
- "8080:80"
- "8019:2019"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/hiepxanh/data/caddy:/data
whoami:
image: traefik/whoami
restart: always
ports:
- "8888:80"
labels:
caddy_1: http://whoami.docker.localhost
caddy_1.reverse_proxy: "{{ upstreams 80}}" |
I faced the same issue while configuring IP filtering for some APIs protected by nginx. In my case everything was fine till the moment Docker Desktop started to facing an issue, reported on their website, that some users may encounter a problem with a popup saying there is a malware and etc. I reinstalled Docker Desktop and after that I decided to test my application on Summary:
|
@Stashevich when you run in Mac or Windows you're actually running in a VM. The best is still to use Linux with services:
edge:
environment:
OTEL_SERVICE_NAME: edge
image: mirror.gcr.io/library/caddy
configs:
- source: Caddyfile
target: /etc/caddy/Caddyfile
volumes:
- caddy_data:/data
- caddy_config:/config
ports:
- target: 80
published: 80
protocol: tcp
# mode: host do not enable for port 80, because only one port can be made mode: host
- target: 443
published: 443
protocol: tcp
mode: host
cap_add:
- NET_BIND_SERVICE
healthcheck:
test: nc -zv 127.0.0.1 443
# networks:
# default:
# ipv4_address: 172.21.0.8
deploy:
mode: global
resources:
reservations:
cpus: "1.0"
memory: 256M
limits:
cpus: "1.0"
memory: 256M |
@trajano Thanks for the advise. |
Why would you do that with the given limitation vs Disable the You'll have a similar issue with external proxies, like Cloudflare sitting between the connecting client and your service. Again a reverse proxy like Caddy can be configured to handle that and preserve the correct information that Cloudflare forwards with the connection. |
Depends on what the person needs, in my case port 80 simply redirects to 443 for my application purposes so there's no point for me to track those hits. It's also the simplest to work with on Docker and works with swarm. |
Hello,
I have an hard time figuring out how to get the real remote ip of a client connecting to a (web) service inside a container which port is exposed to a port on the host.
So far the solution seems to be either one of:
--net=host
Here are related issues:
#7540
nginx-proxy/nginx-proxy#130
nginx-proxy/nginx-proxy#133
None of the current solutions seems to be "right" and they all seem temporary. Can you clarify/explain how things should be, even if that means that the current docker 1.7.1 is bugged in that regard and that we have to use hack X or Y until things are fixed in 1.8.0.
The text was updated successfully, but these errors were encountered: