Jump to content

Emby behind IIS/AAR shows client IP's as Reverse Proxy's IP


TheITJedi
Go to solution Solved by TheITJedi,

Recommended Posts

TheITJedi

Hey,

Hoping someone can help me with this. 

I use IIS/AAR to reverse proxy Emby to be publicly accessible and handle SSL offload. I have had everything working beautifully for quite sometime with one small exception. The client IPs in the Admin Dashboard all show ::1 regardless of where the user signs in from (tested using cellular and my little brothers computer in another state). 

image.png.ce3328c3fef8735fc20c452fa4d26ede.png

I have verified that X-Forwarded-For and the client's IP are showing correctly in the logs for IIS however they do not display in the dashboard.

My stack is:

  • Windows Server 2019
  • IIS 10
  • AAR 3

Flow is: 

Internet -> IIS -> Emby

My Web.Config looks like: 
 

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
				<clear></clear>
				<rule name="Redirect to https" enabled="true" patternSyntax="Wildcard" stopProcessing="true">
					<match url="*" negate="false" />
					<conditions logicalGrouping="MatchAny">
						<add input="{HTTPS}" pattern="off" />
					</conditions>
					<action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" redirectType="Found" />
				</rule>
				<rule name="Proxy to Emby" stopProcessing="true">
                    <match url="(.*)" />
                    <serverVariables>
                        <set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
                        <set name="HTTP_ACCEPT_ENCODING" value="" />
                    </serverVariables>
                    <action type="Rewrite" url="http://localhost:8096/{R:1}" />
                </rule>
            </rules>
            <outboundRules>
				<rule name="Add Strict-Transport-Security when HTTPS" enabled="true">
                    <match serverVariable="RESPONSE_Strict_Transport_Security" pattern=".*" />
                    <conditions>
                        <add input="{HTTPS}" pattern="on" />
                    </conditions>
                    <action type="Rewrite" value="max-age=31536000; includeSubDomains; preload" />
                </rule>
                <rule name="Proxy to Emby" preCondition="ResponseIsHtml1" enabled="true">
                    <match filterByTags="A, Area, Base, Form, Frame, Head, IFrame, Img, Input, Link, Script" pattern="^http(s)?://http://localhost:8096/(.*)" />
                    <action type="Rewrite" value="http{R:1}://publicurl.mydomain.com/{R:2}" />
                </rule>
				<rule name="Restore-AcceptEncoding" preCondition="NeedsRestoringAcceptEncoding">
                    <match serverVariable="HTTP_ACCEPT_ENCODING" pattern="^(.*)" />
                    <action type="Rewrite" value="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" />
                </rule>
                <preConditions>
                    <preCondition name="ResponseIsHtml1">
                        <add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/(.+)" />
                    </preCondition>
                    <preCondition name="NeedsRestoringAcceptEncoding">
                        <add input="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" pattern=".+" />
                    </preCondition>
                </preConditions>
            </outboundRules>
        </rewrite>
        <caching enabled="false" enableKernelCache="false" />
        <httpProtocol>
            <customHeaders>
                <add name="X-Frame-Options" value="SAMEORIGIN" />
                <add name="X-Xss-Protection" value="1; mode=block" />
                <add name="X-Content-Type-Options" value="nosniff" />
                <add name="Referrer-Policy" value="same-origin" />
				<add name="Feature-Policy" value="sync-xhr 'self'" />
                <add name="Cache-Control" value="no-cache" />
            </customHeaders>
        </httpProtocol>
    </system.webServer>
</configuration>

 

As I said, feature-wise everything works fantastic, it does appear that the bit-rate limiting for external streams does not apply due to this either. 

 

Thanks in advance!

Edited by itjedi42
Additonal Information
Link to comment
Share on other sites

Hello itjedi42,

Please wait for someone from staff support or our members to reply to you.

It's recommended to provide more info, as it explain in this thread:

Thank you.

Emby Team

Link to comment
Share on other sites

TheITJedi

@Abobader, I dont know that its a bug. Do you happen to know what headers Emby looks at to get the client IP address? I would assume it would consume the X-Forwarded-For header and be able to use that, however it does not appear to. 

Link to comment
Share on other sites

TheITJedi

@Abobader

It looks very much like Emby just doesnt care about X-Forwarded-For and only cares about what the connection IP address is. 

Link to comment
Share on other sites

TheITJedi
7 hours ago, PenkethBoy said:

::1 = to localhost

yes, im aware.

trying to determine why Emby won't read the X-Forwarded-For header and use it rather than reporting localhost/ip of reverse proxy. 

 

