> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/web/get-started/faq/load_balancing.md).

# Manual Load Balancing with HAProxy

World's #1 PDF SDK Library for Web, Mobile, Server, Desktop

WebViewer Server comes with a load balancer known as `HAProxy` located at our pdftron/wv-loadbalancer repository on DockerHub. This can be used in conjunction with WebViewer Server to load balance.

This guide details how to manage load balancing using the HAProxy image, in a way that is extensible to any environment.

### How it works

HAProxy contains network entries called `webAwebBwebC` ... and so on. These entries indicate the location of a server that HAProxy can send requests to. The methods here will modify these entries to point at the correct server.

By default WebViewer Server does all load balancing using the [leastconn](https://cbonte.github.io/haproxy-dconv/1.9/configuration.html) method. This sends incoming requests to servers with the smallest number of active connections.

### Setting initial servers

You can set the initial locations of these `webX` entries by setting the environment variables `INITIAL_NODE_AINITIAL_NODE_B` ... up to `INITIAL_NODE_F` on the `wv-loadbalancer` image. HAProxy will initially send requests to any healthy and responding servers set in these variables.

### Setting servers dynamically

To set servers dynamically with HAProxy you can take advantage of something known as [TCP Management](https://cbonte.github.io/haproxy-dconv/1.9/management.html) - this can be used to change these `webX` entries to the current location of a server.

There are several ways to send requests to the server with this method, but all commands to HAProxy will be sent with the same structure.

`set server nodes/[webX] addr [WVS ip address] [WVS port]`

* Locally in the server hosting HAProxy using sockets - this can be done through a socket communication application such as socat

{% tabs %}
{% tab title="Bash" %}
{% code lineNumbers="true" %}

```bash
socat /var/run/hapee.sock set server nodes/webA addr 192.168.1.1 8090
```

{% endcode %}
{% endtab %}
{% endtabs %}

* Remotely by setting `ENABLE_TCP_MANAGEMENT` to true on the Docker image and sending requests to the TCP Management port `4893` wherever the balancer is located. The following code does this using Node.js.

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
const connectSocket = (balancer) => {
      return new Promise((resolve, reject) => {
        var socket = new net.createConnection(4893, balancer);
        socket.on('connect', () => {
            resolve(socket);
        });

        socket.on('error', () => {
            reject(balancer + ": Balancer not online.");
        });
      });
};
const writeSocket = (command, socket, forceClose) => {
      return new Promise((resolve, reject) => {
          console.log(command);
          socket.write(command, (error, data) => {
            if (error) {
              console.log(error);
              reject();
            }
          });

          socket.on('data', (data) => {
              //console.log("balancer response:" + data);
              socket.end();
              resolve(data);
          });
      });
};
command = "set server nodes/webA addr 192.168.1.1 8090\n"
var socket = await connectSocket("insert balancer ip here");
await writeSocket(command, socket, false)
```

{% endcode %}
{% endtab %}
{% endtabs %}

The above code sets `webA` to be the Webviewer Server at `192.168.1.1:8090`. HAProxy will now send `webA` requests to this server.

Whenever a change occurs, you can dynamically rewrite remotely using the above code. The changes will instantly occur. More commands can be found at the [HAProxy Management documentation](https://cbonte.github.io/haproxy-dconv/1.9/management.html)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/web/get-started/faq/load_balancing.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
