Skip to content
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

[FEAT] See client IP when used with reverse proxy #32

Closed
1 task done
lyra56k opened this issue Feb 14, 2024 · 25 comments
Closed
1 task done

[FEAT] See client IP when used with reverse proxy #32

lyra56k opened this issue Feb 14, 2024 · 25 comments
Labels
enhancement New feature or request

Comments

@lyra56k
Copy link

lyra56k commented Feb 14, 2024

Is this a new feature request?

  • I have searched the existing issues

Wanted change

I wish for support of X-Forwarded-For header from a reverse proxy.

Reason for change

I use Apache as a proxy for all my various containers and other services, and when loading the speedtest page through the proxy, the IP is listed as “(null)”.

Proposed code change

I don’t really have a change in mind, I’m not entirely sure how IP checks work, but some way to set the IP to the value of X-Forwarded-For if an IP doesn’t already exist.

@lyra56k lyra56k added the enhancement New feature or request label Feb 14, 2024
Copy link

Thanks for opening your first issue here! Be sure to follow the relevant issue templates, or risk having this issue marked as invalid.

@LinuxServer-CI
Copy link
Contributor

This issue has been automatically marked as stale because it has not had recent activity. This might be due to missing feedback from OP. It will be closed if no further activity occurs. Thank you for your contributions.

@aptalca
Copy link
Member

aptalca commented Mar 28, 2024

Nginx does support it, however, the nginx in this container does not trust a proxy unless it is told to do so. By default, nginx should display the source ip it directly sees, which should be your apache container. Not sure why it's showing null.

See the realip header here: https://github.com/linuxserver/docker-nextcloud/blob/master/root/defaults/nginx/site-confs/default.conf.sample#L22-L24

Try adding that to the default site conf for this container and see if that works. The range/address needs to cover your proxy as seen by this container

@lyra56k
Copy link
Author

lyra56k commented Mar 28, 2024

I copied the contents of that conf file into a file on my host, mounted it in the container (to persist it) and added:

set_real_ip_from 0.0.0.0/0;
real_ip_header X-Forwarded-For;

I used 0.0.0.0/0 temporarily because I don't know what the IP would be, my setup is a little complicated, but the librespeed container is only accessible from the proxy anyways due to my firewall.

I restarted the container, but unfortunately it still shows null as the IP. I also tried using a different header name in both my proxy and nginx in the container, and that didn't change things either.

@aptalca
Copy link
Member

aptalca commented Mar 28, 2024

I copied the contents of that conf file into a file on my host, mounted it in the container (to persist it) and added

You need to edit the existing file in the config folder and restart the container. Randomly mapping in a file won't do anything and might break things.
/config/nginx/site-confs/default.conf

@lyra56k
Copy link
Author

lyra56k commented Mar 28, 2024

My problem is that by taking down the container and starting it again, any changes I make will be erased. I mapped the file to that specific path so it should behave like normal, which I’ve done to customize other containers’ files in a similar manner.

@j0nnymoe
Copy link
Member

Post your compose, any changes you make within the /config should not be erased.

@lyra56k
Copy link
Author

lyra56k commented Mar 28, 2024

version: '3.7'
services:
  speedtest:
    container_name: speedtest
    image: registry.gitlab.com/linuxserver.io/docker-librespeed/librespeed:latest
    restart: always
    volumes:
      - ./speedtest/database:/database
      - ./speedtest/default.conf:/config/nginx/site-confs/default.conf // This is the new line
    environment:
      MODE: standalone
      TITLE: "Speedtest"
      ENABLE_ID_OBFUSCATION: "true"
      DISTANCE: "mi"
      WEBPORT: 80
    ports:
      - "9065:80"

@lyra56k
Copy link
Author

lyra56k commented Mar 28, 2024

I ran bash in the (newly created) container and edited the file /config/nginx/site-confs/default.conf. Those lines do show up from the mounted file, but the IP is still null.

@aptalca
Copy link
Member

aptalca commented Mar 28, 2024

Please follow the readme and set up the container with the arguments listed and only the arguments listed.

The config folder is a required persistent folder for this container

@lyra56k
Copy link
Author

lyra56k commented Mar 28, 2024

I think I know what happened, when I set this up (months ago) I had copied the config file from a different speedtest container repo I had already edited and forgot to change stuff. I’ll fix and see if that changes things.

@lyra56k
Copy link
Author

lyra56k commented Mar 28, 2024

I have changed my compose file to the following:

version: '3.7'
services:
  speedtest:
    container_name: speedtest
    image: registry.gitlab.com/linuxserver.io/docker-librespeed/librespeed:latest
    restart: always
    volumes:
      - ./speedtest/config:/config
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Etc/UTC
      - PASSWORD=[Redacted]
    ports:
      - "9065:80"

Then I edited the file on my host. The problem is still occurring.
The reason I used a different path for the container than in the readme, is because the one mentioned which I had used before today contained Apache instead of nginx.

@aptalca
Copy link
Member

aptalca commented Mar 28, 2024

My bad, I thought you meant you were using Apache to reverse proxy.

I just did some local tests.

Created a fresh librespeed container and reverse proxied with SWAG: https://github.com/linuxserver/reverse-proxy-confs/blob/master/librespeed.subdomain.conf.sample

As I suspected, nginx access log in librespeed is displaying the source IPs as the SWAG IP (without the real IP header set).

However, Librespeed gui displays the actual source IP passed in via headers by SWAG.

I accessed both locally and over WAN and Librespeed displayed the correct LAN IP and public IP respectively.

This is likely an issue with your reverse proxy settings.

@lyra56k
Copy link
Author

lyra56k commented Mar 28, 2024

