copyright 1998-2017 by Mark Verboom
ipv6 ready RSS Feed Switch to English

Ga terug naar Nieuws

Thinlinc reverse proxy

Naar blog index

Monday, 19 October, 2015

Thinlinc reverse proxy

I ran into this program a while ago when I wanted to run the HTML5 ThinLinc client behind a reverse proxy. The HTML5 client has a number of references in it (and a redirect) that refers to the root of the webserver. So serving the client from a url like

https://portal.external.com/thinlinc

just doesn't work.

But we have nginx and with some pointers from the excellent people at Cendio I got it working :)

To make the setup a little bit more clear, I wanted to do this:

The portal.external.com server is a system serving multiple web resources. Because they are all within the same namespace (portal.external.com), the content needs to be moved in their own namespace. So for ThinLinc this would mean that when the user requests portal.external.com/thinlinc they get the ThinLinc HTML5 client.

To make this work, the content that is being served by the ThinLinc server needs to be rewritten, so that all the resources the webbrowser wants to retrieve are moved to the correct namespace. During this test I used a ThinLinc 4.4.0 installation.

On the ThinLinc server you need to check which name the agent is configured to. The HTML5 client will use this name in it's code to redirect. This name needs to be intercepted and rewritten so it points to the webserver. In our example the agent is pointing to thinlinc.internal.com.

Nginx version < 1.9.4

Nginx default has the option to rewrite content with the sub_filter directive. However, versions before 1.9.4 can only have one directive. On versions before 1.9.4 I have used the following http substitution filter withi nginx, which works great:

ngx_http_substitutions_filter_module

The configuration I used looks like this:

location /thinlinc/ {
proxy_pass https://thinlinc.internal.com/;
proxy_redirect /main/ /thinlinc/main/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
subs_filter ="/ ="/thinlinc/;
subs_filter :443/main/agent :443/thinlinc/main/agent;
subs_filter thinlinc.internal.com $host;
subs_filter websocket/ thinlinc/websocket/;
}

Nginx version => 1.9.4

With Nginx version 1.9.4 and up it is possible to use multiple sub_filter directives, so it is not required to use additional modules. With the new setup the cofiguration looks like this:

location /thinlinc/ {
proxy_pass https://thinlinc.internal.com/;
proxy_redirect /main/ /thinlinc/main/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
sub_filter ="/ ="/thinlinc/;
sub_filter :443/main/agent :443/thinlinc/main/agent;
sub_filter thinlinc.internal.com $host;
sub_filter websocket/ thinlinc/websocket/;
sub_filter_once off;
}

The only extra directive is the sub_filter_once. This is default on. By turning this off multiple instances of one match will be replaced.

What it does

The above configurations take care of the following problems.

Requesting the root of the ThinLinc website redirects to /main. In this case we want to add the base folder to that. This is what the proxy_redirect takes care of:

proxy_redirect /main/ /thinlinc/main/;

The next bit is for rewriting links that are generated in the HTML code by ThinLinc. The following 2 filters put the extra thinlinc folder reference in:

="/ ="/thinlinc/;
:443/main/agent :443/thinlinc/main/agent;

Take care that if you're running the ThinLinc on the default port 300, you replace the 443 by 300 (or whatever port you're running the ThinLinc webaccess on.

The last substitution is for the page that has the link to the websocket in it. That also needs to be rewritten.

websocket/ thinlinc/websocket/;

Last the http headers need to be passed to the ThinLinc server for upgrading the HTTP connection to a websocket, otherwise the HTML5 client won't be able to create the websocket connection.

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

And that's it, it seems to work fine :)

Update for Thinlinc 4.5

Thinlinc 4.5 has some changes to the way the HTML5 client works. This breaks the above configuration for Nginx. The problem seemed to be the cookie that was set. Adding the following line to the configuration seems to fix the problem:

proxy_cookie_path / /thinlinc/;