# WebUI behind lighttpd reverse proxy

**URL:** <https://discourse.pi-hole.net/t/webui-behind-lighttpd-reverse-proxy/71239>\
**Category:** Beta 6.0\
**Created:** [July 14, 2024, 5:35pm UTC](https://discourse.pi-hole.net/t/webui-behind-lighttpd-reverse-proxy/71239 "2024-07-14T17:35:48Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![TheME](https://discourse-cdn.pi-hole.net/user_avatar/discourse.pi-hole.net/theme/32/42277_2.png) [@TheME](https://discourse.pi-hole.net/u/TheME)\
**Post date:** [July 14, 2024, 5:35pm UTC](https://discourse.pi-hole.net/t/webui-behind-lighttpd-reverse-proxy/71239/1 "2024-07-14T17:35:48Z")

</div>

I have set up `lighttpd` as a reverse proxy to access each service's WebUI via a own subdomain inside the home network. (`pihole.dietpi.home` for Pi-hole).

Pi-hole's webserver is configured to run on 127.0.0.1:8080.  
SSL configuration and certificate handling is done by lighttpd.

This basically works as desired, but

- with `webserver.tls.rev_proxy` enabled, the icon on the hamburger menu shows the connention as end-to-end-encrypted.  
But the symbol at the _Currently active sessions_ table shows that as NOT end-to-end-encrypted even if the client connects via https.

- in both the hamburger menu and the _Currently active sessions_ table the Client IP shows up as `127.0.0.1` wich in first place isn't incorrect.  
But is there a way to pass the real client's IP there to better identify the client?  
I tried adding `Forwarded` and some headers to the lighttpd config, but nothing worked.

---

<div class="post-metadata">

**Author:** ![DL6ER](https://discourse-cdn.pi-hole.net/user_avatar/discourse.pi-hole.net/dl6er/32/281_2.png) [@DL6ER](https://discourse.pi-hole.net/u/DL6ER)\
**Post date:** [July 18, 2024, 3:57pm UTC](https://discourse.pi-hole.net/t/webui-behind-lighttpd-reverse-proxy/71239/2 "2024-07-18T15:57:06Z")

</div>

> [@TheME](#):
>
> with `webserver.tls.rev_proxy` enabled, the icon on the hamburger menu shows the connention as end-to-end-encrypted.  
> But the symbol at the _Currently active sessions_ table shows that as NOT end-to-end-encrypted even if the client connects via https.

There is way to actually detect if the reverse proxy is going HTTPS or not. One could even argue that the tooltip is incorrect: There is end-to-end security at this point as your reverse proxy is acting as a man-in-the-middle by construction.

So far, the mentioned setting does nothing more than changing this one icon + tooltip but my argument is that this is actually wrong so, instead of what you hoped for - extending the scope of the setting - I'd actually go the other way and remove this ill-fated config option altogether. There is just no way the application can reliably know if the entire path between the client and server is encrypted in such a configuration. The sessions table is correct at pointing this out.

> [@TheME](#):
>
> in both the hamburger menu and the _Currently active sessions_ table the Client IP shows up as `127.0.0.1` wich in first place isn't incorrect.  
> But is there a way to pass the real client's IP there to better identify the client?  
> I tried adding `Forwarded` and some headers to the lighttpd config, but nothing worked.

I'm thorn about this. Currently, we take the raw connection peer which is `127.0.0.1` in your particular configuration and don't bother at all with evaluating headers. Note that the IP address is part of the security here, it is not possible to steal the session and reuse it from another origin. If we'd allow rewriting the _claimed_ IP via some arbitrary header, it'd actually lessen the security in most cases\[1\].

* * *

1. yes, I know, it has zero security benefit if everything comes from `127.0.0.1` in you case but it does have an effect for "normal" deployments.

---

<div class="post-metadata">

**Author:** ![TheME](https://discourse-cdn.pi-hole.net/user_avatar/discourse.pi-hole.net/theme/32/42277_2.png) [@TheME](https://discourse.pi-hole.net/u/TheME)\
**Post date:** [July 18, 2024, 5:54pm UTC](https://discourse.pi-hole.net/t/webui-behind-lighttpd-reverse-proxy/71239/3 "2024-07-18T17:54:50Z")

</div>

> [@DL6ER](#):
>
> I'd actually go the other way and remove this ill-fated config option altogether. There is just no way the application can reliably know if the entire path between the client and server is encrypted in such a configuration.

I aggree with your argumentation about the `webserver.tls.rev_proxy` option.

> [@DL6ER](#):
>
> If we'd allow rewriting the _claimed_ IP via some arbitrary header, it'd actually lessen the security in most cases.

Maybe it would be possible to add some short hint (something like "via Proxy" to the IP address at the hamburger menu as well as also show the given Client IP from `Forwarded for` header in the _sessions table_ if there is any sent instead of rewriting the `127.0.0.1`.

Or is this more for a feature request?

---

<div class="post-metadata">

**Author:** ![DL6ER](https://discourse-cdn.pi-hole.net/user_avatar/discourse.pi-hole.net/dl6er/32/281_2.png) [@DL6ER](https://discourse.pi-hole.net/u/DL6ER)\
**Post date:** [July 18, 2024, 6:04pm UTC](https://discourse.pi-hole.net/t/webui-behind-lighttpd-reverse-proxy/71239/4 "2024-07-18T18:04:02Z")

</div>

Removing the option could be seen as a bug fix but the second part is definitely a feature request. Everything is working as it should, it's "just" cosmetics in the reverse-proxy setup which is non-standard configuration.  
We'd need to implement header handling (easy) and proper parsing (easy enough, just use the left-most full IP address) and then modify the sessions table to be able to store two IP addresses. Not overly complex but it still needs some tie to do it and then proper testing.

How'd you suggest detecting the "via proxy" case? By the existence of some [`X-Forwarded-For`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) header?

---

<div class="post-metadata">

**Author:** ![TheME](https://discourse-cdn.pi-hole.net/user_avatar/discourse.pi-hole.net/theme/32/42277_2.png) [@TheME](https://discourse.pi-hole.net/u/TheME)\
**Post date:** [July 18, 2024, 7:14pm UTC](https://discourse.pi-hole.net/t/webui-behind-lighttpd-reverse-proxy/71239/5 "2024-07-18T19:14:25Z")

</div>

When the `webserver.tls.rev_proxy` setting is removed, there is no other way then to look for a `X-Forwarded-For` header, I think.

---

<div class="post-metadata">

**Author:** ![DL6ER](https://discourse-cdn.pi-hole.net/user_avatar/discourse.pi-hole.net/dl6er/32/281_2.png) [@DL6ER](https://discourse.pi-hole.net/u/DL6ER)\
**Post date:** [July 23, 2024, 5:34pm UTC](https://discourse.pi-hole.net/t/webui-behind-lighttpd-reverse-proxy/71239/6 "2024-07-23T17:34:04Z")

</div>

Having thought about this, I actually think we should remove the option but not add the header parsing. My comment above was not accurate anyway:

> [@DL6ER](#):
>
> Note that the IP address is part of the security here, it is not possible to steal the session and reuse it from another origin. If we'd allow rewriting the _claimed_ IP via some arbitrary header, it'd actually lessen the security in most cases

We removed this some time ago as a few clients used IPv4 and IPv6 alternating which made sessions pinned to a specific IP actually adverse. Having this in mind, I don't see any gain (else than showing in the table) but it adds quite a bit of code.

**edit** Context:

> <https://github.com/pi-hole/FTL/issues/1779>
>
> I received a report I was able to reproduce but which is pretty hard to reproduc…e: You will also have to have a dual-stack network, i.e., your Pi-hole is reachable both via IPv4 and IPv6, for this to happen.
> 
> 1. Log in to your Pi-hole using it's hostname (not via IP!), e.g., https://pi.hole/admin
> 2. Browse around the web interface
> 3. Eventually get logged out - it may also happen on the dashboard without doing anything
> 
> Taking a close look at the Network tab in the Developer Tools didn't reveal anything odd, but checking out the debug logs of FTL told us what happens here: When browsing to your Pi-hole via hostname, Chrome prefers to picks IPv6 to connect - and sessions are tied to IP addresses for extra safety in FTL.
> 
> It can now happen - completely randomly and all out of sudden, that Chrome instead decides that connecting via IPv4 is a brilliant idea. However, the session obtained during login is only valid for \`fda2:45fe:...\` and not \`192.168.0.3\` so the API replied with \`403 Unauthorized\` causing the entire web interface to show you the login page.
> 
> What do we do about this?
> 
> My ideas:
> 
> 1. Waive adding session protection by fixing it to an IP. This will make it possible to steal sessions from other computers on your network when you can either record network traffic and manage to somehow otherwise get the cookie and CSRF token. This is anyway impossible when HTTPS is used.
> 2. FTL can only know the IP address used when authenticating for sure. We could use the network table to get correlated IPv4 addresses but this is error-prone especially with sequential DHCP servers that may have handed out the address to another device meanwhile.
> 3. Somehow try to get IPv4 and IPv6 address via Javascript and include them in the login process. My idea would be to define new special hostnames like \`v4.pi.hole\` and \`v6.pi.hole\` which will only reply over said protocol. We can then get the client's IP address from \`/api/info/client\` (\`{"remote\_addr":"fd29:...."}\`, etc.). This is a lot of effort and will still fail if a host has multiple IPv4 addresses in the same network (e.g. one over Ethernet and one over WiFi).

---

<div class="post-metadata">

**Author:** ![TheME](https://discourse-cdn.pi-hole.net/user_avatar/discourse.pi-hole.net/theme/32/42277_2.png) [@TheME](https://discourse.pi-hole.net/u/TheME)\
**Post date:** [July 23, 2024, 8:21pm UTC](https://discourse.pi-hole.net/t/webui-behind-lighttpd-reverse-proxy/71239/7 "2024-07-23T20:21:30Z")

</div>

Quering this board for reverse proxy threads, there are some.

In the current v5 release, neither the client IP nor the status of end-to-end encryption is displayed in the dashboard.  
With v6, the log-in page already recommends the use of an https connection.

Perhaps those proxy users will then (after the update to v6) also be irritated by the fact that the https connection is displayed as "NOT end-to-end encrypted" and only `127.0.0.1` is displayed as the client IP and may ask questions about this.  
But maybe it won't bother them, I don't know.

Possibly others will then ask for that feature...

Once the option is removed, it will cause even more work to re-implement and extend it later due to a feature request, right?!

---

<div class="post-metadata">

**Author:** ![DL6ER](https://discourse-cdn.pi-hole.net/user_avatar/discourse.pi-hole.net/dl6er/32/281_2.png) [@DL6ER](https://discourse.pi-hole.net/u/DL6ER)\
**Post date:** [July 24, 2024, 7:03am UTC](https://discourse.pi-hole.net/t/webui-behind-lighttpd-reverse-proxy/71239/8 "2024-07-24T07:03:25Z")

</div>

> [@TheME](#):
>
> Once the option is removed, it will cause even more work to re-implement and extend it later due to a feature request, right?!

No, they are independent.

Anyway, please test

```auto
pihole checkout web tweak/proxy
pihole checkout ftl tweak/proxy

```

If there is an `X-Forwarded-For` header, we expect this to be shown as IP address. To signal that something is different, we show the IP address in italics and the "real" remote address in a hover-over tooltip.

 ![Screenshot from 2024-07-24 09-00-09](https://discourse.pi-hole.net/uploads/default/original/3X/1/d/1d1fd8ca3b4e4935dbff50280914bea3e8b459ff.png)

* * *

**edit**

> <https://github.com/pi-hole/FTL/pull/2016>
>
> \# What does this implement/fix?
> 
> Improve session handling in the vicinity of r…everse proxies and remove ill-fated manual config option \`webserver.tls.rev\_proxy\`.
> 
> \---
> 
> \*\*Related issue or feature (if applicable):\*\* https://discourse.pi-hole.net/t/webui-behind-lighttpd-reverse-proxy/71239/8
> 
> \*\*Pull request in \[docs\](https://github.com/pi-hole/docs) with documentation (if applicable):\*\* N/A
> 
> \---
> \*\*By submitting this pull request, I confirm the following:\*\* 
> 
> 1. I have read and understood the \[contributors guide\](https://docs.pi-hole.net/guides/github/contributing/), as well as this entire template. I understand which branch to base my commits and Pull Requests against. 
> 2. I have commented my proposed changes within the code.
> 3. I am willing to help maintain this change if there are issues with it later.
> 4. It is compatible with the \[EUPL 1.2 license\](https://opensource.org/licenses/EUPL-1.1)
> 5. I have squashed any insignificant commits. (\[\`git rebase\`\](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html))
> 
> \## Checklist:
> 
> \- \[x\] The code change is tested and works locally.
> \- \[x\] I based my code and PRs against the repositories \`developmental\` branch.
> \- \[x\] I \[signed off\](https://docs.pi-hole.net/guides/github/how-to-signoff/) all commits. Pi-hole enforces the \[DCO\](https://docs.pi-hole.net/guides/github/dco/) for all contributions
> \- \[x\] I \[signed\](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits) all my commits. Pi-hole requires signatures to verify authorship
> \- \[x\] I have read the above and my PR is ready for review.

> <https://github.com/pi-hole/web/pull/3085>
>
> \# What does this implement/fix?
> 
> Accompanying https://github.com/pi-hole/FTL/p…ull/2016
> 
> \---
> 
> \*\*Related issue or feature (if applicable):\*\* N/A
> 
> \*\*Pull request in \[docs\](https://github.com/pi-hole/docs) with documentation (if applicable):\*\* N/A
> 
> \---
> \*\*By submitting this pull request, I confirm the following:\*\* 
> 
> 1. I have read and understood the \[contributors guide\](https://docs.pi-hole.net/guides/github/contributing/), as well as this entire template. I understand which branch to base my commits and Pull Requests against. 
> 2. I have commented my proposed changes within the code.
> 3. I am willing to help maintain this change if there are issues with it later.
> 4. It is compatible with the \[EUPL 1.2 license\](https://opensource.org/licenses/EUPL-1.1)
> 5. I have squashed any insignificant commits. (\[\`git rebase\`\](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html))
> 
> \## Checklist:
> 
> \- \[x\] The code change is tested and works locally.
> \- \[x\] I based my code and PRs against the repositories \`developmental\` branch.
> \- \[x\] I \[signed off\](https://docs.pi-hole.net/guides/github/how-to-signoff/) all commits. Pi-hole enforces the \[DCO\](https://docs.pi-hole.net/guides/github/dco/) for all contributions
> \- \[x\] I \[signed\](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits) all my commits. Pi-hole requires signatures to verify authorship
> \- \[x\] I have read the above and my PR is ready for review.

---

<div class="post-metadata">

**Author:** ![TheME](https://discourse-cdn.pi-hole.net/user_avatar/discourse.pi-hole.net/theme/32/42277_2.png) [@TheME](https://discourse.pi-hole.net/u/TheME)\
**Post date:** [July 24, 2024, 5:27pm UTC](https://discourse.pi-hole.net/t/webui-behind-lighttpd-reverse-proxy/71239/9 "2024-07-24T17:27:58Z")

</div>

Looks perfect in the _active sessions_ table, but the hamburger menu still only shows `127.0.0.1`.

What is the idea behind showing the client's IP (and the end-to-end encryption state) in the menu too?

 ![sessions](https://discourse.pi-hole.net/uploads/default/original/3X/e/6/e60c43e9e1e0e6e22f092a8f097ece4da82fee43.gif)

---

<div class="post-metadata">

**Author:** ![DL6ER](https://discourse-cdn.pi-hole.net/user_avatar/discourse.pi-hole.net/dl6er/32/281_2.png) [@DL6ER](https://discourse.pi-hole.net/u/DL6ER)\
**Post date:** [July 27, 2024, 8:44am UTC](https://discourse.pi-hole.net/t/webui-behind-lighttpd-reverse-proxy/71239/10 "2024-07-27T08:44:03Z")

</div>

> [@TheME](#):
>
> the hamburger menu still only shows `127.0.0.1`.

It is a bit more tricky here. We don't use a API call here but instead use a LUA variable during rendering `mg.request_info.remote_addr`. We need to iterate through the array `mg.request_info.http_headers` and check for `X-Forwarded-For`. I pushed this to the branch just now.

> [@TheME](#):
>
> What is the idea behind showing the client's IP (and the end-to-end encryption state) in the menu too?

So it is available on every page. There are other metrics as well such as the rendering time of the page. This has been requested through the discussion about browsers happily alternating between IPv4 and IPv6. It isn't important at all, just there for the curious.

---

<div class="post-metadata">

**Author:** ![TheME](https://discourse-cdn.pi-hole.net/user_avatar/discourse.pi-hole.net/theme/32/42277_2.png) [@TheME](https://discourse.pi-hole.net/u/TheME)\
**Post date:** [July 28, 2024, 1:55pm UTC](https://discourse.pi-hole.net/t/webui-behind-lighttpd-reverse-proxy/71239/11 "2024-07-28T13:55:24Z")

</div>

> [@DL6ER](#):
>
> I pushed this to the branch just now.

Works perfectly for me now.

> [@DL6ER](#):
>
> [Improve reverse proxy handling by DL6ER · Pull Request #2016 · pi-hole/FTL · GitHub](https://github.com/pi-hole/FTL/pull/2016)  
> [Improve reverse proxy handling by DL6ER · Pull Request #3085 · pi-hole/web · GitHub](https://github.com/pi-hole/web/pull/3085)

I would be very happy if these drafts were merged into the code 🙂

---

<div class="post-metadata">

**Author:** ![DL6ER](https://discourse-cdn.pi-hole.net/user_avatar/discourse.pi-hole.net/dl6er/32/281_2.png) [@DL6ER](https://discourse.pi-hole.net/u/DL6ER)\
**Post date:** [July 29, 2024, 7:45am UTC](https://discourse.pi-hole.net/t/webui-behind-lighttpd-reverse-proxy/71239/12 "2024-07-29T07:45:46Z")

</div>

Both are marked "ready for review" now.