I have Apache as my public-facing proxy, yes, but nginx inside the container as it comes. I’m sorry to make this so confusing. I have set the X-Forwarded-For header on Apache, and it works on other containers (an example of which is the audit logs in Bookstack).

@lyra56k
Copy link
Author

lyra56k commented Apr 6, 2024

@aptalca any ideas? Like I mentioned, my Apache reverse proxy works fine with the other containers I run, so I know the X-Forwarded-For header is working.

@aptalca
Copy link
Member

aptalca commented Apr 6, 2024

No, I never used apache and it's not something we support.

We add a lot of headers in SWAG not just the x-forwarded-for

You may want to ask the upstream dev as librespeed does its own thing when determining the source IP. It doesn't show the same thing as the nginx instance serving it does.

@lyra56k
Copy link
Author

lyra56k commented Apr 6, 2024

Ah okay. Thank you, sorry to bother you.

@lyra56k lyra56k closed this as completed Apr 6, 2024
@LinuxServer-CI LinuxServer-CI moved this from Issues to Done in Issue & PR Tracker Apr 6, 2024
@ain-soph
Copy link

ain-soph commented Nov 24, 2024

@aptalca Sorry for continuing this closed issue.
For my server, I've set swag and librespeed dockers inside a bridge network with 80,443 exposed for swag, but the librespeed gui simply shows 172.18.0.1 - private IPv4 access.

After investigation, I find that the remote_addr is changed from real ip to 172.18.0.1 when passing docker network because of IP masquerading. And at that time, the message doesn't include any X-Forwarded-For so it just lose the source IP. swag inside docker can only see the remote_addr=172.18.0.1 and empty X-Forwarded-For. Any suggestion on how to fix it?

I tried macvlan, but I still need swag to communicate to host via host.docker.internal for some services. So this is not a solution, unless I use some very complex workarounds (i.e., another bridge or virtual network)

Another solution is to set up another nginx before docker to add X-Forwarded-For, which is not an ideal case as well.

Someone also advised to disable IP masquerading for the bridge network, I tried and it seems not working on my side. I guess there is still some NAT after disabling.

@lyra56k
Copy link
Author

lyra56k commented Nov 26, 2024

@ain-soph I'm not sure about your specific case, but I want to put this here as a solution to my original problem.

I had in my TLS-terminating Apache config:

RequestHeader set X-Real-IP "%{HTTP:X-Forwarded-For}e"
RequestHeader set X-Forwarded-For "%{HTTP:X-Forwarded-For}e"
RequestHeader set X-OG-Forwarded-For "%{HTTP:X-Forwarded-For}e"

Which is what works for every other container I've seen so far.
As I was thinking about this issue, I copied the headers that LinuxServer's SWAG container uses, which caused the LibreSpeed page to not load at all. I removed all the header declarations including the three I had originally, and somehow that caused it to work instantly. So whatever this Docker container was doing somehow conflicted with my global Apache config. It's also important to note that it happens both with the official container and the LinuxServer one, so neither one can be absolved from this situation.

@ain-soph
Copy link

ain-soph commented Nov 26, 2024

@bobbyl140 Thanks for your reply.
My case is for my family, I have the ISP -> Router -> NAS server -> docker engine -> Nginx in docker (swag) -> reverse proxy for other containers in the same bridge network and some services on host.
(without publishing ports for other containers, access container via http://<container name> and access host via http://host.docker.internal, which is the default setting for swag profiles)

The issue is that Nginx in docker receives the incoming message with $remote_addr=<docker_gateway> and empty X-Forwarded-For.

It seems I can do nothing at the Nginx side since the message itself has lost the real IP information.
I can only think up 2 bad solutions:

  • Nginx in network_mode=host and publish all other container's port for communication with Nginx
  • add another Nginx before docker engine to add X-Forwarded-For with real IP

@lyra56k
Copy link
Author

lyra56k commented Nov 26, 2024

I don't really know what to suggest, I'm sorry. My setup is using the official LibreSpeed container, which I think comes bundled with Apache, so I have
WAN -> Apache (on my hardware) -> Apache (in container, hosting the actual files directly from webroot)

I also do have the LibreSpeed container running in host mode, so that might help.

@ain-soph
Copy link

I don't really know what to suggest, I'm sorry. My setup is using the official LibreSpeed container, which I think comes bundled with Apache, so I have WAN -> Apache (on my hardware) -> Apache (in container, hosting the actual files directly from webroot)

I also do have the LibreSpeed container running in host mode, so that might help.

Yeah, so you have 2 Apache running. The one running before docker engine could embed the real ip into X-Forwarded-For, which is my proposed second solution. That makes sense, but I really don't want to add another reverse proxy though :(

@lyra56k
Copy link
Author

lyra56k commented Nov 26, 2024

See this is where I'm confused, because when I was using the first Apache to set X-Forwarded-For it did not work, and when I told that Apache to stop putting in the header, it did work.

@ain-soph
Copy link

ain-soph commented Nov 26, 2024

What? That is totally out of my expectation🤔 So your setting is
WAN -> first Apache in host -> second Apache in docker bridge network -> Librespeed in host network

So where do you set the X-Forwarded-For? the second Apache?
I observe $remote_addr=<docker_gateway>; X-Forwarded-For: empty at the second reverse proxy. I don't think we can recover the real IP from here, unless there is already X-Forwarded-For set previously, either from first proxy or further upstream (e.g., cloudflare proxy).

And yeah, maybe Librespeed in host network could directly get the real IP via some additional service-initiated communication not passing docker.

@lyra56k
Copy link
Author

lyra56k commented Nov 26, 2024

  1. The Apache in Docker seems to directly serve the files, rather than proxying to yet another backend.
  2. I really don't know where it's set, it doesn't make sense to me either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Archived in project
Development

No branches or pull requests

5 participants