Orchestrator installation on 2 servers

Hello,

I installed Orchestrator 2020.10 on 2 servers as per the multi-node documentation. My certificate contains the hostnames.

On the first server, no issue :
I use the URL https://hostame1.domain which is redirected, I login and Orchestrator opens.

On the second server :
If i use the URL https://hostame2.domain i have the error : Error, an unknown error has occured (#200). The event viewer shows this error : “Error”:“ unauthorized_client ”, “ErrorDescription”:“Invalid redirect_uri”.

Any idea which could help ? Thanks.

When using multiple orchestrator nodes, there should only be one entry point into the cluster of those nodes, presumably a load balancer URL. You will not be able to browse the orchestrator cluster using the individiual host names

1 Like

Thanks for your reply.

It was possible in the 2018 version.
Is it a change in the 2020.10 which prevents it ?

20.4 introduced identity server, which centralized authentication to the platform. With Identity server there is only one entry point allowed

I see the same thing in our setup, which I haven’t looked into.

Visiting Node 1 redirects to the Load-balanced URL with Identity Server with no error, which I expect.
Visiting Node 2 redirects to the Load-balanced URL however is presented with the An unknown error has occurred. (#200) as unauthorized_client and with an option to go back to the login page.

You can however access the API and Swagger documentation on individual nodes. For example setting up a Health Monitor for your Load Balancer https://<orchestrator>/api/Status/Get and checking for it to return a HTTP 200 OK

@eric.kalkstein I think the question is more around the Error when accessing the root path on the secondary node as it does not behave in the same way as the primary node.

Secondary Node
image

Primary Node which has the client_id, Callback, etc in the URL
image

I’ll also note (recognizing it isn’t supported) that if you have a valid session already, visiting the primary node’s FQDN will redirect you to the Load-balanced URL to authenticate, after logging in it will redirect back to the Primary nodes FQDN.

But I would be curious to the behaviour of the Secondary Node / Is there a missing configuration that would make it more seamless should a user happen to try visiting the specific node?

As I have understood it (installed 2 Orchestrators in 21.4 last week.) You first set up the first Node and use set that it should export the parameters file for use when installing node 1+X. In that parameters.json file there are some settings in the end referring to what the main Identity Server is located. And im guessing that has something to do why you can access it from the First node and from the loadbalancer FQDN but not from the 1+X node.

Yes that is correct as part of the installation of node 1, you provide the OUTPUT_PARAMETERS_FILE property to generate the JSON file during initial installation and then passing SECONDARY_NODE=1 along with PARAMETERS_FILE referencing the JSON file to the additional node during installation.

In the file there is Properties details such as hostname, public_url, databases hosts, connection strings, along with the local features that are installed.

After the Properties you have the IdentitySeedInfo which includes MasterClient, OrchestratorS2SClient, OrchestratorOpenIdClient, and OrchestratorRopcClient.

Of those OrchestratorOpenIdClient is the only one that has a list for LocalRedirectUris, and LocalPostLogoutUris which include localhost, <hostname>, and fqdn. The others include Client Name, ID, Secret with the remaining values empty or null.

I would assume the required configuration could be changed after the fact, but haven’t found the settings/properties/configuration.

I installed Orchestrator in my test environment using a dummy load balancer URL, thinking i could access each machine individually. It seems it’s not possible to access the second node because of identity, or at least no one knows how.

Now i got a working load balancer URL which i am trying to configure on both machines by :

  • adding the binding / certificate in IIS
  • replacing the values in UiPath.Orchestrator.dll.config:
    add key="IdentityServer.Integration.Authority" value="https://[loadbalancerURL]/identity" /
    add key="Auth.OAuth.SharedRobotOAuthAuthority" value="https://[loadbalancerURL]/identity" /
    add key="ExternalAuth.System.OpenIdConnect.Authority" value="https://[loadbalancerURL]/identity"" /
    
    add key="ExternalAuth.System.OpenIdConnect.RedirectUri" value="https://[loadbalancerURL]/signinsystemopenidconnect" /
    add key="ExternalAuth.System.OpenIdConnect.PostLogoutRedirectUri" value="https://[loadbalancerURL]" /
    
  • replacing the values in appsettings.Production.json (Identity folder) :
    "AppSettings": {
        "IdentityServerAddress": "https://[loadbalancerURL]/identity",
        "SigningCredentialSettings": {
          "StoreLocation": {
            "Name": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            "Location": "LocalMachine",
            "NameType": "Thumbprint"
          }
        },
        "OrchestratorUrl": "[loadbalancerURL]",
    

However i now have the below error, and still can access the login screen on both nodes using the local URL (which is strange as it’s not defined in the config files anymore) :

UiPath IdentityServer could not be contacted at "https://[loadbanlancerURL]/identity/.well-known/openid-configuration"System.Net.Http.HttpRequestException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
 ---> System.Net.Sockets.SocketException (10060): A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
   at async ValueTask<Stream> System.Net.Http.ConnectHelper.ConnectAsync(string host, int port, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at async ValueTask<Stream> System.Net.Http.ConnectHelper.ConnectAsync(string host, int port, CancellationToken cancellationToken)
   at TResult System.Threading.Tasks.ValueTask<TResult>.get_Result()
   at TResult System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable<TResult>+ConfiguredValueTaskAwaiter.GetResult()
   at async ValueTask<ValueTuple<Socket, Stream, TransportContext, HttpResponseMessage>> System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, bool allowHttp2, CancellationToken cancellationToken)
   at TResult System.Threading.Tasks.ValueTask<TResult>.get_Result()
   at TResult System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable<TResult>+ConfiguredValueTaskAwaiter.GetResult()
   at async ValueTask<ValueTuple<HttpConnection, HttpResponseMessage>> System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at TResult System.Threading.Tasks.ValueTask<TResult>.get_Result()
   at TResult System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable<TResult>+ConfiguredValueTaskAwaiter.GetResult()
   at async ValueTask<(HttpConnectionBase connection, bool isNewConnection, HttpResponseMessage failureResponse)> System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at TResult System.Threading.Tasks.ValueTask<TResult>.get_Result()
   at TResult System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable<TResult>+ConfiguredValueTaskAwaiter.GetResult()
   at async Task<HttpResponseMessage> System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, bool doRequestAuth, CancellationToken cancellationToken)
   at async Task<HttpResponseMessage> System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at async Task<HttpResponseMessage> System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task<HttpResponseMessage> sendTask, HttpRequestMessage request, CancellationTokenSource cts, bool disposeCts)
   at async Task UiPath.Orchestrator.Security.Auth.SystemOpenIdConnectAuthenticationExtensions.TestIdentityServerConnection(string authority)
System.Net.Sockets.SocketException (10060): A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
   at async ValueTask<Stream> System.Net.Http.ConnectHelper.ConnectAsync(string host, int port, CancellationToken cancellationToken)

Any idea what is missing?

Your configuration looks about right. With your LB configured have you also setup health checks for the node members in the LB Pool? Is it maybe not detecting them as online therefore not routing to them?

Other thoughts are have you started each of the Application Pools and restarted the IIS Site for the changes to take affect? As the configuration has been moved out of the Web.Config file, IIS Site no longer auto-restarts when you save the configurations.

Your error message to me would indicate that either you are not able to route to the resource or the resource is not listening. A quick test is you should be able to reach the API / Swagger or the Orchestrator Login Page without hitting the Identity Service yet.

https://[loadbalancerURL]/swagger
https://[loadbalancerURL]/api/Status/Get should return an HTTP 200