1

Im using .net core 3.1 in an docker environment pointing an IIS Reverse Proxy with ARR installed to it.

Update

I managed to get the rewriting running. BNut since I dont know why it works this way Im unable to answer this question. I changed the rewrite rules from localhost: to 127.0.0.1: Now the handshake works. But it seems not work with websocket protocol only with ServerSentEvents.

Error: Failed to start the transport 'WebSockets': Error: WebSocket failed to connect. The connection could not be found on the server, either the endpoint may not be a SignalR endpoint, the connection ID is not present on the server, or there is a proxy blocking WebSockets. If you have multiple servers check that sticky sessions are enabled.

But Websockets are installed. Im using ARR3. So the last 2 questions in this for me are: Why did it work with the IP instead of localhost? (Full config below) Why does it throw this error even WS is installed?

Full Rewrite config:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <urlCompression doStaticCompression="false" doDynamicCompression="false" />
        <rewrite>
            <rules>
                <rule name="ReverseProxyInboundRule1" stopProcessing="true">
                    <match url="wss://(.*)" />
                    <action type="Rewrite" url="wss://127.0.0.1:3101/{R:1}" />
                </rule>
                <rule name="ReverseProxyInboundRule2" stopProcessing="true">
                    <match url="(.*)" />
                    <action type="Rewrite" url="https://127.0.0.1:3101/{R:1}" />
                </rule> 
            </rules>
            <outboundRules>
                <rule name="ReverseProxyOutboundRule1" preCondition="ResponseIsHtml1">
                    <match filterByTags="A, Form, Img" pattern="^http(s)?://127.0.0.1:3101/(.*)" />
                    <action type="Rewrite" value="http{R:1}://sub.example.com/{R:2}" />
                </rule>
                <preConditions>
                    <preCondition name="ResponseIsHtml1">
                        <add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
                    </preCondition>
                </preConditions>
            </outboundRules>
        </rewrite>
    </system.webServer>
</configuration>

EDIT

Thanks to Bruce Zhang I got to the source of the problem but still not Idea how to fix it.

Ive got an docker environment running via docker compose on a windows server. There I use IIS10 with UrlRewrite and ARR3 together with an .net core 3.1 app and signalR core. As Client I use the typescript version of @microsoft/signalr (latest) For some reasons I dont know the Connection is ok but the handshake call ends in an timeout. I looked at the net for some solutions and applied this so far:

  1. Added URL Rewrite Inbound Rules for wss:// and ws://
  2. Increased the timeouts for signalR
  3. Configured the response buffer in ARR (see picture below)
  4. Enabled failed request tracing

The docker env is running on the same server as the IIS with enabled ARR and Websockets Feature.

The Web-App container exposes port 6652 mapping it to port 443 in the docker container.

My rewrite rule are defined as below:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <urlCompression doStaticCompression="false" doDynamicCompression="false" />
        <rewrite>
            <rules>
                <rule name="WS reverse proxy" stopProcessing="true">
                    <match url="ws://devlocal.example.com" />
                    <conditions>
                        <add input="{CACHE_URL}" pattern="^(.+)://" />
                    </conditions>
                    <action type="Rewrite" url="{C:1}://127.0.0.1:6652" />
                </rule>
                <rule name="WSS reverse proxy" stopProcessing="true">
                    <match url="wss://devlocal.example.com" />
                    <conditions>
                        <add input="{CACHE_URL}" pattern="^(.+)://" />
                    </conditions>
                    <action type="Rewrite" url="{C:1}://127.0.0.1:6652" />
                </rule>

                <rule name="_Inbound_devlocal.example.com.com" stopProcessing="true">
                    <match url="(.*)" />
                    <action type="Rewrite" url="{C:1}://localhost:6652/{R:1}" logRewrittenUrl="true" />
                    <conditions logicalGrouping="MatchAny">
                        <add input="{CACHE_URL}" pattern="^(.+)://" />
                        <add input="{HTTP_HOST}" pattern="^devlocal\.example.com\.com$" />
                    </conditions>
                </rule>

            </rules>
            <outboundRules>
                <rule name="_Outboundund_devlocal.example.com.com" stopProcessing="true">
                    <match filterByTags="A, Form, Img, Link, Script" pattern="^http(s)?://localhost:6652/(.*)" />
                    <action type="Rewrite" value="http{R:1}://devlocal.example.com.com/{R:2}" />
                </rule>
            </outboundRules>
        </rewrite>
    </system.webServer>
</configuration>

