.. meta:: :description: Learn how to use ThinLinc Web Access behind a reverse proxy. .. _reverse_proxy: Reverse proxy ------------- Running :ref:`ThinLinc Web Access ` behind a reverse proxy is a way to integrate ThinLinc into existing infrastructure or meet organizational requirements. This chapter explains the requirements ThinLinc Web Access places on a reverse proxy to function correctly. In a ThinLinc cluster, users start at the ThinLinc master server, but their actual sessions run on individual agents to which ThinLinc Web Access automatically redirects traffic. If a reverse proxy is used, it must be configured to handle this routing and forward the connection to the correct internal agent. To support a proxy environment, specific ThinLinc parameters should be updated. This involves enabling the :file:`X-Forwarded-For` header to identify client IPs (see :ref:`forwarding_client_ip`) and updating :servconf:`/webaccess/login_page` to match the public URL for the login page. Please note that this is a conceptual guide intended to illustrate the routing logic. You must adapt the configuration to match your environment. ThinLinc specific information ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When a user starts a session, the master redirects the client to a specific path in the format :file:`/connect//`. This identifier is determined by the :servconf:`/vsmagent/agent_hostname` (or the agent's IP if unset). The proxy must capture this path to correctly route the traffic to the agent service. .. note:: In a scenario where a large number of simultaneous ThinLinc sessions are directed through a single reverse proxy, the reverse proxy might become a network bottleneck. In such cases, make sure to take ThinLinc's bandwidth requirements into account in your reverse proxy architecture. .. _reverse_proxy_basic_setup: Basic proxy setup ~~~~~~~~~~~~~~~~~ Below is an example Nginx configuration for a setup with a single ThinLinc server running both the master and agent services. All requests to the root :file:`/` are forwarded to the ThinLinc backend. Pay special attention to the path handler :file:`/connect/tl.internal.example.com/`. .. code:: nginx server { listen 443 ssl; server_name tl.example.com; # ... (SSL configuration) ... proxy_read_timeout 999h; location / { proxy_pass https://tl.internal.example.com:300/; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; } location /connect/tl.internal.example.com/ { proxy_pass https://tl.internal.example.com:300/; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; } } ThinLinc Web Access relies on WebSocket connections to establish and maintain user sessions. Therefore, your proxy must set the Upgrade and Connection headers again. If this is not configured correctly, users will be able to load the login page but unable to start a session. Once the session is established, the proxy should allow the connection to remain open for long periods, even when the user is idle. Default proxy read timeouts are typically short and might abruptly disconnect inactive users. To avoid this, it is recommended to increase the proxy's read timeout. .. note:: Do not use the proxy timeout to enforce idle limits. If you wish to disconnect users after a specific period of inactivity, this should be configured within ThinLinc using the :option:`-MaxIdleTime` parameter. For more information, see :ref:`configuration_limiting_lifetime`. Multi-agent setup ~~~~~~~~~~~~~~~~~ In a ThinLinc cluster with more than one agent, follow the instructions in :ref:`reverse_proxy_basic_setup`, but replicate the agent-specific path handler for every additional agent, as in the example below. .. code:: nginx location /connect/agent1.internal.example.com/ { proxy_pass https://agent1.internal.example.com:300/; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; } Custom path configuration ~~~~~~~~~~~~~~~~~~~~~~~~~ You may also want to serve the entire ThinLinc Web Access interface from a specific sub-path, such as :file:`/subpath/`, instead of from the server root :file:`/`. This requires prefixing all of your ThinLinc path handlers. The master's path becomes :file:`/subpath/` and the agent paths will also be nested under it, such as :file:`/subpath/connect/agent1.internal.example.com/`. .. code:: nginx location /subpath/ { proxy_pass https://tl.internal.example.com:300/; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; } location /subpath/connect/tl.internal.example.com/ { proxy_pass https://tl.internal.example.com:300/; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; } location /subpath/connect/agent1.internal.example.com/ { proxy_pass https://agent1.internal.example.com:300/; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; } Distributed agents ~~~~~~~~~~~~~~~~~~ In complex or geographically distributed environments, you may not want to proxy all agent connections through a single entry point. A more scalable approach is to use a main proxy for the login page, which then redirects clients to their specific agent connections. .. code:: nginx location ~ /connect/tl.sweden.example.com/(.*) { return 307 https://tl.sweden.example.com/$1; } The redirection sends the client to a new hostname. This can be the agent server directly, if it is exposed on the network. Alternatively, it can be a dedicated proxy server configured to forward the traffic to the internal agent as below. .. code:: nginx server { listen 443 ssl; server_name tl.sweden.example.com; # ... (SSL configuration) ... location / { proxy_pass https://tl.internal.sweden.example.com:300/; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; } } The following configuration brings together all the concepts discussed in this guide for a more advanced example. .. code:: nginx server { listen 443 ssl; server_name tl.example.com; # ... (SSL configuration) ... proxy_read_timeout 999h; location /subpath/ { proxy_pass https://tl.internal.example.com:300/; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; } location /subpath/connect/tl.internal.example.com/ { proxy_pass https://tl.internal.example.com:300/; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; } location ~ /subpath/connect/tl.sweden.example.com/(.*) { return 307 https://tl.sweden.example.com/$1; } } server { listen 443 ssl; server_name tl.sweden.example.com; # ... (SSL configuration) ... location / { proxy_pass https://tl.internal.sweden.example.com:300/; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; } }