---
title: 'Tutorial: Manage Cluster Settings Using Web API and sacli'
canonical: https://openvpn.net/as-docs/v3/tutorials/tutorial--manage-cluster-settings-using-the-access-server-cli/
product: Access Server Docs
description: Manage OpenVPN Access Server clusters using the Web API or sacli. Learn how to create clusters, add and remove nodes, configure Round Robin DNS, monitor cluster health, and manage cluster-wide settings.
---

# Tutorial: Manage Cluster Settings Using Web API and sacli

## Overview

Access Server clustering provides active-active redundancy and horizontal scaling by allowing multiple Access Server nodes to share configuration and user data through a common database backend.

This tutorial shows how to create and manage clusters, add and remove nodes, configure Round Robin DNS settings, view cluster status, and execute remote API calls on cluster members using either the Web API or `sacli`.

To learn more about clustering, refer to [Access Server Clustering](https://openvpn.net/access-server/features/server-clustering-feature/).

## Prerequisites

- Access Server 3.1.0 or newer (for using the Web API).
- Root privileges on your Access Server console.
- A configured MySQL database for cluster storage.
- (Optional) A remote machine for running API calls.

## Choose a management method

This tutorial provides two ways to manage cluster settings:

| **Method** | **Availability** | **Best for** |
| --- | --- | --- |
| Web API (`apicall`) | Access Server 3.1.0 and newer | Automation and API workflows |
| `sacli` commands | All supported Access Server versions | Direct server administration |

Use the method that best fits your environment and workflow.

> **Important**
>
> The cluster API specification may change between Access Server releases. Always verify the API documentation for your current version. Refer to [Tutorial: Test the New Web API (OpenAPI) in Access Server 3.0](https://openvpn.net/as-docs/v3/tutorials/tutorial--test-the-new-web-api--openapi--in-access-server-3-0.md).

## Before you begin

All examples in this tutorial assume you're connected to the Access Server console with root privileges.

### Placeholder values

Replace the following placeholders with values appropriate for your environment:

| **Placeholder** | **Description** |
| --- | --- |
| `<NODE_NAME>` | Cluster node name |
| `<MYSQL_URL>` | MySQL server hostname or IP address |
| `<MYSQL_PORT>` | MySQL server port |
| `<MYSQL_USER>` | MySQL username |
| `<MYSQL_PASSWORD>` | MySQL password |
| `<ACCESS_SERVER_IP>` | Access Server node IP address |
| `<NEW_ACCESS_SERVER_IP>` | Updated Access Server node IP address |
| `<RRDNS_DOMAIN>` | Round Robin DNS hostname |
| `<KEY>` | Configuration key |
| `<VALUE>` | Configuration value |

## Manage clusters using the Web API

> **Note**
>
> This method requires Access Server 3.1.0 or newer.

> **Tip**
>
> This tutorial uses the `sacli apicall` command, but you can also use cURL or the Swagger UI. Refer to [Tutorial: Test the New Web API (OpenAPI) in Access Server 3.0](https://openvpn.net/as-docs/v3/tutorials/tutorial--test-the-new-web-api--openapi--in-access-server-3-0.md).

### Create and manage a cluster

#### Create a cluster

```
sacli --method POST --url 'api/cluster/create' --value '{"name":"<NODE_NAME>","mysql_uri_parts":{"host":"<MYSQL_URL>","port":<MYSQL_PORT>,"username":"<MYSQL_USER>","password":"<MYSQL_PASSWORD>"},"api_endpoint":"https://<ACCESS_SERVER_IP>:943"}' apicall
```

#### Create a cluster with Round Robin DNS

```
sacli --method POST --url 'api/cluster/create' --value '{"name":"<NODE_NAME>","mysql_uri_parts":{"host":"<MYSQL_URL>","port":<MYSQL_PORT>,"username":"<MYSQL_USER>","password":"<MYSQL_PASSWORD>"},"api_endpoint":"https://<ACCESS_SERVER_IP>:943","rr_dns_hostname":"<RRDNS_DOMAIN>","rr_update_node":true,"rr_dns_new_nodes":true}' apicall
```

**Example output**

```
null
```

#### Join a node to a cluster

```
sacli --method POST --url 'api/cluster/join' --value '{"name":"<NODE_NAME>","mysql_uri_parts":{"host":"<MYSQL_URL>","port":<MYSQL_PORT>,"username":"<MYSQL_USER>","password":"<MYSQL_PASSWORD>"},"api_endpoint":"https://<ACCESS_SERVER_IP>:943"}' apicall
```

**Example output**

```
null
```

#### Leave a cluster

```
sacli --method POST --url 'api/cluster/leave' --value '{}' apicall
```

**Example output**

```
null
```

### Monitor cluster health

#### View the status of a node

```
sacli --method GET --url 'api/cluster/node-status' --value '{}' apicall
```

**Example output:**

```
{"status":"reachable","as_version":"3.1.0 (e22fe316)","as_build":"e22fe316","license":"2","user_data":{"n_clients":0,"ovpn_dco_ver":" ovpn-dco version 0.2.20251017-2+noble\n","ovpn_dco_available":true},"current_users":0,"auth":"local","vlis":"all interfaces","vpn_port":"tcp/443, udp/1194","cipher":"AES-256-CBC","osi_layer":"3 (routing/NAT)","vserv_priv_access":"NAT","server_name":"192.0.2.5","activation_type":"Not Activated"}
```

#### View the status of all nodes

```
sacli --method GET --url 'api/cluster/status' --value '{}' apicall
```

**Example output:**

```
{"Node1":{"api_endpoint":"https://192.0.2.5:943","certificate_fingerprint":"9E:FC:7A:18:58:BF:67:6A:AA:3C:AD:07:86:E1:54:9D:D8:60:6D:A2:DB:F8:81:92:BB:0B:48:D5:00:96:4C:92","name":"Node1","restart_pending":false,"status":"reachable","as_version":"3.1.0 (e22fe316)","as_build":"e22fe316","license":"2","user_data":{"n_clients":0,"ovpn_dco_ver":" ovpn-dco version 0.2.20251017-2+noble\n","ovpn_dco_available":true},"current_users":0,"auth":"local","vlis":"all interfaces","vpn_port":"tcp/443, udp/1194","cipher":"AES-256-CBC","osi_layer":"3 (routing/NAT)","vserv_priv_access":"NAT","server_name":"192.0.2.5","activation_type":"Not Activated"}}
```

#### View ClusterDB contents

```
sacli --method GET --url 'api/cluster/nodes/list' --value '{}' apicall
```

**Example output:**

```
{"nodes":{"Node1":{"api_endpoint":"https://192.0.2.5:943","certificate_fingerprint":"57:AE:CC:0B:21:43:15:DD:A8:AF:59:93:19:4B:5E:88:41:65:59:2B:5B:43:61:B9:DB:D7:B7:C7:69:E9:22:A0","name":"Node1","restart_pending":false}}}
```

### Configure Round Robin DNS

#### View Round Robin DNS settings

```
sacli --method GET --url 'api/cluster/props' --value '{}' apicall
```

**Example output:**

```
{"props":{"rr_dns_hostname":"rrdns-nodes.example.com","rr_dns_new_nodes":true}}
```

#### Configure Round Robin DNS after creating the cluster

```
sacli --method POST --url 'api/cluster/props' --value '{"rr_dns_hostname": "<RRDNS_DOMAIN>","rr_dns_new_nodes": true}' apicall
```

**Example output:**

```
null
```

#### Update all node hostnames

```
sacli --method PUT --url 'api/cluster/rr-dns-hostname' --value '{}' apicall
```

**Example output:**

```
null
```

### Modify cluster settings

#### Change a node API endpoint

```
sacli --method POST --url 'api/cluster/Node1/set' --value '{"api_endpoint": "https://<NEW_ACCESS_SERVER_IP>:943"}' apicall
```

**Example output:**

```
null
```

### Execute commands on remote nodes

You can execute API calls on one cluster node from another cluster node.

For example, assume you have two nodes:

- Node1
- Node2

Run the following commands from **Node1** to execute API calls on **Node2**.

#### View server information from a remote node

```
sacli --node_name "Node2" --method GET --url '/api/server/info' ClusterRPC
```

**Example output:**

```
{"version":"3.1.0","build":"e22fe316","web_version":"51aa6248","web_override":false,"client_version":35,"os_distribution":"Ubuntu 24.04.4 LTS","architecture":"x86_64","cores":2,"system_cores":2,"os_hostname":"Node2"}
```

#### Remove a remote node from the cluster

```
sacli --node_name "Node2" --method POST --url 'api/cluster/leave' ClusterRPC
```

**Example output:**

```
null
```

## Manage clusters using sacli

This method works on all supported Access Server versions.

### Create and manage a cluster

#### Create a cluster

```
sacli --mysql_str mysql://<MYSQL_USER>:<MYSQL_PASSWORD>@<MYSQL_URL>:<MYSQL_PORT> --convert_db --node_name '<NODE_NAME>' ClusterNew
```

**Example output:**

```
(200, [b'application/json'], b'null')
```

#### Join a node to a cluster

```
sacli --mysql_str mysql://<MYSQL_USER>:<MYSQL_PASSWORD>@<MYSQL_URL>:<MYSQL_PORT> --node_name '<NODE_NAME>' ClusterJoin
```

**Example output:**

```
(200, [b'application/json'], b'null')
```

#### Display the ClusterDB URL

Use this command to display the ClusterDB connection string required for additional nodes to join the cluster.

```
sacli ClusterJoinURL
```

**Example output:**

```
mysql://brandonmysql:Pass123ABC@cluster-brandon.example.com:3306
```

#### Leave a cluster

```
sacli ClusterLeave
```

**Example output:**

```
(200, [b'application/json'], b'null')
```

### Monitor cluster health

#### View the status of all nodes

```
sacli ClusterQuery
```

**Example output:**

```
{
  "Node1": {
    "api_endpoint": "https://192.0.2.5:943",
    "certificate_fingerprint": "58:DF:12:B8:D1:A7:D4:F2:77:23:9F:5E:D6:69:B2:55:10:5F:6B:BF:6E:6D:CC:E9:1B:92:93:30:28:9B:C0:A6",
    "name": "Node1"
  },
  "_INTERNAL": {
    "certs_db": "mysql://mysql://brandonmysql:Pass123ABC@cluster-brandon.example.com:3306/as_certs",
    "cluster_db": "mysql://mysql://brandonmysql:Pass123ABC@cluster-brandon.example.com:3306/as_cluster",
    "config_db": "mysql://mysql://brandonmysql:Pass123ABC@cluster-brandon.example.com:3306/as_config",
    "config_db_local": "sqlite:////usr/local/openvpn_as/etc/db/config_local.db",
    "notification_db": "mysql://mysql://brandonmysql:Pass123ABC@cluster-brandon.example.com:3306:25060/as_notification",
    "profile": "Default",
    "user_prop_db": "mysql://mysql://brandonmysql:Pass123ABC@cluster-brandon.example.com:3306/as_userprop"
  }
}
```

#### View ClusterDB contents

```
sacli ClusterNodesStatus
```

**Example output:**

```
{
  "Node1": {
    "activation_type": "Not Activated",
    "api_endpoint": "https://192.0.2.5:943",
    "as_build": "e22fe316",
    "as_version": "3.1.0 (e22fe316)",
    "auth": "local",
    "certificate_fingerprint": "58:DF:12:B8:D1:A7:D4:F2:77:23:9F:5E:D6:69:B2:55:10:5F:6B:BF:6E:6D:CC:E9:1B:92:93:30:28:9B:C0:A6",
    "cipher": "AES-256-CBC",
    "current_users": 0,
    "license": "2",
    "name": "Node1",
    "osi_layer": "3 (routing/NAT)",
    "restart_pending": false,
    "server_name": "192.0.2.5",
    "status": "reachable",
    "user_data": {
      "n_clients": 0,
      "ovpn_dco_available": true,
      "ovpn_dco_ver": " ovpn-dco version 0.2.20251017-2+noble\n"
    },
    "vlis": "all interfaces",
    "vpn_port": "tcp/443, udp/1194",
    "vserv_priv_access": "NAT"
  }
}
```

### Configure cluster-wide settings

Cluster-wide settings are shared across all nodes.

#### Change a cluster-wide setting

```
sacli --key "<KEY>" --value "<VALUE>" ClusterPut
```

For example, change the authentication method to LDAP:

```
sacli --key "auth.module.type" --value "ldap" ClusterPut
```

Restart Access Server:

```
sacli start
```

Repeat the restart on the remaining cluster nodes.

### Configure node-specific settings

Node-specific settings apply only to the selected node.

#### Change a node-specific setting

```
sacli --key "<KEY>" --value "<VALUE>" --prof "<NODE_NAME>" ClusterPut
```

For example, configure a node-specific access rule:

```
sacli --key "vpn.server.routing.private_network.0" --value "198.51.100.0/24" --prof "Node1" ClusterPut
```

Restart Access Server:

```
sacli start
```

### Configure Round Robin DNS

#### Configure a Round Robin DNS hostname after creating the cluster

```
sacli --key "rr_dns_hostname" --value "<RRDNS_DOMAIN>" ClusterPut
```

Restart Access Server:

```
sacli start
```

Repeat the restart on the remaining cluster nodes.

#### Allow new nodes to use the Round Robin DNS hostname

```
sacli --key "rr_dns_new_nodes" --value "true" ClusterPut
```

Restart Access Server:

```
sacli start
```

Repeat the restart on the remaining cluster nodes.

#### Update all node hostnames

```
sacli ClusterUpdateRRDNSAll
```

Restart Access Server:

```
sacli start
```

Repeat the restart on the remaining cluster nodes.

## Troubleshooting

Access Server includes debug flags that can help troubleshoot clustering issues and determine how cluster operations are being processed.

Refer to:

- [DEBUG_CLUSTER1](https://openvpn.net/as-docs/v3/tutorials/tutorial--debug-flags/#debug_cluster-1)
- [Debug flags step](https://openvpn.net/as-docs/v3/tutorials/tutorial--debug-flags/#step-2--select-the-needed-debug-flag)

> **Tip**
>
> Debug flags can generate large amounts of log data. After collecting the necessary information, remove the debug flag and restart Access Server to prevent excessive logging.

> **Important**
>
> **Recommended**
>
> For complex issues, open a [support ticket](https://support.openvpn.com/) and share the relevant log output. Our support team can help analyze the logs and guide you toward a resolution.

## Related tutorials

- [Tutorial: How to Set Up an Access Server Cluster](https://openvpn.net/as-docs/v3/tutorials/tutorial--set-up-access-server-cluster.md)
- [Tutorial: Test the New Web API (OpenAPI) in Access Server 3.0](https://openvpn.net/as-docs/v3/tutorials/tutorial--test-the-new-web-api--openapi--in-access-server-3-0.md)
- [Tutorial: Manage Failover Settings Using the Access Server CLI](https://openvpn.net/as-docs/v3/tutorials/tutorial--manage-failover-from-the-cli.md)

---

Prev: [Tutorial: Smart Routing with Access Server Clustering and AWS Route 53](https://openvpn.net/as-docs/v3/tutorials/tutorial--smart-routing-aws.md)
Next: [Tutorial: Manage Failover Settings Using the Access Server CLI](https://openvpn.net/as-docs/v3/tutorials/tutorial--manage-failover-from-the-cli.md)
Index: https://openvpn.net/as-docs/llms.txt
