Tutorial: Manage Cluster Settings Using Web API and sacli
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.
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.
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 ( | Access Server 3.1.0 and newer | Automation and API workflows |
| 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.
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 |
|---|---|
| Cluster node name |
| MySQL server hostname or IP address |
| MySQL server port |
| MySQL username |
| MySQL password |
| Access Server node IP address |
| Updated Access Server node IP address |
| Round Robin DNS hostname |
| Configuration key |
| 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.
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"}' apicallCreate 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}' apicallExample 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"}' apicallExample output
null
Leave a cluster
sacli --method POST --url 'api/cluster/leave' --value '{}' apicallExample output
null
View the status of a node
sacli --method GET --url 'api/cluster/node-status' --value '{}' apicallExample 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 '{}' apicallExample 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 '{}' apicallExample 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}}}View Round Robin DNS settings
sacli --method GET --url 'api/cluster/props' --value '{}' apicallExample 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}' apicallExample output:
null
Update all node hostnames
sacli --method PUT --url 'api/cluster/rr-dns-hostname' --value '{}' apicallExample output:
null
Change a node API endpoint
sacli --method POST --url 'api/cluster/Node1/set' --value '{"api_endpoint": "https://<NEW_ACCESS_SERVER_IP>:943"}' apicallExample output:
null
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 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')
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"
}
}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.
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 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:
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.
Recommended
For complex issues, open a support ticket and share the relevant log output. Our support team can help analyze the logs and guide you toward a resolution.