SignalR configured as:

services.AddSignalR(hubOptions =>
           {
               hubOptions.ClientTimeoutInterval = TimeSpan.FromSeconds(240);
               hubOptions.HandshakeTimeout = TimeSpan.FromSeconds(120);
               hubOptions.KeepAliveInterval = TimeSpan.FromSeconds(60);
               hubOptions.EnableDetailedErrors =  true;
               hubOptions.MaximumReceiveMessageSize = 200;
               hubOptions.StreamBufferCapacity = 300;
           });
// Mappig hub  like:

app.UseEndpoints(api =>
            {
                api.MapControllers();
                api.MapHub<CommentsHub>("/sockR/hub");
            }
);

The ARR Config: enter image description here

The trace log of the signalR client shows that its the handshake call thats ends in an timeout:

[2022-01-13T18:29:07.232Z] Information: Normalizing '/sockR/hub' to 'https://devlocal.example.com/sockR/hub'.
Utils.js:151 [2022-01-13T18:29:07.233Z] Debug: Starting HubConnection.
Utils.js:151 [2022-01-13T18:29:07.233Z] Debug: Starting connection with transfer format 'Text'.
Utils.js:147 [2022-01-13T18:29:07.342Z] Information: WebSocket connected to wss://devlocal.example.com/sockR/hub.
Utils.js:151 [2022-01-13T18:29:07.342Z] Debug: The HttpConnection connected successfully.
Utils.js:151 [2022-01-13T18:29:07.342Z] Debug: Sending handshake request.
Utils.js:147 [2022-01-13T18:29:07.342Z] Information: Using HubProtocol 'json'.
... After 3 minutes:
ERROR Error: Uncaught (in promise): Error: Server timeout elapsed without receiving a message from the server. Error: Server timeout elapsed without receiving a message from the server.

Is there any way to debug why the request is ending in an timeout? The strange thing is Ive got also an jira instance on the server.Also bound via revers proxy with same settings and the WSS/WS calls there dont fail.

Malte
  • 40
  • 5
  • I think you can use failed request tracing to trace request. Check if the ARR forward request correctly to backend server. Then you can know where the timeout happen, ARR or backend server. – Bruce Zhang Jan 13 '22 at 03:04
  • Failed request tracing is enabled, but the log folder is empty. Application can write into folder on my mashine – Malte Jan 13 '22 at 03:24
  • I mean you can enable it on ARR server so that it will show if it forward request successfully. If folder is empty, that means it doesn't receive request. – Bruce Zhang Jan 13 '22 at 03:28
  • My docker env is running on the same server as the iis does. Plan was to reverse proxy from an iis site (sub.mydomain.com for example) to my site running in a docker container on the same mashine, cause the plan is to switch to azure or aws in future. All requests via http/https work and also the request host is rewritten correctly. What I can see in the console is the handshake seems to work in the hub connection...this error only throws if a new message is sent by hub context. – Malte Jan 13 '22 at 03:39
  • Update seems like the timeout happens also after connecting. So the theory that the request does not come through is right. The debug log from signalR was just wrong saying "Connected". But with my config above also the wss calls should go through. Or am I missing something in my config? – Malte Jan 13 '22 at 09:40

1 Answers1

0

Apperently it works now by removing: Startup.cs

app.UseWebSockets();

And after changing my rewrite config to:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <urlCompression doStaticCompression="false" doDynamicCompression="false" />
        <rewrite>
            <rules>
                <rule name="ReverseProxyInboundRule1" stopProcessing="true">
                    <match url="wss://(.*)" />
                    <action type="Rewrite" url="wss://127.0.0.1:3101/{R:1}" />
                </rule>
                <rule name="ReverseProxyInboundRule2" stopProcessing="true">
                    <match url="(.*)" />
                    <action type="Rewrite" url="https://127.0.0.1:3101/{R:1}" />
                </rule> 
            </rules>
            <outboundRules>
                <rule name="ReverseProxyOutboundRule1" preCondition="ResponseIsHtml1">
                    <match filterByTags="A, Form, Img" pattern="^http(s)?://127.0.0.1:3101/(.*)" />
                    <action type="Rewrite" value="http{R:1}://sub.example.com/{R:2}" />
                </rule>
                <preConditions>
                    <preCondition name="ResponseIsHtml1">
                        <add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
                    </preCondition>
                </preConditions>
            </outboundRules>
        </rewrite>
    </system.webServer>
</configuration>
Malte
  • 40
  • 5