HTTP_X_FORWARDED_FOR/X-Forwarded-For is being set and I can read it fine with other code behind the reverse proxy, however depending on if the reverse proxy rule is "localhost" or 10.0.1.5, Emby will show either ::1 or 10.0.1.5 for all connections. I have a couple other things set up on my server using similar reverse proxy configurations and they successfully consume the correct IP address from X-Forwarded-For.

At this point I am curious as to the exact mechanism that Emby is using to determine the client's IP and why it doesnt appear to observe the industry standard X-Forwarded-For/HTTP_X_FORWARDED_FOR headers/variables. 

Edited by itjedi42
Additional Information
Link to comment
Share on other sites

pir8radio
13 hours ago, itjedi42 said:

yes, im aware.

trying to determine why Emby won't read the X-Forwarded-For header and use it rather than reporting localhost/ip of reverse proxy. 

 

HTTP_X_FORWARDED_FOR/X-Forwarded-For is being set and I can read it fine with other code behind the reverse proxy, however depending on if the reverse proxy rule is "localhost" or 10.0.1.5, Emby will show either ::1 or 10.0.1.5 for all connections. I have a couple other things set up on my server using similar reverse proxy configurations and they successfully consume the correct IP address from X-Forwarded-For.

At this point I am curious as to the exact mechanism that Emby is using to determine the client's IP and why it doesnt appear to observe the industry standard X-Forwarded-For/HTTP_X_FORWARDED_FOR headers/variables. 

 

6 hours ago, Happy2Play said:

@pir8radiodo you have some insight on this.

 

 

I'll have to find the post,   luke said something about a change to x-forwarded for (been months now)....     I'll have to find that post, i could be imagining this conversation.   Try and set x-real-ip  either by mapping it to x-forwarded-for or just passing it..    send an IP to emby via x-real-ip and see what you get..    Im doing both, and I don't have time tonight to test which one emby is actually abiding by.     Emby USED to list all of the proxy IP's for every connecting user like  10.x.x.1, 11.x.x.2    in one line, but that stopped a long time ago, when i think emby started ignoring x-forwarded-for, either that or emby only "looks" at the first or last IP in that string, which could be the wrong IP.

Edited by pir8radio
Link to comment
Share on other sites

TheITJedi
11 hours ago, pir8radio said:

I'll have to find the post,   luke said something about a change to x-forwarded for (been months now)....     I'll have to find that post, i could be imagining this conversation.   Try and set x-real-ip  either by mapping it to x-forwarded-for or just passing it..    send an IP to emby via x-real-ip and see what you get..    Im doing both, and I don't have time tonight to test which one emby is actually abiding by.     Emby USED to list all of the proxy IP's for every connecting user like  10.x.x.1, 11.x.x.2    in one line, but that stopped a long time ago, when i think emby started ignoring x-forwarded-for, either that or emby only "looks" at the first or last IP in that string, which could be the wrong IP.

I am now passing:

- X-Forwarded-For
- X-Real-IP
- X-Client-IP
 

Still only getting IP of reverse proxy in Emby rather than actual user's IP. 

Seriously... is there not a dev for the project that can tell me exactly what headers it wants and will honor?

I can not be the first person to be using IIS for a reverse proxy. 

@Luke

Edited by itjedi42
Link to comment
Share on other sites

TheITJedi

@Luke nginx is not an option in my environment. I just want to know what header Emby will actually read the original client's IP from so it will display in activity and be able to differentiate between external and internal clients. 

None of these are acknowledged by Emby:

- X-Original-Host
- X-Forwarded-For
- X-Real-IP
- X-Client-IP

 

Link to comment
Share on other sites

3 minutes ago, itjedi42 said:

@Luke nginx is not an option in my environment. I just want to know what header Emby will actually read the original client's IP from so it will display in activity and be able to differentiate between external and internal clients. 

None of these are acknowledged by Emby:

- X-Original-Host
- X-Forwarded-For
- X-Real-IP
- X-Client-IP

 

I understand, but you can still look at how he configured it and translate that to the reverse proxy software that you're using.

Link to comment
Share on other sites

  • Solution
TheITJedi

@Luke

Thanks, I was able to find the answer. 

For anyone wondering, it appears that if the X-Real-IP is populated from X-Forwarded-For it won't work. X-Real-IP needs to be populated as such:
 

<set name="HTTP_X_REAL_IP" value="{REMOTE_ADDR}" />

 

Here is the working copy of my Web.Config for any other IIS users. (just change IP for backend host and my.public.url to match your public url.) 
Supports: SSL offload, forced HTTPS, remote control, and is fully transparent to Emby. 
 

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <clear></clear>
        <rule name="Redirect to https" enabled="true" patternSyntax="Wildcard" stopProcessing="true">
          <match url="*" negate="false" />
          <conditions logicalGrouping="MatchAny">
            <add input="{HTTPS}" pattern="off" />
          </conditions>
          <action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" redirectType="Found" />
        </rule>
        <rule name="Proxy to Emby" stopProcessing="false">
          <match url="(.*)" />
          <serverVariables>
            <set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
            <set name="HTTP_ACCEPT_ENCODING" value="" />
            <set name="HTTP_X_REAL_IP" value="{REMOTE_ADDR}" />
          </serverVariables>
          <action type="Rewrite" url="http://10.0.1.5:8096/{R:1}" logRewrittenUrl="true" />
          <conditions>
            <add input="/{R:1}" pattern=".well-known" negate="true" />
          </conditions>
        </rule>
      </rules>
      <outboundRules>
        <rule name="Add Strict-Transport-Security when HTTPS" enabled="true">
          <match serverVariable="RESPONSE_Strict_Transport_Security" pattern=".*" />
          <conditions>
            <add input="{HTTPS}" pattern="on" />
          </conditions>
          <action type="Rewrite" value="max-age=31536000; includeSubDomains; preload" />
        </rule>
        <rule name="Proxy to Emby" preCondition="ResponseIsHtml1" enabled="true">
          <match filterByTags="A, Area, Base, Form, Frame, Head, IFrame, Img, Input, Link, Script" pattern="^http(s)?://http://localhost:8096/(.*)" />
          <action type="Rewrite" value="http{R:1}://my.public.url/{R:2}" />
        </rule>
        <rule name="Restore-AcceptEncoding" preCondition="NeedsRestoringAcceptEncoding">
          <match serverVariable="HTTP_ACCEPT_ENCODING" pattern="^(.*)" />
          <action type="Rewrite" value="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" />
        </rule>
        <preConditions>
          <preCondition name="ResponseIsHtml1">
            <add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/(.+)" />
          </preCondition>
          <preCondition name="NeedsRestoringAcceptEncoding">
            <add input="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" pattern=".+" />
          </preCondition>
        </preConditions>
      </outboundRules>
    </rewrite>
    <caching enabled="false" enableKernelCache="false" />
    <httpProtocol>
      <customHeaders>
        <add name="X-Frame-Options" value="SAMEORIGIN" />
        <add name="X-Xss-Protection" value="1; mode=block" />
        <add name="X-Content-Type-Options" value="nosniff" />
        <add name="Referrer-Policy" value="same-origin" />
        <add name="Feature-Policy" value="sync-xhr 'self'" />
        <add name="Cache-Control" value="no-cache" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>
</configuration>

 

Edited by itjedi42
Link to comment
Share on other sites

pir8radio
4 hours ago, TheITJedi said:

@Luke

Thanks, I was able to find the answer. 

For anyone wondering, it appears that if the X-Real-IP is populated from X-Forwarded-For it won't work. X-Real-IP needs to be populated as such:
 


<set name="HTTP_X_REAL_IP" value="{REMOTE_ADDR}" />

 

Here is the working copy of my Web.Config for any other IIS users. (just change IP for backend host and my.public.url to match your public url.) 
Supports: SSL offload, forced HTTPS, remote control, and is fully transparent to Emby. 
 

 

I started out with IIS as a reverse proxy, but had all kinds of issues,   I think those posts are listed in the forum here somewhere..    Glad you found the answer,   It might be that real_IP cant handle the multiple addresses found in an x_forwarded_for string.     @Luke the emby web server used to grab the "X_Forwarded_For" IP address and pass it on to emby...  What one is the internal webserver "looking" at these days?      I used to see multiple IP's listed in my emby dashboard which would tell me what hops the user took to get to me (through cloudflare) these days i only see ONE ip listed in my dashboard and its usually the client only ip.    Just curious if you know off the top of your head?

Link to comment
Share on other sites

First we check x-forwarded-for, then if we don't get anything from there we move on to x-real-ip. both can handle multiple ip's being specified, comma delimited, in which case, the last one is used.

  • Thanks 1
Link to comment
Share on other sites

  • 1 year later...
benwallner
On 02/03/2021 at 23:39, Luke said:

First we check x-forwarded-for, then if we don't get anything from there we move on to x-real-ip. both can handle multiple ip's being specified, comma delimited, in which case, the last one is used.

Can this behavior be changed? According to the MDN Web Docs the first IP should be used

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...